Преглед изворни кода

feat(workbench): add workbench page

vben пре 4 година
родитељ
комит
1cd75fcf5b

+ 1 - 0
src/hooks/web/useApexCharts.ts

@@ -30,6 +30,7 @@ export function useApexCharts(elRef: Ref<HTMLDivElement>) {
       return;
     }
     chartInstanceRef.value = null;
+    chartInstance.destroy();
   });
   return {
     setOptions,

+ 5 - 1
src/router/menus/modules/demo/dashboard.ts

@@ -6,8 +6,12 @@ const menu: MenuModule = {
     path: '/dashboard',
     children: [
       {
+        path: '/workbench',
+        name: '工作台',
+      },
+      {
         path: '/welcome',
-        name: '欢迎页',
+        name: '页',
       },
     ],
   },

+ 10 - 2
src/router/routes/modules/demo/dashboard.ts

@@ -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 - 0
src/views/dashboard/workbench/components/NewsList.vue

@@ -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 }}&nbsp;</span>申请迭代
+                    <span class="news-list__item-light">&nbsp;{{ item.title }}&nbsp;</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 - 0
src/views/dashboard/workbench/components/ProdTotal.vue

@@ -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 - 0
src/views/dashboard/workbench/components/ShortCuts.vue

@@ -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 - 0
src/views/dashboard/workbench/components/TodoList.vue

@@ -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 - 0
src/views/dashboard/workbench/components/Week.vue

@@ -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 - 0
src/views/dashboard/workbench/data.ts

@@ -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 - 0
src/views/dashboard/workbench/index.vue

@@ -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>