Просмотр исходного кода

完成应急物资详情页面

chauncey 9 месяцев назад
Родитель
Сommit
20a744513b

+ 1 - 1
src/api/emergency-supplier/index.ts

@@ -1,4 +1,4 @@
-import { http } from '@/utils/http/axios/mock';
+import { http } from '@/utils/http/axios';
 import type { QueryPageRequest, QueryPageResponse } from '@/types/basic-query';
 import type { EmergencySupplyListQuery, EmergencySupplyListResponse } from '@/types/emergency-supplier';
 

+ 11 - 0
src/api/system/person-group.ts

@@ -9,6 +9,7 @@ import {
   QueryAvailablePersonPageRes,
   UserGroupOption,
   PersonGroupItem,
+  QueryUserInfoByUserNameRes,
 } from '@/types/person-group/type';
 
 /**
@@ -115,3 +116,13 @@ export const queryUserInfoByIds = (userIds: number[]) => {
     method: 'get',
   });
 };
+
+/**
+ * 根据用户名查询用户列表
+ */
+export const queryUserInfoByUserName = (username: string) => {
+  return http.request<QueryUserInfoByUserNameRes[]>({
+    url: `/admin/user/queryUserListByUsername?username=${username}`,
+    method: 'post',
+  });
+};

+ 3 - 0
src/constant/dict.ts

@@ -6,4 +6,7 @@ export const DICT_CODE = {
   SAFETY_LEVEL: 'disaster_safety_impact',
   EMERGENCY_EVENT: 'emergency_event',
   EMERGENCY_SUPPLY: 'emergency_supply',
+  PARK: 'emergency_park',
+  LOCATION_ZJ: 'zhangjiang_park',
+  LOCATION_DC: 'dachang_park',
 };

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

@@ -34,3 +34,13 @@ export interface InventoryTaskForm {
   taskName: string;
   endTime: string;
 }
+
+export interface AddEmergencyItemForm
+  extends Omit<
+    EmergencySupplyListResponse,
+    'id' | 'keeperName' | 'status' | 'supplementQuantity' | 'requiredQuantity' | 'currentQuantity'
+  > {
+  requiredQuantity: number | null;
+  currentQuantity: number | null;
+  keeperId: number | null;
+}

+ 12 - 0
src/types/person-group/type.ts

@@ -120,3 +120,15 @@ export interface QueryUserFirstLevelTreeRes {
   userList: PersonGroupItem[];
   children: QueryUserFirstLevelTreeRes[];
 }
+
+/**
+ * 根据姓名查询用户信息返回结果
+ */
+export interface QueryUserInfoByUserNameRes {
+  id: number;
+  username: string;
+  realname: string;
+  mobile: string;
+  deptName: string;
+  jobName: string;
+}

+ 23 - 0
src/views/emergency/emergency-supplies/PageEmergencyList.vue

@@ -50,6 +50,16 @@
                 />
               </el-select>
             </template>
+            <template #park>
+              <el-select v-model="searchData.park" placeholder="请选择园区">
+                <el-option
+                  v-for="item in parkDice"
+                  :key="item.itemCode"
+                  :label="item.itemValue"
+                  :value="item.itemCode"
+                />
+              </el-select>
+            </template>
           </BasicSearch>
         </header>
         <BasicTable :tableData="tableData" :tableConfig="tableConfig">
@@ -59,6 +69,12 @@
           <template #supplyType="scope">
             <span>{{ getEmergencySupply(scope.row.supplyType) }}</span>
           </template>
+          <template #park="scope">
+            <span>{{ getPark(scope.row.park) }}</span>
+          </template>
+          <template #location="scope">
+            <span>{{ getLocation(scope.row.location) }}</span>
+          </template>
           <template #status="scope">
             <span :style="{ color: scope.row.status === EMERGENCY_SUPPLY_STATUS.DAMAGED ? 'red' : '' }">
               {{ getEmergencyStatus(scope.row.status) }}
@@ -119,6 +135,11 @@
     getEmergencySupplyDict,
     getEmergencySupply,
     getEmergencyStatus,
