vben
2020-10-11 1cd75fcf5ba7a3114399db8f22cf8eb6f2e4d783
feat(workbench): add workbench page
7个文件已添加
3个文件已修改
612 ■■■■■ 已修改文件
src/hooks/web/useApexCharts.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/menus/modules/demo/dashboard.ts 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/routes/modules/demo/dashboard.ts 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/workbench/components/NewsList.vue 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/workbench/components/ProdTotal.vue 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/workbench/components/ShortCuts.vue 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/workbench/components/TodoList.vue 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/workbench/components/Week.vue 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/workbench/data.ts 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/workbench/index.vue 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/hooks/web/useApexCharts.ts
@@ -30,6 +30,7 @@
      return;
    }
    chartInstanceRef.value = null;
    chartInstance.destroy();
  });
  return {
    setOptions,
src/router/menus/modules/demo/dashboard.ts
@@ -6,8 +6,12 @@
    path: '/dashboard',
    children: [
      {
        path: '/workbench',
        name: '工作台',
      },
      {
        path: '/welcome',
        name: '欢迎页',
        name: '首页',
      },
    ],
  },
src/router/routes/modules/demo/dashboard.ts
@@ -7,7 +7,7 @@
    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 @@
      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,
      },
    },
src/views/dashboard/workbench/components/NewsList.vue
New 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 }}&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>
src/views/dashboard/workbench/components/ProdTotal.vue
New 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>
src/views/dashboard/workbench/components/ShortCuts.vue
New 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>
src/views/dashboard/workbench/components/TodoList.vue
New 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>
src/views/dashboard/workbench/components/Week.vue
New 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>
src/views/dashboard/workbench/data.ts
New 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;
})();
src/views/dashboard/workbench/index.vue
New 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>