mirror of
https://github.com/jekip/naive-ui-admin.git
synced 2026-03-01 00:23:11 +08:00
更新0.1.1版本
This commit is contained in:
111
src/views/dashboard/console/components/FluxTrend.vue
Normal file
111
src/views/dashboard/console/components/FluxTrend.vue
Normal file
@@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref, Ref } from 'vue';
|
||||
|
||||
import { useECharts } from '@/hooks/web/useECharts';
|
||||
|
||||
import { basicProps } from './props';
|
||||
|
||||
export default defineComponent({
|
||||
props: basicProps,
|
||||
setup() {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
|
||||
onMounted(() => {
|
||||
setOptions({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: '#019680',
|
||||
},
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: [
|
||||
'6:00',
|
||||
'7:00',
|
||||
'8:00',
|
||||
'9:00',
|
||||
'10:00',
|
||||
'11:00',
|
||||
'12:00',
|
||||
'13:00',
|
||||
'14:00',
|
||||
'15:00',
|
||||
'16:00',
|
||||
'17:00',
|
||||
'18:00',
|
||||
'19:00',
|
||||
'20:00',
|
||||
'21:00',
|
||||
'22:00',
|
||||
'23:00',
|
||||
],
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
type: 'solid',
|
||||
color: 'rgba(226,226,226,0.5)',
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
max: 80000,
|
||||
splitNumber: 4,
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
splitArea: {
|
||||
show: true,
|
||||
areaStyle: {
|
||||
color: ['rgba(255,255,255,0.2)', 'rgba(226,226,226,0.2)'],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
grid: { left: '1%', right: '1%', top: '2 %', bottom: 0, containLabel: true },
|
||||
series: [
|
||||
{
|
||||
smooth: true,
|
||||
data: [
|
||||
111, 222, 4000, 18000, 33333, 55555, 66666, 33333, 14000, 36000, 66666, 44444,
|
||||
22222, 11111, 4000, 2000, 500, 333, 222, 111,
|
||||
],
|
||||
type: 'line',
|
||||
areaStyle: {},
|
||||
itemStyle: {
|
||||
color: '#5ab1ef',
|
||||
},
|
||||
},
|
||||
{
|
||||
smooth: true,
|
||||
data: [
|
||||
33, 66, 88, 333, 3333, 5000, 18000, 3000, 1200, 13000, 22000, 11000, 2221, 1201,
|
||||
390, 198, 60, 30, 22, 11,
|
||||
],
|
||||
type: 'line',
|
||||
areaStyle: {},
|
||||
itemStyle: {
|
||||
color: '#019680',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
25
src/views/dashboard/console/components/Icons.ts
Normal file
25
src/views/dashboard/console/components/Icons.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import {
|
||||
CaretUpOutlined,
|
||||
CaretDownOutlined,
|
||||
UsergroupAddOutlined,
|
||||
BarChartOutlined,
|
||||
ShoppingCartOutlined,
|
||||
AccountBookOutlined,
|
||||
CreditCardOutlined,
|
||||
MailOutlined,
|
||||
TagsOutlined,
|
||||
SettingOutlined
|
||||
} from '@vicons/antd'
|
||||
|
||||
export default {
|
||||
CaretUpOutlined,
|
||||
CaretDownOutlined,
|
||||
UsergroupAddOutlined,
|
||||
BarChartOutlined,
|
||||
ShoppingCartOutlined,
|
||||
AccountBookOutlined,
|
||||
CreditCardOutlined,
|
||||
MailOutlined,
|
||||
TagsOutlined,
|
||||
SettingOutlined
|
||||
}
|
||||
36
src/views/dashboard/console/components/VisiTab.vue
Normal file
36
src/views/dashboard/console/components/VisiTab.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<div class="mt-4">
|
||||
<NRow :gutter="24">
|
||||
<NCol :span="24">
|
||||
<n-card content-style="padding: 0;" :bordered="false">
|
||||
<n-tabs
|
||||
type="line"
|
||||
size="large"
|
||||
:tabs-padding="20"
|
||||
pane-style="padding: 20px;"
|
||||
>
|
||||
<n-tab-pane name="流量趋势">
|
||||
<FluxTrend/>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="访问量">
|
||||
<VisitAmount/>
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</n-card>
|
||||
</NCol>
|
||||
</NRow>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref, Ref } from 'vue';
|
||||
import FluxTrend from './FluxTrend.vue'
|
||||
import VisitAmount from './VisitAmount.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: { FluxTrend, VisitAmount },
|
||||
setup() {
|
||||
|
||||
return {};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
61
src/views/dashboard/console/components/VisitAmount.vue
Normal file
61
src/views/dashboard/console/components/VisitAmount.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref, Ref } from 'vue';
|
||||
import { useECharts } from '@/hooks/web/useECharts';
|
||||
import { basicProps } from './props';
|
||||
|
||||
export default defineComponent({
|
||||
props: basicProps,
|
||||
setup() {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
|
||||
onMounted(() => {
|
||||
setOptions({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: '#019680',
|
||||
},
|
||||
},
|
||||
},
|
||||
grid: { left: '1%', right: '1%', top: '2 %', bottom: 0, containLabel: true },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: [
|
||||
'1月',
|
||||
'2月',
|
||||
'3月',
|
||||
'4月',
|
||||
'5月',
|
||||
'6月',
|
||||
'7月',
|
||||
'8月',
|
||||
'9月',
|
||||
'10月',
|
||||
'11月',
|
||||
'12月',
|
||||
],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
max: 8000,
|
||||
splitNumber: 4,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: [3000, 2000, 3333, 5000, 3200, 4200, 3200, 2100, 3000, 5100, 6000, 3200, 4800],
|
||||
type: 'bar',
|
||||
barMaxWidth: 80,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
17
src/views/dashboard/console/components/props.ts
Normal file
17
src/views/dashboard/console/components/props.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { PropType } from 'vue';
|
||||
|
||||
export interface BasicProps {
|
||||
width: string;
|
||||
height: string;
|
||||
}
|
||||
|
||||
export const basicProps = {
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: '280px',
|
||||
},
|
||||
};
|
||||
287
src/views/dashboard/console/console.vue
Normal file
287
src/views/dashboard/console/console.vue
Normal file
@@ -0,0 +1,287 @@
|
||||
<template>
|
||||
<div class="console">
|
||||
|
||||
<!--数据卡片-->
|
||||
<n-grid cols="1 s:2 m:3 l:4 xl:4 2xl:4" responsive="screen" :x-gap="12" :y-gap="8" :cols="4">
|
||||
<n-grid-item>
|
||||
<NCard title="访问量" :segmented="{ content: 'hard', footer:'hard' }" size="small" :bordered="false">
|
||||
<template #header-extra>
|
||||
<n-tag type="success">日</n-tag>
|
||||
</template>
|
||||
<div class="py-1 px-1 flex justify-between">
|
||||
<CountTo :startVal="1" :endVal="visits.dayVisits" class="text-3xl"/>
|
||||
</div>
|
||||
<div class="py-1 px-1 flex justify-between ">
|
||||
<div class="text-sn">
|
||||
日同比<CountTo :startVal="1" suffix="%" :endVal="visits.rise"/>
|
||||
<n-icon size="12" style="color: #00ff6f">
|
||||
<component is="CaretUpOutlined"/>
|
||||
</n-icon>
|
||||
</div>
|
||||
<div class="text-sn">
|
||||
周同比<CountTo :startVal="1" suffix="%" :endVal="visits.decline"/>
|
||||
<n-icon size="12" style="color: #ffde66">
|
||||
<component is="CaretDownOutlined"/>
|
||||
</n-icon>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex justify-between ">
|
||||
<div class="text-sn">
|
||||
总访问量:
|
||||
</div>
|
||||
<div class="text-sn">
|
||||
<CountTo :startVal="1" :endVal="visits.amount"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</NCard>
|
||||
</n-grid-item>
|
||||
<n-grid-item>
|
||||
<NCard title="销售额" :segmented="{ content: 'hard', footer:'hard' }" size="small" :bordered="false">
|
||||
<template #header-extra>
|
||||
<n-tag type="info">周</n-tag>
|
||||
</template>
|
||||
<div class="py-1 px-1 flex justify-between">
|
||||
<CountTo prefix="¥" :startVal="1" :endVal="saleroom.weekSaleroom" class="text-3xl"/>
|
||||
</div>
|
||||
<div class="py-2 px-2 flex justify-between ">
|
||||
<div class="text-sn flex-1">
|
||||
<n-progress
|
||||
type="line"
|
||||
:percentage="saleroom.degree"
|
||||
:indicator-placement="'inside'"
|
||||
processing
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex justify-between ">
|
||||
<div class="text-sn">
|
||||
总销售额:
|
||||
</div>
|
||||
<div class="text-sn">
|
||||
<CountTo prefix="¥" :startVal="1" :endVal="saleroom.amount"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</NCard>
|
||||
</n-grid-item>
|
||||
<n-grid-item>
|
||||
<NCard title="订单量" :segmented="{ content: 'hard', footer:'hard' }" size="small" :bordered="false">
|
||||
<template #header-extra>
|
||||
<n-tag type="warning">周</n-tag>
|
||||
</template>
|
||||
<div class="py-1 px-1 flex justify-between">
|
||||
<CountTo :startVal="1" :endVal="orderLarge.weekLarge" class="text-3xl"/>
|
||||
</div>
|
||||
<div class="py-1 px-1 flex justify-between ">
|
||||
<div class="text-sn">
|
||||
日同比<CountTo :startVal="1" suffix="%" :endVal="orderLarge.rise"/>
|
||||
<n-icon size="12" style="color: #00ff6f">
|
||||
<component is="CaretUpOutlined"/>
|
||||
</n-icon>
|
||||
</div>
|
||||
<div class="text-sn">
|
||||
周同比<CountTo :startVal="1" suffix="%" :endVal="orderLarge.rise"/>
|
||||
<n-icon size="12" style="color: #ffde66">
|
||||
<component is="CaretDownOutlined"/>
|
||||
</n-icon>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex justify-between ">
|
||||
<div class="text-sn">
|
||||
转化率:
|
||||
</div>
|
||||
<div class="text-sn">
|
||||
<CountTo :startVal="1" suffix="%" :endVal="orderLarge.amount"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</NCard>
|
||||
</n-grid-item>
|
||||
<n-grid-item>
|
||||
<NCard title="成交额" :segmented="{ content: 'hard', footer:'hard' }" size="small" :bordered="false">
|
||||
<template #header-extra>
|
||||
<n-tag type="error">月</n-tag>
|
||||
</template>
|
||||
<div class="py-1 px-1 flex justify-between">
|
||||
<CountTo prefix="¥" :startVal="1" :endVal="volume.weekLarge" class="text-3xl"/>
|
||||
</div>
|
||||
<div class="py-1 px-1 flex justify-between ">
|
||||
<div class="text-sn">
|
||||
月同比<CountTo :startVal="1" suffix="%" :endVal="volume.rise"/>
|
||||
<n-icon size="12" style="color: #00ff6f">
|
||||
<component is="CaretUpOutlined"/>
|
||||
</n-icon>
|
||||
</div>
|
||||
<div class="text-sn">
|
||||
月同比<CountTo :startVal="1" suffix="%" :endVal="volume.decline"/>
|
||||
<n-icon size="12" style="color: #ffde66">
|
||||
<component is="CaretDownOutlined"/>
|
||||
</n-icon>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex justify-between ">
|
||||
<div class="text-sn">
|
||||
总成交额:
|
||||
</div>
|
||||
<div class="text-sn">
|
||||
<CountTo prefix="¥" :startVal="1" :endVal="volume.amount"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</NCard>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
|
||||
<!--导航卡片-->
|
||||
<div class="mt-4">
|
||||
<n-grid cols="1 s:2 m:3 l:8 xl:8 2xl:8" responsive="screen" :x-gap="16" :y-gap="8" :cols="8">
|
||||
<n-grid-item v-for="(item,index) in iconList" :key="index">
|
||||
<NCard content-style="padding-top: 0;" size="small" :bordered="false">
|
||||
<template #footer>
|
||||
<div class="cursor-pointer">
|
||||
<p class="flex justify-center">
|
||||
<span>
|
||||
<n-icon :size="item.size" class="flex-1" :style="{color:`${item.color}`}">
|
||||
<component :is="item.icon" v-on="item.eventObject || {}"/>
|
||||
</n-icon>
|
||||
</span>
|
||||
</p>
|
||||
<p class="flex justify-center"><span>{{ item.title }}</span></p>
|
||||
</div>
|
||||
</template>
|
||||
</NCard>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</div>
|
||||
|
||||
<!--访问量 | 流量趋势-->
|
||||
<VisiTab></VisiTab>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, reactive, toRefs, ref } from 'vue'
|
||||
import Icons from './components/Icons'
|
||||
import VisiTab from './components/VisiTab.vue'
|
||||
import { CountTo } from '@/components/CountTo/index'
|
||||
import { getConsoleInfo } from '@/api/dashboard/console'
|
||||
|
||||
export default defineComponent({
|
||||
components: { ...Icons, VisiTab, CountTo },
|
||||
setup() {
|
||||
const state = reactive({
|
||||
cardHeaderStyle: {
|
||||
'border-bottom': '1px solid #eee',
|
||||
'font-size': '16px'
|
||||
},
|
||||
visits:{},
|
||||
saleroom:{},
|
||||
orderLarge:{},
|
||||
volume:{},
|
||||
})
|
||||
// 图标列表
|
||||
const iconList = [
|
||||
{
|
||||
icon: 'UsergroupAddOutlined',
|
||||
size: '32',
|
||||
title: '用户',
|
||||
color: '#69c0ff',
|
||||
eventObject: {
|
||||
click: () => {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon: 'BarChartOutlined',
|
||||
size: '32',
|
||||
title: '分析',
|
||||
color: '#69c0ff',
|
||||
eventObject: {
|
||||
click: () => {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon: 'ShoppingCartOutlined',
|
||||
size: '32',
|
||||
title: '商品',
|
||||
color: '#ff9c6e',
|
||||
eventObject: {
|
||||
click: () => {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon: 'AccountBookOutlined',
|
||||
size: '32',
|
||||
title: '订单',
|
||||
color: '#b37feb',
|
||||
eventObject: {
|
||||
click: () => {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon: 'CreditCardOutlined',
|
||||
size: '32',
|
||||
title: '票据',
|
||||
color: '#ffd666',
|
||||
eventObject: {
|
||||
click: () => {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon: 'MailOutlined',
|
||||
size: '32',
|
||||
title: '消息',
|
||||
color: '#5cdbd3',
|
||||
eventObject: {
|
||||
click: () => {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon: 'TagsOutlined',
|
||||
size: '32',
|
||||
title: '标签',
|
||||
color: '#ff85c0',
|
||||
eventObject: {
|
||||
click: () => {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon: 'SettingOutlined',
|
||||
size: '32',
|
||||
title: '配置',
|
||||
color: '#ffc069',
|
||||
eventObject: {
|
||||
click: () => {
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
onMounted(async ()=> {
|
||||
const { visits, saleroom, orderLarge, volume} = await getConsoleInfo()
|
||||
state.visits = visits
|
||||
state.saleroom = saleroom
|
||||
state.orderLarge = orderLarge
|
||||
state.volume = volume
|
||||
})
|
||||
return {
|
||||
...toRefs(state),
|
||||
iconList
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
</style>
|
||||
18
src/views/dashboard/monitor/monitor.vue
Normal file
18
src/views/dashboard/monitor/monitor.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<div>监控台</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {},
|
||||
setup() {
|
||||
return {}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang='less' scoped>
|
||||
|
||||
</style>
|
||||
350
src/views/dashboard/workplace/workplace.vue
Normal file
350
src/views/dashboard/workplace/workplace.vue
Normal file
@@ -0,0 +1,350 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="n-layout-page-header">
|
||||
<n-card :bordered="false" title="工作台">
|
||||
<n-grid cols="2 s:1 m:1 l:2 xl:2 2xl:2" responsive="screen">
|
||||
<n-gi>
|
||||
<div class="flex items-center">
|
||||
<div>
|
||||
<n-avatar
|
||||
circle
|
||||
:size="64"
|
||||
:src="schoolboy"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<p class="px-4 text-xl">早安,Ah jung,开始您一天的工作吧!</p>
|
||||
<p class="px-4 text-gray-400">今日阴转大雨,15℃ - 25℃,出门记得带伞哦。</p>
|
||||
</div>
|
||||
</div>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<div class="flex justify-end w-full">
|
||||
<div class="flex flex-1 flex-col justify-center text-right">
|
||||
<span class="text-secondary">项目数</span>
|
||||
<span class="text-2xl">16</span>
|
||||
</div>
|
||||
<div class="flex flex-1 flex-col justify-center text-right">
|
||||
<span class="text-secondary">待办</span>
|
||||
<span class="text-2xl">3/15</span>
|
||||
</div>
|
||||
<div class="flex flex-1 flex-col justify-center text-right">
|
||||
<span class="text-secondary">消息</span>
|
||||
<span class="text-2xl">35</span>
|
||||
</div>
|
||||
</div>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</n-card>
|
||||
</div>
|
||||
<n-grid class="mt-4" cols="2 s:1 m:1 l:2 xl:2 2xl:2" responsive="screen" :x-gap="12" :y-gap="9" :cols="2">
|
||||
<n-gi>
|
||||
<n-card :segmented="{ content: 'hard' }" content-style="padding: 0;" :bordered="false" size="small" title="项目">
|
||||
<div class="flex flex-wrap project-card">
|
||||
<n-card size="small" class="border rounded-none border-gray-100 cursor-pointer project-card-item ms:w-1/2 md:w-1/3"
|
||||
:bordered="false" hoverable>
|
||||
<div class="flex">
|
||||
<span>
|
||||
<n-icon size="30">
|
||||
<GithubOutlined/>
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lg ml-4">Github</span>
|
||||
</div>
|
||||
<div class="flex mt-2 h-10 text-gray-400">
|
||||
是一个面向开源及私有软件项目的托管平台。
|
||||
</div>
|
||||
<div class="flex mt-2 h-10 text-gray-400">
|
||||
开源君,2021-07-04
|
||||
</div>
|
||||
</n-card>
|
||||
<n-card size="small" class="border rounded-none border-gray-100 cursor-pointer project-card-item ms:w-1/2 md:w-1/3"
|
||||
:bordered="false" hoverable>
|
||||
<div class="flex">
|
||||
<span>
|
||||
<n-icon size="30" style="color: #42b983">
|
||||
<LogoVue/>
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lg ml-4">Vue</span>
|
||||
</div>
|
||||
<div class="flex mt-2 h-10 text-gray-400">
|
||||
渐进式 JavaScript 框架
|
||||
</div>
|
||||
<div class="flex mt-2 h-10 text-gray-400">
|
||||
学不动也要学,2021-07-04
|
||||
</div>
|
||||
</n-card>
|
||||
<n-card size="small" class="border rounded-none border-gray-100 cursor-pointer project-card-item ms:w-1/2 md:w-1/3"
|
||||
:bordered="false" hoverable>
|
||||
<div class="flex">
|
||||
<span>
|
||||
<n-icon size="30" style="color: #e44c27">
|
||||
<Html5Outlined />
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lg ml-4">Html5</span>
|
||||
</div>
|
||||
<div class="flex mt-2 h-10 text-gray-400">
|
||||
HTML5是互联网的下一代标准。
|
||||
</div>
|
||||
<div class="flex mt-2 h-10 text-gray-400">
|
||||
撸码也是一种艺术 2021-04-01
|
||||
</div>
|
||||
</n-card>
|
||||
<n-card size="small" class="border rounded-none border-gray-100 cursor-pointer project-card-item ms:w-1/2 md:w-1/3"
|
||||
:bordered="false" hoverable>
|
||||
<div class="flex">
|
||||
<span>
|
||||
<n-icon size="30" style="color: #dd0031">
|
||||
<LogoAngular/>
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lg ml-4">Angular</span>
|
||||
</div>
|
||||
<div class="flex mt-2 h-10 text-gray-400">
|
||||
现代 Web 开发平台,百万粉丝热捧。
|
||||
</div>
|
||||
<div class="flex mt-2 h-10 text-gray-400">
|
||||
铁粉君 2021-07-04。
|
||||
</div>
|
||||
</n-card>
|
||||
<n-card size="small" class="border rounded-none border-gray-100 cursor-pointer project-card-item ms:w-1/2 md:w-1/3"
|
||||
:bordered="false" hoverable>
|
||||
<div class="flex">
|
||||
<span>
|
||||
<n-icon size="30" style="color: #61dafb">
|
||||
<LogoReact/>
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lg ml-4">React</span>
|
||||
</div>
|
||||
<div class="flex mt-2 h-10 text-gray-400">
|
||||
用于构建用户界面的 JavaScript 库。
|
||||
</div>
|
||||
<div class="flex mt-2 h-10 text-gray-400">
|
||||
技术牛 2021-07-04。
|
||||
</div>
|
||||
</n-card>
|
||||
<n-card size="small" class="border rounded-none border-gray-100 cursor-pointer project-card-item ms:w-1/2 md:w-1/3"
|
||||
:bordered="false" hoverable>
|
||||
<div class="flex">
|
||||
<span>
|
||||
<n-icon size="30">
|
||||
<LogoJavascript/>
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lg ml-4">Js</span>
|
||||
</div>
|
||||
<div class="flex mt-2 h-10 text-gray-400">
|
||||
路是走出来的,而不是空想出来的。
|
||||
</div>
|
||||
<div class="flex mt-2 h-10 text-gray-400">
|
||||
架构组 2021-07-04
|
||||
</div>
|
||||
</n-card>
|
||||
</div>
|
||||
</n-card>
|
||||
|
||||
<n-card :segmented="{ content: 'hard' }" content-style="padding-top: 0;padding-bottom: 0;" :bordered="false"
|
||||
size="small" title="动态" class="mt-4">
|
||||
<template #header-extra><a href="javascript:;">更多</a></template>
|
||||
<n-list>
|
||||
<n-list-item>
|
||||
<template #prefix>
|
||||
<n-avatar
|
||||
circle
|
||||
:size="40"
|
||||
:src="schoolboy"
|
||||
/>
|
||||
</template>
|
||||
<n-thing title="Ah Jung 刚才把工作台页面随便写了一些,凑合能看了!">
|
||||
<template #description><p class="text-xs text-gray-500">2021-07-04 22:37:16</p></template>
|
||||
</n-thing>
|
||||
</n-list-item>
|
||||
<n-list-item>
|
||||
<template #prefix>
|
||||
<n-avatar
|
||||
circle
|
||||
:size="40"
|
||||
:src="schoolboy"
|
||||
/>
|
||||
</template>
|
||||
<n-thing title="Ah Jung 在 开源组 创建了项目 naive-ui-admin?">
|
||||
<template #description><p class="text-xs text-gray-500">2021-07-04 09:37:16</p></template>
|
||||
</n-thing>
|
||||
</n-list-item>
|
||||
<n-list-item>
|
||||
<template #prefix>
|
||||
<n-avatar
|
||||
circle
|
||||
:size="40"
|
||||
:src="schoolboy"
|
||||
/>
|
||||
</template>
|
||||
<n-thing title="@It界风清扬,向naive-ui-admin提交了一个bug,抽时间看看吧!">
|
||||
<template #description><p class="text-xs text-gray-500">2021-07-04 22:37:16</p></template>
|
||||
</n-thing>
|
||||
</n-list-item>
|
||||
<n-list-item>
|
||||
<template #prefix>
|
||||
<n-avatar
|
||||
circle
|
||||
:size="40"
|
||||
:src="schoolboy"
|
||||
/>
|
||||
</template>
|
||||
<n-thing title="技术部那几位童鞋,再次警告,不要摸鱼,不要摸鱼,不要摸鱼啦!">
|
||||
<template #description><p class="text-xs text-gray-500">2021-07-04 09:37:16</p></template>
|
||||
</n-thing>
|
||||
</n-list-item>
|
||||
<n-list-item>
|
||||
<template #prefix>
|
||||
<n-avatar
|
||||
circle
|
||||
:size="40"
|
||||
:src="schoolboy"
|
||||
/>
|
||||
</template>
|
||||
<n-thing title="上班不摸鱼,和咸鱼有什么区别(这话真不是我说的哈)!">
|
||||
<template #description><p class="text-xs text-gray-500">2021-07-04 20:37:16</p></template>
|
||||
</n-thing>
|
||||
</n-list-item>
|
||||
<n-list-item>
|
||||
<template #prefix>
|
||||
<n-avatar
|
||||
circle
|
||||
:size="40"
|
||||
:src="schoolboy"
|
||||
/>
|
||||
</template>
|
||||
<n-thing title="页面切换其实也支持缓存,只是加了过度效果,看起来像是重新渲染了">
|
||||
<template #description>
|
||||
<p class="text-gray-400"><n-input type="text" placeholder="不信,输点文字试试"></n-input></p>
|
||||
</template>
|
||||
</n-thing>
|
||||
</n-list-item>
|
||||
</n-list>
|
||||
</n-card>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-card :segmented="{ content: 'hard' }" content-style="padding: 0;" :bordered="false" size="small" title="快捷操作">
|
||||
<div class="flex flex-wrap project-card">
|
||||
<n-card size="small" class="border rounded-none border-gray-100 cursor-pointer project-card-item"
|
||||
:bordered="false" hoverable>
|
||||
<a href="javascript:;" class="flex flex-col justify-center text-gray-500">
|
||||
<span class="text-center">
|
||||
<n-icon size="30" style="color: #68c755">
|
||||
<DashboardOutlined/>
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lx text-center">主控台</span>
|
||||
</a>
|
||||
</n-card>
|
||||
<n-card size="small" class="border rounded-none border-gray-100 cursor-pointer project-card-item"
|
||||
:bordered="false" hoverable>
|
||||
<a href="javascript:;" class="flex flex-col justify-center text-gray-500">
|
||||
<span class="text-center">
|
||||
<n-icon size="30" style="color: #fab251">
|
||||
<ProfileOutlined/>
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lx text-center">列表</span>
|
||||
</a>
|
||||
</n-card>
|
||||
<n-card size="small" class="border rounded-none border-gray-100 cursor-pointer project-card-item"
|
||||
:bordered="false" hoverable>
|
||||
<a href="javascript:;" class="flex flex-col justify-center text-gray-500">
|
||||
<span class="text-center">
|
||||
<n-icon size="30" style="color: #1890ff">
|
||||
<FileProtectOutlined/>
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lx text-center">表单</span>
|
||||
</a>
|
||||
</n-card>
|
||||
<n-card size="small" class="border rounded-none border-gray-100 cursor-pointer project-card-item"
|
||||
:bordered="false" hoverable>
|
||||
<a href="javascript:;" class="flex flex-col justify-center text-gray-500">
|
||||
<span class="text-center">
|
||||
<n-icon size="30" style="color: #f06b96">
|
||||
<ApartmentOutlined/>
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lx text-center">权限管理</span>
|
||||
</a>
|
||||
</n-card>
|
||||
<n-card size="small" class="border rounded-none border-gray-100 cursor-pointer project-card-item"
|
||||
:bordered="false" hoverable>
|
||||
<a href="javascript:;" class="flex flex-col justify-center text-gray-500">
|
||||
<span class="text-center">
|
||||
<n-icon size="30" style="color: #7238d1">
|
||||
<SettingOutlined/>
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lx text-center">系统管理</span>
|
||||
</a>
|
||||
</n-card>
|
||||
<n-card size="small" class="border rounded-none border-gray-100 cursor-pointer project-card-item"
|
||||
:bordered="false" hoverable>
|
||||
<a href="javascript:;" class="flex flex-col justify-center text-gray-500">
|
||||
<span class="text-center">
|
||||
<n-icon size="30">
|
||||
<DashboardOutlined/>
|
||||
</n-icon>
|
||||
</span>
|
||||
<span class="text-lx text-center">主控台</span>
|
||||
</a>
|
||||
</n-card>
|
||||
</div>
|
||||
</n-card>
|
||||
<n-card :segmented="{ content: 'hard' }" :bordered="false" size="small" class="mt-4">
|
||||
<img src="~@/assets/images/Business.svg" class="w-full"/>
|
||||
</n-card>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import schoolboy from '@/assets/images/schoolboy.png';
|
||||
import {
|
||||
GithubOutlined,
|
||||
DashboardOutlined,
|
||||
ProfileOutlined,
|
||||
FileProtectOutlined,
|
||||
SettingOutlined,
|
||||
ApartmentOutlined,
|
||||
Html5Outlined
|
||||
} from '@vicons/antd'
|
||||
import {
|
||||
LogoVue,
|
||||
LogoAngular,
|
||||
LogoReact,
|
||||
LogoJavascript
|
||||
} from '@vicons/ionicons5'
|
||||
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name:'dashboard_workplace',
|
||||
components: { GithubOutlined, LogoVue, DashboardOutlined, ProfileOutlined, FileProtectOutlined, SettingOutlined, ApartmentOutlined,
|
||||
Html5Outlined, LogoAngular, LogoReact, LogoJavascript
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
schoolboy
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.project-card {
|
||||
margin-right: -6px;
|
||||
&-item {
|
||||
margin: -1px;
|
||||
width:33.333333%
|
||||
}
|
||||
}
|
||||
</style>
|
||||
34
src/views/exception/404.vue
Normal file
34
src/views/exception/404.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<div class="flex flex-col align-center justify-center page-container">
|
||||
<div class="text-center">
|
||||
<h1 class="text-base text-gray-500">哎哟喂,您好像走丢了...</h1>
|
||||
<router-link to="/" class="n-btn n-btn-primary">回到首页</router-link>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<img src="~@/assets/images/Error.svg" alt=""/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { routes } from '@/router'
|
||||
|
||||
export default defineComponent({
|
||||
name: '404'
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.page-container {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background-color: white;
|
||||
border-radius: 4px;
|
||||
|
||||
img {
|
||||
width: 350px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
206
src/views/login/index.vue
Normal file
206
src/views/login/index.vue
Normal file
@@ -0,0 +1,206 @@
|
||||
<template>
|
||||
<div class="view-account">
|
||||
<div class="view-account-header"></div>
|
||||
<div class="view-account-container">
|
||||
<div class="view-account-top">
|
||||
<div class="view-account-top-logo">
|
||||
<img src="~@/assets/images/account-logo.png" alt=""/>
|
||||
</div>
|
||||
<div class="view-account-top-desc">Naive Ui Admin中台前端/设计解决方案</div>
|
||||
</div>
|
||||
<div class="view-account-form">
|
||||
<n-form ref="formRef" label-placement="left" size="large" :model="formInline" :rules="rules">
|
||||
<n-form-item path="username">
|
||||
<n-input v-model:value="formInline.username" placeholder="请输入用户名">
|
||||
<template #prefix>
|
||||
<n-icon size="18" color="#808695">
|
||||
<PersonOutline/>
|
||||
</n-icon>
|
||||
</template>
|
||||
</n-input>
|
||||
</n-form-item>
|
||||
<n-form-item path="password">
|
||||
<n-input v-model:value="formInline.password" type="password" show-password-toggle placeholder="请输入密码">
|
||||
<template #prefix>
|
||||
<n-icon size="18" color="#808695">
|
||||
<LockClosedOutline/>
|
||||
</n-icon>
|
||||
</template>
|
||||
</n-input>
|
||||
</n-form-item>
|
||||
<n-form-item class="default-color">
|
||||
<div class="flex justify-between">
|
||||
<div class="flex-initial">
|
||||
<n-checkbox v-model:checked="autoLogin">自动登录</n-checkbox>
|
||||
</div>
|
||||
<div class="flex-initial order-last">
|
||||
<a href="javascript:;">忘记密码</a>
|
||||
</div>
|
||||
</div>
|
||||
</n-form-item>
|
||||
<n-form-item>
|
||||
<n-button type="primary" @click="handleSubmit" size="large" :loading="loading" block>
|
||||
登录
|
||||
</n-button>
|
||||
</n-form-item>
|
||||
<n-form-item class="default-color">
|
||||
<div class="flex view-account-other">
|
||||
<div class="flex-initial">
|
||||
<span>其它登录方式</span>
|
||||
</div>
|
||||
<div class="flex-initial mx-2">
|
||||
<a href="javascript:;">
|
||||
<n-icon size="24" color="#2d8cf0">
|
||||
<LogoGithub/>
|
||||
</n-icon>
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex-initial mx-2">
|
||||
<a href="javascript:;">
|
||||
<n-icon size="24" color="#2d8cf0">
|
||||
<LogoFacebook/>
|
||||
</n-icon>
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex-initial" style="margin-left:auto">
|
||||
<a href="javascript:;">注册账号</a>
|
||||
</div>
|
||||
</div>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs, ref } from 'vue'
|
||||
import { PersonOutline, LockClosedOutline, LogoGithub, LogoFacebook } from '@vicons/ionicons5'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { useMessage } from 'naive-ui'
|
||||
import { ResultEnum } from '@/enums/httpEnum'
|
||||
|
||||
interface FormState {
|
||||
username: string
|
||||
password: string
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
components: { PersonOutline, LockClosedOutline, LogoGithub, LogoFacebook },
|
||||
setup() {
|
||||
const formRef = ref()
|
||||
const message = useMessage()
|
||||
const state = reactive({
|
||||
loading: false,
|
||||
autoLogin: true,
|
||||
formInline: {
|
||||
username: 'admin',
|
||||
password: '123456'
|
||||
}
|
||||
})
|
||||
const rules = {
|
||||
username: { required: true, message: '请输入用户名!', trigger: 'blur' },
|
||||
password: { required: true, message: '请输入密码!', trigger: 'blur' }
|
||||
}
|
||||
const userStore = useUserStore();
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
let loadingMessage
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault()
|
||||
formRef.value.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
const { username, password } = state.formInline
|
||||
loadingMessage = message.loading('登录中...')
|
||||
state.loading = true
|
||||
|
||||
const params:FormState = {
|
||||
username,
|
||||
password
|
||||
}
|
||||
|
||||
const { code, message: msg } = await userStore.login(params)
|
||||
|
||||
if (code == ResultEnum.SUCCESS) {
|
||||
const toPath = decodeURIComponent((route.query?.redirect || '/') as string)
|
||||
message.success('登录成功!')
|
||||
router.replace(toPath).then((_) => {
|
||||
if (route.name == 'login') {
|
||||
router.replace('/')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
message.info(msg || '登录失败')
|
||||
}
|
||||
} else {
|
||||
message.error('请填写完整信息')
|
||||
}
|
||||
})
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
formRef,
|
||||
rules,
|
||||
handleSubmit
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.view-account {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
overflow: auto;
|
||||
|
||||
&-container {
|
||||
flex: 1;
|
||||
padding: 32px 0;
|
||||
width: 384px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
&-top {
|
||||
padding: 32px 0;
|
||||
text-align: center;
|
||||
|
||||
&-logo {
|
||||
height: 75px;
|
||||
}
|
||||
|
||||
&-desc {
|
||||
font-size: 14px;
|
||||
color: #808695;
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
&-other {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.default-color {
|
||||
color: #515a6e;
|
||||
|
||||
.ant-checkbox-wrapper {
|
||||
color: #515a6e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.view-account {
|
||||
background-image: url('@/assets/images/login.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50%;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.page-account-container {
|
||||
padding: 32px 0 24px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
22
src/views/redirect/index.vue
Normal file
22
src/views/redirect/index.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<script lang="tsx">
|
||||
import { defineComponent, onBeforeMount } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { NEmpty } from 'naive-ui'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Redirect',
|
||||
setup(props) {
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
onBeforeMount(() => {
|
||||
const { params, query } = route
|
||||
const { path } = params
|
||||
router.replace({
|
||||
path: '/' + (Array.isArray(path) ? path.join('/') : path),
|
||||
query
|
||||
})
|
||||
})
|
||||
return () => <NEmpty/>
|
||||
}
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user