Commit 1cd75fcf5ba7a3114399db8f22cf8eb6f2e4d783

Authored by vben
1 parent 21d0ed92

feat(workbench): add workbench page

src/hooks/web/useApexCharts.ts
@@ -30,6 +30,7 @@ export function useApexCharts(elRef: Ref<HTMLDivElement>) { @@ -30,6 +30,7 @@ export function useApexCharts(elRef: Ref<HTMLDivElement>) {
30 return; 30 return;
31 } 31 }
32 chartInstanceRef.value = null; 32 chartInstanceRef.value = null;
  33 + chartInstance.destroy();
33 }); 34 });
34 return { 35 return {
35 setOptions, 36 setOptions,
src/router/menus/modules/demo/dashboard.ts
@@ -6,8 +6,12 @@ const menu: MenuModule = { @@ -6,8 +6,12 @@ const menu: MenuModule = {
6 path: '/dashboard', 6 path: '/dashboard',
7 children: [ 7 children: [
8 { 8 {
  9 + path: '/workbench',
  10 + name: '工作台',
  11 + },
  12 + {
9 path: '/welcome', 13 path: '/welcome',
10 - name: '欢迎页', 14 + name: '页',
11 }, 15 },
12 ], 16 ],
13 }, 17 },
src/router/routes/modules/demo/dashboard.ts
@@ -7,7 +7,7 @@ export default { @@ -7,7 +7,7 @@ export default {
7 path: '/dashboard', 7 path: '/dashboard',
8 name: 'Dashboard', 8 name: 'Dashboard',
9 component: PAGE_LAYOUT_COMPONENT, 9 component: PAGE_LAYOUT_COMPONENT,
10 - redirect: '/dashboard/welcome', 10 + redirect: '/dashboard/workbench',
11 meta: { 11 meta: {
12 icon: 'ant-design:home-outlined', 12 icon: 'ant-design:home-outlined',
13 title: 'Dashboard', 13 title: 'Dashboard',
@@ -20,7 +20,15 @@ export default { @@ -20,7 +20,15 @@ export default {
20 name: 'Welcome', 20 name: 'Welcome',
21 component: () => import('/@/views/dashboard/welcome/index.vue'), 21 component: () => import('/@/views/dashboard/welcome/index.vue'),
22 meta: { 22 meta: {
23 - title: '欢迎页', 23 + title: '首页',
  24 + },
  25 + },
  26 + {
  27 + path: '/workbench',
  28 + name: 'Workbench',
  29 + component: () => import('/@/views/dashboard/workbench/index.vue'),
  30 + meta: {
  31 + title: '工作台',
24 affix: true, 32 affix: true,
25 }, 33 },
26 }, 34 },
src/views/dashboard/workbench/components/NewsList.vue 0 → 100644
  1 +<template>
  2 + <CollapseContainer class="news-list" title="动态" :canExpan="false">
  3 + <ScrollContainer>
  4 + <List>
  5 + <template v-for="item in newList" :key="item.id">
  6 + <ListItem class="news-list__item">
  7 + <ListItemMeta>
  8 + <template #avatar>
  9 + <img src="/@/assets/images/header.jpg" class="news-list__item-avatar" />
  10 + </template>
  11 + <template #description>
  12 + <div class="news-list__item-desc">
  13 + <div class="news-list__item-time mb-1"> {{ item.sendTime }}</div>
  14 + <div class="news-list__item-title mb-1">
  15 + <span class="news-list__item-light">{{ item.sender }}&nbsp;</span>申请迭代
  16 + <span class="news-list__item-light">&nbsp;{{ item.title }}&nbsp;</span>发布
  17 + </div>
  18 + <div class="news-list__item-cnte p-2">
  19 + <span class="news-list__item-cnte__title"> {{ item.cnteId }}</span>
  20 + <br />
  21 + Status: {{ item.cnteStas }}
  22 + <br />
  23 + Repository: {{ item.cnteRepo }}
  24 + <br />
  25 + </div>
  26 + </div>
  27 + </template>
  28 + </ListItemMeta>
  29 + </ListItem>
  30 + </template>
  31 + </List>
  32 + </ScrollContainer>
  33 + </CollapseContainer>
  34 +</template>
  35 +<script lang="ts">
  36 + import { defineComponent } from 'vue';
  37 + import { List } from 'ant-design-vue';
  38 + import { CollapseContainer, ScrollContainer } from '/@/components/Container/index';
  39 +
  40 + import { newList } from '../data';
  41 + export default defineComponent({
  42 + components: {
  43 + List,
  44 + ListItem: List.Item,
  45 + ListItemMeta: List.Item.Meta,
  46 + CollapseContainer,
  47 + ScrollContainer,
  48 + },
  49 + setup() {
  50 + return { newList };
  51 + },
  52 + });
  53 +</script>
  54 +<style lang="less" scoped>
  55 + .news-list {
  56 + &__item {
  57 + &-avatar {
  58 + width: 35px;
  59 + height: 35px;
  60 + border-radius: 50%;
  61 + }
  62 +
  63 + &-title {
  64 + font-size: 14px;
  65 + line-height: 22px;
  66 + color: #000;
  67 + opacity: 0.65;
  68 + }
  69 +
  70 + &-time {
  71 + font-size: 14px;
  72 + line-height: 22px;
  73 + color: #000;
  74 + opacity: 0.45;
  75 + }
  76 +
  77 + &-light {
  78 + font-size: 14px;
  79 + line-height: 22px;
  80 + color: #000;
  81 + opacity: 0.85;
  82 + }
  83 +
  84 + &-cnte {
  85 + background: #eef3fb;
  86 + border-radius: 2px;
  87 + opacity: 0.6;
  88 +
  89 + &__title {
  90 + font-size: 14px;
  91 + line-height: 22px;
  92 + color: #2c3a61;
  93 + }
  94 + }
  95 + }
  96 + }
  97 +</style>
src/views/dashboard/workbench/components/ProdTotal.vue 0 → 100644
  1 +<template>
  2 + <Row class="prod-total">
  3 + <template v-for="(item, index) in wokbProd" :key="item.type">
  4 + <Col :xs="12" :sm="6" class="prod-total__item" :class="`prod-total__item-${index}`">
  5 + <div class="img" :class="`prod-total__item-${index}-img`" />
  6 + <div>{{ item.amount }}</div>
  7 + <span>{{ item.type }}</span>
  8 + </Col>
  9 + </template>
  10 + </Row>
  11 +</template>
  12 +<script lang="tsx">
  13 + import { defineComponent } from 'vue';
  14 + import { Row, Col } from 'ant-design-vue';
  15 +
  16 + import { wokbProd } from '../data';
  17 + // import {ProdTypeEnum} from '@/api/dashboard/model/wokbModel'
  18 + export default defineComponent({
  19 + components: { Row, Col },
  20 + setup() {
  21 + return { wokbProd };
  22 + },
  23 + });
  24 +</script>
  25 +<style lang="less" scoped>
  26 + .prod-total {
  27 + padding: 12px 4px 12px 12px;
  28 + background: #fff;
  29 +
  30 + &__item {
  31 + display: inline-block;
  32 + width: calc(25% - 8px);
  33 + padding: 20px 10px;
  34 + margin-right: 8px;
  35 + border-radius: 4px;
  36 +
  37 + span {
  38 + font-size: 14px;
  39 + line-height: 28px;
  40 + }
  41 +
  42 + div {
  43 + font-size: 26px;
  44 + }
  45 +
  46 + .img {
  47 + float: left;
  48 + width: 62px;
  49 + height: 62px;
  50 + }
  51 +
  52 + &-0 {
  53 + background: rgba(254, 97, 178, 0.1);
  54 +
  55 + &-img {
  56 + background: url(../../../../assets/images/dashboard/wokb/datashow1.png) no-repeat;
  57 + }
  58 +
  59 + div {
  60 + color: #fe61b2;
  61 + }
  62 + }
  63 +
  64 + &-1 {
  65 + background: rgba(254, 163, 64, 0.1);
  66 +
  67 + &-img {
  68 + background: url(../../../..//assets/images/dashboard/wokb/datashow2.png) no-repeat;
  69 + }
  70 +
  71 + div {
  72 + color: #fea340;
  73 + }
  74 + }
  75 +
  76 + &-2 {
  77 + background: rgba(172, 70, 255, 0.1);
  78 +
  79 + &-img {
  80 + background: url(../../../..//assets/images/dashboard/wokb/datashow3.png) no-repeat;
  81 + }
  82 +
  83 + div {
  84 + color: #9e55ff;
  85 + }
  86 + }
  87 +
  88 + &-3 {
  89 + background: rgba(0, 196, 186, 0.1);
  90 +
  91 + &-img {
  92 + background: url(../../../..//assets/images/dashboard/wokb/datashow4.png) no-repeat;
  93 + }
  94 +
  95 + div {
  96 + color: #00c4ba;
  97 + }
  98 + }
  99 + }
  100 + }
  101 +</style>
src/views/dashboard/workbench/components/ShortCuts.vue 0 → 100644
  1 +<template>
  2 + <CollapseContainer class="shortcuts" title="快捷入口" :canExpan="false">
  3 + <template #action>
  4 + <a-button size="small" type="link"> 新建 </a-button>
  5 + </template>
  6 + <Row>
  7 + <template v-for="item in shortCuts" :key="item.img">
  8 + <Col :span="8" class="shortcuts__item p-3">
  9 + <img :src="item.img" class="shortcuts__item-img mb-2" />
  10 + <br />
  11 + <span>{{ item.name }}</span>
  12 + </Col>
  13 + </template>
  14 +
  15 + <Col :span="8" class="shortcuts__item p-3">
  16 + <span class="shortcuts__item-all mb-2">
  17 + <RightOutlined />
  18 + </span>
  19 + <br />
  20 + <span>查看全部</span>
  21 + </Col>
  22 + </Row>
  23 + </CollapseContainer>
  24 +</template>
  25 +<script lang="ts">
  26 + import { defineComponent } from 'vue';
  27 + import { Row, Col } from 'ant-design-vue';
  28 + import { CollapseContainer } from '/@/components/Container/index';
  29 +
  30 + import { RightOutlined } from '@ant-design/icons-vue';
  31 + import wokbImg1 from '/@/assets/images/dashboard/wokb/attendance.png';
  32 + import wokbImg2 from '/@/assets/images/dashboard/wokb/overtime.png';
  33 + import wokbImg3 from '/@/assets/images/dashboard/wokb/meal.png';
  34 + import wokbImg4 from '/@/assets/images/dashboard/wokb/leave.png';
  35 + import wokbImg5 from '/@/assets/images/dashboard/wokb/stamp.png';
  36 + import wokbImg6 from '/@/assets/images/dashboard/wokb/travel.png';
  37 + import wokbImg7 from '/@/assets/images/dashboard/wokb/performance.png';
  38 + import wokbImg8 from '/@/assets/images/dashboard/wokb/approve.png';
  39 + const shortCuts = [
  40 + {
  41 + img: wokbImg1,
  42 + name: '考勤记录',
  43 + },
  44 + {
  45 + img: wokbImg2,
  46 + name: '加班申请',
  47 + },
  48 + {
  49 + img: wokbImg3,
  50 + name: '餐补申请',
  51 + },
  52 + {
  53 + img: wokbImg4,
  54 + name: '请假',
  55 + },
  56 + {
  57 + img: wokbImg5,
  58 + name: '用章申请',
  59 + },
  60 + {
  61 + img: wokbImg6,
  62 + name: '差旅报销',
  63 + },
  64 + {
  65 + img: wokbImg7,
  66 + name: '绩效申请',
  67 + },
  68 + {
  69 + img: wokbImg8,
  70 + name: '审批',
  71 + },
  72 + ];
  73 + export default defineComponent({
  74 + components: { Row, Col, CollapseContainer, RightOutlined },
  75 + setup() {
  76 + return { shortCuts };
  77 + },
  78 + });
  79 +</script>
  80 +<style lang="less" scoped>
  81 + .shortcuts {
  82 + &__item {
  83 + text-align: center;
  84 +
  85 + &-img {
  86 + width: 36px;
  87 + }
  88 +
  89 + &-all {
  90 + display: inline-block;
  91 + width: 36px;
  92 + height: 36px;
  93 + line-height: 36px;
  94 + color: #000;
  95 + cursor: pointer;
  96 + background: lightgrey;
  97 + border-radius: 50%;
  98 + }
  99 + }
  100 + }
  101 +</style>
src/views/dashboard/workbench/components/TodoList.vue 0 → 100644
  1 +<template>
  2 + <CollapseContainer class="todo-list" title="待办事项" :canExpan="false">
  3 + <template #title>
  4 + <span> 待办事项 <span class="todo-list__total">30</span> </span>
  5 + </template>
  6 +
  7 + <List>
  8 + <template v-for="item in todoList" :key="item.id">
  9 + <ListItem class="todo-list__item">
  10 + <ListItemMeta>
  11 + <template #title>
  12 + <div>
  13 + <span class="todo-list__item-title">{{ item.title }}</span>
  14 + <span class="todo-list__item-memo">{{ item.memo }}</span>
  15 + </div>
  16 + </template>
  17 + <template #description>
  18 + <div class="todo-list__item-desc">
  19 + 提交人:{{ item.sbmter }}
  20 + <br />
  21 + 提交时间:{{ item.sbmtTime }}
  22 + </div>
  23 + </template>
  24 + </ListItemMeta>
  25 + <a-button type="link">
  26 + <Tag color="blue">待审批</Tag>
  27 + </a-button>
  28 + </ListItem>
  29 + </template>
  30 + </List>
  31 + <div class="todo-list__all">
  32 + <Tooltip placement="topRight">
  33 + <template #title>查看更多</template>
  34 + <EllipsisOutlined />
  35 + </Tooltip>
  36 + </div>
  37 + </CollapseContainer>
  38 +</template>
  39 +<script lang="ts">
  40 + import { defineComponent } from 'vue';
  41 + import { List, Tag, Tooltip } from 'ant-design-vue';
  42 + import { CollapseContainer } from '/@/components/Container/index';
  43 +
  44 + import { EllipsisOutlined } from '@ant-design/icons-vue';
  45 + import { todoList } from '../data';
  46 +
  47 + export default defineComponent({
  48 + name: 'TodoList',
  49 + components: {
  50 + CollapseContainer,
  51 + List,
  52 + ListItem: List.Item,
  53 + ListItemMeta: List.Item.Meta,
  54 + Tag,
  55 + Tooltip,
  56 + EllipsisOutlined,
  57 + },
  58 + setup() {
  59 + return { todoList };
  60 + },
  61 + });
  62 +</script>
  63 +<style lang="less" scoped>
  64 + .todo-list {
  65 + position: relative;
  66 +
  67 + &__total {
  68 + display: inline-block;
  69 + width: 20px;
  70 + height: 20px;
  71 + font-size: 12px;
  72 + line-height: 20px;
  73 + color: #fff;
  74 + text-align: center;
  75 + background: rgba(255, 0, 0, 0.7);
  76 + border-radius: 50%;
  77 + }
  78 +
  79 + &__all {
  80 + position: absolute;
  81 + top: 0;
  82 + right: 10px;
  83 + height: 56px;
  84 + font-size: 24px;
  85 + line-height: 56px;
  86 + text-align: center;
  87 + cursor: pointer;
  88 + }
  89 +
  90 + &__item {
  91 + padding: 8px;
  92 +
  93 + &-title {
  94 + font-size: 14px;
  95 + font-weight: normal;
  96 + line-height: 22px;
  97 + color: #1c1d21;
  98 + }
  99 +
  100 + &-memo {
  101 + font-size: 12px;
  102 + font-weight: normal;
  103 + line-height: 22px;
  104 + color: #7c8087;
  105 + }
  106 +
  107 + &-desc {
  108 + font-size: 12px;
  109 + line-height: 22px;
  110 + color: #7c8087;
  111 + }
  112 + }
  113 + }
  114 +</style>
src/views/dashboard/workbench/components/Week.vue 0 → 100644
  1 +<template>
  2 + <CollapseContainer title="任务安排" :canExpan="false">
  3 + <div ref="chartRef" :style="{ width: '100%' }" />
  4 + </CollapseContainer>
  5 +</template>
  6 +<script lang="ts">
  7 + import { defineComponent, Ref, ref, onMounted } from 'vue';
  8 +
  9 + import { CollapseContainer } from '/@/components/Container/index';
  10 + import { useApexCharts } from '/@/hooks/web/useApexCharts';
  11 +
  12 + import moment from 'moment';
  13 + export default defineComponent({
  14 + components: { CollapseContainer },
  15 + setup() {
  16 + const chartRef = ref<HTMLDivElement | null>(null);
  17 + const { setOptions } = useApexCharts(chartRef as Ref<HTMLDivElement>);
  18 + onMounted(() => {
  19 + setOptions({
  20 + series: [
  21 + {
  22 + data: [
  23 + {
  24 + x: 'Analysis',
  25 + y: [new Date('2019-02-27').getTime(), new Date('2019-03-04').getTime()],
  26 + fillColor: '#008FFB',
  27 + },
  28 + {
  29 + x: 'Design',
  30 + y: [new Date('2019-03-04').getTime(), new Date('2019-03-08').getTime()],
  31 + fillColor: '#00E396',
  32 + },
  33 + {
  34 + x: 'Coding',
  35 + y: [new Date('2019-03-07').getTime(), new Date('2019-03-10').getTime()],
  36 + fillColor: '#775DD0',
  37 + },
  38 + {
  39 + x: 'Testing',
  40 + y: [new Date('2019-03-08').getTime(), new Date('2019-03-12').getTime()],
  41 + fillColor: '#FEB019',
  42 + },
  43 + {
  44 + x: 'Deployment',
  45 + y: [new Date('2019-03-12').getTime(), new Date('2019-03-17').getTime()],
  46 + fillColor: '#FF4560',
  47 + },
  48 + ],
  49 + },
  50 + ],
  51 + chart: {
  52 + height: 350,
  53 + type: 'rangeBar',
  54 + },
  55 + plotOptions: {
  56 + bar: {
  57 + horizontal: true,
  58 + distributed: true,
  59 + dataLabels: {
  60 + hideOverflowingLabels: false,
  61 + },
  62 + },
  63 + },
  64 + dataLabels: {
  65 + enabled: true,
  66 + formatter: function (val: any, opts: any) {
  67 + var label = opts.w.globals.labels[opts.dataPointIndex];
  68 + var a = moment(val[0]);
  69 + var b = moment(val[1]);
  70 + var diff = b.diff(a, 'days');
  71 + return label + ': ' + diff + (diff > 1 ? ' days' : ' day');
  72 + },
  73 + style: {
  74 + colors: ['#f3f4f5', '#fff'],
  75 + },
  76 + },
  77 + xaxis: {
  78 + type: 'datetime',
  79 + },
  80 + yaxis: {
  81 + show: false,
  82 + },
  83 + grid: {
  84 + row: {
  85 + colors: ['#f3f4f5', '#fff'],
  86 + opacity: 1,
  87 + },
  88 + },
  89 + });
  90 + });
  91 + return { chartRef };
  92 + },
  93 + });
  94 +</script>
src/views/dashboard/workbench/data.ts 0 → 100644
  1 +export const wokbProd = [
  2 + {
  3 + amount: '20',
  4 + type: '成品总数',
  5 + },
  6 + {
  7 + amount: '50',
  8 + type: '未发布',
  9 + },
  10 + {
  11 + amount: '80',
  12 + type: '发布中',
  13 + },
  14 + {
  15 + amount: '100',
  16 + type: '异常',
  17 + },
  18 +];
  19 +
  20 +export const todoList = (() => {
  21 + const ret: any[] = [];
  22 + for (let index = 0; index < 3; index++) {
  23 + ret.push({
  24 + id: index,
  25 + sbmter: '张三',
  26 + sbmtTime: new Date().toLocaleString(),
  27 + title: '主要',
  28 + memo: '工作任务',
  29 + });
  30 + }
  31 + return ret;
  32 +})();
  33 +export const newList = (() => {
  34 + const ret: any[] = [];
  35 + for (let index = 0; index < 3; index++) {
  36 + ret.push({
  37 + id: index,
  38 + sender: '李四',
  39 + sendTime: new Date().toLocaleString(),
  40 + title: '代码',
  41 + memo: '工作任务',
  42 + cnteId: `c${index}`,
  43 + cnteStas: 'opened',
  44 + cnteRepo: index,
  45 + });
  46 + }
  47 + return ret;
  48 +})();
src/views/dashboard/workbench/index.vue 0 → 100644
  1 +<template>
  2 + <Row class="workbench p-4" :gutter="12">
  3 + <Col :md="24" :lg="17">
  4 + <ProdTotal class="mb-3" />
  5 + <TodoList class="mb-3" />
  6 + <NewsList class="mb-3" />
  7 + </Col>
  8 + <Col :md="24" :lg="7">
  9 + <img src="/@/assets/images/dashboard/wokb/wokb.png" class="workbench__wokb-img mb-3" />
  10 + <ShortCuts class="mb-3" />
  11 + <Week class="mb-3" />
  12 + </Col>
  13 + </Row>
  14 +</template>
  15 +<script lang="ts">
  16 + import { defineComponent } from 'vue';
  17 + import { Row, Col } from 'ant-design-vue';
  18 + import ProdTotal from './components/ProdTotal.vue';
  19 + import TodoList from './components/TodoList.vue';
  20 + import Week from './components/Week.vue';
  21 + import NewsList from './components/NewsList.vue';
  22 + import ShortCuts from './components/ShortCuts.vue';
  23 +
  24 + export default defineComponent({
  25 + components: { Row, Col, ProdTotal, TodoList, Week, ShortCuts, NewsList },
  26 + setup() {
  27 + return {};
  28 + },
  29 + });
  30 +</script>
  31 +<style lang="less" scoped>
  32 + .workbench {
  33 + &__wokb-img {
  34 + width: 100%;
  35 + height: 240px;
  36 + }
  37 + }
  38 +</style>