Bläddra i källkod

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

刘洋 1 år sedan
förälder
incheckning
c1c98f147e

+ 19 - 15
src/api/system.js

@@ -88,23 +88,27 @@ export const deviceDetailApi = (id) =>
     url: '/api/sys/device/get',
     params: { id },
   });
-export const deviceEditApi = (data) => {
-  if (data.id) {
-    return request({
-      url: '/api/sys/device/update',
-      data,
-    });
-  } else {
-    return request({
-      url: '/api/sys/device/add',
-      data,
-    });
-  }
-};
-export const deviceDestroyApi = (id) =>
+export const deviceEditApi = (data) =>
+  request({
+    url: '/api/sys/device/save',
+    data,
+  });
+export const deviceDestroyApi = (ids) =>
   request({
     url: '/api/sys/device/delete',
-    params: { id },
+    params: { ids },
+    paramsSerializer,
+  });
+export const deviceEnableApi = (ids, enable) =>
+  request({
+    url: enable ? '/api/sys/device/enable' : '/api/sys/device/disable',
+    params: { ids },
+    paramsSerializer,
+  });
+export const deviceBrandListApi = () =>
+  request({
+    url: '/api/sys/device/brand/list',
+    method: 'get',
   });
 
 // service-level-manage

+ 10 - 16
src/api/work-hours.js

@@ -3,28 +3,22 @@ import { request, paramsSerializer } from '@/utils/request.js';
 // abnormal-check
 export const workHoursWaitCheckListApi = (data) =>
   request({
-    url: '/api/system/work-hourse/wait-check/list',
+    url: '/api/admin/ding/exception/apply/flow/task/un_done/list',
     params: data,
   });
 export const workHoursDoneCheckListApi = (data) =>
   request({
-    url: '/api/system/work-hourse/done-check/list',
+    url: '/api/admin/ding/exception/apply/flow/task/done/list',
     params: data,
   });
