Parcourir la source

Merge remote-tracking branch 'origin/fix-wyf' into dev-bxy

ai0187 il y a 1 mois
Parent
commit
e40a8e4c4d

+ 7 - 2
src/api/emergency-supplier/index.ts

@@ -128,11 +128,16 @@ export const saveInventoryTask = (taskName: string, endTime: string) => {
 /**
  * 物资报废
  */
-export const discardEmergencySupply = (supplyId: number, quantity: number) => {
+export const discardEmergencySupply = (data: {
+  supplyId: number;
+  quantity: number;
+  scrapReason: string;
+  scrapImage: string;
+}) => {
   return http.request({
     url: '/emergencySupplies/scrapEmergencySupplies',
     method: 'post',
-    data: { supplyId, quantity },
+    data,
   });
 };
 /**

+ 4 - 0
src/types/emergency-supplier/index.ts

@@ -57,6 +57,8 @@ export interface ExportDiscardForm {
 }
 export interface DiscardSuppliesForm {
   quantity: number | null;
+  scrapReason: string;
+  scrapImage: string;
 }
 
 export interface AddEmergencyItemForm
@@ -93,6 +95,8 @@ export interface ChangeRecordListRes {
   afterQuantity: number;
   operatorName: string;
   updatedAt: string;
+  scrapReason: string;
+  scrapImage?: string;
 }
 
 export interface InventoryTaskListRes {

+ 18 - 3
src/views/emergency/emergency-drill/PageDrillPlanList.vue

@@ -49,7 +49,17 @@
                 text="演练执行"
                 @click="handleToExecute(scope.row.id)"
               />
-              <ActionButton v-else-if="scope.row.status < 7" text="演练记录" @click="handleToRecord(scope.row)" />
+              <ActionButton
+                v-else-if="scope.row.status < EMERGENCY_DRILL_STATUS.COMPLETE"
+                text="演练记录"
+                @click="handleToRecord(scope.row)"
+              />
+              <ActionButton
+                class="has-problem"
+                v-else-if="scope.row.status === EMERGENCY_DRILL_STATUS.HAS_PROBLEM"
+                text="演练问题"
+                @click="handleViewDrillPlan(scope.row.id, 'records')"
+              />
               <ActionButton
                 text="删除"
                 :popconfirm="{
@@ -78,7 +88,7 @@
   import { DRILL_PLAN_LIST_SEARCH_CONFIG } from './configs/plan/search';
   import { TABLE_OPTIONS, DRILL_PLAN_LIST_TABLE_COLUMNS } from './configs/plan/table';
   import { DrillPlanListSearch, DrillPlanItem } from './types';
-  import { EMERGENCY_DRILL_STATUS_DICT } from './constants';
+  import { EMERGENCY_DRILL_STATUS, EMERGENCY_DRILL_STATUS_DICT } from './constants';
   import { useEmergencyDrillHook } from './hook';
   import { QueryPageRequest } from '@/types/basic-query';
 
@@ -165,11 +175,12 @@
     });
   }
 
-  function handleViewDrillPlan(id: number) {
+  function handleViewDrillPlan(id: number, tab: string = 'activities') {
     router.push({
       name: 'emergency-drill-plan-view',
       query: {
         id: id,
+        tab: tab,
       },
     });
   }
@@ -200,4 +211,8 @@
   @use '@/styles/page-details-layout.scss' as *;
   @use '@/styles/page-main-layout.scss' as *;
   @use '@/styles/basic-table-action.scss' as *;
+
+  .has-problem {
+    color: #ec2828;
+  }
 </style>

+ 2 - 3
src/views/emergency/emergency-drill/PageDrillPlanView.vue

@@ -28,17 +28,16 @@
 <script setup lang="ts">
   import { ref, computed, defineAsyncComponent } from 'vue';
   import { ElMessage } from 'element-plus';
-  import { useRoute, useRouter } from 'vue-router';
+  import { useRoute } from 'vue-router';
   import UploadLoading from '@/components/UploadLoading.vue';
   import { EMERGENCY_DRILL_DETAIL_SUBPAGE } from './constants';
   import { exportEmergencyDrillRecord } from '@/api/emergency-drill/emergency-drill';
   import { downloadFile } from '@/views/disaster/utils/download';
 
   const formLoading = ref(false);
-  const activeName = ref(EMERGENCY_DRILL_DETAIL_SUBPAGE[0].value);
-  const router = useRouter();
   const route = useRoute();
   const id = route.query.id;
+  const activeName = ref(route.query.tab || EMERGENCY_DRILL_DETAIL_SUBPAGE[0].value);
 
   const dynamicComponent = computed(() => {
     switch (activeName.value) {

+ 1 - 0
src/views/emergency/emergency-drill/constants.ts

@@ -7,6 +7,7 @@ export const EMERGENCY_DRILL_STATUS = {
   WAIT_CHECK: 5, // 记录待审批
   RETURN: 6, // 已退回
   COMPLETE: 7, // 已完成
+  HAS_PROBLEM: 8, // 已完成且有问题分析
 };
 
 export const EMERGENCY_DRILL_STATUS_DICT = {

+ 11 - 0
src/views/emergency/emergency-plan/src/components/AddManagementDetail.vue

@@ -29,6 +29,16 @@
           @change="handleChangeDept"
         />
       </template>
+      <template #professionalTestSite>
+        <el-select v-model="ruleFormData.professionalTestSite" placeholder="请选择作业场所">
+          <el-option
+            v-for="item in PROFESSIONAL_TEST_SITE_DICE"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+      </template>
       <template #approvalTemplateId>
         <el-select
           v-model="ruleFormData.approvalTemplateId"
@@ -56,6 +66,7 @@
   import type { AddEmergencyPlanForm } from '@/types/emergency-plan';
   import type { FileItem } from '@/components/UploadFiles/types.ts';
   import { PLAN_MANAGEMENT_FORM_CONFIG, PLAN_MANAGEMENT_FORM_DATA, PLAN_MANAGEMENT_FORM_RULES } from '../config';
+  import { PROFESSIONAL_TEST_SITE_DICE } from '../constant';
 
   const formRef = ref();
   const cascaderRef = ref();

+ 3 - 6
src/views/emergency/emergency-plan/src/config/form.ts

@@ -35,12 +35,9 @@ export const PLAN_MANAGEMENT_FORM_CONFIG: FormConfig[] = [
     slot: 'deptId',
   },
   {
-    label: '试验专业场所:',
+    label: '业场所:',
     prop: 'professionalTestSite',
-    component: 'ElInput',
-    componentProps: {
-      placeholder: '请输入试验专业场所',
-    },
+    slot: 'professionalTestSite',
   },
   {
     label: '审批流程:',
@@ -88,7 +85,7 @@ export const PLAN_MANAGEMENT_FORM_CONFIG_EDIT: FormConfig[] = [
     },
   },
   {
-    label: '试验专业场所:',
+    label: '业场所:',
     prop: 'professionalTestSite',
     component: 'ElInput',
     componentProps: {

+ 2 - 2
src/views/emergency/emergency-plan/src/config/search.ts

@@ -21,11 +21,11 @@ export const EMERGENCY_PLAN_MANAGEMENT_SEARCH_CONFIG: SearchConfig[] = [
     slot: 'eventType',
   },
   {
-    label: '试验专业场所:',
+    label: '业场所:',
     prop: 'professionalTestSite',
     component: 'ElInput',
     componentProps: {
-      placeholder: '请输入试验专业场所',
+      placeholder: '请输入业场所',
     },
   },
   {

+ 1 - 1
src/views/emergency/emergency-plan/src/config/table.ts

@@ -65,7 +65,7 @@ export const EMERGENCY_PLAN_MANAGEMENT_TABLE_COLUMNS: TableColumnProps[] = [
   BASIC_TABLE_COLUMNS.ENENT_TYPE,
   BASIC_TABLE_COLUMNS.DEPT_NAME,
   {
-    label: '试验专业场所',
+    label: '业场所',
     prop: 'professionalTestSite',
     minWidth: '160px',
   },

+ 37 - 2
src/views/emergency/emergency-plan/src/constant.ts

@@ -41,7 +41,7 @@ export const APPROVAL_TYPE_MAP = {
   [APPROVAL_TYPE.ORDINARY_SIGN]: '或签',
 };
 
-export enum APPROVER_TYPE{
+export enum APPROVER_TYPE {
   FIX = 0,
   CUSTOM,
 }
@@ -82,4 +82,39 @@ export const APPROVAL_STATUS_OPTIONS = [
     label: APPROVAL_STATUS_MAP[APPROVAL_STATUS.OHTER],
     value: APPROVAL_STATUS.OHTER,
   },
-];
+];
+
+export const PROFESSIONAL_TEST_SITE_DICE = [
+  {
+    label: '仓储',
+    value: '仓储',
+  },
+  {
+    label: '住宿',
+    value: '住宿',
+  },
+  {
+    label: '办公',
+    value: '办公',
+  },
+  {
+    label: '服务',
+    value: '服务',
+  },
+  {
+    label: '试验',
+    value: '试验',
+  },
+  {
+    label: '文体活动',
+    value: '文体活动',
+  },
+  {
+    label: '施工',
+    value: '施工',
+  },
+  {
+    label: '其他',
+    value: '其他',
+  },
+];

+ 56 - 0
src/views/emergency/emergency-supplies/src/components/ChangeRecord.vue

@@ -8,7 +8,33 @@
         <span v-if="scope.row.changeQuantity > 0">+</span>
         <span>{{ scope.row.changeQuantity }}</span>
       </template>
+      <template #action="scope">
+        <ActionButton text="报废详情" @click="handleViewDetail(scope.row)" />
+      </template>
     </BasicTable>
+    <el-drawer title="报废详情" v-model="drawerVisible" size="40%" :close-on-click-modal="true" :show-close="true">
+      <div class="drawer-body">
+        <div class="drawer-item">
+          <span class="drawer-item-label">报废理由:</span>
+          <span>{{ record?.scrapReason }}</span>
+        </div>
+        <div v-if="uploadedImages.length > 0" class="drawer-item">
+          <span class="drawer-item-label">报废照片:</span>
+          <div class="image-container">
+            <div v-for="(image, index) in uploadedImages" :key="image" class="image-preview">
+              <el-image
+                :src="image"
+                style="width: 100px; height: 100px"
+                :preview-src-list="uploadedImages"
+                show-progress
+                :initial-index="index"
+                fit="cover"
+              />
+            </div>
+          </div>
+        </div>
+      </div>
+    </el-drawer>
   </div>
 </template>
 
@@ -20,6 +46,8 @@
   import { ChangeRecordListRes } from '@/types/emergency-supplier';
   import { getSupplyChangeRecord } from '@/api/emergency-supplier';
   import { CHANGE_TYPE_MAP } from '../constant';
+  import ActionButton from '@/components/ActionButton.vue';
+  import { unformatImage } from '@/components/UploadImages/utils';
 
   const { tableConfig } = useTableConfig(CHANGE_RECORD_TABLE_COLUMNS, CHANGE_RECORD_TABLE_OPTIONS, false);
   const props = defineProps<{
@@ -32,6 +60,17 @@
     tableData.value = res;
     tableConfig.loading = false;
   };
+
+  const uploadedImages = ref<string[]>([]);
+
+  const drawerVisible = ref(false);
+  const record = ref<ChangeRecordListRes>();
+  const handleViewDetail = (row: ChangeRecordListRes) => {
+    record.value = row;
+    uploadedImages.value = unformatImage(row.scrapImage) || [];
+
+    drawerVisible.value = true;
+  };
   onMounted(() => {
     getChangeRecord();
   });
@@ -39,4 +78,21 @@
 
 <style lang="scss" scoped>
   @use '../styles/info.scss' as *;
+  .drawer-item {
+    margin-bottom: 20px;
+  }
+  .drawer-item-label {
+    color: rgba(0, 0, 0, 0.88);
+  }
+  .image-container {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 5px;
+    width: 100%;
+  }
+  .image-preview {
+    width: 100px;
+    height: 100px;
+    border-radius: 4px;
+  }
 </style>

+ 35 - 9
src/views/emergency/emergency-supplies/src/components/DiscardSupplies.vue

@@ -11,9 +11,16 @@
         <template #quantity>
           <el-input v-model.number="ruleFormData.quantity" placeholder="请输入报废数量" type="number" min="1" step="1">
           </el-input>
+          <div>最多可报废数量:{{ supply?.currentQuantity }}</div>
+        </template>
+        <template #scrapReason>
+          <el-input v-model="ruleFormData.scrapReason" placeholder="请输入报废理由" type="textarea" rows="3">
+          </el-input>
+        </template>
+        <template #scrapImage>
+          <UploadImages :maxCount="9" ref="uploadImagesRef" @uploadSuccess="handleUploadSuccess" />
         </template>
       </BasicForm>
-      <div class="discard-note">最多可报废数量:{{ supply?.currentQuantity }}</div>
     </template>
     <template #footer>
       <el-button type="primary" @click="handleSumbit">提交</el-button>
@@ -27,10 +34,17 @@
   import { ElMessage } from 'element-plus';
   import BasicDialog from '@/components/BasicDialog.vue';
   import BasicForm from '@/components/BasicForm.vue';
+  import UploadImages from '@/components/UploadImages/UploadImages.vue';
   import { useFormConfigHook } from '@/hooks/useFormConfigHook';
   import { DiscardSuppliesForm, EmergencySupplyListResponse } from '@/types/emergency-supplier';
   import { discardEmergencySupply } from '@/api/emergency-supplier';
-  import { SUPPLIES_DISCARD_FROM_CONFIG, SUPPLIES_DISCARD_FROM_DATA, SUPPLIES_DISCARD_FROM_RULES } from '../config';
+  import {
+    SUPPLIES_DISCARD_FROM_CONFIG,
+    SUPPLIES_DISCARD_FROM_DATA,
+    SUPPLIES_DISCARD_FROM_RULES,
+  } from '../config/form';
+  import { formatImageList } from '@/components/UploadImages/utils';
+  import type { ImageItem } from '@/types/disaster-control';
 
   const emit = defineEmits<{
     (e: 'refreshList'): void;
@@ -38,6 +52,7 @@
 
   const basicDialogRef = ref<InstanceType<typeof BasicDialog>>();
   const basicFormRef = ref<InstanceType<typeof BasicForm>>();
+  const uploadImagesRef = ref<InstanceType<typeof UploadImages>>();
   const { ruleFormConfig, ruleFormData, formRules } = useFormConfigHook<DiscardSuppliesForm>(
     SUPPLIES_DISCARD_FROM_CONFIG,
     SUPPLIES_DISCARD_FROM_DATA,
@@ -49,6 +64,7 @@
   const openDialog = (item: EmergencySupplyListResponse) => {
     supply.value = item;
     basicDialogRef.value?.openDialog();
+    uploadImagesRef.value?.removeAllImages();
     (formRules.quantity as Array<any>).push({
       validator: (_rule, value, callback) => {
         if (!supply.value) {
@@ -68,12 +84,28 @@
       trigger: 'blur',
     });
   };
+
+  const scrapImage = ref<ImageItem[]>([]);
+  const handleUploadSuccess = (files: ImageItem[]) => {
+    scrapImage.value = files;
+  };
+
   const handleSumbit = async () => {
     const validate = await basicFormRef.value?.validateForm();
     if (!validate) return;
     if (!supply.value) return;
     try {
-      await discardEmergencySupply(supply.value.id, ruleFormData.quantity!);
+      const scrapImageString = await formatImageList(scrapImage.value);
+      if (scrapImageString) {
+        ruleFormData.scrapImage = JSON.stringify(scrapImageString as string[]);
+      }
+      const query = {
+        supplyId: supply.value.id,
+        quantity: ruleFormData.quantity as number,
+        scrapReason: ruleFormData.scrapReason,
+        scrapImage: ruleFormData.scrapImage,
+      };
+      await discardEmergencySupply(query);
       ElMessage.success('物资报废成功');
       emit('refreshList');
       basicDialogRef.value?.closeDialog();
@@ -88,9 +120,3 @@
     openDialog,
   });
 </script>
-
-<style scoped lang="scss">
-  .discard-note {
-    padding-left: 80px;
-  }
-</style>

+ 13 - 0
src/views/emergency/emergency-supplies/src/config/form.ts

@@ -317,16 +317,29 @@ export const SUPPLIES_DISCARD_FROM_CONFIG: FormConfig[] = [
     prop: 'quantity',
     slot: 'quantity',
   },
+  {
+    label: '报废理由:',
+    prop: 'scrapReason',
+    slot: 'scrapReason',
+  },
+  {
+    label: '报废照片:',
+    prop: 'scrapImage',
+    slot: 'scrapImage',
+  },
 ];
 
 // 物资报废单数据
 export const SUPPLIES_DISCARD_FROM_DATA = {
   quantity: null,
+  scrapReason: '',
+  scrapImage: '',
 };
 
 // 物资报废单规则
 export const SUPPLIES_DISCARD_FROM_RULES = {
   quantity: [{ required: true, message: '请输入报废数量', trigger: 'blur' }],
+  scrapReason: [{ required: true, message: '请输入报废理由', trigger: 'blur' }],
 };
 
 // 物资申领计划表单配置

+ 8 - 0
src/views/emergency/emergency-supplies/src/config/table.ts

@@ -150,6 +150,14 @@ export const CHANGE_RECORD_TABLE_COLUMNS: TableColumnProps[] = [
     label: '变更时间',
     prop: 'updatedAt',
   },
+  {
+    label: '操作',
+    prop: 'action',
+    slot: 'action',
+    align: 'center',
+    fixed: 'right',
+    width: '120px',
+  },
 ];
 
 export const CHANGE_RECORD_TABLE_OPTIONS = {