项目初始化
This commit is contained in:
@@ -1,107 +0,0 @@
|
||||
<template>
|
||||
<div class="md:flex">
|
||||
<template v-for="(item, index) in growCardList" :key="item.title">
|
||||
<Card
|
||||
size="small"
|
||||
:loading="loading"
|
||||
:title="item.title"
|
||||
class="w-full cursor-pointer !mt-4 md:w-1/4 !md:mt-0"
|
||||
:class="[index + 1 < 4 && '!md:mr-4']"
|
||||
:canExpan="false"
|
||||
@click="navPage(item.url)"
|
||||
>
|
||||
<template #extra>
|
||||
<Tag :color="item.color">{{ item.action }}</Tag>
|
||||
</template>
|
||||
|
||||
<div class="flex justify-between px-4 py-4">
|
||||
<CountTo prefix="" :startVal="1" :endVal="item.value" class="text-2xl" />
|
||||
<Icon :icon="item.icon" :size="40" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between p-2 px-4">
|
||||
<span>点击我</span>
|
||||
<CountTo prefix="共" :startVal="1" :endVal="item.total" />
|
||||
</div>
|
||||
</Card>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { CountTo } from '@jeesite/core/components/CountTo';
|
||||
import { Icon } from '@jeesite/core/components/Icon';
|
||||
import { Tag, Card } from 'ant-design-vue';
|
||||
import { useGo } from '@jeesite/core/hooks/web/usePage';
|
||||
|
||||
const loading = ref(true);
|
||||
const growCardList = ref<GrowCardItem[]>();
|
||||
const go = useGo();
|
||||
|
||||
interface GrowCardItem {
|
||||
icon: string;
|
||||
title: string;
|
||||
value: number;
|
||||
total: number;
|
||||
color: string;
|
||||
action: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const list: GrowCardItem[] = [
|
||||
{
|
||||
title: '工作台',
|
||||
icon: 'icons/visit-count.svg',
|
||||
value: 1999,
|
||||
total: 120000,
|
||||
color: 'green',
|
||||
action: '时',
|
||||
url: '/desktop/workbench',
|
||||
},
|
||||
{
|
||||
title: '关于我们',
|
||||
icon: 'icons/total-sales.svg',
|
||||
value: 2999,
|
||||
total: 500000,
|
||||
color: 'blue',
|
||||
action: '日',
|
||||
url: '/desktop/about',
|
||||
},
|
||||
{
|
||||
title: '源码下载',
|
||||
icon: 'icons/download-count.svg',
|
||||
value: 3999,
|
||||
total: 120000,
|
||||
color: 'orange',
|
||||
action: '周',
|
||||
url: 'https://gitee.com/thinkgem/jeesite-vue',
|
||||
},
|
||||
{
|
||||
title: '官方网站',
|
||||
icon: 'icons/transaction.svg',
|
||||
value: 9999,
|
||||
total: 99999,
|
||||
color: 'purple',
|
||||
action: '月',
|
||||
url: 'https://jeesite.com',
|
||||
},
|
||||
];
|
||||
// 此处写后端 API 获取 list 数据
|
||||
growCardList.value = list;
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 500);
|
||||
});
|
||||
|
||||
function navPage(url: string) {
|
||||
if (!url || url === '') {
|
||||
return;
|
||||
}
|
||||
if (url.indexOf('://') != -1) {
|
||||
window.open(url);
|
||||
} else {
|
||||
go(url);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,51 +0,0 @@
|
||||
<template>
|
||||
<Card title="成交占比" :loading="loading">
|
||||
<div ref="chartRef" class="h-75 w-full"></div>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, Ref, ref } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { useECharts } from '@jeesite/core/hooks/web/useECharts';
|
||||
import type { EChartsOption } from 'echarts';
|
||||
|
||||
const loading = ref(true);
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
|
||||
onMounted(() => {
|
||||
const options: EChartsOption = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '访问来源',
|
||||
type: 'pie',
|
||||
radius: '80%',
|
||||
center: ['50%', '50%'],
|
||||
color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
|
||||
data: [
|
||||
{ value: 500, name: '电子产品' },
|
||||
{ value: 310, name: '服装' },
|
||||
{ value: 274, name: '化妆品' },
|
||||
{ value: 400, name: '家居' },
|
||||
].sort(function (a, b) {
|
||||
return a.value - b.value;
|
||||
}),
|
||||
roseType: 'radius',
|
||||
animationType: 'scale',
|
||||
animationEasing: 'exponentialInOut',
|
||||
animationDelay: function () {
|
||||
return Math.random() * 400;
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
// 此处写后端 API 获取 options 数据
|
||||
setTimeout(() => {
|
||||
setOptions(options);
|
||||
loading.value = false;
|
||||
}, 900);
|
||||
});
|
||||
</script>
|
||||
@@ -1,44 +0,0 @@
|
||||
<template>
|
||||
<Card
|
||||
v-bind="$attrs"
|
||||
:loading="loading"
|
||||
:tab-list="tabListTitle"
|
||||
:active-tab-key="activeKey"
|
||||
@tab-change="onTabChange"
|
||||
>
|
||||
<p v-if="activeKey === 'tab1'">
|
||||
<VisitAnalysis />
|
||||
</p>
|
||||
<p v-if="activeKey === 'tab2'">
|
||||
<VisitAnalysisBar />
|
||||
</p>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import VisitAnalysis from './VisitAnalysis.vue';
|
||||
import VisitAnalysisBar from './VisitAnalysisBar.vue';
|
||||
|
||||
const loading = ref(true);
|
||||
const activeKey = ref('tab1');
|
||||
|
||||
const tabListTitle = [
|
||||
{
|
||||
key: 'tab1',
|
||||
tab: '流量趋势',
|
||||
},
|
||||
{
|
||||
key: 'tab2',
|
||||
tab: '访问量',
|
||||
},
|
||||
];
|
||||
|
||||
function onTabChange(key) {
|
||||
activeKey.value = key;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 700);
|
||||
</script>
|
||||
@@ -1,109 +0,0 @@
|
||||
<template>
|
||||
<Skeleton active :paragraph="{ rows: 5 }" :loading="loading">
|
||||
<div ref="chartRef" class="h-70 w-full"></div>
|
||||
</Skeleton>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, Ref } from 'vue';
|
||||
import { Skeleton } from 'ant-design-vue';
|
||||
import { useECharts } from '@jeesite/core/hooks/web/useECharts';
|
||||
import type { EChartsOption } from 'echarts';
|
||||
|
||||
const loading = ref(true);
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
|
||||
onMounted(() => {
|
||||
const options: EChartsOption = {
|
||||
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',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
// 此处写后端 API 获取 options 数据
|
||||
setOptions(options);
|
||||
loading.value = false;
|
||||
});
|
||||
</script>
|
||||
@@ -1,49 +0,0 @@
|
||||
<template>
|
||||
<Skeleton active :paragraph="{ rows: 5 }" :loading="loading">
|
||||
<div ref="chartRef" class="h-70 w-full"></div>
|
||||
</Skeleton>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, Ref } from 'vue';
|
||||
import { Skeleton } from 'ant-design-vue';
|
||||
import { useECharts } from '@jeesite/core/hooks/web/useECharts';
|
||||
import type { EChartsOption } from 'echarts';
|
||||
|
||||
const loading = ref(true);
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
|
||||
onMounted(() => {
|
||||
const options: EChartsOption = {
|
||||
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,
|
||||
},
|
||||
],
|
||||
};
|
||||
// 此处写后端 API 获取 options 数据
|
||||
setOptions(options);
|
||||
loading.value = false;
|
||||
});
|
||||
</script>
|
||||
@@ -1,89 +0,0 @@
|
||||
<template>
|
||||
<Card title="转化率" :loading="loading">
|
||||
<div ref="chartRef" class="h-75 w-full"></div>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, Ref, ref } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { useECharts } from '@jeesite/core/hooks/web/useECharts';
|
||||
import type { EChartsOption } from 'echarts';
|
||||
|
||||
const loading = ref(true);
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
|
||||
onMounted(() => {
|
||||
const options: EChartsOption = {
|
||||
legend: {
|
||||
bottom: 0,
|
||||
data: ['访问', '购买'],
|
||||
},
|
||||
tooltip: {},
|
||||
radar: {
|
||||
radius: '60%',
|
||||
splitNumber: 8,
|
||||
indicator: [
|
||||
{
|
||||
name: '电脑',
|
||||
max: 100,
|
||||
},
|
||||
{
|
||||
name: '充电器',
|
||||
max: 100,
|
||||
},
|
||||
{
|
||||
name: '耳机',
|
||||
max: 100,
|
||||
},
|
||||
{
|
||||
name: '手机',
|
||||
max: 100,
|
||||
},
|
||||
{
|
||||
name: 'Ipad',
|
||||
max: 100,
|
||||
},
|
||||
{
|
||||
name: '耳机',
|
||||
max: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'radar',
|
||||
symbolSize: 0,
|
||||
areaStyle: {
|
||||
shadowBlur: 0,
|
||||
shadowColor: 'rgba(0,0,0,.2)',
|
||||
shadowOffsetX: 0,
|
||||
shadowOffsetY: 10,
|
||||
opacity: 1,
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: [90, 50, 86, 40, 50, 20],
|
||||
name: '访问',
|
||||
itemStyle: {
|
||||
color: '#b6a2de',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: [70, 75, 70, 76, 20, 85],
|
||||
name: '购买',
|
||||
itemStyle: {
|
||||
color: '#5ab1ef',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
// 此处写后端 API 获取 options 数据
|
||||
setTimeout(() => {
|
||||
setOptions(options);
|
||||
loading.value = false;
|
||||
}, 900);
|
||||
});
|
||||
</script>
|
||||
@@ -1,71 +0,0 @@
|
||||
<template>
|
||||
<Card title="访问来源" :loading="loading">
|
||||
<div ref="chartRef" class="h-75 w-full"></div>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, Ref, ref } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { useECharts } from '@jeesite/core/hooks/web/useECharts';
|
||||
import type { EChartsOption } from 'echarts';
|
||||
|
||||
const loading = ref(true);
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
|
||||
onMounted(() => {
|
||||
const options: EChartsOption = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
},
|
||||
legend: {
|
||||
bottom: '1%',
|
||||
left: 'center',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
|
||||
name: '访问来源',
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
avoidLabelOverlap: false,
|
||||
itemStyle: {
|
||||
borderRadius: 10,
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2,
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center',
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: '12',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
data: [
|
||||
{ value: 1048, name: '搜索引擎' },
|
||||
{ value: 735, name: '直接访问' },
|
||||
{ value: 580, name: '邮件营销' },
|
||||
{ value: 484, name: '联盟广告' },
|
||||
],
|
||||
animationType: 'scale',
|
||||
animationEasing: 'exponentialInOut',
|
||||
animationDelay: function () {
|
||||
return Math.random() * 100;
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
// 此处写后端 API 获取 options 数据
|
||||
setTimeout(() => {
|
||||
setOptions(options);
|
||||
loading.value = false;
|
||||
}, 900);
|
||||
});
|
||||
</script>
|
||||
@@ -1,23 +1,101 @@
|
||||
<template>
|
||||
<div class="mb-4 jeesite-analysis">
|
||||
<GrowCard class="enter-y" />
|
||||
<SiteAnalysis class="enter-y !my-4" />
|
||||
<div class="enter-y md:flex">
|
||||
<VisitRadar class="w-full md:w-1/3" />
|
||||
<VisitSource class="w-full !my-4 md:w-1/3 !md:mx-4 !md:my-0" />
|
||||
<SalesProductPie class="w-full md:w-1/3" />
|
||||
<div class="jeesite-analysis">
|
||||
<div class="analysis-layout">
|
||||
<div class="analysis-left">
|
||||
<section class="analysis-panel">左上</section>
|
||||
<section class="analysis-panel">左中</section>
|
||||
<section class="analysis-panel">左下</section>
|
||||
</div>
|
||||
<div class="analysis-right">
|
||||
<section class="analysis-panel">右上</section>
|
||||
<section class="analysis-panel">右下</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup name="Analysis">
|
||||
import GrowCard from './components/GrowCard.vue';
|
||||
import SiteAnalysis from './components/SiteAnalysis.vue';
|
||||
import VisitSource from './components/VisitSource.vue';
|
||||
import VisitRadar from './components/VisitRadar.vue';
|
||||
import SalesProductPie from './components/SalesProductPie.vue';
|
||||
</script>
|
||||
<style class="less">
|
||||
<script lang="ts" setup name="Analysis"></script>
|
||||
<style lang="less">
|
||||
@dark-bg: #141414;
|
||||
|
||||
.jeesite-analysis .ant-card {
|
||||
border-radius: 10px !important;
|
||||
}
|
||||
|
||||
.jeesite-analysis {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
margin: 0;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.jeesite-analysis .analysis-layout {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
gap: 12px;
|
||||
padding: 4px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.jeesite-analysis .analysis-left,
|
||||
.jeesite-analysis .analysis-right {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
gap: 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.jeesite-analysis .analysis-left {
|
||||
flex: 2 1 0;
|
||||
grid-template-rows: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.jeesite-analysis .analysis-right {
|
||||
flex: 3 1 0;
|
||||
grid-template-rows: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.jeesite-analysis .analysis-panel {
|
||||
min-height: 0;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgb(226 232 240);
|
||||
background: rgb(248 250 252);
|
||||
box-shadow: 0 1px 3px rgb(15 23 42 / 0.06);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgb(71 85 105);
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .jeesite-analysis .analysis-panel {
|
||||
border-color: rgb(51 65 85);
|
||||
background: @dark-bg !important;
|
||||
color: rgb(203 213 225);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .jeesite-analysis,
|
||||
html[data-theme='dark'] .jeesite-analysis .analysis-layout,
|
||||
html[data-theme='dark'] .jeesite-analysis .analysis-left,
|
||||
html[data-theme='dark'] .jeesite-analysis .analysis-right {
|
||||
background: @dark-bg !important;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .jeesite-analysis {
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .jeesite-analysis,
|
||||
html[data-theme='dark'] .jeesite-analysis * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
interface GroupItem {
|
||||
title: string;
|
||||
icon: string;
|
||||
color: string;
|
||||
desc: string;
|
||||
date: string;
|
||||
group: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface NavItem {
|
||||
title: string;
|
||||
icon: string;
|
||||
color: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface DynamicInfoItem {
|
||||
avatar: string;
|
||||
name: string;
|
||||
date: string;
|
||||
desc: string;
|
||||
}
|
||||
|
||||
export const navItems: NavItem[] = [
|
||||
{
|
||||
title: 'HR 看板',
|
||||
icon: 'i-ant-design:bar-chart-outlined',
|
||||
color: '#bf0c2c',
|
||||
url: '/desktop/about',
|
||||
},
|
||||
{
|
||||
title: '待办任务',
|
||||
icon: 'i-simple-line-icons:envelope-letter',
|
||||
color: '#1fdaca',
|
||||
url: '/bpm/bpmMyTask/todoList',
|
||||
},
|
||||
{
|
||||
title: '角色管理',
|
||||
icon: 'i-simple-line-icons:people',
|
||||
color: '#e18525',
|
||||
url: '/sys/role/list',
|
||||
},
|
||||
{
|
||||
title: '菜单管理',
|
||||
icon: 'i-simple-line-icons:book-open',
|
||||
color: '#3fb27f',
|
||||
url: '/sys/menu/index',
|
||||
},
|
||||
{
|
||||
title: '权限管理',
|
||||
icon: 'i-simple-line-icons:social-dropbox',
|
||||
color: '#4daf1bc9',
|
||||
url: '/sys/role/list',
|
||||
},
|
||||
{
|
||||
title: '统计分析',
|
||||
icon: 'i-ion:bar-chart-outline',
|
||||
color: '#00d8ff',
|
||||
url: '/desktop/about',
|
||||
},
|
||||
];
|
||||
|
||||
export const dynamicInfoItems: DynamicInfoItem[] = [
|
||||
{
|
||||
avatar: 'icons/dynamic-avatar-4.svg',
|
||||
name: 'ThinkGem',
|
||||
date: '刚刚',
|
||||
desc: `在 <a>开源组</a> 创建了项目 <a>Vue</a>`,
|
||||
},
|
||||
{
|
||||
avatar: 'icons/dynamic-avatar-2.svg',
|
||||
name: '果汁',
|
||||
date: '1个小时前',
|
||||
desc: `关注了 <a>JeeSite</a> `,
|
||||
},
|
||||
{
|
||||
avatar: 'icons/dynamic-avatar-3.svg',
|
||||
name: 'JeeSite',
|
||||
date: '1天前',
|
||||
desc: `发布了 <a>个人动态</a> `,
|
||||
},
|
||||
{
|
||||
avatar: 'icons/dynamic-avatar-5.svg',
|
||||
name: 'Vben',
|
||||
date: '2天前',
|
||||
desc: `发表文章 <a>如何编写一个Vite插件</a> `,
|
||||
},
|
||||
{
|
||||
avatar: 'icons/dynamic-avatar-4.svg',
|
||||
name: 'ThinkGem',
|
||||
date: '3天前',
|
||||
desc: `回复了 <a>杰克</a> 的问题 <a>如何进行项目优化?</a>`,
|
||||
},
|
||||
{
|
||||
avatar: 'icons/dynamic-avatar-6.svg',
|
||||
name: 'JeeSite',
|
||||
date: '1周前',
|
||||
desc: `关闭了问题 <a>如何运行项目</a> `,
|
||||
},
|
||||
{
|
||||
avatar: 'icons/dynamic-avatar-1.svg',
|
||||
name: '彩虹',
|
||||
date: '1周前',
|
||||
desc: `发布了 <a>个人动态</a> `,
|
||||
},
|
||||
{
|
||||
avatar: 'icons/dynamic-avatar-1.svg',
|
||||
name: '彩虹',
|
||||
date: '2021-09-01 20:00',
|
||||
desc: `推送了代码到 <a>Gitee</a>`,
|
||||
},
|
||||
];
|
||||
|
||||
export const groupItems: GroupItem[] = [
|
||||
{
|
||||
title: 'Gitee',
|
||||
icon: 'i-simple-icons:gitee',
|
||||
color: '#ce2323',
|
||||
desc: '不要等待机会,而要创造机会。',
|
||||
group: '开源组',
|
||||
date: '2021-09-01',
|
||||
url: '/desktop/about',
|
||||
},
|
||||
{
|
||||
title: 'Vue',
|
||||
icon: 'i-ion:logo-vue',
|
||||
color: '#3fb27f',
|
||||
desc: '现在的你决定将来的你。',
|
||||
group: '前端组',
|
||||
date: '2021-09-01',
|
||||
url: '/desktop/about',
|
||||
},
|
||||
{
|
||||
title: 'Html5',
|
||||
icon: 'i-ion:logo-html5',
|
||||
color: '#e18525',
|
||||
desc: '没有什么才能比努力更重要。',
|
||||
group: '上班摸鱼',
|
||||
date: '2021-09-01',
|
||||
url: '/desktop/about',
|
||||
},
|
||||
{
|
||||
title: 'Java',
|
||||
icon: 'i-logos:java',
|
||||
color: '#bf0c2c',
|
||||
desc: '热情和欲望可以突破一切难关。',
|
||||
group: '算法组',
|
||||
date: '2021-09-01',
|
||||
url: '/desktop/about',
|
||||
},
|
||||
{
|
||||
title: 'Spring',
|
||||
icon: 'i-bx:bxl-spring-boot',
|
||||
color: '#00d8ff',
|
||||
desc: '健康的身体是实目标的基石。',
|
||||
group: '技术牛',
|
||||
date: '2021-09-01',
|
||||
url: '/desktop/about',
|
||||
},
|
||||
{
|
||||
title: 'JeeSite',
|
||||
icon: 'i-ion:logo-javascript',
|
||||
color: '#4daf1bc9',
|
||||
desc: '路是走出来的,而不是空想出来的。',
|
||||
group: '架构组',
|
||||
date: '2021-09-01',
|
||||
url: '/desktop/about',
|
||||
},
|
||||
];
|
||||
@@ -1,31 +0,0 @@
|
||||
<template>
|
||||
<Card title="最新动态" v-bind="$attrs">
|
||||
<template #extra>
|
||||
<a-button type="link" size="small">更多</a-button>
|
||||
</template>
|
||||
<List item-layout="horizontal" :data-source="dynamicInfoItems">
|
||||
<template #renderItem="{ item }">
|
||||
<ListItem>
|
||||
<ListItemMeta>
|
||||
<template #description>
|
||||
{{ item.date }}
|
||||
</template>
|
||||
<!-- eslint-disable-next-line -->
|
||||
<template #title> {{ item.name }} <span v-html="item.desc"> </span> </template>
|
||||
<template #avatar>
|
||||
<Icon :icon="item.avatar" :size="30" />
|
||||
</template>
|
||||
</ListItemMeta>
|
||||
</ListItem>
|
||||
</template>
|
||||
</List>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Card, List } from 'ant-design-vue';
|
||||
import { dynamicInfoItems } from './Data';
|
||||
import { Icon } from '@jeesite/core/components/Icon';
|
||||
|
||||
const ListItem = List.Item;
|
||||
const ListItemMeta = List.Item.Meta;
|
||||
</script>
|
||||
@@ -1,29 +0,0 @@
|
||||
<template>
|
||||
<Card title="项目" v-bind="$attrs">
|
||||
<template #extra>
|
||||
<a-button type="link" size="small">更多</a-button>
|
||||
</template>
|
||||
|
||||
<template v-for="item in groupItems" :key="item.title">
|
||||
<Card.Grid class="!w-full !md:w-1/3 cursor-pointer" @click="go(item.url)">
|
||||
<span class="flex">
|
||||
<Icon :icon="item.icon" :color="item.color" size="30" />
|
||||
<span class="ml-4 text-lg">{{ item.title }}</span>
|
||||
</span>
|
||||
<div class="text-secondary mt-2 h-10 flex">{{ item.desc }}</div>
|
||||
<div class="text-secondary flex justify-between">
|
||||
<span>{{ item.group }}</span>
|
||||
<span>{{ item.date }}</span>
|
||||
</div>
|
||||
</Card.Grid>
|
||||
</template>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { Icon } from '@jeesite/core/components/Icon';
|
||||
import { groupItems } from './Data';
|
||||
import { useGo } from '@jeesite/core/hooks/web/usePage';
|
||||
|
||||
const go = useGo();
|
||||
</script>
|
||||
@@ -1,20 +0,0 @@
|
||||
<template>
|
||||
<Card title="快捷导航" v-bind="$attrs">
|
||||
<template v-for="item in navItems" :key="item.title">
|
||||
<Card.Grid class="cursor-pointer" @click="go(item.url)">
|
||||
<span class="flex flex-col items-center">
|
||||
<Icon :icon="item.icon" :color="item.color" size="20" />
|
||||
<span class="text-md mt-2">{{ item.title }}</span>
|
||||
</span>
|
||||
</Card.Grid>
|
||||
</template>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { navItems } from './Data';
|
||||
import { Icon } from '@jeesite/core/components/Icon';
|
||||
import { useGo } from '@jeesite/core/hooks/web/usePage';
|
||||
|
||||
const go = useGo();
|
||||
</script>
|
||||
@@ -1,100 +0,0 @@
|
||||
<template>
|
||||
<Card title="销售统计" :loading="loading">
|
||||
<div ref="chartRef" :style="{ width, height }"></div>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Ref, ref, watch } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { useECharts } from '@jeesite/core/hooks/web/useECharts';
|
||||
|
||||
const props = defineProps({
|
||||
loading: Boolean,
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: '400px',
|
||||
},
|
||||
});
|
||||
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
watch(
|
||||
() => props.loading,
|
||||
() => {
|
||||
if (props.loading) {
|
||||
return;
|
||||
}
|
||||
setOptions({
|
||||
legend: {
|
||||
bottom: 0,
|
||||
data: ['Visits', 'Sales'],
|
||||
},
|
||||
tooltip: {},
|
||||
radar: {
|
||||
radius: '60%',
|
||||
splitNumber: 8,
|
||||
indicator: [
|
||||
{
|
||||
name: '2017',
|
||||
max: 100,
|
||||
},
|
||||
{
|
||||
name: '2017',
|
||||
max: 100,
|
||||
},
|
||||
{
|
||||
name: '2018',
|
||||
max: 100,
|
||||
},
|
||||
{
|
||||
name: '2019',
|
||||
max: 100,
|
||||
},
|
||||
{
|
||||
name: '2020',
|
||||
max: 100,
|
||||
},
|
||||
{
|
||||
name: '2021',
|
||||
max: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'radar',
|
||||
symbolSize: 0,
|
||||
areaStyle: {
|
||||
shadowBlur: 0,
|
||||
shadowColor: 'rgba(0,0,0,.2)',
|
||||
shadowOffsetX: 0,
|
||||
shadowOffsetY: 10,
|
||||
opacity: 1,
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: [90, 50, 86, 40, 50, 20],
|
||||
name: 'Visits',
|
||||
itemStyle: {
|
||||
color: '#b6a2de',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: [70, 75, 70, 76, 20, 85],
|
||||
name: 'Sales',
|
||||
itemStyle: {
|
||||
color: '#67e0e3',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
||||
@@ -1,36 +1,98 @@
|
||||
<template>
|
||||
<PageWrapper>
|
||||
<template #headerContent> <WorkbenchHeader /> </template>
|
||||
<div class="lg:flex">
|
||||
<div class="enter-y w-full !mr-4 lg:w-7/10">
|
||||
<ProjectCard :loading="loading" class="enter-y" />
|
||||
<DynamicInfo :loading="loading" class="enter-y !my-4" />
|
||||
</div>
|
||||
<div class="enter-y w-full lg:w-3/10">
|
||||
<QuickNav :loading="loading" class="enter-y" />
|
||||
|
||||
<Card class="enter-y !my-4" :loading="loading">
|
||||
<img class="mx-auto h-30 xl:h-50" src="@jeesite/assets/svg/illustration.svg" />
|
||||
</Card>
|
||||
|
||||
<SaleRadar :loading="loading" class="enter-y" />
|
||||
<template #headerContent>
|
||||
<WorkbenchHeader />
|
||||
</template>
|
||||
<div class="jeesite-workbench">
|
||||
<div class="workbench-layout">
|
||||
<div class="workbench-top">10% 区域</div>
|
||||
<div class="workbench-row">
|
||||
<div class="workbench-col">30% 区域左侧</div>
|
||||
<div class="workbench-col">30% 区域右侧</div>
|
||||
</div>
|
||||
<div class="workbench-row">
|
||||
<div class="workbench-col">30% 区域左侧</div>
|
||||
<div class="workbench-col">30% 区域右侧</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts" setup name="Workbench">
|
||||
import { ref } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { PageWrapper } from '@jeesite/core/components/Page';
|
||||
import WorkbenchHeader from './components/WorkbenchHeader.vue';
|
||||
import ProjectCard from './components/ProjectCard.vue';
|
||||
import QuickNav from './components/QuickNav.vue';
|
||||
import DynamicInfo from './components/DynamicInfo.vue';
|
||||
import SaleRadar from './components/SaleRadar.vue';
|
||||
|
||||
const loading = ref(true);
|
||||
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 800);
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@dark-bg: #141414;
|
||||
|
||||
.jeesite-workbench {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
margin: 0;
|
||||
background: #FFFFFF;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-layout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
padding: 4px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-top {
|
||||
flex: 0 0 10%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-row {
|
||||
display: flex;
|
||||
flex: 0 0 30%;
|
||||
gap: 12px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-col,
|
||||
.jeesite-workbench .workbench-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgb(226 232 240);
|
||||
background: #FFFFFF;
|
||||
color: rgb(71 85 105);
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-col {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .jeesite-workbench,
|
||||
html[data-theme='dark'] .jeesite-workbench .workbench-layout,
|
||||
html[data-theme='dark'] .jeesite-workbench .workbench-row {
|
||||
background: @dark-bg !important;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .jeesite-workbench .workbench-top,
|
||||
html[data-theme='dark'] .jeesite-workbench .workbench-col {
|
||||
border-color: rgb(51 65 85);
|
||||
background: @dark-bg !important;
|
||||
color: rgb(226 232 240);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -166,9 +166,4 @@
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleOauth2(event: Event) {
|
||||
window.location.href = 'https://vue.jeesite.com/js/oauth2/login/gitee?state=vue';
|
||||
event.preventDefault();
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user