+    parkDice,
+    getParkDict,
+    getPark,
+    getLocationDict,
+    getLocation
   } = useEmergencySuppliesHook();
   const { permissions } = useUserInfoHook();
   const { tableConfig, pagination } = useTableConfig(SUPPLY_LIST_TABLE_COLUMNS, SUPPLY_LIST_TABLE_OPTIONS);
@@ -189,6 +210,8 @@
   onMounted(() => {
     getEmergencyEventDict();
     getEmergencySupplyDict();
+    getParkDict();
+    getLocationDict('all');
     getTableData();
     emergencySupplyPermissions.value = Boolean(
       permissions.find((item: { code: string }) => item.code === EMERGENCY_PERMISSIONS.SUPPLY_LIST),

+ 10 - 3
src/views/emergency/emergency-supplies/PageEmergencyListInfo.vue

@@ -1,19 +1,25 @@
 <template>
   <div class="safety-platform-container">
     <div class="safety-platform-container__header">
+      <BreadcrumbBack />
       <div class="breadcrumb-title">{{ headerTitle }}</div>
     </div>
-    <div class="safety-platform-container__main">
+    <main class="safety-platform-container__main">
       <component :is="dynamicComponent" />
-    </div>
+    </main>
+    <footer class="safety-platform-container__footer">
+      <el-button @click="router.back()">取消</el-button>
+      <el-button type="primary">提交</el-button>
+    </footer>
   </div>
 </template>
 
 <script setup lang="ts">
-  import { useRoute } from 'vue-router';
+  import { useRoute, useRouter } from 'vue-router';
   import { computed, defineAsyncComponent } from 'vue';
 
   const route = useRoute();
+  const router = useRouter();
   const type = String(route.query.type);
   const headerTitle = computed(() => {
     const title = '应急物资';
@@ -32,4 +38,5 @@
 
 <style scoped lang="scss">
   @use '@/styles/page-details-layout.scss' as *;
+  @use './src/styles/info-common.scss' as *;
 </style>

+ 126 - 3
src/views/emergency/emergency-supplies/src/components/AddEmergencyItem.vue

@@ -1,11 +1,134 @@
 <template>
-  <div>this is add emergency item</div>
+  <div class="emergency-supply-container">
+    <BasicForm ref="formRef" :formData="ruleFormData" :formRules="customFormRules" :formConfig="ruleFormConfig">
+      <template #emergencyType>
+        <el-select v-model="ruleFormData.emergencyType" placeholder="请选择应急类型" filterable>
+          <el-option
+            v-for="item in emergencyEventDice"
+            :key="item.itemCode"
+            :label="item.itemValue"
+            :value="item.itemCode"
+          />
+        </el-select>
+      </template>
+      <template #supplyType>
+        <el-select v-model="ruleFormData.supplyType" placeholder="请选择物资类型" filterable>
+          <el-option
+            v-for="item in emergencySupplyDice"
+            :key="item.itemCode"
+            :label="item.itemValue"
+            :value="item.itemCode"
+          />
+        </el-select>
+      </template>
+      <template #park>
+        <el-select v-model="ruleFormData.park" placeholder="请选择园区" filterable @change="handleChangePark">
+          <el-option v-for="item in parkDice" :key="item.itemCode" :label="item.itemValue" :value="item.itemCode" />
+        </el-select>
+      </template>
+      <template #location>
+        <el-select v-model="ruleFormData.location" placeholder="请输入地点" :disabled="Boolean(!ruleFormData.park)">
+          <el-option v-for="item in locationDice" :key="item.itemCode" :label="item.itemValue" :value="item.itemCode" />
+        </el-select>
+      </template>
+      <template #keeperId>
+        <el-select
+          v-model="ruleFormData.keeperId"
+          placeholder="请输入保管人姓名"
+          filterable
+          remote
+          :remote-method="remoteMethod"
+        >
+          <el-option
+            v-for="item in userOptions"
+            :key="item.id"
+            :label="`${item.realname}(${item.username})`"
+            :value="item.id"
+          />
+        </el-select>
+      </template>
+    </BasicForm>
+  </div>
 </template>
 
 <script setup lang="ts">
+  import { ref, onMounted, computed } from 'vue';
+  import BasicForm from '@/components/BasicForm.vue';
+  import { useFormConfigHook } from '@/hooks/useFormConfigHook';
+  import { useEmergencySuppliesHook } from '../hook';
+  import type { QueryUserInfoByUserNameRes } from '@/types/person-group/type';
+  import type { AddEmergencyItemForm } from '@/types/emergency-supplier';
+  import { queryUserInfoByUserName } from '@/api/system/person-group';
+  import { ADD_EMERGENCY_ITEM_FROM_CONFIG, EMERGENCY_ITEM_DATA, ADD_EMERGENCY_ITEM_RULES } from '../config';
+  import type { FormRules } from 'element-plus';
 
+  const formRef = ref();
+  const { ruleFormConfig, ruleFormData, formRules, cloneRuleFormData, beforeRouteLeave } =
+    useFormConfigHook<AddEmergencyItemForm>(
+      ADD_EMERGENCY_ITEM_FROM_CONFIG,
+      EMERGENCY_ITEM_DATA,
+      ADD_EMERGENCY_ITEM_RULES,
+    );
+  
+  // 验证当前数量不大于应备数量
+  const validateQuantity = (rule: any, value: any, callback: any) => {
+    if (value === '' || value === null || value === undefined) {
+      callback();
+      return;
+    }
+    
+    const currentQuantity = Number(value);
+    const requiredQuantity = Number(ruleFormData.requiredQuantity);
+    
+    if (currentQuantity > requiredQuantity) {
+      callback(new Error('当前数量不能大于应备数量'));
+    } else {
+      callback();
+    }
+  };
+  
+  // 扩展原有的表单规则,添加自定义验证
+  const customFormRules = computed<FormRules>(() => {
+    return {
+      ...formRules,
+      currentQuantity: [
+        { required: true, message: '请输入当前数量', trigger: 'blur' },
+        { validator: validateQuantity, trigger: 'blur' }
+      ]
+    };
+  });
+
+  const {
+    emergencyEventDice,
+    getEmergencyEventDict,
+    emergencySupplyDice,
+    getEmergencySupplyDict,
+    parkDice,
+    getParkDict,
+    locationDice,
+    getLocationDict,
+  } = useEmergencySuppliesHook();
+  const handleChangePark = (type: 'zhangjiang_park' | 'dachang_park') => {
+    getLocationDict(type);
+  };
+  const userOptions = ref<QueryUserInfoByUserNameRes[]>([]);
+  const loading = ref(false);
+  const remoteMethod = async (query: string) => {
+    if (!query) {
+      userOptions.value = [];
+      return;
+    }
+    loading.value = true;
+    userOptions.value = await queryUserInfoByUserName(query);
+    loading.value = false;
+  };
+  onMounted(() => {
+    getEmergencyEventDict();
+    getEmergencySupplyDict();
+    getParkDict();
+  });
 </script>
 
 <style lang="scss" scoped>
-
-</style>
+  @use '../styles/info.scss' as *;
+</style>

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

@@ -43,3 +43,116 @@ export const INVENTORY_TASK_FROM_RULES = {
     { validator: validateFormTime, trigger: 'change' },
   ],
 };
+
+export const ADD_EMERGENCY_ITEM_FROM_CONFIG: FormConfig[] = [
+  {
+    label: '应急类型:',
+    prop: 'emergencyType',
+    slot: 'emergencyType',
+  },
+  {
+    label: '物资类型:',
+    prop: 'supplyType',
+    slot: 'supplyType',
+  },
+  {
+    label: '应急物资名称:',
+    prop: 'supplyName',
+    component: 'ElInput',
+    componentProps: {
+      placeholder: '请输入应急物资名称',
+    },
+  },
+  {
+    label: '应备数量:',
+    prop: 'requiredQuantity',
+    component: 'ElInput',
+    componentProps: {
+      placeholder: '请输入应备数量',
+      type: 'number',
+    },
+  },
+  {
+    label: '当前数量:',
+    prop: 'currentQuantity',
+    component: 'ElInput',
+    componentProps: {
+      placeholder: '请输入当前数量',
+      type: 'number',
+    },
+  },
+  {
+    label: '数量单位:',
+    prop: 'unit',
+    component: 'ElInput',
+    componentProps: {
+      placeholder: '请输入数量单位',
+    },
+  },
+  {
+    label: '园区:',
+    prop: 'park',
+    slot: 'park',
+  },
+  {
+    label: '地点:',
+    prop: 'location',
+    slot: 'location',
+  },
+  {
+    label: '保管人:',
+    prop: 'keeperId',
+    slot: 'keeperId',
+  },
+  {
+    label: '使用期限:',
+    prop: 'expirationDate',
+    component: 'ElDatePicker',
+    componentProps: {
+      placeholder: '请选择使用期限',
+      type: 'date',
+      format: 'YYYY-MM-DD',
+      valueFormat: 'YYYY-MM-DD',
+    },
+  },
+  {
+    label: '备注:',
+    prop: 'remark',
+    component: 'ElInput',
+    componentProps: {
+      placeholder: '请输入备注',
+      type: 'textarea',
+      rows: 5,
+    },
+  },
+];
+
+// 盘点任务表单数据
+export const EMERGENCY_ITEM_DATA = {
+  emergencyType: '',
+  supplyType: '',
+  supplyName: '',
+  requiredQuantity: null,
+  currentQuantity: null,
+  unit: '',
+  park: '',
+  location: '',
+  keeperId: null,
+  expirationDate: '',
+  remark: '',
+};
+
+export const ADD_EMERGENCY_ITEM_RULES = {
+  emergencyType: [{ required: true, message: '请选择应急类型', trigger: 'blur' }],
+  supplyType: [{ required: true, message: '请选择物资类型', trigger: 'blur' }],
+  supplyName: [{ required: true, message: '请输入应急物资名称', trigger: 'blur' }],
+  requiredQuantity: [{ required: true, message: '请输入应备数量', trigger: 'blur' }],
+  currentQuantity: [
+    { required: true, message: '请输入当前数量', trigger: 'blur' }
+    // 验证器已移至组件中实现
+  ],
+  park: [{ required: true, message: '请选择园区', trigger: 'blur' }],
+  location: [{ required: true, message: '请选择地点', trigger: 'blur' }],
+  keeperId: [{ required: true, message: '请选择保管人', trigger: 'blur' }],
+  expirationDate: [{ validator: validateFormTime, trigger: 'blur' }],
+};

+ 11 - 1
src/views/emergency/emergency-supplies/src/config/index.ts

@@ -5,7 +5,14 @@ import {
   SUPPLY_LIST_TABLE_MAX_HEIGHT_DEFAULT,
   SUPPLY_LIST_TABLE_MAX_HEIGHT_PERMISSION,
 } from './table';
-import { INVENTORY_TASK_FROM_CONFIG, INVENTORY_TASK_FROM_DATA, INVENTORY_TASK_FROM_RULES } from './form';
+import {
+  INVENTORY_TASK_FROM_CONFIG,
+  INVENTORY_TASK_FROM_DATA,
+  INVENTORY_TASK_FROM_RULES,
+  ADD_EMERGENCY_ITEM_FROM_CONFIG,
+  EMERGENCY_ITEM_DATA,
+  ADD_EMERGENCY_ITEM_RULES,
+} from './form';
 
 export {
   SUPPLY_LIST_SEARCH_CONFIG,
@@ -16,4 +23,7 @@ export {
   INVENTORY_TASK_FROM_CONFIG,
   INVENTORY_TASK_FROM_DATA,
   INVENTORY_TASK_FROM_RULES,
+  ADD_EMERGENCY_ITEM_FROM_CONFIG,
+  EMERGENCY_ITEM_DATA,
+  ADD_EMERGENCY_ITEM_RULES,
 };

+ 2 - 6
src/views/emergency/emergency-supplies/src/config/search.ts

@@ -1,5 +1,5 @@
 import type { SearchConfig } from '@/types/basic-search';
-import { LOCATION_OPTIONS, EMERGENCY_SUPPLY_STATUS_OPTIONS } from '../constant';
+import { EMERGENCY_SUPPLY_STATUS_OPTIONS } from '../constant';
 
 export const SUPPLY_LIST_SEARCH_CONFIG: SearchConfig[] = [
   {
@@ -23,11 +23,7 @@ export const SUPPLY_LIST_SEARCH_CONFIG: SearchConfig[] = [
   {
     label: '园区:',
     prop: 'park',
-    component: 'ElSelect',
-    selectOptions: LOCATION_OPTIONS,
-    componentProps: {
-      placeholder: '请选择园区',
-    },
+    slot: 'park',
   },
   {
     label: '地点:',

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

@@ -82,11 +82,13 @@ export const SUPPLY_LIST_TABLE_COLUMNS: TableColumnProps[] = [
   {
     label: '园区',
     prop: 'park',
+    slot: 'park',
     minWidth: '140px',
   },
   {
     label: '地点',
     prop: 'location',
+    slot:'location',
     minWidth: '120px',
   },
   {

+ 0 - 11
src/views/emergency/emergency-supplies/src/constant/index.ts

@@ -1,17 +1,6 @@
 /**
  * 应急物资常量
  */
-export const LOCATION_OPTIONS = [
-  {
-    label: '张江',
-    value: 'zhangjiang',
-  },
-  {
-    label: '大场',
-    value: 'dachang',
-  },
-];
-
 export enum EMERGENCY_SUPPLY_STATUS {
   INTACT = 0,
   DAMAGED,

+ 31 - 0
src/views/emergency/emergency-supplies/src/hook.ts

@@ -28,6 +28,31 @@ export const useEmergencySuppliesHook = () => {
   const getEmergencyStatus = (status: number) => {
     return EMERGENCY_SUPPLY_STATUS_OPTIONS.find((item) => item.value === status)?.label;
   };
+  // 园区
+  const parkDice = ref<SysDictDataDetail[]>([]);
+  const getParkDict = async () => {
+    const parkRes = await queryDictTypeDetail(DICT_CODE.PARK);
+    parkDice.value = parkRes.sysDictDataList;
+  };
+  const getPark = (park: string) => {
+    return parkDice.value.find((item) => item.itemCode === park)?.itemValue;
+  };
+  // 地点
+  const locationDice = ref<SysDictDataDetail[]>([]);
+  const getLocationDict = async (type: 'zhangjiang_park' | 'dachang_park' | 'all') => {
+    const locationZJRes = await queryDictTypeDetail(DICT_CODE.LOCATION_ZJ);
+    const locationDCRes = await queryDictTypeDetail(DICT_CODE.LOCATION_DC);
+    if (type === 'all') {
+      locationDice.value = [...locationZJRes.sysDictDataList, ...locationDCRes.sysDictDataList];
+    } else if (type === 'zhangjiang_park') {
+      locationDice.value = locationZJRes.sysDictDataList;
+    } else if (type === 'dachang_park') {
+      locationDice.value = locationDCRes.sysDictDataList;
+    }
+  };
+  const getLocation = (location: string) => {
+    return locationDice.value.find((item) => item.itemCode === location)?.itemValue;
+  };
   return {
     emergencyEventDice,
     getEmergencyEventDict,
@@ -36,5 +61,11 @@ export const useEmergencySuppliesHook = () => {
     getEmergencySupplyDict,
     getEmergencySupply,
     getEmergencyStatus,
+    parkDice,
+    getParkDict,
+    getPark,
+    locationDice,
+    getLocationDict,
+    getLocation
   };
 };

+ 5 - 0
src/views/emergency/emergency-supplies/src/styles/info-common.scss

@@ -0,0 +1,5 @@
+.safety-platform-container__header {
+  flex-direction: row !important;
+  justify-content: flex-start !important;
+  gap: 8px !important;
+}

+ 3 - 0
src/views/emergency/emergency-supplies/src/styles/info.scss

@@ -0,0 +1,3 @@
+.emergency-supply-container{
+    overflow-y: auto;
+}