-export const workHoursWaitCheckAuditApi = (ids, pass) => {
-  if (pass) {
-    return request({
-      url: '/api/system/work-hourse/wait-check/pass',
-      params: { ids },
-      paramsSerializer,
-    });
-  } else {
-    return request({
-      url: '/api/system/work-hourse/wait-check/refuse',
-      params: { ids },
-      paramsSerializer,
-    });
-  }
+export const workHoursWaitCheckAuditApi = (data, isBatch) => {
+  return request({
+    url: isBatch
+      ? '/api/admin/ding/exception/apply/flow/batch/approve'
+      : '/api/admin/ding/exception/apply/flow/approve',
+    params: data,
+    paramsSerializer,
+  });
 };
 
 // work-attendance

+ 9 - 18
src/components/global/search-form/index.vue

@@ -17,12 +17,9 @@
           :style="{ width: colToWidth(item.colSpan || 0) }"
           :class="{ 'buttons-wrap': item.type == 'buttons' }"
         >
-          <slot
-            v-if="item.cell"
-            :name="item.cell"
-            v-bind="{ item, params }"
-          ></slot>
-          <SearchFormItem v-else :item="item" :params="params" />
+          <slot :name="item.cell || item.prop" v-bind="{ item, params }">
+            <SearchFormItem :item="item" :params="params" />
+          </slot>
         </t-form-item>
         <div class="flex-1"></div>
         <t-form-item
@@ -33,12 +30,9 @@
           :style="{ width: colToWidth(item.colSpan || 0) }"
           :class="{ 'buttons-wrap': item.type == 'buttons' }"
         >
-          <slot
-            v-if="item.cell"
-            :name="item.cell"
-            v-bind="{ item, params }"
-          ></slot>
-          <SearchFormItem v-else :item="item" :params="params" />
+          <slot :name="item.cell || item.prop" v-bind="{ item, params }">
+            <SearchFormItem :item="item" :params="params" />
+          </slot>
         </t-form-item>
         <div v-if="showExpandBtn && !showAll" class="flex-1 text-right">
           <t-button
@@ -63,12 +57,9 @@
           :style="{ width: colToWidth(item.colSpan || 0) }"
           :class="{ 'buttons-wrap': item.type == 'buttons' }"
         >
-          <slot
-            v-if="item.cell"
-            :name="item.cell"
-            v-bind="{ item, params }"
-          ></slot>
-          <SearchFormItem v-else :item="item" :params="params" />
+          <slot :name="item.cell || item.prop" v-bind="{ item, params }">
+            <SearchFormItem :item="item" :params="params" />
+          </slot>
         </t-form-item>
       </div>
     </t-form>

+ 7 - 2
src/config/constants.js

@@ -21,6 +21,11 @@ export const EDUCATION_TYPE = {
   HIGH_SCHOOL: '高中',
   MIDDLE_SCHOOL: '初中',
 };
+// 启用/禁用
+export const ABLE_TYPE = {
+  false: '禁用',
+  true: '启用',
+};
 // 审核结果
 export const AUDITING_RESULT = {
   NOT_PASS: '未通过',
@@ -96,8 +101,8 @@ export const ISSUES_INFLUENCE_DEGREE = ['A', 'B', 'C', 'D'];
 // 工时管理
 // 考勤类型
 export const ATTENDANCE_TYPE = {
-  INTER: '签到',
-  OUTER: '签退',
+  IN: '签到',
+  OUT: '签退',
 };
 export const ATTENDANCE_RESULT = {
   NORMAL: '正常',

+ 52 - 14
src/views/system/config-manage/device-manage/edit-device-dialog.vue

@@ -10,8 +10,8 @@
     <t-form ref="formRef" :data="formData" :rules="rules" :labelWidth="100">
       <t-row :gutter="[0, 20]">
         <t-col :span="6">
-          <t-form-item label="设备编号" name="name">
-            <t-input v-model="formData.name" clearable />
+          <t-form-item label="设备编号" name="deviceCode">
+            <t-input v-model="formData.deviceCode" clearable />
           </t-form-item>
         </t-col>
         <t-col :span="6">
@@ -21,7 +21,21 @@
         </t-col>
         <t-col :span="6">
           <t-form-item label="品牌" name="brand">
-            <t-input v-model="formData.brand" clearable />
+            <t-select
+              v-model="formData.brand"
+              :options="brandList"
+              clearable
+              @change="brandChange"
+            />
+          </t-form-item>
+        </t-col>
+        <t-col :span="6">
+          <t-form-item label="型号" name="model">
+            <t-select
+              v-model="formData.model"
+              :options="brandModelList"
+              clearable
+            />
           </t-form-item>
         </t-col>
         <t-col :span="6">
@@ -81,24 +95,33 @@ import { MessagePlugin } from 'tdesign-vue-next';
 import useClearDialog from '@/hooks/useClearDialog';
 import { RUNNING_STATUS } from '@/config/constants';
 import { deviceEditApi } from '@/api/system';
-const emit = defineEmits(['update:visible', 'success']);
-const formRef = ref(null);
 
+const emit = defineEmits(['update:visible', 'success']);
 const props = defineProps({
   visible: Boolean,
   curRow: Object,
+  brandList: {
+    type: Array,
+    default() {
+      return [];
+    },
+  },
 });
 
 const title = computed(() => {
   return (isEdit.value ? '编辑' : '新增') + '设备';
 });
 
+const formRef = ref(null);
+const brandModelList = ref([]);
+
 const { formData, isEdit } = useClearDialog(
   {
     id: null,
-    name: '',
+    deviceCode: '',
     serialNo: '',
     brand: '',
+    model: '',
     buyTime: '',
     supplierId: '',
     status: '',
@@ -113,10 +136,12 @@ const { formData, isEdit } = useClearDialog(
     for (let key in formData) {
       formData[key] = props.curRow[key];
     }
+
+    getBrandModelList(formData.brand);
   }
 );
 const rules = {
-  name: [
+  deviceCode: [
     {
       required: true,
       message: '设备编号必填',
@@ -145,13 +170,10 @@ const rules = {
     },
   ],
   brand: [
-    { required: true, message: '品牌必填', type: 'error', trigger: 'change' },
-    {
-      max: 50,
-      message: '至多需要50个字',
-      type: 'error',
-      trigger: 'change',
-    },
+    { required: true, message: '品牌必选', type: 'error', trigger: 'change' },
+  ],
+  model: [
+    { required: true, message: '型号必选', type: 'error', trigger: 'change' },
   ],
   buyTime: [
     {
@@ -181,6 +203,22 @@ const rules = {
     },
   ],
 };
+
+const brandChange = () => {
+  formData.model = '';
+  brandModelList.value = [];
+  getBrandModelList(formData.brand);
+};
+
+const getBrandModelList = (brand) => {
+  const curBrand = props.brandList.value.find((item) => item.value === brand);
+  if (!curBrand) {
+    brandModelList.value = [];
+    return;
+  }
+  brandModelList.value = curBrand.list;
+};
+
 const save = async () => {
   const valid = await formRef.value.validate();
   if (valid !== true) return;

+ 250 - 12
src/views/system/config-manage/device-manage/index.vue

@@ -1,9 +1,57 @@
 <template>
   <div class="registration-query flex flex-col h-full">
+    <SearchForm :fields="fields" :params="params">
+      <template #supplier="{ item, params }">
+        <select-supplier
+          v-model="params[item.prop]"
+          type="DEVICE"
+        ></select-supplier>
+      </template>
+      <template #brand="{ item, params }">
+        <t-select
+          v-model="params[item.prop]"
+          :options="brandList"
+          clearable
+          @change="brandChange"
+        />
+      </template>
+      <template #model="{ item, params }">
+        <t-select
+          v-model="params[item.prop]"
+          :options="brandModelList"
+          clearable
+        />
+      </template>
+    </SearchForm>
     <div class="flex-1 page-wrap">
-      <div class="btn-group">
-        <t-button theme="success" @click="handleAdd">新增</t-button>
-      </div>
+      <t-space size="small">
+        <t-button theme="success" @click="handleAdd">新增设备</t-button>
+        <t-button
+          theme="danger"
+          :disabled="!selectedRowKeys.length"
+          @click="handleDestroy"
+          >批量作废</t-button
+        >
+        <t-button
+          theme="success"
+          :disabled="!selectedRowKeys.length"
+          @click="handleEable(selectedRowKeys, true)"
+          >批量启用</t-button
+        >
+        <t-button
+          theme="danger"
+          :disabled="!selectedRowKeys.length"
+          @click="handleEable(selectedRowKeys, false)"
+          >批量禁用</t-button
+        >
+        <upload-button
+          upload-url="/api/sys/device/import"
+          :button-props="{
+            content: '批量导入',
+            theme: 'success',
+          }"
+        ></upload-button>
+      </t-space>
       <t-table
         size="small"
         row-key="id"
@@ -15,22 +63,35 @@
           defaultPageSize: 10,
           onChange,
           total: pagination.total,
+          current: pagination.pageNumber,
         }"
         v-loading="tableLoading"
+        :selected-row-keys="selectedRowKeys"
+        @select-change="selectChange"
       >
+        <template #enable="{ col, row }">
+          {{ enableFilter(row[col.colKey]) }}
+        </template>
         <template #buy-time="{ col, row }">
           {{ timestampFilter(row[col.colKey]) }}
         </template>
         <template #status="{ col, row }">
           {{ runningStatusFilter(row[col.colKey]) }}
         </template>
+        <template #bound="{ col, row }">
+          {{ inoutTypeFilter(row[col.colKey]) }}
+        </template>
         <template #operate="{ row }">
           <div class="table-operations">
             <t-link theme="primary" hover="color" @click="handleEdit(row)">
               修改
             </t-link>
-            <t-link theme="danger" hover="color" @click="handleDestroy(row)">
-              作废
+            <t-link
+              :theme="row.enable ? 'danger' : 'success'"
+              hover="color"
+              @click="handleEable([row.id], !row.enable)"
+            >
+              {{ row.enable ? '禁用' : '启用' }}
             </t-link>
           </div>
         </template>
@@ -40,31 +101,171 @@
     <edit-device-dialog
       v-model:visible="showEditDeviceDialog"
       :curRow="curRow"
+      :brand-list="brandList"
       @success="fetchData"
     ></edit-device-dialog>
   </div>
 </template>
 
 <script setup name="DeviceManage">
-import { ref } from 'vue';
+import { ref, reactive, onMounted } from 'vue';
 import { DialogPlugin, MessagePlugin } from 'tdesign-vue-next';
 import useFetchTable from '@/hooks/useFetchTable';
 import EditDeviceDialog from './edit-device-dialog.vue';
-import { deviceQueryApi, deviceDestroyApi } from '@/api/system';
-import { runningStatusFilter, timestampFilter } from '@/utils/filter';
+import {
+  deviceQueryApi,
+  deviceDestroyApi,
+  deviceEnableApi,
+  deviceBrandListApi,
+} from '@/api/system';
+import {
+  runningStatusFilter,
+  timestampFilter,
+  enableFilter,
+  inoutTypeFilter,
+} from '@/utils/filter';
+import { dictToOptionList } from '@/utils/tool';
+import { ABLE_TYPE, RUNNING_STATUS, INOUT_TYPE } from '@/config/constants';
 
 const showEditDeviceDialog = ref(false);
 const curRow = ref(null);
+const selectedRowKeys = ref([]);
+const brandList = ref([]);
+const brandModelList = ref([]);
+
+const getBrandList = async () => {
+  const res = await deviceBrandListApi().catch(() => {});
+  if (!res) return;
+  brandList.value = res.map((item) => {
+    return {
+      label: item.brand,
+      value: item.brand,
+      list: item.list.map((elem) => {
+        return {
+          label: elem.model,
+          value: elem.model,
+        };
+      }),
+    };
+  });
+};
+const brandChange = () => {
+  params.model = '';
+  brandModelList.value = [];
+  getBrandModelList(params.brand);
+};
+
+const getBrandModelList = (brand) => {
+  const curBrand = brandList.value.find((item) => item.value === brand);
+  if (!curBrand) {
+    brandModelList.value = [];
+    return;
+  }
+  brandModelList.value = curBrand.list;
+};
+
+const fields = ref([
+  {
+    prop: 'supplierId',
+    label: '设备供应商',
+    type: 'select',
+    labelWidth: 100,
+    colSpan: 5,
+    cell: 'supplier',
+  },
+  {
+    prop: 'brand',
+    label: '品牌',
+    type: 'select',
+    labelWidth: 60,
+    colSpan: 5,
+  },
+  {
+    prop: 'model',
+    label: '型号',
+    type: 'select',
+    labelWidth: 60,
+    colSpan: 5,
+  },
+  {
+    prop: 'deviceCode',
+    label: '设备编号',
+    labelWidth: 100,
+    colSpan: 5,
+    attrs: {
+      clearable: true,
+    },
+  },
+  {
+    type: 'buttons',
+    colSpan: 2,
+    children: [
+      {
+        type: 'button',
+        text: '查询',
+        onClick: () => {
+          search();
+        },
+      },
+    ],
+  },
+  {
+    prop: 'status',
+    label: '运行状态',
+    type: 'select',
+    labelWidth: 100,
+    colSpan: 5,
+    options: dictToOptionList(RUNNING_STATUS),
+    attrs: {
+      clearable: true,
+    },
+  },
+  {
+    prop: 'bound',
+    label: '出库/入库',
+    type: 'select',
+    labelWidth: 100,
+    colSpan: 5,
+    options: dictToOptionList(INOUT_TYPE),
+    attrs: {
+      clearable: true,
+    },
+  },
+  {
+    prop: 'enable',
+    label: '启用/禁用',
+    type: 'select',
+    labelWidth: 100,
+    colSpan: 5,
+    options: dictToOptionList(ABLE_TYPE),
+    attrs: {
+      clearable: true,
+    },
+  },
+]);
+const params = reactive({
+  supplierId: '',
+  brand: '',
+  model: '',
+  deviceCode: '',
+  status: '',
+  bound: '',
+  enable: '',
+});
 
 const columns = [
-  { colKey: 'name', title: '设备编号' },
+  { colKey: 'row-select', type: 'multiple', width: 50 },
+  { colKey: 'deviceCode', title: '设备编号' },
   { colKey: 'serialNo', title: '序列号' },
   { colKey: 'brand', title: '品牌' },
+  { colKey: 'model', title: '型号' },
   { colKey: 'buyTime', title: '购买时间', cell: 'buy-time', width: 170 },
-  { colKey: 'supplier', title: '供应商' },
+  { colKey: 'supplier', title: '设备供应商' },
   { colKey: 'status', title: '运行状态', cell: 'status', width: 80 },
   { colKey: 'location', title: '当前所在地' },
   { colKey: 'scanCount', title: '总扫描量', width: 80 },
+  { colKey: 'bound', title: '出库/入库', width: 100 },
+  { colKey: 'enable', title: '启用/禁用', width: 100 },
   {
     title: '操作',
     colKey: 'operate',
@@ -79,14 +280,24 @@ const {
   pagination,
   tableData,
   fetchData,
+  search,
   onChange,
 } = useFetchTable(deviceQueryApi);
 
+const selectChange = (value) => {
+  selectedRowKeys.value = value;
+};
 const handleAdd = () => {
   curRow.value = null;
   showEditDeviceDialog.value = true;
 };
-const handleDestroy = (row) => {
+
+const handleDestroy = () => {
+  if (!selectedRowKeys.value.length) {
+    MessagePlugin.error('请选择要作废的记录');
+    return;
+  }
+
   const confirmDia = DialogPlugin({
     header: '操作提示',
     body: `确定要作废选中的记录吗`,
@@ -94,15 +305,42 @@ const handleDestroy = (row) => {
     cancelBtn: '取消',
     onConfirm: async () => {
       confirmDia.hide();
-      const res = await deviceDestroyApi(row.id).catch(() => {});
+      const res = await deviceDestroyApi(selectedRowKeys.value).catch(() => {});
       if (!res) return;
       MessagePlugin.success('删除成功');
       fetchData();
     },
   });
 };
+const handleEable = (selectedIds, enable) => {
+  const name = enable ? '启用' : '禁用';
+
+  if (!selectedIds.length) {
+    MessagePlugin.error(`请选择要${name}的记录`);
+    return;
+  }
+
+  const confirmDia = DialogPlugin({
+    header: `${name}提示`,
+    body: `确定要${name}选中的记录吗`,
+    confirmBtn: '确定',
+    cancelBtn: '取消',
+    onConfirm: async () => {
+      confirmDia.hide();
+      const res = await deviceEnableApi(selectedIds, enable).catch(() => {});
+      if (!res) return;
+      MessagePlugin.success('操作成功');
+      fetchData();
+    },
+  });
+};
+
 const handleEdit = (row) => {
   curRow.value = row;
   showEditDeviceDialog.value = true;
 };
+
+onMounted(() => {
+  getBrandList();
+});
 </script>

+ 35 - 21
src/views/work-hours/work-hours-manage/abnormal-check/done-check.vue

@@ -28,7 +28,7 @@
       <template #apply-time="{ col, row }">
         {{ timestampFilter(row[col.colKey]) }}
       </template>
-      <template #audit-time="{ col, row }">
+      <template #approve-time="{ col, row }">
         {{ timestampFilter(row[col.colKey]) }}
       </template>
       <template #custom-type="{ col, row }">
@@ -41,7 +41,7 @@
   </div>
 </template>
 
-<script setup lang="jsx" name="DoneCheck">
+<script setup name="DoneCheck">
 import { reactive, ref, computed } from 'vue';
 import { omit } from 'lodash';
 
@@ -82,15 +82,18 @@ const fields = ref([
     cell: 'supplier',
   },
   {
-    prop: 'result',
+    prop: 'dingExceptionApprove',
     label: '审核结果',
     type: 'select',
     labelWidth: 100,
     colSpan: 5,
     options: dictToOptionList(AUDITING_RESULT),
+    attrs: {
+      clearable: true,
+    },
   },
   {
-    prop: 'custom',
+    prop: 'customName',
     label: '客户名称',
     labelWidth: 100,
     colSpan: 5,
@@ -136,37 +139,48 @@ const params = reactive({
   serviceId: '',
   name: '',
   supplierId: '',
-  result: '',
-  custom: '',
+  dingExceptionApprove: '',
+  customName: '',
   exceptionTime: [],
   applyTime: [],
 });
 const computedParams = computed(() => {
   let data = omit(params, ['exceptionTime', 'applyTime']);
-  data.exceptionStartTime = params.exceptionTime[0];
-  data.exceptionEndTime = params.exceptionTime[1];
+  data.startTime = params.exceptionTime[0];
+  data.endTime = params.exceptionTime[1];
   data.applyStartTime = params.applyTime[0];
   data.applyEndTime = params.applyTime[1];
   return data;
 });
 
 const columns = [
-  { colKey: 'service', title: '服务单元' },
+  { colKey: 'serviceName', title: '服务单元' },
   { colKey: 'sopNo', title: 'SOP流水号' },
-  { colKey: 'name', title: '姓名' },
-  { colKey: 'supplier', title: '供应商' },
-  { colKey: 'custom', title: '客户名称' },
+  { colKey: 'createRealName', title: '姓名' },
+  { colKey: 'supplierName', title: '供应商' },
+  { colKey: 'customName', title: '客户名称' },
   { colKey: 'customType', title: '客户类型', cell: 'custom-type', width: 100 },
-  { colKey: 'exceptionType', title: '异常类型' },
-  { colKey: 'exceptionDate', title: '异常日期' },
-  { colKey: 'backupTime', title: '补卡时间', cell: 'backup-time', width: 170 },
+  { colKey: 'dingExceptionTypeStr', title: '异常类型' },
+  { colKey: 'exceptionTime', title: '异常日期' },
+  { colKey: 'applyTime', title: '补卡时间', cell: 'backup-time', width: 170 },
   { colKey: 'reason', title: '理由' },
-  { colKey: 'attachment', title: '附件/截图' },
-  { colKey: 'applyTime', title: '申请时间', cell: 'apply-time', width: 170 },
-  { colKey: 'status', title: '审核状态', width: 100 },
-  { colKey: 'result', title: '审核结果', cell: 'result', width: 100 },
-  { colKey: 'auditor', title: '审核人' },
-  { colKey: 'auditTime', title: '审核时间', cell: 'audit-time', width: 170 },
+  // TODO:附件展示
+  { colKey: 'attachmentPaths', title: '附件/截图' },
+  { colKey: 'createTime', title: '申请时间', cell: 'apply-time', width: 170 },
+  { colKey: 'statusStr', title: '审核状态', width: 100 },
+  {
+    colKey: 'dingExceptionApprove',
+    title: '审核结果',
+    cell: 'result',
+    width: 100,
+  },
+  { colKey: 'approveUsersName', title: '审核人' },
+  {
+    colKey: 'approveTime',
+    title: '审核时间',
+    cell: 'approve-time',
+    width: 170,
+  },
 ];
 const { pagination, tableData, search, onChange } = useFetchTable(
   workHoursDoneCheckListApi,

+ 29 - 20
src/views/work-hours/work-hours-manage/abnormal-check/wait-check.vue

@@ -24,7 +24,7 @@
     </div>
     <t-table
       size="small"
-      row-key="id"
+      row-key="taskId"
       :columns="columns"
       :data="tableData"
       bordered
@@ -52,14 +52,14 @@
           <t-link
             theme="primary"
             hover="color"
-            @click="handleAudit([row.id], true)"
+            @click="handleAudit([row.taskId], true)"
           >
             通过
           </t-link>
           <t-link
             theme="danger"
             hover="color"
-            @click="handleAudit([row.id], false)"
+            @click="handleAudit([row.taskId], false)"
           >
             拒绝
           </t-link>
@@ -69,7 +69,7 @@
   </div>
 </template>
 
-<script setup lang="jsx" name="WaitCheck">
+<script setup name="WaitCheck">
 import { reactive, ref, computed } from 'vue';
 import { omit } from 'lodash';
 
@@ -113,7 +113,7 @@ const fields = ref([
     cell: 'supplier',
   },
   {
-    prop: 'custom',
+    prop: 'customName',
     label: '客户名称',
     labelWidth: 100,
     colSpan: 5,
@@ -159,14 +159,14 @@ const params = reactive({
   serviceId: '',
   name: '',
   supplierId: '',
-  custom: '',
+  customName: '',
   exceptionTime: [],
   applyTime: [],
 });
 const computedParams = computed(() => {
   let data = omit(params, ['exceptionTime', 'applyTime']);
-  data.exceptionStartTime = params.exceptionTime[0];
-  data.exceptionEndTime = params.exceptionTime[1];
+  data.startTime = params.exceptionTime[0];
+  data.endTime = params.exceptionTime[1];
   data.applyStartTime = params.applyTime[0];
   data.applyEndTime = params.applyTime[1];
   return data;
@@ -179,20 +179,21 @@ const columns = [
     width: 50,
     fixed: 'left',
   },
-  { colKey: 'service', title: '服务单元' },
+  { colKey: 'serviceName', title: '服务单元' },
   { colKey: 'sopNo', title: 'SOP流水号' },
-  { colKey: 'name', title: '姓名' },
-  { colKey: 'supplier', title: '供应商' },
-  { colKey: 'custom', title: '客户名称' },
+  { colKey: 'createRealName', title: '姓名' },
+  { colKey: 'supplierName', title: '供应商' },
+  { colKey: 'customName', title: '客户名称' },
   { colKey: 'customType', title: '客户类型', cell: 'custom-type', width: 100 },
-  { colKey: 'exceptionType', title: '异常类型' },
-  { colKey: 'exceptionDate', title: '异常日期' },
-  { colKey: 'backupTime', title: '补卡时间', cell: 'backup-time', width: 170 },
+  { colKey: 'dingExceptionTypeStr', title: '异常类型' },
+  { colKey: 'exceptionTime', title: '异常日期' },
+  { colKey: 'applyTime', title: '补卡时间', cell: 'backup-time', width: 170 },
   { colKey: 'reason', title: '理由' },
-  { colKey: 'attachment', title: '附件/截图' },
-  { colKey: 'status', title: '审核状态', width: 100 },
-  { colKey: 'approvorName', title: '当前审核人' },
-  { colKey: 'applyTime', title: '申请时间', cell: 'apply-time', width: 170 },
+  // TODO:附件展示
+  { colKey: 'attachmentPaths', title: '附件/截图' },
+  { colKey: 'statusStr', title: '审核状态', width: 100 },
+  { colKey: 'approveUserName', title: '当前审核人' },
+  { colKey: 'createTime', title: '申请时间', cell: 'apply-time', width: 170 },
   {
     title: '操作',
     colKey: 'operate',
@@ -230,7 +231,15 @@ const handleAudit = async (selectedIds, pass) => {
     cancelBtn: '取消',
     onConfirm: async () => {
       confirmDia.hide();
-      const res = await workHoursWaitCheckAuditApi(selectedIds, pass).catch(
+      let data = { dingExceptionApprove: pass ? 'PASS' : 'NO_PASS' };
+      const isBatch = selectedIds.length > 1;
+      if (isBatch) {
+        data.taskIds = selectedIds;
+      } else {
+        data.taskId = selectedIds[0];
+      }
+
+      const res = await workHoursWaitCheckAuditApi(data, isBatch).catch(
         () => {}
       );
       if (!res) return;