瀏覽代碼

跟进相关

zhangjie 1 年之前
父節點
當前提交
933e7b95c9

+ 0 - 6
src/api/sop.js

@@ -64,12 +64,6 @@ export const restartViolation = (id) =>
     url: '/api/admin/tb/violation/restart?id=' + id,
     url: '/api/admin/tb/violation/restart?id=' + id,
     loading: true,
     loading: true,
   });
   });
-// 单个违规登记的详情
-export const violationDetail = (id) =>
-  request({
-    url: '/api/admin/tb/violation/get?id=' + id,
-    method: 'get',
-  });
 // 违规登记明细表
 // 违规登记明细表
 export const violationDetailList = (id) =>
 export const violationDetailList = (id) =>
   request({
   request({

+ 5 - 0
src/api/user.js

@@ -140,3 +140,8 @@ export const getAttachmentFile = (taskId, type) =>
     url: '/api/admin/common/file/download',
     url: '/api/admin/common/file/download',
     params: { taskId, type },
     params: { taskId, type },
   });
   });
+export const getAttachmentList = (ids) =>
+  request({
+    url: '/api/admin/common/file/preview',
+    data: ids,
+  });

+ 3 - 0
src/components/common/select-customer/index.vue

@@ -64,6 +64,9 @@ watch(
   () => props.modelValue,
   () => props.modelValue,
   (val) => {
   (val) => {
     selected.value = val;
     selected.value = val;
+  },
+  {
+    immediate: true,
   }
   }
 );
 );
 watch(
 watch(

+ 14 - 1
src/components/common/select-filter-user/index.vue

@@ -23,6 +23,12 @@ import { getUserList } from '@/api/user';
 const emit = defineEmits(['update:modelValue', 'change']);
 const emit = defineEmits(['update:modelValue', 'change']);
 const props = defineProps({
 const props = defineProps({
   modelValue: { type: [Number, String], default: '' },
   modelValue: { type: [Number, String], default: '' },
+  defaultList: {
+    type: Array,
+    default() {
+      return [];
+    },
+  },
 });
 });
 
 
 let optionList = ref([]);
 let optionList = ref([]);
@@ -30,8 +36,12 @@ let selected = ref('');
 let loading = ref(false);
 let loading = ref(false);
 
 
 async function search(userInfo) {
 async function search(userInfo) {
+  if (!userInfo) {
+    optionList.value = defaultList;
+    return;
+  }
+
   optionList.value = [];
   optionList.value = [];
-  if (!userInfo) return;
 
 
   if (loading.value) return;
   if (loading.value) return;
   loading.value = true;
   loading.value = true;
@@ -59,6 +69,9 @@ watch(
   () => props.modelValue,
   () => props.modelValue,
   (val) => {
   (val) => {
     selected.value = val;
     selected.value = val;
+  },
+  {
+    immediate: true,
   }
   }
 );
 );
 </script>
 </script>

+ 3 - 0
src/components/common/select-free-engineer/index.vue

@@ -72,6 +72,9 @@ watch(
   () => props.modelValue,
   () => props.modelValue,
   (val) => {
   (val) => {
     selected.value = val;
     selected.value = val;
+  },
+  {
+    immediate: true,
   }
   }
 );
 );
 watch(
 watch(

+ 3 - 0
src/components/common/select-metadata/index.vue

@@ -83,6 +83,9 @@ watch(
   () => props.modelValue,
   () => props.modelValue,
   (val) => {
   (val) => {
     selected.value = val;
     selected.value = val;
+  },
+  {
+    immediate: true,
   }
   }
 );
 );
 </script>
 </script>

+ 3 - 0
src/components/common/select-product/index.vue

@@ -60,6 +60,9 @@ watch(
   () => props.modelValue,
   () => props.modelValue,
   (val) => {
   (val) => {
     selected.value = val;
     selected.value = val;
+  },
+  {
+    immediate: true,
   }
   }
 );
 );
 </script>
 </script>

+ 3 - 0
src/components/common/select-role/index.vue

@@ -59,6 +59,9 @@ watch(
   () => props.modelValue,
   () => props.modelValue,
   (val) => {
   (val) => {
     selected.value = val;
     selected.value = val;
+  },
+  {
+    immediate: true,
   }
   }
 );
 );
 </script>
 </script>

+ 3 - 0
src/components/common/select-service-level/index.vue

@@ -65,6 +65,9 @@ watch(
   () => props.modelValue,
   () => props.modelValue,
   (val) => {
   (val) => {
     selected.value = val;
     selected.value = val;
+  },
+  {
+    immediate: true,
   }
   }
 );
 );
 watch(
 watch(

+ 3 - 0
src/components/common/select-service-unit/index.vue

@@ -81,6 +81,9 @@ watch(
   () => props.modelValue,
   () => props.modelValue,
   (val) => {
   (val) => {
     selected.value = val;
     selected.value = val;
+  },
+  {
+    immediate: true,
   }
   }
 );
 );
 watch(
 watch(

+ 3 - 0
src/components/common/select-supplier/index.vue

@@ -65,6 +65,9 @@ watch(
   () => props.modelValue,
   () => props.modelValue,
   (val) => {
   (val) => {
     selected.value = val;
     selected.value = val;
+  },
+  {
+    immediate: true,
   }
   }
 );
 );
 watch(
 watch(

+ 3 - 0
src/components/common/select-type-user/index.vue

@@ -61,6 +61,9 @@ watch(
   () => props.modelValue,
   () => props.modelValue,
   (val) => {
   (val) => {
     selected.value = val;
     selected.value = val;
+  },
+  {
+    immediate: true,
   }
   }
 );
 );
 watch(
 watch(

+ 125 - 0
src/components/global/attachment-view/index.vue

@@ -0,0 +1,125 @@
+<template>
+  <div class="attachment-view">
+    <div v-if="attachments.images.length" class="attachment-image-list">
+      <t-space :size="8">
+        <t-image
+          v-for="(img, index) in attachments.images"
+          :key="index"
+          :src="img"
+          fit="scale-down"
+          :style="imgStyle"
+          overlay-trigger="hover"
+          @click="openView(index)"
+        >
+          <template #overlayContent>
+            <div
+              :style="{
+                background: 'rgba(0,0,0,.4)',
+                color: '#fff',
+                height: '100%',
+                display: 'flex',
+                alignItems: 'center',
+                justifyContent: 'center',
+              }"
+              >预览</div
+            >
+          </template>
+        </t-image>
+      </t-space>
+      <t-image-viewer
+        v-model:visible="imgVisible"
+        :default-index="imgIndex"
+        :images="attachments.images"
+      >
+      </t-image-viewer>
+    </div>
+    <div v-if="attachments.files.length" class="attachment-link-list">
+      <t-link v-for="file in attachments.files" :key="file" theme="primary">
+        {{ file }}
+      </t-link>
+    </div>
+  </div>
+</template>
+
+<script setup name="AttachmentView">
+import { computed, reactive, ref, watch } from 'vue';
+import { objTypeOf } from '@/utils/tool';
+import { getAttachmentList } from '@/api/user';
+
+const props = defineProps({
+  ids: {
+    type: [String, Array],
+    default: '',
+  },
+  imgSize: {
+    type: Number,
+    default: 80,
+  },
+  imageList: {
+    type: Array,
+    default() {
+      return [];
+    },
+  },
+});
+
+const imgVisible = ref(false);
+const imgIndex = ref(0);
+
+const openView = (index) => {
+  imgIndex.value = index;
+  imgVisible.value = true;
+};
+
+const imgStyle = computed(() => {
+  return {
+    width: `${props.imgSize}px`,
+    height: `${props.imgSize}px`,
+  };
+});
+
+const attachmentIds = computed(() => {
+  if (objTypeOf(props.ids) === 'string') return props.ids.split(',');
+  if (objTypeOf(props.ids) === 'array') return props.ids;
+  return [];
+});
+
+const attachments = reactive({ images: [], files: [] });
+const getAttachments = async () => {
+  attachments.images = [];
+  attachments.files = [];
+
+  // 直接传图片数据时,直接展示
+  if (props.imageList && props.imageList.length) {
+    attachments.images = props.imageList;
+    return;
+  }
+
+  if (!attachmentIds.value.length) return;
+
+  const res = await getAttachmentList(attachmentIds.value);
+  const data = res || [];
+  data.forEach((item) => {
+    const type = checkFileType(item.url);
+    if (type === 'image') {
+      attachments.images.push(item.url);
+    } else {
+      attachments.files.push(item.url);
+    }
+  });
+};
+
+function checkFileType(filepath) {
+  const fileFormat = filepath.split('.').pop().toLocaleLowerCase();
+  const imgTypes = ['jpg', 'jpeg', 'png'];
+  return imgTypes.includes(fileFormat) ? 'image' : 'file';
+}
+
+watch(
+  () => attachmentIds,
+  () => {
+    getAttachments();
+  },
+  { immediate: true }
+);
+</script>

+ 9 - 2
src/components/global/my-upload/index.vue

@@ -13,6 +13,7 @@
     :before-upload="handleBeforeUpload"
     :before-upload="handleBeforeUpload"
     :request-method="upload"
     :request-method="upload"
     @fail="handleFail"
     @fail="handleFail"
+    @change="handleChange"
   >
   >
   </t-upload>
   </t-upload>
 </template>
 </template>
@@ -21,6 +22,7 @@ import { ref } from 'vue';
 import { MessagePlugin } from 'tdesign-vue-next';
 import { MessagePlugin } from 'tdesign-vue-next';
 import { uploadFiles } from '@/api/common';
 import { uploadFiles } from '@/api/common';
 import { getFileMD5 } from '@/utils/crypto';
 import { getFileMD5 } from '@/utils/crypto';
+
 const emit = defineEmits(['change']);
 const emit = defineEmits(['change']);
 const props = defineProps({
 const props = defineProps({
   theme: {
   theme: {
@@ -78,10 +80,15 @@ const upload = async (files) => {
 
 
   const res = await uploadFiles(formData, md5).catch(() => {});
   const res = await uploadFiles(formData, md5).catch(() => {});
   if (res) {
   if (res) {
-    emit('change', res);
-    return { status: 'success', response: res };
+    return { status: 'success', response: { id: res.id, url: res.previewUrl } };
   } else {
   } else {
     return { status: 'fail', error: '上传失败' };
     return { status: 'fail', error: '上传失败' };
   }
   }
 };
 };
+const handleChange = () => {
+  emit(
+    'change',
+    files.value.map((item) => item.response)
+  );
+};
 </script>
 </script>

+ 8 - 0
src/utils/filter.js

@@ -25,6 +25,8 @@ import {
   DEVICE_USAGE_TYPE,
   DEVICE_USAGE_TYPE,
   ATTENDANCE_SUBMIT_STATUS,
   ATTENDANCE_SUBMIT_STATUS,
   ATTENDANCE_STATISTICS_SUBMIT_STATUS,
   ATTENDANCE_STATISTICS_SUBMIT_STATUS,
+  VIOLATION_TYPE,
+  VIOLATION_FLOW_STATUS,
 } from '@/config/constants';
 } from '@/config/constants';
 import { dateFormat } from './tool';
 import { dateFormat } from './tool';
 
 
@@ -131,3 +133,9 @@ export function attendanceSubmitStatusFilter(val) {
 export function attendanceStatisticsSubmitStatusFilter(val) {
 export function attendanceStatisticsSubmitStatusFilter(val) {
   return ATTENDANCE_STATISTICS_SUBMIT_STATUS[val] || DEFAULT_FIELD;
   return ATTENDANCE_STATISTICS_SUBMIT_STATUS[val] || DEFAULT_FIELD;
 }
 }
+export function violationTypeFilter(val) {
+  return VIOLATION_TYPE[val] || DEFAULT_FIELD;
+}
+export function violationFlowStatusFilter(val) {
+  return VIOLATION_FLOW_STATUS[val] || DEFAULT_FIELD;
+}

+ 22 - 0
src/utils/tool.js

@@ -419,3 +419,25 @@ export function objAssign(target, sources) {
   }
   }
   return targ;
   return targ;
 }
 }
+
+/**
+ * 判断对象类型
+ * @param {*} obj 对象
+ */
+export function objTypeOf(obj) {
+  const toString = Object.prototype.toString;
+  const map = {
+    '[object Boolean]': 'boolean',
+    '[object Number]': 'number',
+    '[object String]': 'string',
+    '[object Function]': 'function',
+    '[object Array]': 'array',
+    '[object Date]': 'date',
+    '[object RegExp]': 'regExp',
+    '[object Undefined]': 'undefined',
+    '[object Null]': 'null',
+    '[object Object]': 'object',
+    '[object Blob]': 'blob',
+  };
+  return map[toString.call(obj)];
+}

+ 3 - 1
src/views/resource-guard/device-guard/registration-query/registration-detail-dialog.vue

@@ -44,7 +44,9 @@
               {{ runningStatusFilter(row[col.colKey]) }}
               {{ runningStatusFilter(row[col.colKey]) }}
             </template>
             </template>
             <template #photo="{ col, row }">
             <template #photo="{ col, row }">
-              <t-image-viewer :images="[row[col.colKey]]"> </t-image-viewer>
+              <attachment-view
+                :image-list="[row[col.colKey]]"
+              ></attachment-view>
             </template>
             </template>
           </t-table>
           </t-table>
         </t-col>
         </t-col>

+ 3 - 3
src/views/service-unit/service-unit-manage/unit-manage/index.vue

@@ -294,7 +294,7 @@ const handlePublish = (row) => {
       confirmDia.hide();
       confirmDia.hide();
       const res = await serviceUnitPublishApi(row.id).catch(() => {});
       const res = await serviceUnitPublishApi(row.id).catch(() => {});
       if (!res) return;
       if (!res) return;
-      MessagePlugin.success('删除成功');
+      MessagePlugin.success('发布成功');
       fetchData();
       fetchData();
     },
     },
   });
   });
@@ -310,7 +310,7 @@ const handleRestart = (row) => {
       confirmDia.hide();
       confirmDia.hide();
       const res = await serviceUnitRestartApi(row.id).catch(() => {});
       const res = await serviceUnitRestartApi(row.id).catch(() => {});
       if (!res) return;
       if (!res) return;
-      MessagePlugin.success('删除成功');
+      MessagePlugin.success('重启成功');
       fetchData();
       fetchData();
     },
     },
   });
   });
