Browse Source

Merge branch 'master' of http://git.qmth.com.cn/sop/web

刘洋 1 year ago
parent
commit
8cc9d9afb2
35 changed files with 854 additions and 837 deletions
  1. 5 0
      src/api/my-workbenches.js
  2. 16 1
      src/layout/children-menu.vue
  3. 49 3
      src/layout/index.vue
  4. 2 1
      src/router/modules/projectQuality.js
  5. 4 2
      src/router/modules/resourceGuard.js
  6. 0 13
      src/router/modules/serviceUnit.js
  7. 6 2
      src/router/modules/sop.js
  8. 3 2
      src/router/modules/user.js
  9. 4 1
      src/router/modules/workHours.js
  10. 2 1
      src/store/index.js
  11. 51 0
      src/store/modules/work.js
  12. 2 0
      src/style/color.less
  13. 143 5
      src/style/global.less
  14. 0 15
      src/style/tdesign-reset.less
  15. 9 0
      src/utils/filter.js
  16. 46 44
      src/views/my-workbenches/workbenches/message-reminder/index.vue
  17. 22 65
      src/views/my-workbenches/workbenches/message-reminder/message-list.vue
  18. 37 44
      src/views/my-workbenches/workbenches/my-waits/index.vue
  19. 26 78
      src/views/my-workbenches/workbenches/my-waits/waits-list.vue
  20. 57 44
      src/views/my-workbenches/workbenches/notice/index.vue
  21. 38 26
      src/views/my-workbenches/workbenches/notice/notice-list.vue
  22. 17 15
      src/views/project-quality/project-quality-manage/issues-feedback/index.vue
  23. 0 208
      src/views/service-unit/service-unit-manage/add-range/index.vue
  24. 2 0
      src/views/system/config-manage/customer-manage/edit-customer-dialog.vue
  25. 15 14
      src/views/user/auth-manage/role-manage/index.vue
  26. 17 6
      src/views/user/auth-manage/user-manage/add-user-dialog.vue
  27. 16 16
      src/views/user/auth-manage/user-manage/index.vue
  28. 2 2
      src/views/user/auth-manage/user-manage/update-user-pwd-dialog.vue
  29. 16 13
      src/views/user/org-struct-manage/struct-manage/index.vue
  30. 46 42
      src/views/work-hours/work-hours-manage/abnormal-check/done-check.vue
  31. 38 18
      src/views/work-hours/work-hours-manage/abnormal-check/index.vue
  32. 68 65
      src/views/work-hours/work-hours-manage/abnormal-check/wait-check.vue
  33. 9 9
      src/views/work-hours/work-hours-manage/work-attendance-detail/index.vue
  34. 56 51
      src/views/work-hours/work-hours-manage/work-attendance/index.vue
  35. 30 31
      src/views/work-hours/work-hours-manage/work-statistics/index.vue

+ 5 - 0
src/api/my-workbenches.js

@@ -5,6 +5,11 @@ export const getMyMessages = (data) =>
     url: '/api/sys/message/pageByTypes',
     params: data,
   });
