mirror of
https://github.com/vbenjs/vben-admin-thin-next.git
synced 2025-01-23 17:50:22 +08:00
feat(workbench): add workbench page
This commit is contained in:
parent
21d0ed92df
commit
1cd75fcf5b
@ -30,6 +30,7 @@ export function useApexCharts(elRef: Ref<HTMLDivElement>) {
|
||||
return;
|
||||
}
|
||||
chartInstanceRef.value = null;
|
||||
chartInstance.destroy();
|
||||
});
|
||||
return {
|
||||
setOptions,
|
||||
|
@ -5,9 +5,13 @@ const menu: MenuModule = {
|
||||
name: 'Dashboard',
|
||||
path: '/dashboard',
|
||||
children: [
|
||||
{
|
||||
path: '/workbench',
|
||||
name: '工作台',
|
||||
},
|
||||
{
|
||||
path: '/welcome',
|
||||
name: '欢迎页',
|
||||
name: '首页',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -7,7 +7,7 @@ export default {
|
||||
path: '/dashboard',
|
||||
name: 'Dashboard',
|
||||
component: PAGE_LAYOUT_COMPONENT,
|
||||
redirect: '/dashboard/welcome',
|
||||
redirect: '/dashboard/workbench',
|
||||
meta: {
|
||||
icon: 'ant-design:home-outlined',
|
||||
title: 'Dashboard',
|
||||
@ -20,7 +20,15 @@ export default {
|
||||
name: 'Welcome',
|
||||
component: () => import('/@/views/dashboard/welcome/index.vue'),
|
||||
meta: {
|
||||
title: '欢迎页',
|
||||
title: '首页',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/workbench',
|
||||
name: 'Workbench',
|
||||
component: () => import('/@/views/dashboard/workbench/index.vue'),
|
||||
meta: {
|
||||
title: '工作台',
|
||||
affix: true,
|
||||
},
|
||||
},
|
||||
|
97
src/views/dashboard/workbench/components/NewsList.vue
Normal file
97
src/views/dashboard/workbench/components/NewsList.vue
Normal file
@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<CollapseContainer class="news-list" title="动态" :canExpan="false">
|
||||
<ScrollContainer>
|
||||
<List>
|
||||
<template v-for="item in newList" :key="item.id">
|
||||
<ListItem class="news-list__item">
|
||||
<ListItemMeta>
|
||||
<template #avatar>
|
||||
<img src="/@/assets/images/header.jpg" class="news-list__item-avatar" />
|
||||
</template>
|
||||
<template #description>
|
||||
<div class="news-list__item-desc">
|
||||
<div class="news-list__item-time mb-1"> {{ item.sendTime }}</div>
|
||||
<div class="news-list__item-title mb-1">
|
||||
<span class="news-list__item-light">{{ item.sender }} </span>申请迭代
|
||||
<span class="news-list__item-light"> {{ item.title }} </span>发布
|
||||
</div>
|
||||
<div class="news-list__item-cnte p-2">
|
||||
<span class="news-list__item-cnte__title"> {{ item.cnteId }}</span>
|
||||
<br />
|
||||
Status: {{ item.cnteStas }}
|
||||
<br />
|
||||
Repository: {{ item.cnteRepo }}
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</ListItemMeta>
|
||||
</ListItem>
|
||||
</template>
|
||||
</List>
|
||||
</ScrollContainer>
|
||||
</CollapseContainer>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { List } from 'ant-design-vue';
|
||||
import { CollapseContainer, ScrollContainer } from '/@/components/Container/index';
|
||||
|
||||
import { newList } from '../data';
|
||||
export default defineComponent({
|
||||
components: {
|
||||
List,
|
||||
ListItem: List.Item,
|
||||
ListItemMeta: List.Item.Meta,
|
||||
CollapseContainer,
|
||||
ScrollContainer,
|
||||
},
|
||||
setup() {
|
||||
return { newList };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.news-list {
|
||||
&__item {
|
||||
&-avatar {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&-title {
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: #000;
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
&-time {
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: #000;
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
&-light {
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: #000;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
&-cnte {
|
||||
background: #eef3fb;
|
||||
border-radius: 2px;
|
||||
opacity: 0.6;
|
||||
|
||||
&__title {
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: #2c3a61;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
101
src/views/dashboard/workbench/components/ProdTotal.vue
Normal file
101
src/views/dashboard/workbench/components/ProdTotal.vue
Normal file
@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<Row class="prod-total">
|
||||
<template v-for="(item, index) in wokbProd" :key="item.type">
|
||||
<Col :xs="12" :sm="6" class="prod-total__item" :class="`prod-total__item-${index}`">
|
||||
<div class="img" :class="`prod-total__item-${index}-img`" />
|
||||
<div>{{ item.amount }}</div>
|
||||
<span>{{ item.type }}</span>
|
||||
</Col>
|
||||
</template>
|
||||
</Row>
|
||||
</template>
|
||||
<script lang="tsx">
|
||||
import { defineComponent } from 'vue';
|
||||
import { Row, Col } from 'ant-design-vue';
|
||||
|
||||
import { wokbProd } from '../data';
|
||||
// import {ProdTypeEnum} from '@/api/dashboard/model/wokbModel'
|
||||
export default defineComponent({
|
||||
components: { Row, Col },
|
||||
setup() {
|
||||
return { wokbProd };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.prod-total {
|
||||
padding: 12px 4px 12px 12px;
|
||||
background: #fff;
|
||||
|
||||
&__item {
|
||||
display: inline-block;
|
||||
width: calc(25% - 8px);
|
||||
padding: 20px 10px;
|
||||
margin-right: 8px;
|
||||
border-radius: 4px;
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
div {
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
.img {
|
||||
float: left;
|
||||
width: 62px;
|
||||
height: 62px;
|
||||
}
|
||||
|
||||
&-0 {
|
||||
background: rgba(254, 97, 178, 0.1);
|
||||
|
||||
&-img {
|
||||
background: url(../../../../assets/images/dashboard/wokb/datashow1.png) no-repeat;
|
||||
}
|
||||
|
||||
div {
|
||||
color: #fe61b2;
|
||||
}
|
||||
}
|
||||
|
||||
&-1 {
|
||||
background: rgba(254, 163, 64, 0.1);
|
||||
|
||||
&-img {
|
||||
background: url(../../../..//assets/images/dashboard/wokb/datashow2.png) no-repeat;
|
||||
}
|
||||
|
||||
div {
|
||||
color: #fea340;
|
||||
}
|
||||
}
|
||||
|
||||
&-2 {
|
||||
background: rgba(172, 70, 255, 0.1);
|
||||
|
||||
&-img {
|
||||
background: url(../../../..//assets/images/dashboard/wokb/datashow3.png) no-repeat;
|
||||
}
|
||||
|
||||
div {
|
||||
color: #9e55ff;
|
||||
}
|
||||
}
|
||||
|
||||
&-3 {
|
||||
background: rgba(0, 196, 186, 0.1);
|
||||
|
||||
&-img {
|
||||
background: url(../../../..//assets/images/dashboard/wokb/datashow4.png) no-repeat;
|
||||
}
|
||||
|
||||
div {
|
||||
color: #00c4ba;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
101
src/views/dashboard/workbench/components/ShortCuts.vue
Normal file
101
src/views/dashboard/workbench/components/ShortCuts.vue
Normal file
@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<CollapseContainer class="shortcuts" title="快捷入口" :canExpan="false">
|
||||
<template #action>
|
||||
<a-button size="small" type="link"> 新建 </a-button>
|
||||
</template>
|
||||
<Row>
|
||||
<template v-for="item in shortCuts" :key="item.img">
|
||||
<Col :span="8" class="shortcuts__item p-3">
|
||||
<img :src="item.img" class="shortcuts__item-img mb-2" />
|
||||
<br />
|
||||
<span>{{ item.name }}</span>
|
||||
</Col>
|
||||
</template>
|
||||
|
||||
<Col :span="8" class="shortcuts__item p-3">
|
||||
<span class="shortcuts__item-all mb-2">
|
||||
<RightOutlined />
|
||||
</span>
|
||||
<br />
|
||||
<span>查看全部</span>
|
||||
</Col>
|
||||
</Row>
|
||||
</CollapseContainer>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { Row, Col } from 'ant-design-vue';
|
||||
import { CollapseContainer } from '/@/components/Container/index';
|
||||
|
||||
import { RightOutlined } from '@ant-design/icons-vue';
|
||||
import wokbImg1 from '/@/assets/images/dashboard/wokb/attendance.png';
|
||||
import wokbImg2 from '/@/assets/images/dashboard/wokb/overtime.png';
|
||||
import wokbImg3 from '/@/assets/images/dashboard/wokb/meal.png';
|
||||
import wokbImg4 from '/@/assets/images/dashboard/wokb/leave.png';
|
||||
import wokbImg5 from '/@/assets/images/dashboard/wokb/stamp.png';
|
||||
import wokbImg6 from '/@/assets/images/dashboard/wokb/travel.png';
|
||||
import wokbImg7 from '/@/assets/images/dashboard/wokb/performance.png';
|
||||
import wokbImg8 from '/@/assets/images/dashboard/wokb/approve.png';
|
||||
const shortCuts = [
|
||||
{
|
||||
img: wokbImg1,
|
||||
name: '考勤记录',
|
||||
},
|
||||
{
|
||||
img: wokbImg2,
|
||||
name: '加班申请',
|
||||
},
|
||||
{
|
||||
img: wokbImg3,
|
||||
name: '餐补申请',
|
||||
},
|
||||
{
|
||||
img: wokbImg4,
|
||||
name: '请假',
|
||||
},
|
||||
{
|
||||
img: wokbImg5,
|
||||
name: '用章申请',
|
||||
},
|
||||
{
|
||||
img: wokbImg6,
|
||||
name: '差旅报销',
|
||||
},
|
||||
{
|
||||
img: wokbImg7,
|
||||
name: '绩效申请',
|
||||
},
|
||||
{
|
||||
img: wokbImg8,
|
||||
name: '审批',
|
||||
},
|
||||
];
|
||||
export default defineComponent({
|
||||
components: { Row, Col, CollapseContainer, RightOutlined },
|
||||
setup() {
|
||||
return { shortCuts };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.shortcuts {
|
||||
&__item {
|
||||
text-align: center;
|
||||
|
||||
&-img {
|
||||
width: 36px;
|
||||
}
|
||||
|
||||
&-all {
|
||||
display: inline-block;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
color: #000;
|
||||
cursor: pointer;
|
||||
background: lightgrey;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
114
src/views/dashboard/workbench/components/TodoList.vue
Normal file
114
src/views/dashboard/workbench/components/TodoList.vue
Normal file
@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<CollapseContainer class="todo-list" title="待办事项" :canExpan="false">
|
||||
<template #title>
|
||||
<span> 待办事项 <span class="todo-list__total">30</span> </span>
|
||||
</template>
|
||||
|
||||
<List>
|
||||
<template v-for="item in todoList" :key="item.id">
|
||||
<ListItem class="todo-list__item">
|
||||
<ListItemMeta>
|
||||
<template #title>
|
||||
<div>
|
||||
<span class="todo-list__item-title">{{ item.title }}</span>
|
||||
<span class="todo-list__item-memo">{{ item.memo }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #description>
|
||||
<div class="todo-list__item-desc">
|
||||
提交人:{{ item.sbmter }}
|
||||
<br />
|
||||
提交时间:{{ item.sbmtTime }}
|
||||
</div>
|
||||
</template>
|
||||
</ListItemMeta>
|
||||
<a-button type="link">
|
||||
<Tag color="blue">待审批</Tag>
|
||||
</a-button>
|
||||
</ListItem>
|
||||
</template>
|
||||
</List>
|
||||
<div class="todo-list__all">
|
||||
<Tooltip placement="topRight">
|
||||
<template #title>查看更多</template>
|
||||
<EllipsisOutlined />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</CollapseContainer>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { List, Tag, Tooltip } from 'ant-design-vue';
|
||||
import { CollapseContainer } from '/@/components/Container/index';
|
||||
|
||||
import { EllipsisOutlined } from '@ant-design/icons-vue';
|
||||
import { todoList } from '../data';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TodoList',
|
||||
components: {
|
||||
CollapseContainer,
|
||||
List,
|
||||
ListItem: List.Item,
|
||||
ListItemMeta: List.Item.Meta,
|
||||
Tag,
|
||||
Tooltip,
|
||||
EllipsisOutlined,
|
||||
},
|
||||
setup() {
|
||||
return { todoList };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.todo-list {
|
||||
position: relative;
|
||||
|
||||
&__total {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
background: rgba(255, 0, 0, 0.7);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&__all {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
height: 56px;
|
||||
font-size: 24px;
|
||||
line-height: 56px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&__item {
|
||||
padding: 8px;
|
||||
|
||||
&-title {
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
line-height: 22px;
|
||||
color: #1c1d21;
|
||||
}
|
||||
|
||||
&-memo {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
line-height: 22px;
|
||||
color: #7c8087;
|
||||
}
|
||||
|
||||
&-desc {
|
||||
font-size: 12px;
|
||||
line-height: 22px;
|
||||
color: #7c8087;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
94
src/views/dashboard/workbench/components/Week.vue
Normal file
94
src/views/dashboard/workbench/components/Week.vue
Normal file
@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<CollapseContainer title="任务安排" :canExpan="false">
|
||||
<div ref="chartRef" :style="{ width: '100%' }" />
|
||||
</CollapseContainer>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, Ref, ref, onMounted } from 'vue';
|
||||
|
||||
import { CollapseContainer } from '/@/components/Container/index';
|
||||
import { useApexCharts } from '/@/hooks/web/useApexCharts';
|
||||
|
||||
import moment from 'moment';
|
||||
export default defineComponent({
|
||||
components: { CollapseContainer },
|
||||
setup() {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useApexCharts(chartRef as Ref<HTMLDivElement>);
|
||||
onMounted(() => {
|
||||
setOptions({
|
||||
series: [
|
||||
{
|
||||
data: [
|
||||
{
|
||||
x: 'Analysis',
|
||||
y: [new Date('2019-02-27').getTime(), new Date('2019-03-04').getTime()],
|
||||
fillColor: '#008FFB',
|
||||
},
|
||||
{
|
||||
x: 'Design',
|
||||
y: [new Date('2019-03-04').getTime(), new Date('2019-03-08').getTime()],
|
||||
fillColor: '#00E396',
|
||||
},
|
||||
{
|
||||
x: 'Coding',
|
||||
y: [new Date('2019-03-07').getTime(), new Date('2019-03-10').getTime()],
|
||||
fillColor: '#775DD0',
|
||||
},
|
||||
{
|
||||
x: 'Testing',
|
||||
y: [new Date('2019-03-08').getTime(), new Date('2019-03-12').getTime()],
|
||||
fillColor: '#FEB019',
|
||||
},
|
||||
{
|
||||
x: 'Deployment',
|
||||
y: [new Date('2019-03-12').getTime(), new Date('2019-03-17').getTime()],
|
||||
fillColor: '#FF4560',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
height: 350,
|
||||
type: 'rangeBar',
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: true,
|
||||
distributed: true,
|
||||
dataLabels: {
|
||||
hideOverflowingLabels: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
formatter: function (val: any, opts: any) {
|
||||
var label = opts.w.globals.labels[opts.dataPointIndex];
|
||||
var a = moment(val[0]);
|
||||
var b = moment(val[1]);
|
||||
var diff = b.diff(a, 'days');
|
||||
return label + ': ' + diff + (diff > 1 ? ' days' : ' day');
|
||||
},
|
||||
style: {
|
||||
colors: ['#f3f4f5', '#fff'],
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
type: 'datetime',
|
||||
},
|
||||
yaxis: {
|
||||
show: false,
|
||||
},
|
||||
grid: {
|
||||
row: {
|
||||
colors: ['#f3f4f5', '#fff'],
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
48
src/views/dashboard/workbench/data.ts
Normal file
48
src/views/dashboard/workbench/data.ts
Normal file
@ -0,0 +1,48 @@
|
||||
export const wokbProd = [
|
||||
{
|
||||
amount: '20',
|
||||
type: '成品总数',
|
||||
},
|
||||
{
|
||||
amount: '50',
|
||||
type: '未发布',
|
||||
},
|
||||
{
|
||||
amount: '80',
|
||||
type: '发布中',
|
||||
},
|
||||
{
|
||||
amount: '100',
|
||||
type: '异常',
|
||||
},
|
||||
];
|
||||
|
||||
export const todoList = (() => {
|
||||
const ret: any[] = [];
|
||||
for (let index = 0; index < 3; index++) {
|
||||
ret.push({
|
||||
id: index,
|
||||
sbmter: '张三',
|
||||
sbmtTime: new Date().toLocaleString(),
|
||||
title: '主要',
|
||||
memo: '工作任务',
|
||||
});
|
||||
}
|
||||
return ret;
|
||||
})();
|
||||
export const newList = (() => {
|
||||
const ret: any[] = [];
|
||||
for (let index = 0; index < 3; index++) {
|
||||
ret.push({
|
||||
id: index,
|
||||
sender: '李四',
|
||||
sendTime: new Date().toLocaleString(),
|
||||
title: '代码',
|
||||
memo: '工作任务',
|
||||
cnteId: `c${index}`,
|
||||
cnteStas: 'opened',
|
||||
cnteRepo: index,
|
||||
});
|
||||
}
|
||||
return ret;
|
||||
})();
|
38
src/views/dashboard/workbench/index.vue
Normal file
38
src/views/dashboard/workbench/index.vue
Normal file
@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<Row class="workbench p-4" :gutter="12">
|
||||
<Col :md="24" :lg="17">
|
||||
<ProdTotal class="mb-3" />
|
||||
<TodoList class="mb-3" />
|
||||
<NewsList class="mb-3" />
|
||||
</Col>
|
||||
<Col :md="24" :lg="7">
|
||||
<img src="/@/assets/images/dashboard/wokb/wokb.png" class="workbench__wokb-img mb-3" />
|
||||
<ShortCuts class="mb-3" />
|
||||
<Week class="mb-3" />
|
||||
</Col>
|
||||
</Row>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { Row, Col } from 'ant-design-vue';
|
||||
import ProdTotal from './components/ProdTotal.vue';
|
||||
import TodoList from './components/TodoList.vue';
|
||||
import Week from './components/Week.vue';
|
||||
import NewsList from './components/NewsList.vue';
|
||||
import ShortCuts from './components/ShortCuts.vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: { Row, Col, ProdTotal, TodoList, Week, ShortCuts, NewsList },
|
||||
setup() {
|
||||
return {};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.workbench {
|
||||
&__wokb-img {
|
||||
width: 100%;
|
||||
height: 240px;
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user