Ver Fonte

调接口

刘洋 há 1 ano atrás
pai
commit
88a8cff9e2

+ 14 - 1
src/api/sop.js

@@ -100,12 +100,25 @@ export const deviceOutInSave = (data) =>
     url: '/api/admin/device/in/out/submit',
     data,
   });
-
+//项目计划变更列表
 export const planChangeList = (params) =>
   request({
     url: '/api/admin/project/exchange/list',
     params,
   });
+//项目变更计划申请(第一步)
+export const createPlanChange = (data) =>
+  request({
+    url: '/api/admin/ding/exception/apply/save',
+    data,
+  });
+//项目变更计划审批
+export const approvePlanChange = (params) =>
+  request({
+    url: '/api/admin/project/exchange/flow/approve',
+    params,
+    loading: true,
+  });
 
 //获取流程部署信息接口
 export const getFlowDeployment = () =>

+ 40 - 7
src/components/common/dynamic-table/index.vue

@@ -23,7 +23,12 @@
         </div>
       </template>
     </t-table>
-    <t-button theme="primary" class="m-t-15px" @click="createOneRow">
+    <t-button
+      theme="primary"
+      class="m-t-15px"
+      @click="createOneRow"
+      v-if="!readonly"
+    >
       <template #icon><Icon name="add"></Icon></template>
       添加
     </t-button>
@@ -31,11 +36,27 @@
 </template>
 
 <script setup name="DynamicTable">
-import { computed, ref, watch } from 'vue';
+import { computed, ref } from 'vue';
 import { Icon } from 'tdesign-icons-vue-next';
-const { columns } = defineProps(['columns']);
+import { omit } from 'lodash';
+const { columns, readonly, data } = defineProps([
+  'columns',
+  'readonly',
+  'data',
+]);
+
 const tableRef = ref();
-const tableData = ref([]);
+const tableData = ref(data || []);
+// const newColumns = computed(() => {
+//   return columns.map((item) => {
+//     if (item.edit) {
+//       item.edit.onEdited = (context) => {
+//         console.log(context);
+//         tableData.value.splice(context.rowIndex, 1, context.newRowData);
+//       };
+//     }
+//   });
+// });
 const resetKeys = () => {
   tableData.value.forEach((item, index) => {
     item.key = index + 1 + '';
@@ -51,9 +72,16 @@ const createOneRow = () => {
   resetKeys();
 };
 
-createOneRow();
+if (!readonly) {
+  createOneRow();
+}
 
-const onRowEdit = () => {};
+const onRowEdit = (params) => {
+  const { row, editedRow } = params;
+  for (let k in editedRow) {
+    row[k] = editedRow[k];
+  }
+};
 const onRowValidate = () => {};
 const onValidate = () => {};
 
@@ -72,8 +100,13 @@ const validate = (cb) => {
     }
   });
 };
+const exportTableData = () => {
+  return tableData.value.map((item) => ({
+    ...omit(item, 'key'),
+  }));
+};
 
-defineExpose({ validate });
+defineExpose({ validate, exportTableData });
 </script>
 
 <style lang="less" name="TABLE">

+ 2 - 1
src/components/global/search-form/index.vue

@@ -240,7 +240,8 @@ const colToWidth = (colSpan) => {
   if (colSpan === 0) {
     return 'auto';
   }
-  let canUseWidth = comWidth.value - (props.showAll ? 20 : 60);
+  // let canUseWidth = comWidth.value - (props.showAll ? 20 : 60);
+  let canUseWidth = comWidth.value - (props.showAll ? 40 : 60);
   return Math.floor((canUseWidth * colSpan) / 24) + 'px';
 };
 </script>

+ 5 - 0
src/store/modules/app.js

@@ -28,6 +28,11 @@ const useAppStore = defineStore('app', {
       let res = await getFlowDeployment();
       this.flowParams = res;
     },
+    getFlowDetailByType(type) {
+      return this.flowParams
+        ? this.flowParams.find((item) => item.type == type)
+        : null;
+    },
   },
 });
 