@@ -326,7 +326,7 @@ const handleCloze = (row) => {
       confirmDia.hide();
       confirmDia.hide();
       const res = await serviceUnitClozeApi(row.id).catch(() => {});
       const res = await serviceUnitClozeApi(row.id).catch(() => {});
       if (!res) return;
       if (!res) return;
-      MessagePlugin.success('删除成功');
+      MessagePlugin.success('关闭成功');
       fetchData();
       fetchData();
     },
     },
   });
   });

+ 0 - 1
src/views/sop/sop-manage/office-sop/index.vue

@@ -148,7 +148,6 @@
     <add-violation-dialog
     <add-violation-dialog
       v-model:visible="showAddViolationDialog"
       v-model:visible="showAddViolationDialog"
       :sop="curSopData"
       :sop="curSopData"
-      type="new"
     ></add-violation-dialog>
     ></add-violation-dialog>
   </div>
   </div>
 </template>
 </template>

+ 2 - 3
src/views/sop/sop-manage/student-sop/index.vue

@@ -141,7 +141,6 @@
     <add-violation-dialog
     <add-violation-dialog
       v-model:visible="showAddViolationDialog"
       v-model:visible="showAddViolationDialog"
       :sop="curSopData"
       :sop="curSopData"
-      type="new"
     ></add-violation-dialog>
     ></add-violation-dialog>
   </div>
   </div>
 </template>
 </template>