+export const getMyMessagesCount = (types) =>
+  request({
+    url: '/api/sys/message/countByTypes',
+    params: { types },
+  });
 
 export const getMyWaits = (data) =>
   request({

+ 16 - 1
src/layout/children-menu.vue

@@ -11,8 +11,17 @@
         <template v-if="menu.meta.icon" #icon>
           <svg-icon :name="menu.meta.icon"></svg-icon>
         </template>
-        {{ menu.meta.title }}
+        <span>
+          {{ menu.meta.title }}
+        </span>
+        <span
+          v-if="menu.meta?.alias && counts[menu.meta.alias]"
+          class="t-menu__count"
+        >
+          {{ counts[menu.meta?.alias] }}
+        </span>
       </t-menu-item>
+      <!-- 下面这个目前是用不上了 -->
       <t-submenu v-else :value="menu.name">
         <template v-if="menu.meta.icon" #icon>
           <svg-icon :name="menu.meta.icon"></svg-icon>
@@ -30,10 +39,16 @@
 
 <script setup name="ChildrenMenu">
 import { useRouter } from 'vue-router';
+import { useWorkStore } from '@/store';
+import { computed } from 'vue';
 
 defineProps({ modelValue: Array });
 
 const router = useRouter();
+const workStore = useWorkStore();
+
+const counts = computed(() => workStore.counts);
+
 const routerPush = (menu) => {
   if (menu.meta && menu.meta.type === 'L') {
     window.open(menu.path);

+ 49 - 3
src/layout/index.vue

@@ -53,8 +53,8 @@
 </template>
 
 <script setup name="Layout" lang="jsx">
-import { ref, onMounted } from 'vue';
-import { useUserStore } from '@/store';
+import { ref, onMounted, watch } from 'vue';
+import { useUserStore, useWorkStore } from '@/store';
 import { useRouter, useRoute } from 'vue-router';
 import LeftMenu from './left-menu.vue';
 import { moduleMap } from '@/router/asyncRoutes';
@@ -63,6 +63,8 @@ import { ChevronDownIcon } from 'tdesign-icons-vue-next';
 const router = useRouter();
 const route = useRoute();
 const userStore = useUserStore();
+const workStore = useWorkStore();
+
 const moduleChange = (name) => {
   userStore.setCurPageModule(name);
   router.push({ name });
@@ -86,6 +88,24 @@ const clickHandler = (data) => {
     userStore.logout();
   }
 };
+
+watch(
+  () => userStore.curPageModule,
+  (val) => {
+    if (val !== 'MyWorkbenches') return;
+    workStore.updateWorkCounts();
+  },
+  {
+    immediate: true,
+  }
+);
+watch(
+  () => route.name,
+  () => {
+    if (userStore.curPageModule !== 'MyWorkbenches') return;
+    workStore.updateWorkCounts();
+  }
+);
 </script>
 
 <style lang="less" scoped>
@@ -101,6 +121,8 @@ const clickHandler = (data) => {
   .app-menu {
     background-color: #f2f3f5;
     height: 100%;
+    overflow-x: hidden;
+    overflow-y: auto;
 
     &-list {
       padding: 16px 8px 40px;
@@ -160,9 +182,16 @@ const clickHandler = (data) => {
   }
   .app-submenu {
     background-color: #fff;
-    padding-bottom: 68px;
     position: relative;
     color: #262626;
+    height: 100%;
+    overflow-x: hidden;
+    overflow-y: auto;
+
+    &-body {
+      padding-bottom: 68px;
+      height: 100%;
+    }
 
     &-footer {
       position: absolute;
@@ -197,6 +226,23 @@ const clickHandler = (data) => {
         }
       }
     }
+    :deep(.t-menu__content) {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      flex-grow: 2;
+    }
+    :deep(.t-menu__count) {
+      color: #fff;
+      padding: 0 3px;
+      background-color: var(--td-error-color);
+      line-height: 20px;
+      height: 20px;
+      border-radius: 3px;
+      min-width: 20px;
+      text-align: center;
+      font-size: 12px;
+    }
     :deep(.t-menu__item .svg-icon) {
       margin-right: 8px;
     }

+ 2 - 1
src/router/modules/projectQuality.js

@@ -17,7 +17,6 @@ export default {
       meta: {
         title: '项目质量管理',
         sort: 1,
-        icon: 'control-platform',
         alias: 'projectChildQualityManage',
       },
       children: [
@@ -32,6 +31,7 @@ export default {
             title: '质量问题反馈',
             sort: 1,
             alias: 'qualityProblem',
+            icon: 'service-crm',
           },
         },
         {
@@ -45,6 +45,7 @@ export default {
             title: '质量问题查询',
             sort: 1,
             alias: 'qualityProblemQuery',
+            icon: 'service-crm',
           },
         },
       ],

+ 4 - 2
src/router/modules/resourceGuard.js

@@ -17,7 +17,6 @@ export default {
       meta: {
         title: '人资保障',
         sort: 1,
-        icon: 'usergroup',
         alias: 'humanManage',
       },
       children: [
@@ -32,6 +31,7 @@ export default {
             title: '人员档案管理',
             sort: 1,
             alias: 'userArchives',
+            icon: 'service-crm',
           },
         },
         {
@@ -45,6 +45,7 @@ export default {
             title: '人员调配',
             sort: 2,
             alias: 'userAllocate',
+            icon: 'service-crm',
           },
         },
       ],
@@ -56,7 +57,6 @@ export default {
       meta: {
         title: '设备保障',
         sort: 2,
-        icon: 'print',
         alias: 'deviceManage',
       },
       children: [
@@ -71,6 +71,7 @@ export default {
             title: '出入库登记查询',
             sort: 1,
             alias: 'deviceInOut',
+            icon: 'service-crm',
           },
         },
         {
@@ -84,6 +85,7 @@ export default {
             title: '设备资源监控',
             sort: 2,
             alias: 'deviceControl',
+            icon: 'service-crm',
           },
         },
       ],

+ 0 - 13
src/router/modules/serviceUnit.js

@@ -72,19 +72,6 @@ export default {
             icon: 'service-range',
           },
         },
-        {
-          name: 'AddRange',
-          path: '/service-unit/service-unit-manage/add-range',
-          component: () =>
-            import(
-              '@/views/service-unit/service-unit-manage/add-range/index.vue'
-            ),
-          meta: {
-            title: '新增服务范围',
-            bind: 'serviceScope',
-            // bind: 'RangeManage', //注意,这种不是菜单,但是也属于路由,比如name为"RangeManage"的时候,该路由也要有权限。需要在addRoute的时候考虑进去
-          },
-        },
         {
           name: 'RegionalPlanning',
           path: '/service-unit/service-unit-manage/regional-planning',

+ 6 - 2
src/router/modules/sop.js

@@ -17,7 +17,6 @@ export default {
       meta: {
         title: 'SOP管理',
         sort: 1,
-        icon: 'layers',
         alias: 'sopChildManage',
       },
       children: [
@@ -30,6 +29,7 @@ export default {
             title: '教务处SOP管理',
             sort: 1,
             alias: 'office',
+            icon: 'service-crm',
           },
         },
         {
@@ -70,6 +70,7 @@ export default {
             title: '研究生SOP管理', //后端菜单暂时没有提供,等待需求落定
             sort: 2,
             alias: 'cloudMark',
+            icon: 'service-crm',
           },
         },
         {
@@ -81,6 +82,7 @@ export default {
             title: '设备出入库登记',
             sort: 3,
             alias: 'deviceInOutSop',
+            icon: 'service-crm',
           },
         },
         {
@@ -92,6 +94,7 @@ export default {
             title: '项目计划变更报备',
             sort: 4,
             alias: 'projectExchange',
+            icon: 'service-crm',
           },
         },
       ],
@@ -103,7 +106,6 @@ export default {
       meta: {
         title: 'SOP监控',
         sort: 1,
-        icon: 'browse',
         alias: 'sopControlManage',
       },
       children: [
@@ -116,6 +118,7 @@ export default {
             title: '延期预警',
             sort: 2,
             alias: 'delayWarn',
+            icon: 'service-crm',
           },
         },
         {
@@ -127,6 +130,7 @@ export default {
             title: '违规登记',
             sort: 3,
             alias: 'violation',
+            icon: 'service-crm',
           },
         },
       ],

+ 3 - 2
src/router/modules/user.js

@@ -17,7 +17,6 @@ export default {
       meta: {
         title: '组织架构管理',
         sort: 1,
-        icon: 'fork',
         alias: 'orgManage',
       },
       children: [
@@ -30,6 +29,7 @@ export default {
             title: '组织架构管理',
             sort: 1,
             alias: 'org',
+            icon: 'service-crm',
           },
         },
       ],
@@ -41,7 +41,6 @@ export default {
       meta: {
         title: '用户权限管理',
         sort: 2,
-        icon: 'pin',
         alias: 'userPrivilegeManage',
       },
       children: [
@@ -54,6 +53,7 @@ export default {
             title: '用户管理',
             sort: 1,
             alias: 'user',
+            icon: 'service-crm',
           },
         },
         {
@@ -65,6 +65,7 @@ export default {
             title: '角色管理',
             sort: 2,
             alias: 'role',
+            icon: 'service-crm',
           },
         },
         {

+ 4 - 1
src/router/modules/workHours.js

@@ -17,7 +17,6 @@ export default {
       meta: {
         title: '工时管理',
         sort: 1,
-        icon: 'history',
         alias: 'hoursChildManage',
       },
       children: [
@@ -32,6 +31,7 @@ export default {
             title: '异常审核',
             sort: 1,
             alias: 'exception',
+            icon: 'service-crm',
           },
         },
         {
@@ -45,6 +45,7 @@ export default {
             title: '考勤提交',
             sort: 2,
             alias: 'dingSubmit',
+            icon: 'service-crm',
           },
         },
         {
@@ -58,6 +59,7 @@ export default {
             title: '考勤明细查询',
             sort: 2,
             alias: 'dingDetail',
+            icon: 'service-crm',
           },
         },
         {
@@ -71,6 +73,7 @@ export default {
             title: '工时统计',
             sort: 3,
             alias: 'hourSubmit',
+            icon: 'service-crm',
           },
         },
       ],

+ 2 - 1
src/store/index.js

@@ -1,9 +1,10 @@
 import { createPinia } from 'pinia';
 import useAppStore from './modules/app';
 import useUserStore from './modules/user';
+import useWorkStore from './modules/work';
 import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
 
 const pinia = createPinia();
 pinia.use(piniaPluginPersistedstate);
-export { useAppStore, useUserStore };
+export { useAppStore, useUserStore, useWorkStore };
 export default pinia;

+ 51 - 0
src/store/modules/work.js

@@ -0,0 +1,51 @@
+import { defineStore } from 'pinia';
+
+import { getMyMessagesCount, getMyWaits } from '@/api/my-workbenches';
+import { MESSAGE_TYPE } from '@/config/constants';
+
+const useWorkStore = defineStore('work', {
+  state: () => ({
+    counts: {
+      message: 0,
+      work: 0,
+      notice: 0,
+    },
+  }),
+  actions: {
+    async updateWorkCounts() {
+      const task = [
+        {
+          type: 'message',
+          func: () => getMyMessagesCount(Object.keys(MESSAGE_TYPE).join()),
+        },
+        {
+          type: 'work',
+          func: async () => {
+            const data = await getMyWaits({
+              flowTaskTypeEnum: 'ALL',
+              pageNumber: 1,
+              pageSize: 1,
+            });
+
+            return data ? data.total : 0;
+          },
+        },
+        {
+          type: 'notice',
+          func: () => getMyMessagesCount('SYSTEM'),
+        },
+      ];
+      let countAll = task.map((item) => item.func());
+      const data = await Promise.all(countAll).catch(() => {});
+      if (!data) return;
+
+      let counts = {};
+      data.forEach((count, index) => {
+        counts[task[index].type] = count;
+      });
+      this.counts = counts;
+    },
+  },
+});
+
+export default useWorkStore;

+ 2 - 0
src/style/color.less

@@ -1,2 +1,4 @@
 @dark-text-color: #262626;
+@dark-text-color-2: #595959;
 @light-text-color: #8c8c8c;
+@light-border-color: #e5e5e5;

+ 143 - 5
src/style/global.less

@@ -6,7 +6,7 @@ body {
   height: 100%;
   background-size: cover;
   font-size: 14px;
-  color: #262626;
+  color: @dark-text-color;
 }
 #app {
   height: 100%;
@@ -18,6 +18,12 @@ body {
   // box-shadow: 1px 1px 2px var(--color-neutral-2);
 }
 
+.table-operations {
+  & > .t-link:not(:first-child) {
+    margin-left: 15px;
+  }
+}
+
 .page-action {
   padding: 16px 16px 1px;
   background-color: #fff;
@@ -29,7 +35,7 @@ body {
 }
 .page-header {
   padding: 16px;
-  border-bottom: 1px solid #e5e5e5;
+  border-bottom: 1px solid @light-border-color;
 }
 .table-search {
   .t-form__item {
@@ -46,7 +52,7 @@ body {
   }
 }
 .page-wrap {
-  margin: 12px 16px;
+  margin: 16px;
   &-tips {
     color: #4e5969;
     .t-icon {
@@ -58,7 +64,7 @@ body {
 
     th {
       background-color: #fff;
-      color: #8c8c8c;
+      color: @light-text-color;
       font-weight: 400;
       padding: 12px 16px;
     }
@@ -84,13 +90,73 @@ body {
     td,
     th,
     .t-table__content {
-      border-color: #e5e5e5;
+      border-color: @light-border-color;
     }
     .t-table__content {
       border-radius: 4px;
     }
   }
 }
+.page-pagination {
+  padding: 12px 0;
+  .t-input-adornment__append {
+    border: 1px solid #d9d9d9;
+    padding: 0 3px;
+    height: var(--td-comp-size-m);
+  }
+  .t-input-number .t-input {
+    height: var(--td-comp-size-m);
+  }
+}
+.page-tab {
+  color: var(--td-text-color-primary);
+  box-sizing: border-box;
+  margin: 0;
+  padding: 0;
+  font-size: var(--td-font-body-large);
+  cursor: pointer;
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  vertical-align: middle;
+  white-space: nowrap;
+  border-radius: var(--td-radius-default);
+  transition: all 0.2s linear;
+  touch-action: manipulation;
+  text-decoration: none;
+  position: relative;
+
+  height: var(--td-comp-size-xl);
+  font: var(--td-font-body-large);
+  padding-left: calc(var(--td-comp-paddingLR-xl) - 1px);
+  padding-right: calc(var(--td-comp-paddingLR-xl) - 1px);
+
+  &:not(:first-child) {
+    margin-left: 8px;
+  }
+
+  &.is-active {
+    color: var(--td-brand-color);
+    background-color: #e8f3ff;
+  }
+  &.is-mark {
+    &::after {
+      content: '';
+      display: block;
+      position: absolute;
+      width: 8px;
+      height: 8px;
+      background: var(--td-error-color);
+      border-radius: 50%;
+      top: 50%;
+      margin-top: -4px;
+      right: 8px;
+    }
+  }
+  &:not(.is-active):hover {
+    background-color: var(--td-gray-color-3);
+  }
+}
 .btn-group {
   & > .t-button {
     &:not(:first-child) {
@@ -157,6 +223,11 @@ body {
     margin-top: 20px;
   }
 }
+.box-justify {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
 
 .text-indent {
   text-indent: 2em;
@@ -164,3 +235,70 @@ body {
 .red {
   color: #e4393d;
 }
+
+// pages ---------------->
+// message-list
+.message-list {
+  .none-box {
+    text-align: center;
+    margin-top: 100px;
+    img {
+      height: 120px;
+    }
+    p {
+      color: @light-text-color;
+      font-size: 14px;
+      margin-top: 10px;
+    }
+  }
+  .message-item {
+    border: 1px solid @light-border-color;
+    border-radius: 4px;
+    background-color: #fff;
+    padding: 16px;
+    margin-bottom: 10px;
+    .m-head {
+      border-bottom: 1px solid @light-border-color;
+      line-height: 24px;
+      padding-bottom: 16px;
+
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+
+      .m-title {
+        font-size: 16px;
+        color: @dark-text-color;
+        font-weight: bold;
+        margin-right: 12px;
+        flex-grow: 2;
+        font-size: 0;
+
+        > span {
+          display: inline-block;
+          vertical-align: middle;
+          margin-right: 12px;
+        }
+        span:first-child {
+          font-size: 14px;
+        }
+      }
+      .m-time {
+        flex-grow: 0;
+        color: @light-text-color;
+      }
+    }
+    .m-body {
+      .m-content {
+        color: @dark-text-color-2;
+        font-weight: 500;
+        line-height: 22px;
+        padding: 16px 0 8px 0;
+      }
+      .m-info {
+        color: @light-text-color;
+        line-height: 22px;
+      }
+    }
+  }
+}

+ 0 - 15
src/style/tdesign-reset.less

@@ -6,21 +6,6 @@
   --td-success-color: #00b42a;
 }
 
-.t-layout .t-table {
-  margin-top: 10px;
-  font-size: 14px !important;
-  color: #515a6e;
-  th {
-    background-color: #f8f8f9;
-    font-weight: bold;
-    color: #515a6e;
-  }
-  .table-operations {
-    & > .t-link:not(:first-child) {
-      margin-left: 15px;
-    }
-  }
-}
 .t-dialog--default {
   padding-top: 20px;
 }

+ 9 - 0
src/utils/filter.js

@@ -19,6 +19,8 @@ import {
   DATA_TASK_STATUS,
   DATA_TASK_RESULT,
   DATA_TASK_TYPE,
+  MESSAGE_TYPE,
+  WAIT_HANDLE_TYPE,
 } from '@/config/constants';
 import { dateFormat } from './tool';
 
@@ -49,6 +51,13 @@ export function timestampFilter(val, fmt = 'ss') {
 export function dayCountFilter(val) {
   return Math.ceil(val / (24 * 60 * 60 * 1000));
 }
+// 工作台
+export function messageTypeFilter(val) {
+  return MESSAGE_TYPE[val] || DEFAULT_FIELD;
+}
+export function waitHandleTypeFilter(val) {
+  return WAIT_HANDLE_TYPE[val] || DEFAULT_FIELD;
+}
 // 系统管理
 export function customerTypeFilter(val) {
   return CUSTOMER_TYPE[val] || DEFAULT_FIELD;

+ 46 - 44
src/views/my-workbenches/workbenches/message-reminder/index.vue

@@ -1,5 +1,20 @@
 <template>
   <div class="message-reminder flex flex-col h-full">
+    <div class="page-action">
+      <div
+        v-for="item in tabs"
+        :key="item.value"
+        :class="[
+          'page-tab',
+          {
+            'is-active': params.status === item.value,
+            'is-mark': item.value === 'false' && workStore.counts.notice,
+          },
+        ]"
+        @click="switchTab(item)"
+        >{{ item.label }}</div
+      >
+    </div>
     <SearchForm :fields="fields" :params="params">
       <template #service="{ item, params }">
         <select-service-unit
@@ -8,38 +23,12 @@
         ></select-service-unit>
       </template>
     </SearchForm>
-    <div class="page-wrap flex-1">
-      <t-tabs
-        v-model="params.status"
-        class="h-full"
-        @change="tabChange"
-        v-loading="loading"
-      >
-        <t-tab-panel value="undefined" label="全部">
-          <MessageList
-            :loading="loading"
-            :tableData="tableData"
-            :pagination="pagination"
-            :onChange="onChange"
-          ></MessageList>
-        </t-tab-panel>
-        <t-tab-panel value="false" label="未读">
-          <MessageList
-            :loading="loading"
-            :tableData="tableData"
-            :pagination="pagination"
-            :onChange="onChange"
-          ></MessageList>
-        </t-tab-panel>
-        <t-tab-panel value="true" label="已读">
-          <MessageList
-            :loading="loading"
-            :tableData="tableData"
-            :pagination="pagination"
-            :onChange="onChange"
-          ></MessageList>
-        </t-tab-panel>
-      </t-tabs>
+    <div v-loading="loading" class="page-wrap flex-1">
+      <MessageList
+        :tableData="tableData"
+        :pagination="pagination"
+        :onChange="onChange"
+      ></MessageList>
     </div>
   </div>
 </template>
@@ -51,14 +40,36 @@ import { getMyMessages } from '@/api/my-workbenches';
 import { MESSAGE_TYPE } from '@/config/constants';
 import { dictToOptionList } from '@/utils/tool';
 import MessageList from './message-list.vue';
+import { useWorkStore } from '@/store';
+
+const workStore = useWorkStore();
+const tabs = [
+  {
+    label: '全部',
+    value: 'undefined',
+  },
+  {
+    label: '未读',
+    value: 'false',
+  },
+  {
+    label: '已读',
+    value: 'true',
+  },
+];
+
 const params = reactive({
   types: [],
   serviceId: '',
   custom: '',
   status: 'undefined',
 });
+
 const transParams = computed(() => {
   let types = params.types.join(',');
+  if (!types.length && params.status === 'undefined') {
+    types = Object.keys(MESSAGE_TYPE).join();
+  }
   let status = eval(params.status);
   return { ...params, types, status };
 });
@@ -71,7 +82,9 @@ const {
 } = useFetchTable(getMyMessages, {
   params: transParams,
 });
-const tabChange = () => {
+
+const switchTab = (tab) => {
+  params.status = tab.value;
   search();
 };
 const fields = ref([
@@ -115,14 +128,3 @@ const fields = ref([
   },
 ]);
 </script>
-
-<style lang="less" scoped>
-.message-reminder {
-  .page-wrap {
-    :deep(.t-tabs__content) {
-      height: calc(100% - var(--td-comp-size-xxl));
-      overflow: auto;
-    }
-  }
-}
-</style>

+ 22 - 65
src/views/my-workbenches/workbenches/message-reminder/message-list.vue

@@ -2,28 +2,40 @@
   <div class="message-list">
     <div class="message-item" v-for="item in tableData" :key="item.id">
       <div class="m-head">
-        <span class="m-title">{{ item.messageType }}</span>
-        <t-tag theme="danger" variant="light" v-if="!item.readStatus"
-          >未读</t-tag
-        >
+        <div class="m-title">
+          <span>{{ messageTypeFilter(item.messageType) }}</span>
+          <t-tag
+            theme="danger"
+            variant="light"
+            size="small"
+            v-if="!item.readStatus"
+            >未读</t-tag
+          >
+        </div>
+        <div class="m-time">{{ timestampFilter(item.sendTime, 'mm') }}</div>
       </div>
       <div class="m-body">
         <div class="m-content">{{ item.content }}</div>
-        <div class="m-info flex items-center">
+        <t-space class="m-info" :size="5">
           <p>发起人:{{ item.formUser }}</p>
           <p>服务单元:{{ item.service }} </p>
           <p>客户类型:{{ item.customType }}</p>
           <p>客户名称:{{ item.custom }}</p>
-        </div>
+          <template #separator>
+            <t-divider layout="vertical" />
+          </template>
+        </t-space>
       </div>
     </div>
 
     <t-pagination
       v-if="pagination.total > 0"
-      class="m-t-20px"
+      class="page-pagination"
       v-model="pagination.pageNumber"
       v-model:pageSize="pagination.pageSize"
       :total="pagination.total"
+      showJumper
+      :showPageSize="false"
       @change="onChange"
     />
 
@@ -35,66 +47,11 @@
 </template>
 
 <script setup name="MessageList">
-const { tableData, loading, pagination, onChange } = defineProps([
+import { messageTypeFilter, timestampFilter } from '@/utils/filter';
+
+const { tableData, pagination, onChange } = defineProps([
   'tableData',
-  'loading',
   'pagination',
   'onChange',
 ]);
 </script>
-
-<style lang="less" scoped>
-.message-list {
-  .none-box {
-    text-align: center;
-    margin-top: 100px;
-    img {
-      height: 120px;
-    }
-    p {
-      color: @light-text-color;
-      font-size: 14px;
-      margin-top: 10px;
-    }
-  }
-  .message-item {
-    border: 1px solid #e5e5e5;
-    border-radius: 4px;
-    background-color: #fff;
-    padding: 0 15px;
-    margin-bottom: 10px;
-    .m-head {
-      height: 55px;
-      border-bottom: 1px solid #e5e5e5;
-      .m-title {
-        font-size: 16px;
-        color: #262626;
-        font-weight: bold;
-        line-height: 54px;
-        margin-right: 12px;
-      }
-    }
-    .m-body {
-      padding: 15px 0;
-      .m-content {
-        color: #595959;
-        font-size: 14px;
-        font-weight: bold;
-      }
-      .m-info {
-        margin-top: 20px;
-        p {
-          padding-right: 20px;
-          border-right: 1px solid #e5e5e5;
-          color: @light-text-color;
-          line-height: 1;
-          margin-right: 20px;
-          &:last-child {
-            border-right: none;
-          }
-        }
-      }
-    }
-  }
-}
-</style>

+ 37 - 44
src/views/my-workbenches/workbenches/my-waits/index.vue

@@ -1,5 +1,17 @@
 <template>
   <div class="message-reminder flex flex-col h-full">
+    <div class="page-action">
+      <div
+        v-for="item in tabs"
+        :key="item.value"
+        :class="[
+          'page-tab',
+          { 'is-active': params.flowTaskTypeEnum === item.value },
+        ]"
+        @click="switchTab(item)"
+        >{{ item.label }}</div
+      >
+    </div>
     <SearchForm :fields="fields" :params="params">
       <template #service="{ item, params }">
         <select-service-unit
@@ -8,38 +20,12 @@
         ></select-service-unit>
       </template>
     </SearchForm>
-    <div class="page-wrap flex-1">
-      <t-tabs
-        v-model="params.flowTaskTypeEnum"
-        class="h-full"
-        @change="tabChange"
-        v-loading="loading"
-      >
-        <t-tab-panel value="ALL" label="全部">
-          <TaskList
-            :loading="loading"
-            :tableData="tableData"
-            :pagination="pagination"
-            :onChange="onChange"
-          ></TaskList>
-        </t-tab-panel>
-        <t-tab-panel value="OVER_TIME" label="已超时">
-          <TaskList
-            :loading="loading"
-            :tableData="tableData"
-            :pagination="pagination"
-            :onChange="onChange"
-          ></TaskList>
-        </t-tab-panel>
-        <t-tab-panel value="DRAFT" label="暂存">
-          <TaskList
-            :loading="loading"
-            :tableData="tableData"
-            :pagination="pagination"
-            :onChange="onChange"
-          ></TaskList>
-        </t-tab-panel>
-      </t-tabs>
+    <div v-loading="loading" class="page-wrap flex-1">
+      <TaskList
+        :tableData="tableData"
+        :pagination="pagination"
+        :onChange="onChange"
+      ></TaskList>
     </div>
   </div>
 </template>
@@ -51,6 +37,22 @@ import { getMyWaits } from '@/api/my-workbenches';
 import { WAIT_HANDLE_TYPE } from '@/config/constants';
 import { dictToOptionList } from '@/utils/tool';
 import TaskList from './waits-list.vue';
+
+const tabs = [
+  {
+    label: '全部',
+    value: 'ALL',
+  },
+  {
+    label: '已超时',
+    value: 'OVER_TIME',
+  },
+  {
+    label: '暂存',
+    value: 'DRAFT',
+  },
+];
+
 const params = reactive({
   type: '',
   serviceId: '',
@@ -67,7 +69,9 @@ const {
 } = useFetchTable(getMyWaits, {
   params: params,
 });
-const tabChange = () => {
+
+const switchTab = (tab) => {
+  params.flowTaskTypeEnum = tab.value;
   search();
 };
 const fields = ref([
@@ -111,14 +115,3 @@ const fields = ref([
   },
 ]);
 </script>
-
-<style lang="less" scoped>
-.message-reminder {
-  .page-wrap {
-    :deep(.t-tabs__content) {
-      height: calc(100% - var(--td-comp-size-xxl));
-      overflow: auto;
-    }
-  }
-}
-</style>

+ 26 - 78
src/views/my-workbenches/workbenches/my-waits/waits-list.vue

@@ -1,39 +1,47 @@
 <template>
-  <div class="message-list">
+  <div class="message-list waits-list">
     <div
-      class="message-item cursor-pointer"
       v-for="item in tableData"
       :key="item.id"
+      class="message-item cursor-pointer"
     >
       <div class="m-head">
-        <span class="m-title">{{ item.taskName }}</span>
-        <t-tag theme="success" variant="light" v-if="item.diffTime == 0"
-          >正常</t-tag
-        >
-        <template v-else>
-          <t-tag theme="danger" variant="light">已超时</t-tag>
-          <t-tag class="m-l-5px" theme="danger" variant="light"
-            >超时时长:{{ item.diffTime <= 30 ? '30天' : '大于30天' }}</t-tag
+        <div class="m-title">
+          <span>{{ item.taskName }}</span>
+          <t-tag v-if="item.diffTime == 0" theme="success" variant="light"
+            >正常</t-tag
           >
-        </template>
+          <template v-else>
+            <t-tag theme="danger" variant="light">已超时</t-tag>
+            <t-tag theme="danger" variant="light"
+              >超时时长:{{ item.diffTime <= 30 ? '30天' : '大于30天' }}</t-tag
+            >
+          </template>
+        </div>
+        <div class="m-time">{{ timestampFilter(item.flowTime, 'mm') }}</div>
       </div>
       <div class="m-body">
         <div class="m-content">{{ item.typeStr }}</div>
-        <div class="m-info flex items-center">
+        <t-space class="m-info" :size="5">
           <p>发起人:{{ item.createRealName }}</p>
           <p>服务单元: {{ item.serviceName }} </p>
-          <p>客户类型:{{ CUSTOMER_TYPE[item.customType] }}</p>
+          <p>客户类型:{{ customerTypeFilter(item.customType) }}</p>
           <p>客户名称:{{ item.customName }}</p>
-        </div>
+          <template #separator>
+            <t-divider layout="vertical" />
+          </template>
+        </t-space>
       </div>
     </div>
 
     <t-pagination
       v-if="pagination.total > 0"
-      class="m-t-20px"
+      class="page-pagination"
       v-model="pagination.pageNumber"
       v-model:pageSize="pagination.pageSize"
       :total="pagination.total"
+      showJumper
+      :showPageSize="false"
       @change="onChange"
     />
     <div class="none-box" v-if="!tableData.length">
@@ -44,71 +52,11 @@
 </template>
 
 <script setup name="MyTaskList">
-import { CUSTOMER_TYPE } from '@/config/constants';
-const { tableData, loading, pagination, onChange } = defineProps([
+import { timestampFilter, customerTypeFilter } from '@/utils/filter';
+
+const { tableData, pagination, onChange } = defineProps([
   'tableData',
-  'loading',
   'pagination',
   'onChange',
 ]);
 </script>
-
-<style lang="less" scoped>
-.message-list {
-  .none-box {
-    text-align: center;
-    margin-top: 100px;
-    img {
-      height: 120px;
-    }
-    p {
-      color: @light-text-color;
-      font-size: 14px;
-      margin-top: 10px;
-    }
-  }
-  .message-item {
-    border: 1px solid #e5e5e5;
-    border-radius: 4px;
-    background-color: #fff;
-    padding: 0 15px;
-    margin-bottom: 10px;
-    transition: all 0.3s;
-    &:hover {
-      background-color: #f3f3f3;
-    }
-    .m-head {
-      height: 55px;
-      border-bottom: 1px solid #e5e5e5;
-      .m-title {
-        font-size: 16px;
-        color: #262626;
-        font-weight: bold;
-        line-height: 54px;
-        margin-right: 12px;
-      }
-    }
-    .m-body {
-      padding: 15px 0;
-      .m-content {
-        color: #595959;
-        font-size: 14px;
-        font-weight: bold;
-      }
-      .m-info {
-        margin-top: 20px;
-        p {
-          padding-right: 20px;
-          border-right: 1px solid #e5e5e5;
-          color: @light-text-color;
-          line-height: 1;
-          margin-right: 20px;
-          &:last-child {
-            border-right: none;
-          }
-        }
-      }
-    }
-  }
-}
-</style>

+ 57 - 44
src/views/my-workbenches/workbenches/notice/index.vue

@@ -1,5 +1,21 @@
 <template>
   <div class="notice flex flex-col h-full">
+    <div class="page-action">
+      <div
+        v-for="item in tabs"
+        :key="item.value"
+        :class="[
+          'page-tab',
+          {
+            'is-active': params.status === item.value,
+            'is-mark': item.value === 'false' && workStore.counts.notice,
+          },
+        ]"
+        @click="switchTab(item)"
+        >{{ item.label }}</div
+      >
+    </div>
+
     <SearchForm :fields="fields" :params="params">
       <template #service="{ item, params }">
         <select-service-unit
@@ -8,53 +24,32 @@
         ></select-service-unit>
       </template>
     </SearchForm>
-    <div class="page-wrap flex-1">
-      <t-tabs
-        v-model="params.status"
-        class="h-full"
-        v-loading="loading"
-        @change="tabChange"
-      >
-        <t-tab-panel value="undefined" label="全部">
-          <NoticeList
-            :loading="loading"
-            :tableData="tableData"
-            :pagination="pagination"
-            :onChange="onChange"
-            @open="open"
-          ></NoticeList>
-        </t-tab-panel>
-        <t-tab-panel value="false" label="未读">
-          <NoticeList
-            :loading="loading"
-            :tableData="tableData"
-            :pagination="pagination"
-            :onChange="onChange"
-            @open="open"
-          ></NoticeList>
-        </t-tab-panel>
-        <t-tab-panel value="true" label="已读">
-          <NoticeList
-            :loading="loading"
-            :tableData="tableData"
-            :pagination="pagination"
-            :onChange="onChange"
-            @open="open"
-          ></NoticeList>
-        </t-tab-panel>
-      </t-tabs>
+
+    <div v-loading="loading" class="page-wrap flex-1">
+      <NoticeList
+        :loading="loading"
+        :tableData="tableData"
+        :pagination="pagination"
+        :onChange="onChange"
+        @open="open"
+      ></NoticeList>
     </div>
+
     <t-drawer
       v-model:visible="visible"
       header="通知公告"
-      :footer="false"
-      size="700px"
+      size="80%"
+      :close-btn="true"
     >
       <h2 class="text-center notice-title">{{ curNotice.title }}</h2>
       <div class="text-center notice-subtitle"
         >发布时间:{{ dateFormat(curNotice.sendTime, 'yyyy-MM-dd') }}</div
       >
       <p class="notice-content">{{ curNotice.content }}</p>
+
+      <template #footer>
+        <t-button theme="primary" @click="visible = false">返回</t-button>
+      </template>
     </t-drawer>
   </div>
 </template>
@@ -66,11 +61,32 @@ import { getMyMessages } from '@/api/my-workbenches';
 import NoticeList from './notice-list.vue';
 import { omit } from 'lodash';
 import { dateFormat } from '@/utils/tool';
+import { useWorkStore } from '@/store';
+
+const workStore = useWorkStore();
+
 const curNotice = ref({});
 const visible = ref(false);
 const open = (notice) => {
   curNotice.value = notice;
+  visible.value = true;
 };
+
+const tabs = [
+  {
+    label: '全部',
+    value: 'undefined',
+  },
+  {
+    label: '未读',
+    value: 'false',
+  },
+  {
+    label: '已读',
+    value: 'true',
+  },
+];
+
 const params = reactive({
   types: ['SYSTEM'],
   title: '',
@@ -97,9 +113,12 @@ const {
 } = useFetchTable(getMyMessages, {
   params: transParams,
 });
-const tabChange = () => {
+
+const switchTab = (tab) => {
+  params.status = tab.value;
   search();
 };
+
 const fields = ref([
   {
     prop: 'time',
@@ -136,12 +155,6 @@ const fields = ref([
 
 <style lang="less" scoped>
 .notice {
-  .page-wrap {
-    :deep(.t-tabs__content) {
-      height: calc(100% - var(--td-comp-size-xxl));
-      overflow: auto;
-    }
-  }
   .notice-title {
     color: #333;
     font-size: 20px;

+ 38 - 26
src/views/my-workbenches/workbenches/notice/notice-list.vue

@@ -1,29 +1,42 @@
 <template>
-  <div class="notice-list">
-    <t-table
-      size="small"
-      row-key="id"
-      :columns="columns"
-      :data="tableData"
-      bordered
-      :pagination="{
-        defaultCurrent: 1,
-        defaultPageSize: 10,
-        onChange,
-        total: pagination.total,
-        current: pagination.pageNumber,
-      }"
-    >
-      <template #title="{ row }">
-        <t-link theme="primary" hover="color" @click="open(row)">
-          {{ row.title }}
-        </t-link>
-      </template>
-    </t-table>
-  </div>
+  <t-table
+    size="small"
+    row-key="id"
+    :columns="columns"
+    :data="tableData"
+    bordered
+    :pagination="{
+      defaultCurrent: 1,
+      defaultPageSize: 10,
+      onChange,
+      showJumper: true,
+      showPageSize: false,
+      total: pagination.total,
+      current: pagination.pageNumber,
+    }"
+  >
+    <template #title="{ row }">
+      <t-link hover="color" @click="open(row)">
+        {{ row.title }}
+      </t-link>
+      <t-tag
+        v-if="!row.readStatus"
+        theme="danger"
+        variant="light"
+        size="small"
+        class="m-l-10px"
+        >未读</t-tag
+      >
+    </template>
+    <template #send-time="{ col, row }">
+      {{ timestampFilter(row[col.colKey], 'mm') }}
+    </template>
+  </t-table>
 </template>
 
 <script setup name="NoticeList">
+import { timestampFilter } from '@/utils/filter';
+
 const columns = [
   {
     colKey: 'title',
@@ -33,11 +46,12 @@ const columns = [
   {
     colKey: 'sendTime',
     title: '发送时间',
+    width: 180,
+    cell: 'send-time',
   },
 ];
-const { tableData, loading, pagination, onChange } = defineProps([
+const { tableData, pagination, onChange } = defineProps([
   'tableData',
-  'loading',
   'pagination',
   'onChange',
 ]);
@@ -46,5 +60,3 @@ const open = (row) => {
   emit('open', row);
 };
 </script>
-
-<style lang="less" scoped></style>

+ 17 - 15
src/views/project-quality/project-quality-manage/issues-feedback/index.vue

@@ -1,19 +1,21 @@
 <template>
-  <div class="issues-feedback flex flex-col h-full">
+  <div class="flex flex-col h-full">
+    <div class="page-action">
+      <t-button
+        variant="outline"
+        :disabled="!selectedRowKeys.length"
+        @click="handleDestroy"
+      >
+        <template #icon><svg-icon name="delete" color="#262626" /></template>
+        作废
+      </t-button>
+    </div>
     <SearchForm :fields="fields" :params="params">
       <template #service="{ item, params }">
         <select-service-unit v-model="params[item.prop]"></select-service-unit>
       </template>
     </SearchForm>
     <div class="flex-1 page-wrap">
-      <div class="btn-group">
-        <t-button
-          theme="success"
-          :disabled="!selectedRowKeys.length"
-          @click="handleDestroy"
-          >作废</t-button
-        >
-      </div>
       <t-table
         size="small"
         row-key="id"
@@ -207,15 +209,15 @@ const columns = [
   },
   { colKey: 'problemNo', title: '质量问题编号', minWidth: 120 },
   { colKey: 'crmNo', title: '项目单号', minWidth: 120 },
-  { colKey: 'customType', title: '客户类型', cell: 'type', width: 100 },
-  { colKey: 'custom', title: '客户名称' },
+  { colKey: 'customType', title: '客户类型', cell: 'type', width: 120 },
+  { colKey: 'custom', title: '客户名称', width: 140 },
   { colKey: 'sopType', title: '实施产品' },
   { colKey: 'summary', title: '问题简要' },
   { colKey: 'userNames', title: '责任人' },
   { colKey: 'type', title: '问题类型', cell: 'issues-type', width: 120 },
   { colKey: 'reason', title: '问题归因', cell: 'issues-reason', width: 120 },
-  { colKey: 'influenceDegree', title: '影响度', width: 70 },
-  { colKey: 'submitter', title: '提交人' },
+  { colKey: 'influenceDegree', title: '影响度', width: 100 },
+  { colKey: 'submitter', title: '提交人', width: 140 },
   {
     colKey: 'submissionTime',
     title: '提交时间',
@@ -228,9 +230,9 @@ const columns = [
     cell: 'update-time',
     width: 180,
   },
-  { colKey: 'status', title: '流程状态', cell: 'flow-status', width: 100 },
+  { colKey: 'status', title: '流程状态', cell: 'flow-status', width: 120 },
   { colKey: 'setup', title: '当前节点' },
-  { colKey: 'pendApproveUsers', title: '当前负责人' },
+  { colKey: 'pendApproveUsers', title: '当前负责人', width: 120 },
 ];
 
 const { pagination, tableData, fetchData, search, onChange } = useFetchTable(

+ 0 - 208
src/views/service-unit/service-unit-manage/add-range/index.vue

@@ -1,208 +0,0 @@
-<template>
-  <div class="add-range flex flex-col h-full">
-    <SearchForm :fields="fields" :params="params">
-      <template #user="{ item, params }">
-        <select-type-user
-          v-model="params[item.prop]"
-          type="ACCOUNT_MANAGER"
-        ></select-type-user>
-      </template>
-    </SearchForm>
-
-    <div class="flex-1 page-wrap">
-      <div class="btn-group">
-        <t-button
-          theme="success"
-          :disabled="!selectedRowKeys.length"
-          @click="handlerBatchBind"
-          >批量划定</t-button
-        >
-      </div>
-      <t-table
-        size="small"
-        row-key="id"
-        :columns="columns"
-        :data="tableData"
-        bordered
-        :pagination="{
-          defaultCurrent: 1,
-          defaultPageSize: 10,
-          onChange,
-          showJumper: true,
-          showPageSize: false,
-          current: pagination.pageNumber,
-        }"
-        v-loading="tableLoading"
-        :selected-row-keys="selectedRowKeys"
-        @select-change="selectChange"
-      >
-        <template #type="{ col, row }">
-          {{ customerTypeFilter(row[col.colKey]) }}
-        </template>
-        <template #begin-time="{ col, row }">
-          {{ timestampFilter(row[col.colKey]) }}
-        </template>
-        <template #exam-start-time="{ col, row }">
-          {{ timestampFilter(row[col.colKey]) }}
-        </template>
-        <template #exam-end-time="{ col, row }">
-          {{ timestampFilter(row[col.colKey]) }}
-        </template>
-        <template #create-time="{ col, row }">
-          {{ timestampFilter(row[col.colKey]) }}
-        </template>
-      </t-table>
-    </div>
-
-    <!-- MultDelineationDialog -->
-    <mult-delineation-dialog
-      v-model:visible="showMultDelineationDialog"
-      :crm-ids="selectedRowKeys"
-      @success="search"
-    ></mult-delineation-dialog>
-  </div>
-</template>
-
-<script setup name="AddRange">
-import { reactive, ref, computed } from 'vue';
-import { omit } from 'lodash';
-import { MessagePlugin } from 'tdesign-vue-next';
-import { serviceScopeUnbindCrmQueryApi } from '@/api/service-unit';
-import useFetchTable from '@/hooks/useFetchTable';
-import { CUSTOMER_TYPE } from '@/config/constants';
-import { customerTypeFilter, timestampFilter } from '@/utils/filter';
-import MultDelineationDialog from '../../dispatch/dispatch-manage/mult-delineation-dialog.vue';
-import { dictToOptionList } from '@/utils/tool';
-
-let showMultDelineationDialog = ref(false);
-
-const fields = ref([
-  {
-    prop: 'crmUserId',
-    label: '客户经理',
-    type: 'select',
-    labelWidth: 80,
-    colSpan: 5,
-    cell: 'user',
-  },
-  {
-    prop: 'productType',
-    label: '客户类型',
-    type: 'select',
-    labelWidth: 80,
-    colSpan: 5,
-    attrs: {
-      clearable: true,
-    },
-  },
-  {
-    prop: 'customName',
-    label: '客户名称',
-    labelWidth: 80,
-    colSpan: 5,
-    options: dictToOptionList(CUSTOMER_TYPE),
-    attrs: {
-      clearable: true,
-    },
-  },
-  {
-    prop: 'crmNo',
-    label: '项目单号',
-    labelWidth: 80,
-    colSpan: 5,
-    attrs: {
-      clearable: true,
-    },
-  },
-  {
-    type: 'buttons',
-    colSpan: 2,
-    children: [
-      {
-        type: 'button',
-        text: '查询',
-        onClick: () => {
-          search();
-        },
-      },
-    ],
-  },
-  {
-    prop: 'crmTime',
-    label: '派单时间',
-    type: 'daterange',
-    labelWidth: 80,
-    colSpan: 10,
-    attrs: {
-      clearable: true,
-    },
-  },
-]);
-const params = reactive({
-  crmUserId: '',
-  productType: '',
-  customName: '',
-  crmNo: '',
-  crmTime: [],
-});
-const computedParams = computed(() => {
-  let data = omit(params, ['crmTime']);
-  data.startTime = params.crmTime[0];
-  data.endTime = params.crmTime[1];
-  return data;
-});
-
-const selectedRowKeys = ref([]);
-const selectChange = (value) => {
-  selectedRowKeys.value = value;
-};
-const columns = [
-  {
-    colKey: 'row-select',
-    type: 'multiple',
-    width: 50,
-    fixed: 'left',
-  },
-  { colKey: 'crmNo', title: '项目单号', minWidth: 80 },
-  { colKey: 'beginTime', title: '派单时间', width: 180, cell: 'begin-time' },
-  { colKey: 'crmUserName', title: '客户经理', minWidth: 80 },
-  { colKey: 'productType', title: '客户类型', width: 90, cell: 'type' },
-  { colKey: 'customName', title: '客户名称', minWidth: 100 },
-  { colKey: 'productName', title: '项目名称', minWidth: 80 },
-  { colKey: 'productName', title: '实施产品', minWidth: 80 },
-  {
-    colKey: 'examStartTime',
-    title: '考试开始时间',
-    width: 180,
-    cell: 'exam-start-time',
-  },
-  {
-    colKey: 'examEndTime',
-    title: '考试结束时间',
-    width: 180,
-    cell: 'exam-end-time',
-  },
-  { colKey: 'creatorName', title: '提交人', minWidth: 80 },
-  { colKey: 'createTime', title: '提交时间', width: 180, cell: 'create-time' },
-];
-const {
-  loading: tableLoading,
-  pagination,
-  tableData,
-  search,
-  onChange,
-} = useFetchTable(serviceScopeUnbindCrmQueryApi, {
-  fetchDataHandle: () => {
-    selectedRowKeys.value = [];
-  },
-  params: computedParams,
-});
-
-const handlerBatchBind = () => {
-  if (!selectedRowKeys.value.length) {
-    MessagePlugin.error('请选择要划定的记录');
-    return;
-  }
-  showMultDelineationDialog.value = true;
-};
-</script>

+ 2 - 0
src/views/system/config-manage/customer-manage/edit-customer-dialog.vue

@@ -187,6 +187,8 @@ const areaChagne = (val) => {
   formData.area = val[2];
 };
 
+// 获取经纬度 https://apis.map.qq.com/ws/geocoder/v1/?address=%E6%AD%A6%E6%B1%89%E9%94%A6%E7%BB%A3%E9%BE%99%E5%9F%8E&key=ORUBZ-OXNW4-HMGUJ-KMTZJ-46N37-YWFVF
+
 const save = async () => {
   const valid = await formRef.value.validate();
   if (valid !== true) return;

+ 15 - 14
src/views/user/auth-manage/role-manage/index.vue

@@ -1,14 +1,12 @@
 <template>
   <div class="role h-full">
+    <div v-perm="'role_BUTTON_Add'" class="page-action page-header">
+      <t-button theme="primary" @click="handleAdd({})">
+        <template #icon><svg-icon name="add-circle" color="#fff" /></template>
+        新增角色
+      </t-button>
+    </div>
     <div class="flex-1 page-wrap">
-      <div class="btn-group">
-        <t-button
-          v-perm="'role_BUTTON_Add'"
-          theme="success"
-          @click="toAddRole({})"
-          >新增角色</t-button
-        >
-      </div>
       <t-table
         size="small"
         row-key="id"
@@ -31,22 +29,19 @@
 </template>
 
 <script setup name="User" lang="jsx">
-import { reactive, ref } from 'vue';
 import { DialogPlugin, MessagePlugin } from 'tdesign-vue-next';
 import useFetchTable from '@/hooks/useFetchTable';
 import { getRoleList, deleteRole } from '@/api/user';
 import { useRouter } from 'vue-router';
 const router = useRouter();
-const toAddRole = (params) => {
-  router.push({ name: 'AddRole', query: params });
-};
+
 const columns = [
   { colKey: 'name', title: '角色名称' },
   {
     title: '管理',
     colKey: 'operate',
     fixed: 'right',
-    width: 200,
+    width: 120,
     cell: (h, { row }) => {
       return (
         <div class="table-operations">
@@ -56,7 +51,7 @@ const columns = [
             hover="color"
             onClick={(e) => {
               e.stopPropagation();
-              toAddRole({ id: row.id });
+              handleAdd({ id: row.id });
             }}
           >
             修改
@@ -77,12 +72,18 @@ const columns = [
     },
   },
 ];
+
+const handleAdd = (params) => {
+  router.push({ name: 'AddRole', query: params });
+};
+
 const handleDelete = (row) => {
   const confirmDia = DialogPlugin({
     header: '操作提示',
     body: `确定要删除角色 ${row.name} 吗`,
     confirmBtn: '确定',
     cancelBtn: '取消',
+    theme: 'warning',
     onConfirm: async () => {
       confirmDia.hide();
       const res = await deleteRole({ roleId: row.id }).catch(() => {});

+ 17 - 6
src/views/user/auth-manage/user-manage/add-user-dialog.vue

@@ -7,17 +7,20 @@
     :closeOnOverlayClick="false"
     :callBacks="[run1, run2.bind(null, { pageNumber: 1, pageSize: 1000 })]"
   >
-    <t-form ref="formRef" :data="formData" labelWidth="120px" :rules="rules">
+    <t-form ref="formRef" :data="formData" labelWidth="100px" :rules="rules">
       <t-form-item label="登录名" name="loginName">
         <t-input v-model="formData.loginName"></t-input>
       </t-form-item>
       <t-form-item label="姓名" name="realName">
         <t-input v-model="formData.realName"></t-input>
       </t-form-item>
-      <t-form-item label="性别" name="genderStr">
-        <t-radio-group v-model="formData.genderStr">
-          <t-radio value="男">男</t-radio>
-          <t-radio value="女">女</t-radio>
+      <t-form-item label="性别" name="gender">
+        <t-radio-group v-model="formData.gender">
+          <t-radio
+            v-for="(val, key) in GENDER_TYPE"
+            :value="key"
+            :label="val"
+          ></t-radio>
         </t-radio-group>
       </t-form-item>
       <t-form-item label="手机" name="mobileNumber">
@@ -51,6 +54,8 @@ import useClearDialog from '@/hooks/useClearDialog';
 import { ref, computed } from 'vue';
 import { getOrgStructList, getRoleList, addUser } from '@/api/user';
 import { useRequest } from 'vue-request';
+import { GENDER_TYPE } from '@/config/constants';
+
 const props = defineProps({
   visible: Boolean,
   curRow: Object,
@@ -70,7 +75,7 @@ const { formData, isEdit } = useClearDialog(
   {
     loginName: '',
     realName: '',
-    genderStr: '',
+    gender: '',
     mobileNumber: '',
     orgId: '',
     roleIds: [],
@@ -123,6 +128,12 @@ const rules = {
       message: '请选择机构',
     },
   ],
+  gender: [
+    {
+      required: true,
+      message: '请选择性别',
+    },
+  ],
   roleIds: [
     {
       required: true,

+ 16 - 16
src/views/user/auth-manage/user-manage/index.vue

@@ -1,17 +1,12 @@
 <template>
   <div class="user h-full">
+    <div v-perm="'user_BUTTON_Add'" class="page-action page-header">
+      <t-button theme="primary" @click="handleAdd">
+        <template #icon><svg-icon name="add-circle" color="#fff" /></template>
+        新增用户
+      </t-button>
+    </div>
     <div class="flex-1 page-wrap">
-      <div class="btn-group">
-        <t-button
-          v-perm="'user_BUTTON_Add'"
-          theme="success"
-          @click="
-            curRow = null;
-            showAddUserDialog = true;
-          "
-          >新增用户</t-button
-        >
-      </div>
       <t-table
         size="small"
         row-key="id"
@@ -68,12 +63,12 @@ const toggleStatus = (row) => {
   });
 };
 const columns = [
-  { colKey: 'id', title: '用户ID', width: 180 },
+  { colKey: 'id', title: '用户ID', width: 200 },
   { colKey: 'realName', title: '姓名' },
-  { colKey: 'genderStr', title: '性别', width: 60 },
-  { colKey: 'mobileNumber', title: '手机' },
-  { colKey: 'roles', title: '角色', minWidth: 200 },
-  { colKey: 'enable', title: '状态', width: 80 },
+  { colKey: 'genderStr', title: '性别', width: 80 },
+  { colKey: 'mobileNumber', title: '手机', width: 160 },
+  { colKey: 'roles', title: '角色' },
+  { colKey: 'enable', title: '状态', width: 100 },
   {
     title: '管理',
     colKey: 'operate',
@@ -132,6 +127,11 @@ const {
   search,
 } = useFetchTable(getUserList);
 
+const handleAdd = () => {
+  curRow.value = null;
+  showAddUserDialog.value = true;
+};
+
 const addSuccess = () => {
   showAddUserDialog.value = false;
   MessagePlugin.success('操作成功');

+ 2 - 2
src/views/user/auth-manage/user-manage/update-user-pwd-dialog.vue

@@ -6,7 +6,7 @@
     :width="500"
     :closeOnOverlayClick="false"
   >
-    <t-form ref="formRef" :data="formData" labelWidth="120px" :rules="rules">
+    <t-form ref="formRef" :data="formData" labelWidth="80px" :rules="rules">
       <t-form-item label="新密码" name="newPassword">
         <t-input
           v-model="formData.newPassword"
@@ -53,7 +53,7 @@ const rules = {
 };
 const updateHandler = () => {
   updateUserPassword({
-    newPassword: getBase64(formData.getBase64),
+    newPassword: getBase64(formData.newPassword),
     id: props.curRow.id,
   }).then(() => {
     emit('success');

+ 16 - 13
src/views/user/org-struct-manage/struct-manage/index.vue

@@ -1,17 +1,13 @@
 <template>
   <div class="struct-manage h-full">
+    <div v-perm="'org_BUTTON_Add'" class="page-action page-header">
+      <t-button theme="primary" @click="handleAdd">
+        <template #icon><svg-icon name="add-circle" color="#fff" /></template>
+        新增管理节点
+      </t-button>
+    </div>
+
     <div class="flex-1 page-wrap">
-      <div class="btn-group">
-        <t-button
-          v-perm="'org_BUTTON_Add'"
-          theme="success"
-          @click="
-            curRow = null;
-            showAddNodeDialog = true;
-          "
-          >新增管理节点</t-button
-        >
-      </div>
       <t-table
         size="small"
         row-key="id"
@@ -35,13 +31,14 @@
 </template>
 
 <script setup name="StructManage" lang="jsx">
-import { computed, ref } from 'vue';
+import { ref } from 'vue';
 import { MessagePlugin } from 'tdesign-vue-next';
 import { useRequest } from 'vue-request';
 import { getOrgStructList, toggleOrgNodeStatus } from '@/api/user';
 import AddNodeDialog from './add-node-dialog.vue';
 const showAddNodeDialog = ref(false);
 const curRow = ref(null);
+
 const toggleStatus = (row) => {
   toggleOrgNodeStatus({ id: row.id, enable: !row.enable }).then(() => {
     MessagePlugin.success('操作成功');
@@ -50,11 +47,12 @@ const toggleStatus = (row) => {
 };
 const columns = [
   { colKey: 'name', title: '管理节点' },
-  { colKey: 'enable', title: '状态' },
+  { colKey: 'enable', title: '状态', width: 120 },
   {
     title: '管理',
     colKey: 'operate',
     fixed: 'right',
+    width: 120,
     cell: (h, { row }) => {
       return (
         <div class="table-operations">
@@ -85,6 +83,11 @@ const columns = [
   },
 ];
 
+const handleAdd = () => {
+  curRow.value = null;
+  showAddNodeDialog.value = true;
+};
+
 const {
   data: tableData,
   loading: tableLoading,

+ 46 - 42
src/views/work-hours/work-hours-manage/abnormal-check/done-check.vue

@@ -8,36 +8,40 @@
         <select-supplier v-model="params[item.prop]"> </select-supplier>
       </template>
     </SearchForm>
-    <t-table
-      size="small"
-      row-key="id"
-      :columns="columns"
-      :data="tableData"
-      bordered
-      :pagination="{
-        defaultCurrent: 1,
-        defaultPageSize: 10,
-        onChange,
-        total: pagination.total,
-        current: pagination.pageNumber,
-      }"
-    >
-      <template #backup-time="{ col, row }">
-        {{ timestampFilter(row[col.colKey]) }}
-      </template>
-      <template #apply-time="{ col, row }">
-        {{ timestampFilter(row[col.colKey]) }}
-      </template>
-      <template #approve-time="{ col, row }">
-        {{ timestampFilter(row[col.colKey]) }}
-      </template>
-      <template #custom-type="{ col, row }">
-        {{ customerTypeFilter(row[col.colKey]) }}
-      </template>
-      <template #result="{ col, row }">
-        {{ auditingResultFilter(row[col.colKey]) }}
-      </template>
-    </t-table>
+    <div class="flex-1 page-wrap">
+      <t-table
+        size="small"
+        row-key="id"
+        :columns="columns"
+        :data="tableData"
+        bordered
+        :pagination="{
+          defaultCurrent: 1,
+          defaultPageSize: 10,
+          onChange,
+          showJumper: true,
+          showPageSize: false,
+          total: pagination.total,
+          current: pagination.pageNumber,
+        }"
+      >
+        <template #backup-time="{ col, row }">
+          {{ timestampFilter(row[col.colKey]) }}
+        </template>
+        <template #apply-time="{ col, row }">
+          {{ timestampFilter(row[col.colKey]) }}
+        </template>
+        <template #approve-time="{ col, row }">
+          {{ timestampFilter(row[col.colKey]) }}
+        </template>
+        <template #custom-type="{ col, row }">
+          {{ customerTypeFilter(row[col.colKey]) }}
+        </template>
+        <template #result="{ col, row }">
+          {{ auditingResultFilter(row[col.colKey]) }}
+        </template>
+      </t-table>
+    </div>
   </div>
 </template>
 
@@ -154,27 +158,27 @@ const computedParams = computed(() => {
 });
 
 const columns = [
-  { colKey: 'serviceName', title: '服务单元' },
-  { colKey: 'sopNo', title: 'SOP流水号' },
-  { colKey: 'createRealName', title: '姓名' },
-  { colKey: 'supplierName', title: '供应商' },
-  { colKey: 'customName', title: '客户名称' },
-  { colKey: 'customType', title: '客户类型', cell: 'custom-type', width: 100 },
-  { colKey: 'dingExceptionTypeStr', title: '异常类型' },
-  { colKey: 'exceptionTime', title: '异常日期' },
-  { colKey: 'applyTime', title: '补卡时间', cell: 'backup-time', width: 170 },
+  { colKey: 'serviceName', title: '服务单元', width: 140 },
+  { colKey: 'sopNo', title: 'SOP流水号', width: 200 },
+  { colKey: 'createRealName', title: '姓名', width: 140 },
+  { colKey: 'supplierName', title: '供应商', width: 140 },
+  { colKey: 'customName', title: '客户名称', width: 140 },
+  { colKey: 'customType', title: '客户类型', cell: 'custom-type', width: 120 },
+  { colKey: 'dingExceptionTypeStr', title: '异常类型', width: 120 },
+  { colKey: 'exceptionTime', title: '异常日期', width: 140 },
+  { colKey: 'applyTime', title: '补卡时间', cell: 'backup-time', width: 180 },
   { colKey: 'reason', title: '理由' },
   // TODO:附件展示
   { colKey: 'attachmentPaths', title: '附件/截图' },
-  { colKey: 'createTime', title: '申请时间', cell: 'apply-time', width: 170 },
-  { colKey: 'statusStr', title: '审核状态', width: 100 },
+  { colKey: 'createTime', title: '申请时间', cell: 'apply-time', width: 180 },
+  { colKey: 'statusStr', title: '审核状态', width: 120 },
   {
     colKey: 'dingExceptionApprove',
     title: '审核结果',
     cell: 'result',
     width: 100,
   },
-  { colKey: 'approveUsersName', title: '审核人' },
+  { colKey: 'approveUsersName', title: '审核人', width: 140 },
   {
     colKey: 'approveTime',
     title: '审核时间',

+ 38 - 18
src/views/work-hours/work-hours-manage/abnormal-check/index.vue

@@ -1,27 +1,47 @@
 <template>
   <div class="abnormal-check h-full overflow-auto">
-    <t-tabs v-model="curTab" theme="card">
-      <t-tab-panel value="1">
-        <template #label>待审核</template>
-        <WaitCheck></WaitCheck>
-      </t-tab-panel>
-      <t-tab-panel value="2">
-        <template #label>已审核</template>
-        <DoneCheck></DoneCheck>
-      </t-tab-panel>
-    </t-tabs>
+    <div class="page-action">
+      <div
+        v-for="item in tabs"
+        :key="item.value"
+        :class="['page-tab', { 'is-active': curTab === item.value }]"
+        @click="switchTab(item)"
+        >{{ item.label }}</div
+      >
+    </div>
+
+    <component :is="tabComp"></component>
   </div>
 </template>
 
 <script setup name="AbnormalCheck">
-import { ref } from 'vue';
+import { computed, ref } from 'vue';
 import WaitCheck from './wait-check';
 import DoneCheck from './done-check';
-const curTab = ref('1');
-</script>
 
-<style lang="less" scoped>
-.abnormal-check {
-  padding: 15px;
-}
-</style>
+const tabs = [
+  {
+    label: '待审核',
+    value: 'wait',
+  },
+  {
+    label: '已审核',
+    value: 'done',
+  },
+];
+
+const tabComps = {
+  wait: WaitCheck,
+  done: DoneCheck,
+};
+let curTab = ref('');
+const tabComp = computed(() => {
+  return tabComps[curTab.value];
+});
+
+const switchTab = (tab) => {
+  curTab.value = tab.value;
+};
+
+switchTab(tabs[0]);
+</script>

+ 68 - 65
src/views/work-hours/work-hours-manage/abnormal-check/wait-check.vue

@@ -1,71 +1,75 @@
 <template>
   <div class="wait-check">
-    <SearchForm :fields="fields" :params="params" showAll>
-      <template #service="{ item, params }">
-        <select-service-unit v-model="params[item.prop]"></select-service-unit>
-      </template>
-      <template #supplier="{ item, params }">
-        <select-supplier v-model="params[item.prop]"> </select-supplier>
-      </template>
-    </SearchForm>
-    <div class="btn-group">
+    <div class="page-action">
       <t-button
-        theme="success"
+        theme="primary"
         :disabled="!selectedRowKeys.length"
         @click="handleAudit(selectedRowKeys, true)"
         >批量通过</t-button
       >
       <t-button
-        theme="danger"
+        theme="primary"
         :disabled="!selectedRowKeys.length"
         @click="handleAudit(selectedRowKeys, false)"
         >批量拒绝</t-button
       >
     </div>
-    <t-table
-      size="small"
-      row-key="taskId"
-      :columns="columns"
-      :data="tableData"
-      bordered
-      :pagination="{
-        defaultCurrent: 1,
-        defaultPageSize: 10,
-        onChange,
-        total: pagination.total,
-        current: pagination.pageNumber,
-      }"
-      :selected-row-keys="selectedRowKeys"
-      @select-change="selectChange"
-    >
-      <template #backup-time="{ col, row }">
-        {{ timestampFilter(row[col.colKey]) }}
-      </template>
-      <template #apply-time="{ col, row }">
-        {{ timestampFilter(row[col.colKey]) }}
-      </template>
-      <template #custom-type="{ col, row }">
-        {{ customerTypeFilter(row[col.colKey]) }}
+    <SearchForm :fields="fields" :params="params" showAll>
+      <template #service="{ item, params }">
+        <select-service-unit v-model="params[item.prop]"></select-service-unit>
       </template>
-      <template #operate="{ row }">
-        <div class="table-operations" @click.stop>
-          <t-link
-            theme="primary"
-            hover="color"
-            @click="handleAudit([row.taskId], true)"
-          >
-            通过
-          </t-link>
-          <t-link
-            theme="danger"
-            hover="color"
-            @click="handleAudit([row.taskId], false)"
-          >
-            拒绝
-          </t-link>
-        </div>
+      <template #supplier="{ item, params }">
+        <select-supplier v-model="params[item.prop]"> </select-supplier>
       </template>
-    </t-table>
+    </SearchForm>
+    <div class="flex-1 page-wrap">
+      <t-table
+        size="small"
+        row-key="taskId"
+        :columns="columns"
+        :data="tableData"
+        bordered
+        :pagination="{
+          defaultCurrent: 1,
+          defaultPageSize: 10,
+          onChange,
+          showJumper: true,
+          showPageSize: false,
+          total: pagination.total,
+          current: pagination.pageNumber,
+        }"
+        :selected-row-keys="selectedRowKeys"
+        @select-change="selectChange"
+      >
+        <template #backup-time="{ col, row }">
+          {{ timestampFilter(row[col.colKey]) }}
+        </template>
+        <template #apply-time="{ col, row }">
+          {{ timestampFilter(row[col.colKey]) }}
+        </template>
+        <template #custom-type="{ col, row }">
+          {{ customerTypeFilter(row[col.colKey]) }}
+        </template>
+        <template #operate="{ row }">
+          <div class="table-operations" @click.stop>
+            <t-link
+              theme="primary"
+              hover="color"
+              @click="handleAudit([row.taskId], true)"
+            >
+              通过
+            </t-link>
+            <t-link
+              theme="danger"
+              hover="color"
+              @click="handleAudit([row.taskId], false)"
+            >
+              拒绝
+            </t-link>
+          </div>
+        </template>
+      </t-table>
+    </div>
   </div>
 </template>
 
@@ -179,25 +183,24 @@ const columns = [
     width: 50,
     fixed: 'left',
   },
-  { colKey: 'serviceName', title: '服务单元' },
-  { colKey: 'sopNo', title: 'SOP流水号' },
-  { colKey: 'createRealName', title: '姓名' },
-  { colKey: 'supplierName', title: '供应商' },
-  { colKey: 'customName', title: '客户名称' },
-  { colKey: 'customType', title: '客户类型', cell: 'custom-type', width: 100 },
+  { colKey: 'serviceName', title: '服务单元', width: 140 },
+  { colKey: 'sopNo', title: 'SOP流水号', width: 200 },
+  { colKey: 'createRealName', title: '姓名', width: 140 },
+  { colKey: 'supplierName', title: '供应商', width: 140 },
+  { colKey: 'customName', title: '客户名称', width: 140 },
+  { colKey: 'customType', title: '客户类型', cell: 'custom-type', width: 120 },
   { colKey: 'dingExceptionTypeStr', title: '异常类型' },
-  { colKey: 'exceptionTime', title: '异常日期' },
-  { colKey: 'applyTime', title: '补卡时间', cell: 'backup-time', width: 170 },
+  { colKey: 'exceptionTime', title: '异常日期', width: 140 },
+  { colKey: 'applyTime', title: '补卡时间', cell: 'backup-time', width: 180 },
   { colKey: 'reason', title: '理由' },
   // TODO:附件展示
   { colKey: 'attachmentPaths', title: '附件/截图' },
-  { colKey: 'statusStr', title: '审核状态', width: 100 },
-  { colKey: 'approveUserName', title: '当前审核人' },
-  { colKey: 'createTime', title: '申请时间', cell: 'apply-time', width: 170 },
+  { colKey: 'statusStr', title: '审核状态', width: 120 },
+  { colKey: 'approveUserName', title: '当前审核人', width: 140 },
+  { colKey: 'createTime', title: '申请时间', cell: 'apply-time', width: 180 },
   {
     title: '管理',
     colKey: 'operate',
-    cell: 'operate',
     fixed: 'right',
     width: 120,
   },

+ 9 - 9
src/views/work-hours/work-hours-manage/work-attendance-detail/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="work-attendance flex flex-col h-full">
+  <div class="flex flex-col h-full">
     <SearchForm :fields="fields" :params="params" showAll>
       <template #service="{ item, params }">
         <select-service-unit v-model="params[item.prop]"></select-service-unit>
@@ -10,14 +10,13 @@
     </SearchForm>
 
     <div class="flex-1 page-wrap">
-      <div class="flex justify-between items-center">
-        <t-space>
-          <span>考勤总计:{{ statisticsInfo.total }}</span>
-          <span>异常考勤:{{ statisticsInfo.abnormal }}</span>
-          <span>累计人天:{{ statisticsInfo.allDays }}天</span>
-          <span>累计工时:{{ statisticsInfo.allHours }}小时</span>
-        </t-space>
-      </div>
+      <p class="page-wrap-tips">
+        <ErrorCircleFilledIcon /> 考勤总计:{{
+          statisticsInfo.total
+        }},异常考勤:{{ statisticsInfo.abnormal }},累计人天:{{
+          statisticsInfo.allDays
+        }}天,累计工时:{{ statisticsInfo.allHours }}小时
+      </p>
 
       <t-table
         size="small"
@@ -52,6 +51,7 @@
 <script setup name="WorkAttendanceDetail">
 import { reactive, ref } from 'vue';
 import { omit } from 'lodash';
+import { ErrorCircleFilledIcon } from 'tdesign-icons-vue-next';
 
 import useFetchTable from '@/hooks/useFetchTable';
 import {

+ 56 - 51
src/views/work-hours/work-hours-manage/work-attendance/index.vue

@@ -1,5 +1,19 @@
 <template>
-  <div class="work-attendance flex flex-col h-full">
+  <div class="flex flex-col h-full">
+    <div class="page-action">
+      <t-button
+        theme="primary"
+        :disabled="!selectedRowKeys.length"
+        @click="multSubmit"
+        >批量提交</t-button
+      >
+      <t-button
+        theme="primary"
+        :disabled="!selectedRowKeys.length"
+        @click="multExport"
+        >批量导出</t-button
+      >
+    </div>
     <SearchForm :fields="fields" :params="params">
       <template #service="{ item, params }">
         <select-service-unit v-model="params[item.prop]"></select-service-unit>
@@ -13,29 +27,15 @@
     </SearchForm>
 
     <div class="flex-1 page-wrap">
-      <div class="flex justify-between items-center">
-        <t-space>
-          <span>考勤总计:{{ statisticsInfo.total }}</span>
-          <span>已提交:{{ statisticsInfo.submitted }}</span>
-          <span>待提交:{{ statisticsInfo.unSubmitted }}</span>
-          <span>累计人天:{{ statisticsInfo.allDays }}天</span>
-          <span>累计工时:{{ statisticsInfo.allHours }}小时</span>
-        </t-space>
-        <div class="btn-group">
-          <t-button
-            theme="success"
-            :disabled="!selectedRowKeys.length"
-            @click="multSubmit"
-            >批量提交</t-button
-          >
-          <t-button
-            theme="success"
-            :disabled="!selectedRowKeys.length"
-            @click="multExport"
-            >批量导出</t-button
-          >
-        </div>
-      </div>
+      <p class="page-wrap-tips">
+        <ErrorCircleFilledIcon /> 考勤总计:{{
+          statisticsInfo.total
+        }},已提交:{{ statisticsInfo.submitted }},待提交:{{
+          statisticsInfo.unSubmitted
+        }},累计人天:{{ statisticsInfo.allDays }}天,累计工时:{{
+          statisticsInfo.allHours
+        }}小时
+      </p>
 
       <t-table
         size="small"
@@ -92,9 +92,10 @@
   </div>
 </template>
 
-<script setup lang="jsx" name="WorkAttendance">
+<script setup name="WorkAttendance">
 import { reactive, ref } from 'vue';
 import { DialogPlugin, MessagePlugin } from 'tdesign-vue-next';
+import { ErrorCircleFilledIcon } from 'tdesign-icons-vue-next';
 import useFetchTable from '@/hooks/useFetchTable';
 import {
   workAttendanceListApi,
@@ -168,7 +169,7 @@ const fields = ref([
     prop: 'supplierId',
     label: '所属供应商',
     type: 'select',
-    labelWidth: 120,
+    labelWidth: 100,
     colSpan: 5,
     cell: 'supplier',
   },
@@ -201,7 +202,7 @@ const fields = ref([
       decimalPlaces: 0,
       max: 1000000,
       min: 0,
-      style: 'width: 120px',
+      style: 'width: 100%',
     },
   },
   {
@@ -215,7 +216,7 @@ const fields = ref([
       decimalPlaces: 0,
       max: 1000000,
       min: 0,
-      style: 'width: 120px',
+      style: 'width: 100%',
     },
   },
   {
@@ -229,7 +230,7 @@ const fields = ref([
       decimalPlaces: 0,
       max: 1000000,
       min: 0,
-      style: 'width: 120px',
+      style: 'width: 100%',
     },
   },
   {
@@ -243,7 +244,7 @@ const fields = ref([
       decimalPlaces: 0,
       max: 1000000,
       min: 0,
-      style: 'width: 120px',
+      style: 'width: 100%',
     },
   },
 ]);
@@ -268,27 +269,27 @@ const columns = [
     width: 50,
     fixed: 'left',
   },
-  { colKey: 'serviceUnitName', title: '服务单元' },
-  { colKey: 'sopNo', title: 'SOP流水号' },
-  { colKey: 'customName', title: '客户名称' },
-  { colKey: 'province', title: '省份', minWidth: 60 },
-  { colKey: 'city', title: '城市', minWidth: 60 },
-  { colKey: 'enterTime', title: '进场时间', cell: 'enter-time', width: 170 },
-  { colKey: 'outerTime', title: '撤场时间', cell: 'outer-time', width: 170 },
-  { colKey: 'userName', title: '姓名(人员档案号)', cell: 'user', width: 150 },
+  { colKey: 'serviceUnitName', title: '服务单元', width: 160 },
+  { colKey: 'sopNo', title: 'SOP流水号', width: 200 },
+  { colKey: 'customName', title: '客户名称', width: 120 },
+  { colKey: 'province', title: '省份', width: 120 },
+  { colKey: 'city', title: '城市', width: 120 },
+  { colKey: 'enterTime', title: '进场时间', cell: 'enter-time', width: 180 },
+  { colKey: 'outerTime', title: '撤场时间', cell: 'outer-time', width: 180 },
+  { colKey: 'userName', title: '姓名(人员档案号)', cell: 'user', width: 170 },
   { colKey: 'roleName', title: '项目角色' },
   { colKey: 'supplier', title: '供应商' },
-  { colKey: 'attendance', title: '实际出勤(天)', width: 120 },
-  { colKey: 'weekdays', title: '工作日(天)', width: 110 },
-  { colKey: 'weekends', title: '周末(天)', width: 100 },
-  { colKey: 'holidays', title: '法定节假日(天)', width: 140 },
-  { colKey: 'workHours', title: '累计工时(天)', width: 120 },
-  { colKey: 'violationDays', title: '违规工时(天)', width: 120 },
-  { colKey: 'q', title: '考勤异常数(天)', width: 140 },
-  { colKey: 'r', title: '剩余补卡次数', width: 110 },
-  { colKey: 's', title: '待处理异常数', width: 110 },
-  { colKey: 'status', title: '提交状态', cell: 'status', width: 100 },
-  { colKey: 'submitter', title: '提交人' },
+  { colKey: 'attendance', title: '实际出勤(天)', width: 140 },
+  { colKey: 'weekdays', title: '工作日(天)', width: 130 },
+  { colKey: 'weekends', title: '周末(天)', width: 120 },
+  { colKey: 'holidays', title: '法定节假日(天)', width: 160 },
+  { colKey: 'workHours', title: '累计工时(天)', width: 140 },
+  { colKey: 'violationDays', title: '违规工时(天)', width: 140 },
+  { colKey: 'q', title: '考勤异常数(天)', width: 150 },
+  { colKey: 'r', title: '剩余补卡次数', width: 120 },
+  { colKey: 's', title: '待处理异常数', width: 120 },
+  { colKey: 'status', title: '提交状态', cell: 'status', width: 120 },
+  { colKey: 'submitter', title: '提交人', width: 120 },
   {
     colKey: 'submissionTime',
     title: '提交时间',
@@ -298,9 +299,8 @@ const columns = [
   {
     title: '管理',
     colKey: 'operate',
-    cell: 'operate',
     fixed: 'right',
-    width: 120,
+    width: 160,
   },
 ];
 const { pagination, tableData, fetchData, search, onChange } = useFetchTable(
@@ -328,6 +328,7 @@ const multSubmit = () => {
     body: `确定要提交选择的所有记录吗?`,
     confirmBtn: '确定',
     cancelBtn: '取消',
+    theme: 'success',
     onConfirm: async () => {
       confirmDia.hide();
       const res = await workAttendanceSubmitApi(selectedRowKeys.value).catch(
@@ -349,6 +350,7 @@ const multExport = () => {
     body: `确定要导出选择的所有记录吗?`,
     confirmBtn: '确定',
     cancelBtn: '取消',
+    theme: 'info',
     onConfirm: async () => {
       confirmDia.hide();
       const res = await workAttendanceExportApi(selectedRowKeys.value).catch(
@@ -366,6 +368,7 @@ const handleSubmit = (row) => {
     body: `该工时数据提交后就可以进行工时统计结算,且该工时数据无法进行任何修改操作,您要继续提交吗?`,
     confirmBtn: '确定',
     cancelBtn: '取消',
+    theme: 'success',
     onConfirm: async () => {
       confirmDia.hide();
       const res = await workAttendanceSubmitApi([row.id]).catch(() => {});
@@ -381,6 +384,7 @@ const handleWithdraw = (row) => {
     body: `您确定要撤回这条已提交的工时数据吗?您操作撤回后,还需要工时管理人员同意撤回,这条工时数据才能被真正撤回。`,
     confirmBtn: '确定',
     cancelBtn: '取消',
+    theme: 'warning',
     onConfirm: async () => {
       confirmDia.hide();
       const res = await workAttendanceWithdrawApi(row.id).catch(() => {});
@@ -396,6 +400,7 @@ const handleCancelWithdraw = (row) => {
     body: `确定要取消撤回当前记录吗?`,
     confirmBtn: '确定',
     cancelBtn: '取消',
+    theme: 'warning',
     onConfirm: async () => {
       confirmDia.hide();
       const res = await workAttendanceCancelWithdrawApi(row.id).catch(() => {});

+ 30 - 31
src/views/work-hours/work-hours-manage/work-statistics/index.vue

@@ -1,5 +1,8 @@
 <template>
   <div class="work-statistics flex flex-col h-full">
+    <div class="page-action">
+      <t-button theme="primary" @click="handleExport">导出统计结果</t-button>
+    </div>
     <SearchForm :fields="fields" :params="params">
       <template #service="{ item, params }">
         <select-service-unit v-model="params[item.prop]"></select-service-unit>
@@ -12,20 +15,16 @@
       </template>
     </SearchForm>
     <div class="flex-1 page-wrap">
-      <div class="flex justify-between items-center">
-        <t-space>
-          <span>考勤总计:{{ statisticsInfo.total }}</span>
-          <span>已提交:{{ statisticsInfo.submitted }}</span>
-          <span>待提交:{{ statisticsInfo.unSubmitted }}</span>
-          <span>已提交累计人天:{{ statisticsInfo.allDays }}天</span>
-          <span>已提交累计工时:{{ statisticsInfo.allHours }}小时</span>
-        </t-space>
-        <div class="btn-group">
-          <t-button theme="success" @click="handleExport"
-            >导出统计结果</t-button
-          >
-        </div>
-      </div>
+      <p class="page-wrap-tips">
+        <ErrorCircleFilledIcon /> 考勤总计:{{
+          statisticsInfo.total
+        }},已提交:{{ statisticsInfo.submitted }},待提交:{{
+          statisticsInfo.unSubmitted
+        }},已提交累计人天:{{ statisticsInfo.allDays }}天,已提交累计工时:{{
+          statisticsInfo.allHours
+        }}小时
+      </p>
+
       <t-table
         size="small"
         row-key="id"
@@ -74,9 +73,10 @@
   </div>
 </template>
 
-<script setup lang="jsx" name="WorkStatistics">
+<script setup name="WorkStatistics">
 import { ref, reactive, onMounted } from 'vue';
 import { DialogPlugin, MessagePlugin } from 'tdesign-vue-next';
+import { ErrorCircleFilledIcon } from 'tdesign-icons-vue-next';
 import useFetchTable from '@/hooks/useFetchTable';
 import {
   workStatisticsListApi,
@@ -176,7 +176,7 @@ const fields = ref([
       decimalPlaces: 0,
       max: 1000000,
       min: 0,
-      style: 'width: 120px',
+      style: 'width: 100%',
     },
   },
 ]);
@@ -192,11 +192,11 @@ const params = reactive({
 });
 
 const columns = [
-  { colKey: 'service', title: '服务单元' },
-  { colKey: 'sopNo', title: 'SOP流水号' },
-  { colKey: 'custom', title: '客户名称' },
-  { colKey: 'province', title: '省份' },
-  { colKey: 'city', title: '城市' },
+  { colKey: 'service', title: '服务单元', width: 160 },
+  { colKey: 'sopNo', title: 'SOP流水号', width: 200 },
+  { colKey: 'custom', title: '客户名称', width: 120 },
+  { colKey: 'province', title: '省份', width: 120 },
+  { colKey: 'city', title: '城市', width: 120 },
   {
     colKey: 'examStartTime',
     title: '项目开始时间',
@@ -209,16 +209,16 @@ const columns = [
     width: 180,
     cell: 'end-time',
   },
-  { colKey: 'userName', title: '姓名(人员档案号)', cell: 'user', width: 150 },
-  { colKey: 'roleName', title: '项目角色' },
+  { colKey: 'userName', title: '姓名(人员档案号)', cell: 'user', width: 170 },
+  { colKey: 'roleName', title: '项目角色', width: 120 },
   { colKey: 'supplier', title: '供应商' },
-  { colKey: 'attendance', title: '实际出勤(天)', width: 120 },
-  { colKey: 'weekdays', title: '工作日(天)', width: 110 },
-  { colKey: 'weekends', title: '周末(天)', width: 100 },
-  { colKey: 'holidays', title: '法定节假日(天)', width: 140 },
-  { colKey: 'workHours', title: '累计工时(天)', width: 120 },
-  { colKey: 'violationDays', title: '违规工时(天)', width: 120 },
-  { colKey: 'submitter', title: '提交人' },
+  { colKey: 'attendance', title: '实际出勤(天)', width: 140 },
+  { colKey: 'weekdays', title: '工作日(天)', width: 130 },
+  { colKey: 'weekends', title: '周末(天)', width: 120 },
+  { colKey: 'holidays', title: '法定节假日(天)', width: 160 },
+  { colKey: 'workHours', title: '累计工时(天)', width: 140 },
+  { colKey: 'violationDays', title: '违规工时(天)', width: 140 },
+  { colKey: 'submitter', title: '提交人', width: 120 },
   {
     colKey: 'submissionTime',
     title: '提交时间',
@@ -229,7 +229,6 @@ const columns = [
   {
     title: '管理',
     colKey: 'operate',
-    cell: 'operate',
     fixed: 'right',
     width: 100,
   },