+ 3 - 1
src/utils/request.js

@@ -81,7 +81,9 @@ function createService() {
       const err = (text) => {
         Message.error({
           content:
-            (error?.response?.status == 401 ? error?.config?.url + ' ' : '') +
+            (error?.response?.data?.message?.includes('权限')
+              ? error?.config?.url + ' '
+              : '') +
             (error.response &&
             error.response.data &&
             error.response.data.message

+ 6 - 1
src/views/sop/components/DATE.vue

@@ -1,5 +1,10 @@
 <template>
-  <t-date-picker v-model="value" @change="change" style="width: 100%" />
+  <t-date-picker
+    v-model="value"
+    @change="change"
+    style="width: 100%"
+    value-type="time-stamp"
+  />
 </template>
 <script setup name="DATE">
 import { ref } from 'vue';

+ 59 - 10
src/views/sop/sop-manage/device-out-in/index.vue

@@ -15,9 +15,18 @@
       <template #service="{ item, params }">
         <select-service-unit v-model="params[item.prop]"></select-service-unit>
       </template>
-      <template #area>
+      <template #location>
+        <select-area v-model="params.location" value-type="full"></select-area>
+      </template>
+      <template #address>
         <select-area v-model="params.address" value-type="full"></select-area>
       </template>
+      <template #user="{ item, params }">
+        <select-filter-user
+          v-model="params[item.prop]"
+          clearable
+        ></select-filter-user>
+      </template>
     </SearchForm>
 
     <div class="flex-1 page-wrap">
@@ -54,6 +63,8 @@ import useFetchTable from '@/hooks/useFetchTable';
 import AddDeviceDialog from './add-device-dialog.vue';
 import { deviceOutInSearch } from '@/api/sop';
 import { omit } from 'lodash';
+import { DEVICE_USAGE_TYPE, RUNNING_STATUS } from '@/config/constants';
+import { dictToOptionList } from '@/utils/tool';
 
 const selectedRowKeys = ref([]);
 const selectChange = (value, { selectedRowData }) => {
@@ -84,21 +95,53 @@ const fields = ref([
     label: '服务单元',
     type: 'select',
     labelWidth: 100,
-    colSpan: 5,
+    colSpan: 6,
     cell: 'service',
   },
+  {
+    prop: 'usageType',
+    label: '用途类型',
+    type: 'select',
+    labelWidth: 100,
+    colSpan: 6,
+    options: dictToOptionList(DEVICE_USAGE_TYPE),
+  },
+  {
+    prop: 'userId',
+    label: '登记人',
+    type: 'select',
+    labelWidth: 100,
+    colSpan: 6,
+    cell: 'user',
+  },
+  {
+    prop: 'deviceStatus',
+    label: '运行状态',
+    labelWidth: 100,
+    colSpan: 6,
+    options: dictToOptionList(RUNNING_STATUS),
+    attrs: {
+      clearable: true,
+    },
+  },
   {
     prop: 'time',
     label: '出/入库时间',
     type: 'daterange',
     labelWidth: 100,
-    colSpan: 10,
+    colSpan: 12,
+  },
+  {
+    prop: 'deviceNo',
+    label: '设备编号',
+    labelWidth: 100,
+    colSpan: 6,
   },
   {
     prop: 'customName',
     label: '客户名称',
     labelWidth: 100,
-    colSpan: 5,
+    colSpan: 6,
   },
   {
     type: 'buttons',
@@ -114,34 +157,40 @@ const fields = ref([
     ],
   },
   {
-    prop: 'deviceNo',
-    label: '设备编号',
+    prop: 'location',
+    label: '当前地',
     labelWidth: 100,
-    colSpan: 5,
+    colSpan: 7,
+    cell: 'location',
   },
   {
     prop: 'address',
     label: '发往地',
     labelWidth: 100,
     colSpan: 7,
-    cell: 'area',
+    cell: 'address',
   },
 ]);
 const params = reactive({
   serviceUnitId: '',
+  usageType: '',
+  userId: '',
+  deviceStatus: '',
   time: [],
-  customName: '',
   deviceNo: '',
+  customName: '',
+  location: ['', '', ''],
   address: ['', '', ''],
 });
 const transParams = computed(() => {
   return {
-    ...omit(params, ['time', 'address']),
+    ...omit(params, ['time', 'location', 'address']),
     inOutTimeStart: params.time[0],
     inOutTimeEnd: params.time[1],
     address: params.address,
     deviceNo: params.deviceNo,
     address: params.address.join(''),
+    location: params.location.join(''),
   };
 });
 const {

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

@@ -148,7 +148,7 @@ const toCurSopFlow = (row) => {
 const planChange = (row) => {
   // curRow.value = row;
   // showPlanChangeDialog.value = true;
-  router.push({ name: 'PlanChange' });
+  router.push({ name: 'PlanChange', query: { new: true } });
 };
 const qualityIssue = (row) => {
   router.push({ name: 'QualityIssue' });

+ 205 - 111
src/views/sop/sop-manage/plan-change/index.vue

@@ -1,166 +1,260 @@
 <template>
   <div class="plan-change">
-    <div class="page-wrap">
-      <t-form ref="formRef" :data="formData" :labelWidth="180">
-        <t-row :gutter="[0, 20]">
-          <t-col :span="12">
-            <div class="form-group-title" style="margin-bottom: 0">
-              项目派单信息(SOP流水单号:20230601001)
-            </div>
-          </t-col>
-          <t-col :span="6">
-            <t-form-item class="my-form-item" label="项目单号"
-              >1111
-            </t-form-item>
-          </t-col>
-          <t-col :span="6">
-            <t-form-item class="my-form-item" label="项目名称">
-              1111
-            </t-form-item>
-          </t-col>
-          <t-col :span="6">
-            <t-form-item class="my-form-item" label="派单时间">
-              1111
-            </t-form-item>
-          </t-col>
-          <t-col :span="6">
-            <t-form-item class="my-form-item" label="客户经理">
-              1111
-            </t-form-item>
-          </t-col>
-          <t-col :span="6">
-            <t-form-item class="my-form-item" label="客户类型">
-              1111
-            </t-form-item>
-          </t-col>
-          <t-col :span="6">
-            <t-form-item class="my-form-item" label="客户名称">
-              1111
-            </t-form-item>
-          </t-col>
-          <t-col :span="6">
-            <t-form-item class="my-form-item" label="考试开始时间">
-              1111
-            </t-form-item>
-          </t-col>
-          <t-col :span="6">
-            <t-form-item class="my-form-item" label="考试结束时间">
-              1111
-            </t-form-item>
-          </t-col>
-          <t-col :span="6">
-            <t-form-item class="my-form-item" label="实施产品">
-              1111
-            </t-form-item>
-          </t-col>
-          <t-col :span="6">
-            <t-form-item class="my-form-item" label="服务单元">
-              1111
-            </t-form-item>
-          </t-col>
-          <t-col :span="12">
-            <div class="form-group-title"> SOP项目计划变更说明 </div>
-            <div class="sub-title">
-              <p :style="{ color: 'gray' }">
-                SOP项目计划需要变更时,可手动发起一个或多个申请,质控专员审核后,在SOP流程中进行计划变更调整,完成变更后,申请流程结束并通知到发起申请人
-              </p>
-            </div>
-          </t-col>
-          <t-col :span="6">
-            <t-form-item class="my-form-item" label="报备申请人">
-              1111
-            </t-form-item>
-          </t-col>
-          <t-col :span="6">
-            <t-form-item class="my-form-item" label="报备申请时间">
-              1111
-            </t-form-item>
-          </t-col>
+    <t-form ref="formRef" :data="formData" :labelWidth="180" :rules="rules">
+      <t-row :gutter="[0, 20]">
+        <t-col :span="12">
+          <div class="form-group-title" style="margin-bottom: 0">
+            项目派单信息(SOP流水单号:20230601001)
+          </div>
+        </t-col>
+        <t-col :span="6">
+          <t-form-item label="项目单号">1111 </t-form-item>
+        </t-col>
+        <t-col :span="6">
+          <t-form-item label="项目名称"> 1111 </t-form-item>
+        </t-col>
+        <t-col :span="6">
+          <t-form-item label="派单时间"> 1111 </t-form-item>
+        </t-col>
+        <t-col :span="6">
+          <t-form-item label="客户经理"> 1111 </t-form-item>
+        </t-col>
+        <t-col :span="6">
+          <t-form-item label="客户类型"> 1111 </t-form-item>
+        </t-col>
+        <t-col :span="6">
+          <t-form-item label="客户名称"> 1111 </t-form-item>
+        </t-col>
+        <t-col :span="6">
+          <t-form-item label="考试开始时间"> 1111 </t-form-item>
+        </t-col>
+        <t-col :span="6">
+          <t-form-item label="考试结束时间"> 1111 </t-form-item>
+        </t-col>
+        <t-col :span="6">
+          <t-form-item label="实施产品"> 1111 </t-form-item>
+        </t-col>
+        <t-col :span="6">
+          <t-form-item label="服务单元"> 1111 </t-form-item>
+        </t-col>
+        <t-col :span="12">
+          <div class="form-group-title"> SOP项目计划变更说明 </div>
+          <div class="sub-title">
+            <p :style="{ color: 'gray' }">
+              SOP项目计划需要变更时,可手动发起一个或多个申请,质控专员审核后,在SOP流程中进行计划变更调整,完成变更后,申请流程结束并通知到发起申请人
+            </p>
+          </div>
+        </t-col>
+        <t-col :span="6">
+          <t-form-item label="报备申请人"> 1111 </t-form-item>
+        </t-col>
+        <t-col :span="6">
+          <t-form-item label="报备申请时间"> 1111 </t-form-item>
+        </t-col>
 
-          <t-col :span="12">
-            <t-form-item class="my-form-item" label="变更类型">
-              <div>
-                <div class="sub-title">
-                  <p :style="{ color: 'gray' }">
-                    1.关键信息及计划变更:项目关键信息里填写的项目关键信息或时间计划内容调整;
-                  </p>
-                  <p :style="{ color: 'gray' }">
-                    2.项目取消:若项目取消,则只需填写变更原因后提交。
-                  </p>
-                </div>
-                <t-radio-group v-model="formData.b">
-                  <t-radio value="1">项目信息及计划变更</t-radio>
-                  <t-radio value="2">项目取消</t-radio>
-                </t-radio-group>
+        <t-col :span="12">
+          <t-form-item label="变更类型">
+            <div>
+              <div class="sub-title">
+                <p :style="{ color: 'gray' }">
+                  1.关键信息及计划变更:项目关键信息里填写的项目关键信息或时间计划内容调整;
+                </p>
+                <p :style="{ color: 'gray' }">
+                  2.项目取消:若项目取消,则只需填写变更原因后提交。
+                </p>
               </div>
-            </t-form-item>
+              <t-radio-group v-model="formData.type">
+                <t-radio
+                  :value="item.value"
+                  :key="item.value"
+                  v-for="item in dictToOptionList(PLAN_CHANGE_TYPE)"
+                  >{{ item.label }}</t-radio
+                >
+              </t-radio-group>
+            </div>
+          </t-form-item>
+        </t-col>
+        <t-col :span="12">
+          <t-form-item label="变更原因" name="reason">
+            <t-input
+              :disabled="readonly"
+              v-model="formData.reason"
+              placeholder="50字以内"
+              :maxlength="50"
+            ></t-input>
+          </t-form-item>
+        </t-col>
+        <t-col :span="12">
+          <t-form-item label="项目信息及计划变更明细">
+            <dynamic-table
+              :columns="columns"
+              ref="dTable"
+              :readonly="readonly"
+            ></dynamic-table>
+          </t-form-item>
+        </t-col>
+        <template v-if="!route.new">
+          <t-col :span="12">
+            <div class="form-group-title next"> 变更处理结果 </div>
           </t-col>
           <t-col :span="12">
-            <t-form-item class="my-form-item" label="变更原因">
-              <t-input v-model="formData.a" placeholder="50字以内"></t-input>
+            <t-form-item label="处理结果">
+              <t-radio-group v-model="formData.projectExchangeApprove">
+                <t-radio value="FINISH">已完成</t-radio>
+                <t-radio value="NOT_UPDATE"
+                  >经沟通,取消变更(原因请填写变更备注)</t-radio
+                >
+                <t-radio value="PARTIAL_UPDATE"
+                  >经沟通,部分变更(详情请填写变更备注)</t-radio
+                >
+              </t-radio-group>
             </t-form-item>
           </t-col>
+
           <t-col :span="12">
-            <t-form-item class="my-form-item" label="项目信息及计划变更明细">
-              <dynamic-table :columns="columns" ref="dTable"></dynamic-table>
+            <t-form-item label="变更备注" name="remark">
+              <t-textarea v-model="formData.remark"></t-textarea>
             </t-form-item>
           </t-col>
-        </t-row>
-        <s-button @cancel="router.back()" @confirm="save"></s-button>
-      </t-form>
-    </div>
+        </template>
+      </t-row>
+      <s-button
+        class="m-t-30px"
+        @cancel="router.back()"
+        confirm-text="保存"
+        @confirm="save"
+      ></s-button>
+    </t-form>
   </div>
 </template>
 <script setup name="PlanChange">
-import { ref, computed } from 'vue';
-import { Input } from 'tdesign-vue-next';
-import { useRouter } from 'vue-router';
+import { ref, computed, reactive } from 'vue';
+import { Input, MessagePlugin } from 'tdesign-vue-next';
+import { useRouter, useRoute } from 'vue-router';
 import dynamicTable from '@/components/common/dynamic-table';
+import { dictToOptionList } from '@/utils/tool';
+import { PLAN_CHANGE_TYPE } from '@/config/constants';
+import { createPlanChange, approvePlanChange } from '@/api/sop';
+import { useAppStore } from '@/store';
+import { omit } from 'lodash';
+const appStore = useAppStore();
 const dTable = ref();
 const router = useRouter();
+const route = useRoute();
+const readonly = computed(() => {
+  return !route.query.new;
+});
 const columns = computed(() => [
   {
-    colKey: 'a',
+    colKey: 'before',
     title: '变更字段(全称)',
     edit: {
       component: Input,
       props: {
         clearable: true,
+        disabled: readonly.value,
       },
       validateTrigger: 'change',
       rules: [{ required: true, message: '不能为空' }],
     },
   },
   {
-    colKey: 'b',
+    colKey: 'after',
     title: '变更后内容',
     edit: {
       component: Input,
       props: {
         clearable: true,
+        disabled: readonly.value,
       },
       validateTrigger: 'change',
       rules: [{ required: true, message: '不能为空' }],
     },
   },
   {
-    colKey: 'c',
+    colKey: 'remark',
     title: '备注',
     edit: {
       component: Input,
       props: {
         clearable: true,
+        disabled: readonly.value,
       },
     },
   },
 ]);
 const formRef = ref(null);
-const formData = ref({
-  a: '',
-  b: '',
+const formData = reactive({
+  serviceId: '',
+  sopNo: '',
+  crmNo: '',
+  type: 'PLAN',
+  reason: '',
+  projectExchangeApprove: 'FINISH',
+  remark: '',
+});
+const rules = computed(() => {
+  return {
+    reason: [
+      {
+        required: true,
+        message: '请填写变更原因',
+        type: 'error',
+        trigger: 'change',
+      },
+    ],
+    remark: [
+      {
+        validator: (val) => {
+          if (!val && formData.projectExchangeApprove !== 'FINISH') {
+            return {
+              result: false,
+              message: '请填写备注',
+            };
+          }
+          return {
+            result: true,
+            type: 'success',
+          };
+        },
+      },
+    ],
+  };
 });
 const save = () => {
-  dTable.value?.validate(() => {});
+  formRef.value.validate().then(async (result) => {
+    if (result === true) {
+      if (!readonly) {
+        dTable.value?.validate(() => {
+          let tableData = dTable.value.exportTableData();
+          createPlanChange({
+            ...omit(formData, ['projectExchangeApprove', 'remark']),
+            contentJson: JSON.stringify(tableData),
+            flowApprove: 'START',
+            flowDeploymentId: appStore.getFlowDetailByType(
+              'PROJECT_EXCHANGE_FLOW'
+            ).flowDeploymentId,
+          });
+        });
+      } else {
+        //流程审批
+        approvePlanChange({
+          flowApprove: 'PASS',
+          projectExchangeApprove: formData.projectExchangeApprove,
+          remark: formData.remark,
+          taskId: route.query.taskId,
+        }).then(() => {
+          MessagePlugin.success('操作成功');
+          router.back();
+        });
+      }
+    }
+  });
 };
 </script>
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+.plan-change {
+  background-color: #fff;
+  padding: 16px;
+}
+</style>

+ 27 - 0
src/views/sop/sop-manage/project-change-report/index.vue

@@ -47,12 +47,14 @@ import { ref, reactive, computed } from 'vue';
 import useFetchTable from '@/hooks/useFetchTable';
 import { dictToOptionList } from '@/utils/tool';
 import { omit } from 'lodash';
+import { useRouter } from 'vue-router';
 import { planChangeList } from '@/api/sop';
 import {
   PLAN_CHANGE_TYPE,
   CUSTOMER_TYPE,
   FLOW_CHECK_STATUS,
 } from '@/config/constants';
+const router = useRouter();
 const selectedRowKeys = ref([]);
 const selectChange = (value, { selectedRowData }) => {
   selectedRowKeys.value = value;
@@ -77,7 +79,32 @@ const columns = [
   { colKey: 'projectExchangeFlowStatusStr', title: '流程状态' },
   { colKey: 'approveUsersName', title: '处理人' },
   { colKey: 'flowTime', title: '处理时间' },
+  {
+    title: '管理',
+    colKey: 'operate',
+    fixed: 'right',
+    width: 400,
+    cell: (h, { row }) => {
+      return (
+        <div class="table-operations">
+          <t-link
+            theme="primary"
+            hover="color"
+            onClick={(e) => {
+              e.stopPropagation();
+              handleApply(row);
+            }}
+          >
+            处理申请
+          </t-link>
+        </div>
+      );
+    },
+  },
 ];
+const handleApply = (row) => {
+  router.push({ name: 'PlanChange', query: { taskId: row.taskId } });
+};
 const fields = ref([
   {
     prop: 'serviceId',

+ 7 - 6
src/views/sop/sop-monitor/delay-warning/index.vue

@@ -81,17 +81,18 @@ const closeHandler = (row) => {
   });
 };
 const columns = [
-  { colKey: 'service', title: '服务单元' },
+  { colKey: 'service', title: '服务单元', width: 150 },
   // { colKey: 'b', title: '预警流水号' },
-  { colKey: 'warnTime', title: '预警时间' },
-  { colKey: 'sopNo', title: 'SOP流水号' },
-  { colKey: 'userName', title: '节点负责人' },
-  { colKey: 'custom', title: '客户名称' },
-  { colKey: 'crmNo', title: '项目单号' },
+  { colKey: 'warnTime', title: '预警时间', width: 150 },
+  { colKey: 'sopNo', title: 'SOP流水号', width: 160 },
+  { colKey: 'userName', title: '节点负责人', width: 120 },
+  { colKey: 'custom', title: '客户名称', width: 120 },
+  { colKey: 'crmNo', title: '项目单号', width: 140 },
   { colKey: 'crmName', title: '项目名称' },
   {
     colKey: 'type',
     title: '预警类型',
+    width: 150,
     cell: (h, { row }) => {
       return <span>{WARN_TYPE[row.type] || row.type}</span>;
     },