@@ -283,8 +282,8 @@ const editSopFlowHandle = (row, type = 'fill') => {
   if (type === 'new') {
   if (type === 'new') {
     curSopData.value = {
     curSopData.value = {
       ...row,
       ...row,
-      flowDeploymentId:
-        appStore.getFlowDetailByType('OFFICE_SOP_FLOW')?.flowDeploymentId,
+      flowDeploymentId: appStore.getFlowDetailByType('CLOUD_MARK_SOP_FLOW')
+        ?.flowDeploymentId,
     };
     };
   } else {
   } else {
     curSopData.value = row;
     curSopData.value = row;

+ 6 - 37
src/views/sop/sop-monitor/violation-registration/add-violation-dialog.vue

@@ -2,7 +2,7 @@
   <my-drawer
   <my-drawer
     class="sop-dialog"
     class="sop-dialog"
     :visible="visible"
     :visible="visible"
-    :header="title"
+    header="新增违规"
     size="80%"
     size="80%"
     attach="body"
     attach="body"
     :closeOnOverlayClick="false"
     :closeOnOverlayClick="false"
@@ -59,19 +59,6 @@
           colon
           colon
         >
         >
           <t-row :gutter="[0, 20]">
           <t-row :gutter="[0, 20]">
-            <template v-if="!IS_NEW_MODE">
-              <t-col :span="4">
-                <t-form-item label="登记人">
-                  {{ formData.creator }}
-                </t-form-item>
-              </t-col>
-              <t-col :span="4">
-                <t-form-item label="违规登记时间">
-                  {{ timestampFilter(formData.createTime) }}
-                </t-form-item>
-              </t-col>
-            </template>
-
             <t-col :span="5">
             <t-col :span="5">
               <t-form-item label="节点负责人" name="userId">
               <t-form-item label="节点负责人" name="userId">
                 <select-filter-user
                 <select-filter-user
@@ -101,10 +88,7 @@
             </t-col>
             </t-col>
             <t-col :span="12">
             <t-col :span="12">
               <t-form-item label="截图说明">
               <t-form-item label="截图说明">
-                <upload-image
-                  :config="{ length: 3 }"
-                  :on-change="imageChange"
-                ></upload-image>
+                <my-upload @change="imageChange"></my-upload>
               </t-form-item>
               </t-form-item>
             </t-col>
             </t-col>
           </t-row>
           </t-row>
@@ -121,21 +105,15 @@
 </template>
 </template>
 
 
 <script setup name="AddViolationDialog">
 <script setup name="AddViolationDialog">
-import { ref, computed, reactive, watch } from 'vue';
+import { ref, reactive, watch } from 'vue';
 import { VIOLATION_TYPE } from '@/config/constants';
 import { VIOLATION_TYPE } from '@/config/constants';
 import { dictToOptionList, objAssign } from '@/utils/tool';
 import { dictToOptionList, objAssign } from '@/utils/tool';
-import { timestampFilter } from '@/utils/filter';
 import { saveViolation } from '@/api/sop';
 import { saveViolation } from '@/api/sop';
-import UploadImage from '../../components/UPLOAD_IMAGE.vue';
 import { MessagePlugin } from 'tdesign-vue-next';
 import { MessagePlugin } from 'tdesign-vue-next';
 
 
 const emit = defineEmits(['update:visible', 'success']);
 const emit = defineEmits(['update:visible', 'success']);
 const props = defineProps({
 const props = defineProps({
   visible: Boolean,
   visible: Boolean,
-  type: {
-    type: String,
-    default: 'new',
-  },
   sop: {
   sop: {
     type: Object,
     type: Object,
     default() {
     default() {
@@ -146,13 +124,11 @@ const props = defineProps({
 
 
 const initFormData = {
 const initFormData = {
   id: null,
   id: null,
-  creator: '',
-  createTime: null,
   userId: null,
   userId: null,
   type: '',
   type: '',
   status: 'NOT_START',
   status: 'NOT_START',
   content: '',
   content: '',
-  attachmentIds: [],
+  attachmentIds: '',
   crmNo: '',
   crmNo: '',
   serviceId: null,
   serviceId: null,
   sopNo: '',
   sopNo: '',
@@ -161,13 +137,6 @@ const initFormData = {
 let formData = reactive(initFormData);
 let formData = reactive(initFormData);
 const formRef = ref(null);
 const formRef = ref(null);
 
 
-const IS_NEW_MODE = computed(() => {
-  return props.type === 'new';
-});
-const title = computed(() => {
-  return props.type === 'new' ? '新增违规' : '';
-});
-
 const rules = {
 const rules = {
   userId: [
   userId: [
     {
     {
@@ -203,8 +172,8 @@ watch(
   }
   }
 );
 );
 
 
-const imageChange = (data) => {
-  formData.attachmentIds = data.value.map((item) => item.id);
+const imageChange = (fileList) => {
+  formData.attachmentIds = fileList.map((item) => item.id).join(',');
 };
 };
 
 
 const save = async () => {
 const save = async () => {

+ 173 - 140
src/views/sop/sop-monitor/violation-registration/flow-dialog.vue

@@ -1,147 +1,183 @@
 <template>
 <template>
-  <my-dialog
+  <my-drawer
+    class="sop-dialog"
     :visible="visible"
     :visible="visible"
-    @close="emit('update:visible', false)"
-    :header="`跟进`"
-    :width="1000"
+    :header="title"
+    size="80%"
+    attach="body"
     :closeOnOverlayClick="false"
     :closeOnOverlayClick="false"
+    :close-btn="true"
+    :footer="false"
+    @close="emit('update:visible', false)"
   >
   >
-    <t-form ref="formRef" :data="formData" labelWidth="100px" :rules="rules">
-      <div class="form-group-title">违规信息</div>
-      <t-row :gutter="[0, 10]">
-        <t-col :span="3">
-          <t-form-item label="服务单元:">
-            {{ asyncDetail.service }}</t-form-item
-          >
-        </t-col>
-        <t-col :span="3">
-          <t-form-item label="SOP流水号:">
-            {{ asyncDetail.sopNo }}
-          </t-form-item>
-        </t-col>
-        <t-col :span="3">
-          <t-form-item label="客户类型:">
-            {{ asyncDetail.customType }}
-          </t-form-item>
-        </t-col>
-        <t-col :span="3">
-          <t-form-item label="客户名称:">
-            {{ asyncDetail.custom }}
-          </t-form-item>
-        </t-col>
-        <t-col :span="3">
-          <t-form-item label="登记时间:">
-            {{ dateFormat(asyncDetail.createTime, 'yyyy-MM-dd hh:mm') }}
-          </t-form-item>
-        </t-col>
-        <t-col :span="3">
-          <t-form-item label="登记人:">
-            {{ asyncDetail.createName }}
-          </t-form-item>
-        </t-col>
-        <t-col :span="3">
-          <t-form-item label="节点负责人:">
-            {{ asyncDetail.userName }}
-          </t-form-item>
-        </t-col>
-        <t-col :span="3">
-          <t-form-item label="违规类型:">
-            {{ VIOLATION_TYPE[asyncDetail.type] || asyncDetail.type }}
-          </t-form-item>
-        </t-col>
-        <t-col :span="12">
-          <t-form-item label="违规情况说明:">
-            {{ asyncDetail.content }}
-          </t-form-item>
-        </t-col>
-        <t-col :span="12">
-          <t-form-item label="附件说明:">
-            {{ asyncDetail.attachmentIds }}
-          </t-form-item>
-        </t-col>
-      </t-row>
-      <div class="form-group-title next-title">新增跟进</div>
-      <t-row :gutter="[0, 10]">
-        <t-col :span="12">
-          <t-form-item label="跟进人:">
-            {{ userStore.user.realName }}</t-form-item
-          >
-        </t-col>
-        <t-col :span="12">
-          <t-form-item label="跟进说明:" name="remark">
-            <t-textarea
-              v-model="formData.remark"
-              tips="限100字以内"
-              :maxlength="100"
-            ></t-textarea>
-          </t-form-item>
-        </t-col>
-        <t-col :span="12">
-          <t-form-item label="附件说明:">
-            <my-upload @change="fileChange"></my-upload>
-          </t-form-item>
-        </t-col>
-      </t-row>
-      <div class="m-t-20px">
-        <t-button theme="primary" @click="save">保存</t-button>
-        <t-link
-          theme="primary"
-          underline
-          class="m-l-40px"
-          @click="showHistory = !showHistory"
-          >查看历史跟进记录</t-link
+    <div class="sop-step">
+      <t-collapse class="sop-step-mid" defaultExpandAll>
+        <t-collapse-panel disabled>
+          <template #expandIcon></template>
+          <template #header> SOP信息 </template>
+          <t-form colon label-width="120px">
+            <t-row :gutter="[0, 4]">
+              <t-col :span="3">
+                <t-form-item label="服务单元">{{ curRow.service }}</t-form-item>
+              </t-col>
+              <t-col :span="3">
+                <t-form-item label="SOP流水号">{{ curRow.sopNo }}</t-form-item>
+              </t-col>
+              <t-col :span="3">
+                <t-form-item label="客户类型">{{
+                  curRow.customType
+                }}</t-form-item>
+              </t-col>
+              <t-col :span="3">
+                <t-form-item label="客户名称">{{ curRow.custom }}</t-form-item>
+              </t-col>
+              <t-col :span="3">
+                <t-form-item label="登记时间">{{
+                  timestampFilter(curRow.createTime, 'mm')
+                }}</t-form-item>
+              </t-col>
+              <t-col :span="3">
+                <t-form-item label="登记人">{{
+                  curRow.createName
+                }}</t-form-item>
+              </t-col>
+              <t-col :span="3">
+                <t-form-item label="节点负责人">{{
+                  curRow.userName
+                }}</t-form-item>
+              </t-col>
+              <t-col :span="3">
+                <t-form-item label="违规类型">{{
+                  violationTypeFilter(curRow.type)
+                }}</t-form-item>
+              </t-col>
+              <t-col :span="12">
+                <t-form-item label="违规情况说明">{{
+                  curRow.content
+                }}</t-form-item>
+              </t-col>
+              <t-col :span="12">
+                <t-form-item label="截图说明">
+                  <attachment-view
+                    :ids="curRow.attachmentIds"
+                  ></attachment-view>
+                </t-form-item>
+              </t-col>
+            </t-row>
+          </t-form>
+        </t-collapse-panel>
+      </t-collapse>
+      <div class="sop-step-list" style="flex-direction: column">
+        <t-form
+          ref="formRef"
+          :data="formData"
+          labelWidth="100px"
+          :rules="rules"
+          colon
+          class="sop-step-body"
         >
         >
+          <t-row :gutter="[0, 30]">
+            <t-col :span="12">
+              <div class="form-group-title"> 新增跟进 </div>
+            </t-col>
+            <t-col :span="12">
+              <t-form-item label="跟进人">
+                {{ userStore.user.realName }}</t-form-item
+              >
+            </t-col>
+            <t-col :span="12">
+              <t-form-item label="跟进说明" name="remark">
+                <t-textarea
+                  v-model="formData.remark"
+                  tips="限100字以内"
+                  :maxlength="100"
+                ></t-textarea>
+              </t-form-item>
+            </t-col>
+            <t-col :span="12">
+              <t-form-item label="截图说明">
+                <my-upload @change="fileChange"></my-upload>
+              </t-form-item>
+            </t-col>
+            <t-col :span="12">
+              <div class="m-b-10px">
+                历史明细查阅
+                <t-link
+                  theme="primary"
+                  class="m-l-10px"
+                  @click="showHistory = !showHistory"
+                  >查看 <ChevronUpIcon v-if="showHistory" />
+                  <ChevronDownIcon v-else /></t-link
+              ></div>
+              <t-table
+                v-if="showHistory"
+                size="small"
+                row-key="id"
+                :columns="columns"
+                :data="tableData"
+                bordered
+              >
+                <template #createTime="{ row, col }">
+                  {{ timestampFilter(row[col.colKey], 'mm') }}
+                </template>
+                <template #attachment="{ row, col }">
+                  <attachment-view
+                    :ids="row[col.colKey]"
+                    :imgSize="60"
+                  ></attachment-view>
+                </template>
+              </t-table>
+            </t-col>
+          </t-row>
+        </t-form>
+        <t-space class="sop-step-footer">
+          <t-button theme="primary" @click="save">保存</t-button>
+          <t-button theme="default" @click="emit('update:visible', false)"
+            >取消</t-button
+          >
+        </t-space>
       </div>
       </div>
-      <template v-if="showHistory">
-        <div class="form-group-title next-title">历史明细查阅</div>
-        <t-table
-          size="small"
-          row-key="id"
-          :columns="columns"
-          :data="tableData"
-          bordered
-        ></t-table>
-      </template>
-    </t-form>
-    <template #foot>
-      <!-- <t-button theme="default" @click="emit('update:visible', false)"
-          >取消</t-button
-        >
-        <t-button theme="primary" @click="save">保存</t-button> -->
-    </template>
-  </my-dialog>
+    </div>
+  </my-drawer>
 </template>
 </template>
 <script setup name="ViolationFlowDialog">
 <script setup name="ViolationFlowDialog">
 import useClearDialog from '@/hooks/useClearDialog';
 import useClearDialog from '@/hooks/useClearDialog';
+import { ChevronUpIcon, ChevronDownIcon } from 'tdesign-icons-vue-next';
+import { MessagePlugin } from 'tdesign-vue-next';
+
 import { ref, computed } from 'vue';
 import { ref, computed } from 'vue';
-import { VIOLATION_TYPE, VIOLATION_FLOW_STATUS } from '@/config/constants';
-import { dateFormat } from '@/utils/tool';
 import { useUserStore } from '@/store';
 import { useUserStore } from '@/store';
-import { violationDetail, violationDetailList, flowViolation } from '@/api/sop';
+import { violationDetailList, flowViolation } from '@/api/sop';
+import { timestampFilter, violationTypeFilter } from '@/utils/filter';
+
 const userStore = useUserStore();
 const userStore = useUserStore();
+
 const props = defineProps({
 const props = defineProps({
   visible: Boolean,
   visible: Boolean,
-  curRow: Object,
+  curRow: {
+    type: Object,
+    default() {
+      return {};
+    },
+  },
 });
 });
-const { curRow } = props;
 const emit = defineEmits(['update:visible', 'success']);
 const emit = defineEmits(['update:visible', 'success']);
+
 const formRef = ref(null);
 const formRef = ref(null);
 const asyncDetail = ref({});
 const asyncDetail = ref({});
 const tableData = ref([]);
 const tableData = ref([]);
 const showHistory = ref(false);
 const showHistory = ref(false);
+
+const title = computed(() => {
+  return `违规信息(违规流水号:${props.curRow.code})`;
+});
+
 const getDetail = async () => {
 const getDetail = async () => {
-  //编辑状态下获取回显数据的接口请求业务,如果curRow里的字段够用,就直接把curRow里的字段赋值给formData
-  // for (let key in formData) {
-  //   formData[key] = props.curRow[key];
-  // }
-  violationDetail(curRow.id).then((res) => {
-    asyncDetail.value = res;
-  });
-  violationDetailList(curRow.id).then((res) => {
-    tableData.value = res;
-  });
+  const res = await violationDetailList(props.curRow.id);
+  tableData.value = res;
 };
 };
-const { formData, isEdit } = useClearDialog(
+
+const { formData } = useClearDialog(
   {
   {
     attachmentIds: '',
     attachmentIds: '',
     remark: '',
     remark: '',
@@ -162,30 +198,27 @@ const rules = {
   ],
   ],
 };
 };
 const fileChange = (fileList) => {
 const fileChange = (fileList) => {
-  formData.attachmentIds = fileList.map((item) => item.response.id).join(',');
+  formData.attachmentIds = fileList.map((item) => item.id).join(',');
 };
 };
 const columns = [
 const columns = [
   { colKey: 'createTime', title: '跟进时间' },
   { colKey: 'createTime', title: '跟进时间' },
   { colKey: 'createName', title: '跟进人' },
   { colKey: 'createName', title: '跟进人' },
   { colKey: 'remark', title: '跟进说明' },
   { colKey: 'remark', title: '跟进说明' },
-  { colKey: 'attachmentIds', title: '附件说明' },
+  { colKey: 'attachmentIds', title: '附件说明', cell: 'attachment' },
 ];
 ];
-const flowHandler = () => {
-  flowViolation({
+
+const save = async () => {
+  const valid = await formRef.value.validate();
+  if (valid !== true) return;
+
+  const res = await flowViolation({
     ...formData,
     ...formData,
-    delayWarnId: curRow.id,
-    id: asyncDetail.value.id || undefined,
-    createId: asyncDetail.createId || undefined,
-    createTime: asyncDetail.createTime || undefined,
-  }).then((res) => {
-    emit('success');
-  });
-};
-const save = () => {
-  formRef.value.validate().then(async (result) => {
-    if (result === true) {
-      flowHandler();
-    }
-  });
+    violationId: props.curRow.id,
+  }).catch(() => {});
+  if (!res) return;
+
+  MessagePlugin.success('保存成功');
+  emit('update:visible', false);
+  emit('success');
 };
 };
 </script>
 </script>

+ 83 - 79
src/views/sop/sop-monitor/violation-registration/index.vue

@@ -35,9 +35,51 @@
           showPageSize: false,
           showPageSize: false,
           total: pagination.total,
           total: pagination.total,
         }"
         }"
+        v-loading="tableLoading"
       >
       >
+        <template #type="{ col, row }">
+          {{ violationTypeFilter(row[col.colKey]) }}
+        </template>
+        <template #status="{ col, row }">
+          {{ violationFlowStatusFilter(row[col.colKey]) }}
+        </template>
+        <template #operate="{ row }">
+          <div class="table-operations">
+            <t-link
+              v-if="row.status !== 'CLOSE'"
+              theme="primary"
+              hover="color"
+              @click="handleFollow(row)"
+            >
+              跟进
+            </t-link>
+            <t-link
+              v-if="row.status === 'CLOSE'"
+              theme="primary"
+              hover="color"
+              @click="restartHandler(row)"
+            >
+              重启
+            </t-link>
+            <t-link
+              v-else
+              theme="primary"
+              hover="color"
+              @click="closeHandler(row)"
+            >
+              关闭
+            </t-link>
+          </div>
+        </template>
       </t-table>
       </t-table>
     </div>
     </div>
+
+    <!-- FlowDialog -->
+    <violation-flow-dialog
+      v-model:visible="showViolationFlowDialog"
+      :curRow="curRow"
+      @confirm="fetchData"
+    ></violation-flow-dialog>
   </div>
   </div>
 </template>
 </template>
 
 
@@ -50,12 +92,15 @@ import { dictToOptionList } from '@/utils/tool';
 import { VIOLATION_TYPE, VIOLATION_FLOW_STATUS } from '@/config/constants';
 import { VIOLATION_TYPE, VIOLATION_FLOW_STATUS } from '@/config/constants';
 import { omit } from 'lodash';
 import { omit } from 'lodash';
 import { DialogPlugin, MessagePlugin } from 'tdesign-vue-next';
 import { DialogPlugin, MessagePlugin } from 'tdesign-vue-next';
+import { violationTypeFilter, violationFlowStatusFilter } from '@/utils/filter';
+import ViolationFlowDialog from './flow-dialog.vue';
+
+const showViolationFlowDialog = ref(false);
+const curRow = ref({});
 
 
-const showFlowDialog = ref(false);
-const curRow = ref(null);
-const editSuccess = () => {
-  MessagePlugin.success('操作成功');
-  showFlowDialog.value = false;
+const handleFollow = (row) => {
+  curRow.value = row;
+  showViolationFlowDialog.value = true;
 };
 };
 const restartHandler = (row) => {
 const restartHandler = (row) => {
   const confirmDia = DialogPlugin({
   const confirmDia = DialogPlugin({
@@ -63,12 +108,12 @@ const restartHandler = (row) => {
     body: `您确定要重启当前预警信息吗?`,
     body: `您确定要重启当前预警信息吗?`,
     confirmBtn: '确定',
     confirmBtn: '确定',
     cancelBtn: '取消',
     cancelBtn: '取消',
-    onConfirm: () => {
-      restartViolation(row.id).then(() => {
-        confirmDia.hide();
-        MessagePlugin.success('操作成功');
-        fetchData();
-      });
+    onConfirm: async () => {
+      confirmDia.hide();
+      const res = await restartViolation(row.id).catch(() => {});
+      if (!res) return;
+      MessagePlugin.success('操作成功');
+      fetchData();
     },
     },
   });
   });
 };
 };
@@ -78,87 +123,42 @@ const closeHandler = (row) => {
     body: `您确定要关闭当前预警信息吗?`,
     body: `您确定要关闭当前预警信息吗?`,
     confirmBtn: '确定',
     confirmBtn: '确定',
     cancelBtn: '取消',
     cancelBtn: '取消',
-    onConfirm: () => {
-      closeViolation(row.id).then(() => {
-        confirmDia.hide();
-        MessagePlugin.success('操作成功');
-        fetchData();
-      });
+    onConfirm: async () => {
+      confirmDia.hide();
+      const res = await closeViolation(row.id).catch(() => {});
+      if (!res) return;
+      MessagePlugin.success('操作成功');
+      fetchData();
     },
     },
   });
   });
 };
 };
+
 const columns = [
 const columns = [
-  // { colKey: 'a', title: '违规流水号' },
-  { colKey: 'sopNo', title: 'SOP流水号', width: 160 },
-  { colKey: 'userName', title: '节点负责人', width: 120 },
-  { colKey: 'custom', title: '客户名称', width: 120 },
-  { colKey: 'crmNo', title: '项目单号', width: 140 },
+  { colKey: 'service', title: '服务单元', width: 140 },
+  { colKey: 'code', title: '违规流水号', width: 200 },
+  { colKey: 'sopNo', title: 'SOP流水号', width: 200 },
+  { colKey: 'userName', title: '节点负责人', width: 140 },
+  { colKey: 'custom', title: '客户名称', width: 140 },
+  { colKey: 'crmNo', title: '项目单号', width: 200 },
   { colKey: 'crmName', title: '项目名称' },
   { colKey: 'crmName', title: '项目名称' },
   {
   {
     colKey: 'type',
     colKey: 'type',
     title: '违规类型',
     title: '违规类型',
     width: 130,
     width: 130,
-    cell: (h, { row }) => {
-      return <span>{VIOLATION_TYPE[row.type] || row.type}</span>;
-    },
   },
   },
   { colKey: 'content', title: '违规情况' },
   { colKey: 'content', title: '违规情况' },
   {
   {
     colKey: 'status',
     colKey: 'status',
     title: '跟进状态',
     title: '跟进状态',
-    cell: (h, { row }) => {
-      return <span>{VIOLATION_FLOW_STATUS[row.status] || row.status}</span>;
-    },
+    width: 120,
   },
   },
-  { colKey: 'createTime', title: '登记时间' },
-  { colKey: 'createName', title: '登记人', width: 120 },
+  { colKey: 'createTime', title: '登记时间', width: 180 },
+  { colKey: 'createName', title: '登记人', width: 140 },
   {
   {
     title: '管理',
     title: '管理',
     colKey: 'operate',
     colKey: 'operate',
     fixed: 'right',
     fixed: 'right',
-    width: 130,
-    cell: (h, { row }) => {
-      return (
-        <div class="table-operations">
-          {row.status === 'NOT_START' ? (
-            <t-link
-              theme="primary"
-              hover="color"
-              onClick={(e) => {
-                e.stopPropagation();
-                curRow.value = row;
-                showFlowDialog.value = true;
-              }}
-            >
-              跟进
-            </t-link>
-          ) : null}
-          {row.status === 'CLOSE' ? (
-            <t-link
-              theme="primary"
-              hover="color"
-              onClick={(e) => {
-                e.stopPropagation();
-                restartHandler(row);
-              }}
-            >
-              重启
-            </t-link>
-          ) : (
-            <t-link
-              theme="primary"
-              hover="color"
-              onClick={(e) => {
-                e.stopPropagation();
-                closeHandler(row);
-              }}
-            >
-              关闭
-            </t-link>
-          )}
-        </div>
-      );
-    },
+    width: 120,
   },
   },
 ];
 ];
 
 
@@ -262,10 +262,14 @@ const transParams = computed(() => {
     endTime: params.time[1],
     endTime: params.time[1],
   };
   };
 });
 });
-const { loading, pagination, tableData, onChange, fetchData, search } =
-  useFetchTable(getViolationList, {
-    params: transParams,
-  });
+const {
+  loading: tableLoading,
+  pagination,
+  tableData,
+  onChange,
+  fetchData,
+  search,
+} = useFetchTable(getViolationList, {
+  params: transParams,
+});
 </script>
 </script>
-
-<style></style>