浏览代码

完成mock数据物资清单页面

chauncey 10 月之前
父节点
当前提交
2955c1ec1a
共有 39 个文件被更改,包括 666 次插入45 次删除
  1. 49 0
      mock/emergency-supplier/table.ts
  2. 1 1
      src/api/disaster-control/index.ts
  3. 1 1
      src/api/disaster-precaution/index.ts
  4. 1 1
      src/api/disaster-warning/index.ts
  5. 14 0
      src/api/emergency-supplier/index.ts
  6. 48 0
      src/components/BasicDialog.vue
  7. 3 1
      src/constant/dict.ts
  8. 21 0
      src/hooks/useUserInfoHook.ts
  9. 6 0
      src/styles/basic-table-action.scss
  10. 10 0
      src/styles/common.scss
  11. 9 0
      src/styles/custom-component.scss
  12. 0 0
      src/types/basic-query/index.ts
  13. 36 0
      src/types/emergency-supplier/index.ts
  14. 0 0
      src/utils/validateFormTime.ts
  15. 1 0
      src/views/disaster/disaster-control/PageDisposalManagement.vue
  16. 1 0
      src/views/disaster/disaster-control/PageDisposalRectification.vue
  17. 1 0
      src/views/disaster/disaster-control/src/components/LossRecord.vue
  18. 2 1
      src/views/disaster/disaster-control/src/components/ReportTask.vue
  19. 1 1
      src/views/disaster/disaster-control/src/config/form.ts
  20. 2 1
      src/views/disaster/disaster-precaution/PageTaskExecution.vue
  21. 2 1
      src/views/disaster/disaster-precaution/PageTaskManagement.vue
  22. 1 1
      src/views/disaster/disaster-precaution/src/config/form.ts
  23. 2 1
      src/views/disaster/disaster-warning/PageDefenseNotice.vue
  24. 2 1
      src/views/disaster/disaster-warning/PageWarningInfo.vue
  25. 2 9
      src/views/disaster/hooks/userInfo.ts
  26. 0 7
      src/views/disaster/style/disaster.scss
  27. 1 2
      src/views/disaster/utils/index.ts
  28. 154 5
      src/views/emergency/emergency-supplies/PageEmergencyList.vue
  29. 44 0
      src/views/emergency/emergency-supplies/src/components/InventoryTask.vue
  30. 45 0
      src/views/emergency/emergency-supplies/src/config/form.ts
  31. 17 2
      src/views/emergency/emergency-supplies/src/config/index.ts
  32. 6 2
      src/views/emergency/emergency-supplies/src/config/search.ts
  33. 115 0
      src/views/emergency/emergency-supplies/src/config/table.ts
  34. 10 0
      src/views/emergency/emergency-supplies/src/constant/index.ts
  35. 40 0
      src/views/emergency/emergency-supplies/src/hook.ts
  36. 3 0
      src/views/emergency/emergency-supplies/src/styles/page-common.scss
  37. 4 0
      src/views/emergency/src/constant.ts
  38. 5 5
      src/views/system/dictionary/components/AddDict.vue
  39. 6 2
      src/views/system/dictionary/dictionary.vue

+ 49 - 0
mock/emergency-supplier/table.ts

@@ -0,0 +1,49 @@
+import { resultSuccess } from '../_util';
+
+const emergencySupplyList = {
+  records: [
+    {
+      id: 1,
+      emergencyType: 'flood_typhoon_prevention',
+      supplyType: 'protective',
+      supplyName: '雨衣',
+      requiredQuantity: 100,
+      currentQuantity: 50,
+      unit: '件',
+      park: 'zhangjiang',
+      location: '10号楼',
+      keeperName: '张三',
+      expirationDate: '2025-05-23 10:00',
+      status: 1,
+      supplementQuantity: 50,
+      remark: '需要补充50件雨衣',
+    },
+    {
+      id: 2,
+      emergencyType: 'fire',
+      supplyType: 'rescue',
+      supplyName: '救生衣',
+      requiredQuantity: 150,
+      currentQuantity: 150,
+      unit: '件',
+      park: 'dachang',
+      location: '7号楼',
+      keeperName: '李四',
+      expirationDate: '2025-05-23 10:00',
+      status: 0,
+      supplementQuantity: 0,
+      remark: '无需补充',
+    },
+  ],
+  totalRow: 2,
+};
+export default [
+  {
+    url: '/safety_mock_api/emergencySupplies/queryEmergencySuppliesInfoPage',
+    timeout: 500,
+    method: 'post',
+    response: () => {
+      return resultSuccess(emergencySupplyList);
+    },
+  },
+];

+ 1 - 1
src/api/disaster-control/index.ts

@@ -18,7 +18,7 @@ import type {
   DisasterLossDetailQuery,
   DisasterLossDetailResponse,
 } from '@/types/disaster-control';
-import type { QueryPageResponse, QueryPageRequest } from '@/types/disaster';
+import type { QueryPageResponse, QueryPageRequest } from '@/types/basic-query';
 /**
  * 获取台风灾害管理表格数据
  */

+ 1 - 1
src/api/disaster-precaution/index.ts

@@ -9,7 +9,7 @@ import type {
 } from '@/types/disaster-precaution';
 import type { SpanTableData } from '@/views/disaster/disaster-precaution/src/type';
 import type { PersonGroupItem } from '@/types/person-group/type';
-import type { QueryPageRequest, QueryPageResponse } from '@/types/disaster';
+import type { QueryPageRequest, QueryPageResponse } from '@/types/basic-query';
 import type { TaskManagementRuleForm } from '@/views/disaster/disaster-precaution/src/type';
 /**
  * 获取任务管理表格数据

+ 1 - 1
src/api/disaster-warning/index.ts

@@ -8,7 +8,7 @@ import type {
   WarningInfoListQuery,
 } from '@/types/disaster-warning';
 import type { WarningInfoRuleForm, DefenseNoticeRuleForm } from '@/views/disaster/disaster-warning/src/type';
-import type { QueryPageRequest, QueryPageResponse } from '@/types/disaster';
+import type { QueryPageRequest, QueryPageResponse } from '@/types/basic-query';
 /**
  * 获取预警信息列表
  */

+ 14 - 0
src/api/emergency-supplier/index.ts

@@ -0,0 +1,14 @@
+import { http } from '@/utils/http/axios/mock';
+import type { QueryPageRequest, QueryPageResponse } from '@/types/basic-query';
+import type { EmergencySupplyListQuery, EmergencySupplyListResponse } from '@/types/emergency-supplier';
+
+/**
+ * 获取物资清单列表
+ */
+export function getEmergencySupplyList(query: QueryPageRequest<EmergencySupplyListQuery>) {
+  return http.request<QueryPageResponse<EmergencySupplyListResponse>>({
+    url: '/emergencySupplies/queryEmergencySuppliesInfoPage',
+    method: 'post',
+    data: query,
+  });
+}

+ 48 - 0
src/components/BasicDialog.vue

@@ -0,0 +1,48 @@
+<template>
+  <div class="basic-dialog">
+    <el-dialog v-model="dialogVisible" width="640px" align-center :close-on-click-modal="false" v-bind="$attrs" class="basic-dialog--custom">
+      <div class="basic-dialog-container">
+        <main class="basic-dialog-main">
+          <slot name="form"></slot>
+        </main>
+        <div class="basic-dialog-footer">
+          <slot name="footer"></slot>
+        </div>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { ref } from 'vue';
+  const dialogVisible = ref(false);
+  const emit = defineEmits(['refresh']);
+  const openDialog = () => {
+    emit('refresh');
+    dialogVisible.value = true;
+  };
+  const closeDialog = () => {
+    dialogVisible.value = false;
+  };
+  defineExpose({
+    openDialog,
+    closeDialog,
+  });
+</script>
+
+<style lang="scss" scoped>
+  .basic-dialog-container {
+    display: flex;
+    flex-direction: column;
+    align-items: space-between;
+    height: 100%;
+  }
+  .basic-dialog-main {
+    flex: 1;
+    overflow-y: auto;
+  }
+  .basic-dialog-footer {
+    flex-shrink: 0;
+    text-align: right;
+  }
+</style>

+ 3 - 1
src/constant/dict.ts

@@ -3,5 +3,7 @@ export const DICT_CODE = {
   DISASTER_LEVEL: 'disaster_level',
   DISASTER_TYPE: 'disaster_type',
   PRIORITY: 'disaster_fix_priority',
-  SAFETY_LEVEL: 'disaster_safety_impact'
+  SAFETY_LEVEL: 'disaster_safety_impact',
+  EMERGENCY_EVENT: 'emergency_event',
+  EMERGENCY_SUPPLY: 'emergency_supply',
 };

+ 21 - 0
src/hooks/useUserInfoHook.ts

@@ -0,0 +1,21 @@
+import { storeToRefs } from 'pinia';
+import { useUserStore } from '@/store/modules/user';
+
+const userStore = useUserStore();
+const { getUserInfo } = storeToRefs(userStore);
+/**
+ * 获取登录账户信息
+ */
+export const useUserInfoHook = () => {
+  const userInfo = getUserInfo.value;
+  const id = userInfo.id;
+  const staffNo = userInfo.staffNo;
+  const realname = userInfo.realname;
+  const permissions = userInfo.permissions;
+  return {
+    id,
+    realname,
+    permissions,
+    staffNo,
+  };
+};

+ 6 - 0
src/styles/basic-table-action.scss

@@ -0,0 +1,6 @@
+.action-container--div {
+  display: flex;
+  justify-content: center;
+  width: 100%;
+  gap: 12px;
+}

+ 10 - 0
src/styles/common.scss

@@ -49,3 +49,13 @@
 .el-select {
   font-weight: 0 !important;
 }
+
+.el-dialog {
+  min-height: 500px;
+  max-height: 60vh;
+  overflow-y: auto;
+  .el-dialog__title {
+    color: rgba(0, 0, 0, 0.88);
+    font-weight: 600;
+  }
+}

+ 9 - 0
src/styles/custom-component.scss

@@ -20,6 +20,15 @@
   }
 }
 
+.basic-dialog--custom {
+  display: flex;
+  flex-direction: column;
+  height: 500px;
+  .el-dialog__body {
+    flex: 1;
+  }
+}
+
 $message-box-content-padding--default: 0;
 $message-box-content-padding--icon: 36px;
 

src/types/disaster/index.ts → src/types/basic-query/index.ts


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

@@ -0,0 +1,36 @@
+interface BasicListQuery {
+  emergencyType?: string | null;
+  supplyType?: string | null;
+  supplyName?: string | null;
+  keeperName?: string | null;
+}
+
+interface BasicResponse {
+  id: number;
+  emergencyType: string;
+  supplyType: string;
+  remark: string;
+}
+
+export interface EmergencySupplyListQuery extends BasicListQuery {
+  park?: string | null;
+  location?: string | null;
+  status?: number | null;
+}
+
+export interface EmergencySupplyListResponse extends BasicResponse {
+  requiredQuantity: number;
+  currentQuantity: number;
+  unit: string;
+  park: string;
+  location: string;
+  keeperName: string;
+  expirationDate: string;
+  status: number;
+  supplementQuantity: number;
+}
+
+export interface InventoryTaskForm {
+  taskName: string;
+  endTime: string;
+}

src/views/disaster/utils/validateTime.ts → src/utils/validateFormTime.ts


+ 1 - 0
src/views/disaster/disaster-control/PageDisposalManagement.vue

@@ -470,6 +470,7 @@
 <style scoped lang="scss">
   @use '@/styles/page-main-layout.scss' as *;
   @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
   @use '@/views/disaster/style/disaster.scss' as *;
   @use './src/style/collapse.scss' as *;
   @use './src/style/common.scss' as *;

+ 1 - 0
src/views/disaster/disaster-control/PageDisposalRectification.vue

@@ -348,6 +348,7 @@
 <style scoped lang="scss">
   @use '@/styles/page-main-layout.scss' as *;
   @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
   @use './src/style/collapse.scss' as *;
   @use './src/style/common.scss' as *;
   @use '@/views/disaster/style/disaster.scss' as *;

+ 1 - 0
src/views/disaster/disaster-control/src/components/LossRecord.vue

@@ -357,6 +357,7 @@
 
 <style lang="scss" scoped>
   @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
   @use '../style/collapse.scss' as *;
   @use '../style/common.scss' as *;
   @use '@/views/disaster/style/disaster.scss' as *;

+ 2 - 1
src/views/disaster/disaster-control/src/components/ReportTask.vue

@@ -78,7 +78,7 @@
   import useTableConfig from '@/hooks/useTableConfigHook';
   import { getTaskStage } from '../util';
   import type { LossReportReportTaskQuery, LossReportReportTaskResponse } from '@/types/disaster-control';
-  import type { QueryPageRequest } from '@/types/disaster';
+  import type { QueryPageRequest } from '@/types/basic-query';
   import { getReportTaskList, addReporter } from '@/api/disaster-control';
   import {
     LOSS_REPORT_REPORT_TASK_SEARCH_CONFIG,
@@ -201,5 +201,6 @@
 
 <style lang="scss" scoped>
   @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
   @use '@/views/disaster/style/disaster.scss' as *;
 </style>

+ 1 - 1
src/views/disaster/disaster-control/src/config/form.ts

@@ -2,7 +2,7 @@
  * 灾害预警信息表单配置
  */
 import type { FormConfig } from '@/types/basic-form';
-import { validateFormTime } from '@/views/disaster/utils/validateTime';
+import { validateFormTime } from '@/utils/validateFormTime';
 import { FIX_STATUS_OPTIONS_DISPOSAL_RECTIFICATION } from '../constant';
 // 通用表单信息
 const BASIC_FROM_CONFIG = {};

+ 2 - 1
src/views/disaster/disaster-precaution/PageTaskExecution.vue

@@ -112,7 +112,7 @@
   import useTableConfig from '@/hooks/useTableConfigHook';
   import { isToolTip } from './src/utils';
   import type { TaskExecutionListResponse, TaskExecutionListQuery } from '@/types/disaster-precaution';
-  import type { QueryPageRequest } from '@/types/disaster';
+  import type { QueryPageRequest } from '@/types/basic-query';
   import type { PersonGroupItem } from '@/types/person-group/type';
   import {
     getTaskExecutionList,
@@ -248,6 +248,7 @@
 <style scoped lang="scss">
   @use '@/styles/page-details-layout.scss' as *;
   @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
   @use './src/style/task-execution.scss' as *;
   @use '@/views/disaster/style/disaster.scss' as *;
 </style>

+ 2 - 1
src/views/disaster/disaster-precaution/PageTaskManagement.vue

@@ -147,7 +147,7 @@
   import { openMessageBox } from '@/utils/element-plus/messageBox';
   import { isToolTip } from './src/utils';
   import type { TaskManagementListQuery, TaskManagementListResponse } from '@/types/disaster-precaution';
-  import type { QueryPageRequest } from '@/types/disaster';
+  import type { QueryPageRequest } from '@/types/basic-query';
   import {
     getTaskManagementList,
     deleteTaskManagementItem,
@@ -319,6 +319,7 @@
 <style scoped lang="scss">
   @use '@/styles/page-details-layout.scss' as *;
   @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
   @use './src/style/task-execution.scss' as *;
   @use '@/views/disaster/style/disaster.scss' as *;
   .batch-table {

+ 1 - 1
src/views/disaster/disaster-precaution/src/config/form.ts

@@ -3,7 +3,7 @@
  */
 import type { FormConfig } from '@/types/basic-form';
 import type { TaskManagementRuleForm } from '../type';
-import { validateFormTime } from '@/views/disaster/utils/validateTime';
+import { validateFormTime } from '@/utils/validateFormTime';
 
 // 通用表单配置
 const BASIC_FORM_CONFIG = {

+ 2 - 1
src/views/disaster/disaster-warning/PageDefenseNotice.vue

@@ -116,7 +116,7 @@
   import { useDisasterWarningHook } from './src/hook';
   import { useUserInfoHook } from '@/views/disaster/hooks';
   import type { DefenseNoticeListResponse, DefenseNoticeListQuery } from '@/types/disaster-warning';
-  import type { QueryPageRequest } from '@/types/disaster';
+  import type { QueryPageRequest } from '@/types/basic-query';
   import { getDefenseNoticeList, deleteDefenseNoticeItem, publishDefenseNoticeItem } from '@/api/disaster-warning';
   import {
     ACTIVE_STATUS,
@@ -239,6 +239,7 @@
 <style lang="scss" scoped>
   @use '@/styles/page-details-layout.scss' as *;
   @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
   @use './src/style/common.scss' as *;
   @use '@/views/disaster/style/disaster.scss' as *;
 </style>

+ 2 - 1
src/views/disaster/disaster-warning/PageWarningInfo.vue

@@ -133,7 +133,7 @@
   import { useDisasterWarningHook } from './src/hook';
   import { useUserInfoHook } from '@/views/disaster/hooks';
   import type { WarningInfoListResponse, WarningInfoListQuery } from '@/types/disaster-warning';
-  import type { QueryPageRequest } from '@/types/disaster';
+  import type { QueryPageRequest } from '@/types/basic-query';
   import { getWarningInfoList, deleteWarningInfoItem, publishWarningInfoItem } from '@/api/disaster-warning';
   import {
     ACTIVE_STATUS,
@@ -263,6 +263,7 @@
 <style lang="scss" scoped>
   @use '@/styles/page-details-layout.scss' as *;
   @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
   @use './src/style/common.scss' as *;
   @use '@/views/disaster/style/disaster.scss' as *;
   .weather-warning-icon {

+ 2 - 9
src/views/disaster/hooks/userInfo.ts

@@ -1,21 +1,14 @@
-import { storeToRefs } from 'pinia';
 import { computed, ref } from 'vue';
-import { useUserStore } from '@/store/modules/user';
 import type { QueryUserFirstLevelTreeRes } from '@/types/person-group/type';
 import type { TreeNode } from '@/views/disaster/types';
 import { getUserFirstLevelTree } from '@/api/system/person-group';
+import { useUserInfoHook as useUserHook } from '@/hooks/useUserInfoHook';
 
-const userStore = useUserStore();
-const { getUserInfo } = storeToRefs(userStore);
 /**
  * 获取登录账户信息
  */
 export const useUserInfoHook = () => {
-  const userInfo = getUserInfo.value;
-  const id = userInfo.id;
-  const staffNo = userInfo.staffNo;
-  const realname = userInfo.realname;
-  const permissions = userInfo.permissions;
+  const { id, realname, permissions, staffNo } = useUserHook();
   const userFirstLevelTreeList = ref<QueryUserFirstLevelTreeRes>();
   const getUserFirstLevelTreeList = async () => {
     const res = await getUserFirstLevelTree();

+ 0 - 7
src/views/disaster/style/disaster.scss

@@ -15,10 +15,3 @@
     text-align: left;
   }
 }
-
-.action-container--div {
-  display: flex;
-  justify-content: center;
-  width: 100%;
-  gap: 12px;
-}

+ 1 - 2
src/views/disaster/utils/index.ts

@@ -1,5 +1,4 @@
 import { downloadFile } from './download';
 import { formatDeptTree } from './formatDeptTree';
-import { validateFormTime } from './validateTime';
 
-export { downloadFile, formatDeptTree, validateFormTime };
+export { downloadFile, formatDeptTree };

+ 154 - 5
src/views/emergency/emergency-supplies/PageEmergencyList.vue

@@ -6,28 +6,126 @@
     <div class="safety-platform-container__main">
       <div class="search-table-container">
         <header class="disaster-precaution__header">
-          <el-button type="primary" class="search-table-container--button" :icon="Plus">添加物资</el-button>
-          <el-button type="primary" class="search-table-container--button">
+          <el-button
+            type="primary"
+            class="search-table-container--button"
+            :icon="Plus"
+            v-if="emergencySupplyPermissions"
+            >添加物资</el-button
+          >
+          <el-button
+            type="primary"
+            class="search-table-container--button"
+            v-if="emergencySupplyPermissions"
+            @click="handleInventory"
+          >
             <template #icon>
               <SvgIcon iconName="inventory-check" />
             </template>
             发起盘点
           </el-button>
-          <BasicSearch :searchConfig="SUPPLY_LIST_SEARCH_CONFIG" :searchData="searchData" />
+          <BasicSearch
+            :searchConfig="SUPPLY_LIST_SEARCH_CONFIG"
+            :searchData="searchData"
+            @update:searchData="handleSearch"
+          >
+            <template #emergencyType>
+              <el-select v-model="searchData.emergencyType" placeholder="请选择应急事件类型">
+                <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="searchData.supplyType" placeholder="请选择物资类型">
+                <el-option
+                  v-for="item in emergencySupplyDice"
+                  :key="item.itemCode"
+                  :label="item.itemValue"
+                  :value="item.itemCode"
+                />
+              </el-select>
+            </template>
+          </BasicSearch>
         </header>
+        <BasicTable :tableData="tableData" :tableConfig="tableConfig">
+          <template #emergencyType="scope">
+            <span>{{ getEmergencyEvent(scope.row.emergencyType) }}</span>
+          </template>
+          <template #supplyType="scope">
+            <span>{{ getEmergencySupply(scope.row.supplyType) }}</span>
+          </template>
+          <template #status="scope">
+            <span :style="{ color: scope.row.status === EMERGENCY_SUPPLY_STATUS.DAMAGED ? 'red' : '' }">
+              {{ getEmergencyStatus(scope.row.status) }}
+            </span>
+          </template>
+          <template #action="scope">
+            <div class="action-container--div">
+              <ActionButton text="查看" />
+              <ActionButton text="编辑" v-if="emergencySupplyPermissions" />
+              <ActionButton
+                text="删除"
+                v-if="emergencySupplyPermissions"
+                :popconfirm="{
+                  title: '确定删除?',
+                }"
+              />
+            </div>
+          </template>
+        </BasicTable>
       </div>
     </div>
   </div>
+  <InventoryTask ref="inventoryTaskRef" />
 </template>
 
 <script setup lang="ts">
-  import { reactive } from 'vue';
+  import { ref, reactive, onMounted } from 'vue';
   import { Plus } from '@element-plus/icons-vue';
   // @ts-ignore
   import SvgIcon from '@/components/SvgIcon/SvgIcon.vue';
   import BasicSearch from '@/components/BasicSearch.vue';
-  import { SUPPLY_LIST_SEARCH_CONFIG } from './src/config';
+  import BasicTable from '@/components/BasicTable.vue';
+  import ActionButton from '@/components/ActionButton.vue';
+  import InventoryTask from './src/components/InventoryTask.vue';
+  import {
+    SUPPLY_LIST_SEARCH_CONFIG,
+    SUPPLY_LIST_TABLE_COLUMNS,
+    SUPPLY_LIST_TABLE_OPTIONS,
+    SUPPLY_LIST_TABLE_MAX_HEIGHT_DEFAULT,
+    SUPPLY_LIST_TABLE_MAX_HEIGHT_PERMISSION,
+  } from './src/config';
+  import useTableConfig from '@/hooks/useTableConfigHook';
+  import { useUserInfoHook } from '@/hooks/useUserInfoHook';
+  import { useEmergencySuppliesHook } from './src/hook';
+  import type { EmergencySupplyListQuery, EmergencySupplyListResponse } from '@/types/emergency-supplier';
+  import type { QueryPageRequest } from '@/types/basic-query';
+  import { getEmergencySupplyList } from '@/api/emergency-supplier';
+  import { EMERGENCY_PERMISSIONS } from '@/views/emergency/src/constant';
+  import { EMERGENCY_SUPPLY_STATUS } from './src/constant';
 
+  const {
+    emergencyEventDice,
+    getEmergencyEventDict,
+    getEmergencyEvent,
+    emergencySupplyDice,
+    getEmergencySupplyDict,
+    getEmergencySupply,
+    getEmergencyStatus,
+  } = useEmergencySuppliesHook();
+  const { permissions } = useUserInfoHook();
+  const { tableConfig, pagination } = useTableConfig(SUPPLY_LIST_TABLE_COLUMNS, SUPPLY_LIST_TABLE_OPTIONS);
+  const emergencySupplyPermissions = ref<Boolean>(false);
+  let emergencySupplyListQuery: QueryPageRequest<EmergencySupplyListQuery> = {
+    pageNumber: pagination.pageNumber,
+    pageSize: pagination.pageSize,
+    queryParam: {},
+  };
+  const tableData = ref<EmergencySupplyListResponse[]>([]);
   const searchData = reactive({
     emergencyType: null,
     supplyType: null,
@@ -37,9 +135,60 @@
     keeperName: null,
     status: null,
   });
+  const handleSearch = () => {
+    emergencySupplyListQuery.queryParam = {};
+    if (searchData.emergencyType) {
+      emergencySupplyListQuery.queryParam.emergencyType = searchData.emergencyType;
+    }
+    if (searchData.supplyType) {
+      emergencySupplyListQuery.queryParam.supplyType = searchData.supplyType;
+    }
+    if (searchData.supplyName) {
+      emergencySupplyListQuery.queryParam.supplyName = searchData.supplyName;
+    }
+    if (searchData.park) {
+      emergencySupplyListQuery.queryParam.park = searchData.park;
+    }
+    if (searchData.location) {
+      emergencySupplyListQuery.queryParam.location = searchData.location;
+    }
+    if (searchData.keeperName) {
+      emergencySupplyListQuery.queryParam.keeperName = searchData.keeperName;
+    }
+    if (searchData.status !== null) {
+      emergencySupplyListQuery.queryParam.status = searchData.status;
+    }
+    getTableData();
+  };
+  const getTableData = async () => {
+    tableConfig.loading = true;
+    const res = await getEmergencySupplyList(emergencySupplyListQuery);
+    tableData.value = res.records;
+    pagination.total = res.totalRow;
+    tableConfig.loading = false;
+  };
+
+  const inventoryTaskRef = ref<InstanceType<typeof InventoryTask>>();
+  const handleInventory = () => {
+    inventoryTaskRef.value?.openDialog();
+  };
+
+  onMounted(() => {
+    getEmergencyEventDict();
+    getEmergencySupplyDict();
+    getTableData();
+    emergencySupplyPermissions.value = Boolean(
+      permissions.find((item: { code: string }) => item.code === EMERGENCY_PERMISSIONS.SUPPLY_LIST),
+    );
+    tableConfig.maxHeight = emergencySupplyPermissions.value
+      ? SUPPLY_LIST_TABLE_MAX_HEIGHT_PERMISSION
+      : SUPPLY_LIST_TABLE_MAX_HEIGHT_DEFAULT;
+  });
 </script>
 
 <style scoped lang="scss">
   @use '@/styles/page-details-layout.scss' as *;
   @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
+  @use './src/styles/page-common.scss' as *;
 </style>

+ 44 - 0
src/views/emergency/emergency-supplies/src/components/InventoryTask.vue

@@ -0,0 +1,44 @@
+<template>
+  <BasicDialog ref="basicDialogRef" title="发起盘点任务" @refresh="refreshFromData">
+    <template #form>
+      <BasicForm ref="basicFormRef" :formData="ruleFormData" :formRules="formRules" :formConfig="ruleFormConfig" />
+    </template>
+    <template #footer>
+      <el-button type="primary" @click="handleSumbit">提交</el-button>
+      <el-button @click="basicDialogRef?.closeDialog">取消</el-button>
+    </template>
+  </BasicDialog>
+</template>
+
+<script setup lang="ts">
+  import { ref } from 'vue';
+  import BasicDialog from '@/components/BasicDialog.vue';
+  import BasicForm from '@/components/BasicForm.vue';
+  import { useFormConfigHook } from '@/hooks/useFormConfigHook';
+  import { InventoryTaskForm } from '@/types/emergency-supplier';
+  import { INVENTORY_TASK_FROM_CONFIG, INVENTORY_TASK_FROM_DATA, INVENTORY_TASK_FROM_RULES } from '../config';
+
+  const basicDialogRef = ref<InstanceType<typeof BasicDialog>>();
+  const basicFormRef = ref<InstanceType<typeof BasicForm>>();
+  const { ruleFormConfig, ruleFormData, formRules } = useFormConfigHook<InventoryTaskForm>(
+    INVENTORY_TASK_FROM_CONFIG,
+    INVENTORY_TASK_FROM_DATA,
+    INVENTORY_TASK_FROM_RULES,
+  );
+  const openDialog = () => {
+    basicDialogRef.value?.openDialog();
+  };
+  const handleSumbit = async () => {
+    const validate = await basicFormRef.value?.validateForm();
+    if (!validate) return;
+    basicDialogRef.value?.closeDialog();
+  };
+  const refreshFromData = () => {
+    basicFormRef.value?.clearValidate();
+  };
+  defineExpose({
+    openDialog,
+  });
+</script>
+
+<style scoped lang="scss"></style>

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

@@ -0,0 +1,45 @@
+/**
+ * 应急物资表单配置
+ */
+import type { FormConfig } from '@/types/basic-form';
+import { validateFormTime } from '@/utils/validateFormTime';
+
+// 盘点任务表单信息
+export const INVENTORY_TASK_FROM_CONFIG: FormConfig[] = [
+  {
+    label: '盘点任务名称:',
+    prop: 'taskName',
+    component: 'ElInput',
+    componentProps: {
+      placeholder: '请输入盘点任务名称',
+    },
+  },
+  {
+    label: '任务截止时间:',
+    prop: 'endTime',
+    component: 'ElDatePicker',
+    componentProps: {
+      placeholder: '请选择任务截止时间',
+      type: 'datetime',
+      format: 'YYYY-MM-DD HH:mm',
+      dateFormat: 'MMM DD, YYYY',
+      timeFormat: 'HH:mm',
+      valueFormat: 'YYYY-MM-DD HH:mm',
+    },
+  },
+];
+
+// 盘点任务表单数据
+export const INVENTORY_TASK_FROM_DATA = {
+  taskName: '',
+  endTime: '',
+};
+
+// 盘点任务表单规则
+export const INVENTORY_TASK_FROM_RULES = {
+  taskName: [{ required: true, message: '请输入盘点任务名称', trigger: 'blur' }],
+  endTime: [
+    { required: true, message: '请选择任务截止时间', trigger: 'change' },
+    { validator: validateFormTime, trigger: 'change' },
+  ],
+};

+ 17 - 2
src/views/emergency/emergency-supplies/src/config/index.ts

@@ -1,4 +1,19 @@
 import { SUPPLY_LIST_SEARCH_CONFIG } from './search';
+import {
+  SUPPLY_LIST_TABLE_COLUMNS,
+  SUPPLY_LIST_TABLE_OPTIONS,
+  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';
 
-export { SUPPLY_LIST_SEARCH_CONFIG };
-
+export {
+  SUPPLY_LIST_SEARCH_CONFIG,
+  SUPPLY_LIST_TABLE_COLUMNS,
+  SUPPLY_LIST_TABLE_OPTIONS,
+  SUPPLY_LIST_TABLE_MAX_HEIGHT_DEFAULT,
+  SUPPLY_LIST_TABLE_MAX_HEIGHT_PERMISSION,
+  INVENTORY_TASK_FROM_CONFIG,
+  INVENTORY_TASK_FROM_DATA,
+  INVENTORY_TASK_FROM_RULES,
+};

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

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

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

@@ -0,0 +1,115 @@
+/**
+ * 应急物资表格配置
+ */
+import type { TableColumnProps } from '@/types/basic-table';
+
+export const SUPPLY_LIST_TABLE_MAX_HEIGHT_DEFAULT = 'calc(70vh - 100px)';
+export const SUPPLY_LIST_TABLE_MAX_HEIGHT_PERMISSION = 'calc(70vh - 150px)';
+
+// 基础表格样式配置
+const TABLE_OPTIONS = {
+  emptyText: '暂无数据',
+  loading: true,
+};
+
+// 应急物资表格样式配置
+export const SUPPLY_LIST_TABLE_OPTIONS = {
+  ...TABLE_OPTIONS,
+};
+
+// 基础表格配置
+const BASIC_TABLE_COLUMNS = {
+  INDEX: {
+    prop: 'index',
+    label: '序号',
+    width: '80px',
+    type: 'index',
+    align: 'center',
+  },
+  EMERGENCY_TYPE: {
+    prop: 'emergencyType',
+    label: '应急事件类型',
+    slot: 'emergencyType',
+    minWidth: '140px',
+  },
+  SUPPLY_TYPE: {
+    prop: 'supplyType',
+    label: '物资类型',
+    slot: 'supplyType',
+    minWidth: '140px',
+  },
+  SUPPLY_NAME: {
+    prop: 'supplyName',
+    label: '应急物资名称',
+    minWidth: '140px',
+  },
+  REMARK: {
+    prop: 'remark',
+    label: '备注',
+    minWidth: '120px',
+  },
+  ACTION: {
+    prop: 'action',
+    label: '操作',
+    align: 'center',
+    slot: 'action',
+    fixed: 'right',
+    width: '250px',
+  },
+};
+
+// 应急物资表格列配置
+export const SUPPLY_LIST_TABLE_COLUMNS: TableColumnProps[] = [
+  BASIC_TABLE_COLUMNS.INDEX,
+  BASIC_TABLE_COLUMNS.EMERGENCY_TYPE,
+  BASIC_TABLE_COLUMNS.SUPPLY_TYPE,
+  BASIC_TABLE_COLUMNS.SUPPLY_NAME,
+  {
+    label: '应备数量',
+    prop: 'requiredQuantity',
+    minWidth: '120px',
+  },
+  {
+    label: '当前数量',
+    prop: 'currentQuantity',
+    minWidth: '120px',
+  },
+  {
+    label: '数量单位',
+    prop: 'unit',
+    minWidth: '120px',
+  },
+  {
+    label: '园区',
+    prop: 'park',
+    minWidth: '140px',
+  },
+  {
+    label: '地点',
+    prop: 'location',
+    minWidth: '120px',
+  },
+  {
+    label: '保管人',
+    prop: 'keeperName',
+    minWidth: '120px',
+  },
+  {
+    label: '使用期限',
+    prop: 'expirationDate',
+    minWidth: '200px',
+  },
+  {
+    label: '状态',
+    prop: 'status',
+    slot: 'status',
+    minWidth: '120px',
+  },
+  {
+    label: '需补充数量',
+    prop: 'supplementQuantity',
+    minWidth: '120px',
+  },
+  BASIC_TABLE_COLUMNS.REMARK,
+  BASIC_TABLE_COLUMNS.ACTION,
+];

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

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

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

@@ -0,0 +1,40 @@
+/**
+ * 应急物资公用hook
+ */
+import { ref } from 'vue';
+import type { SysDictDataDetail } from '@/api/dict';
+import { queryDictTypeDetail } from '@/api/dict';
+import { DICT_CODE } from '@/constant/dict';
+import { EMERGENCY_SUPPLY_STATUS_OPTIONS } from './constant';
+export const useEmergencySuppliesHook = () => {
+  // 应急事件类型
+  const emergencyEventDice = ref<SysDictDataDetail[]>([]);
+  const getEmergencyEventDict = async () => {
+    const emergencyEventRes = await queryDictTypeDetail(DICT_CODE.EMERGENCY_EVENT);
+    emergencyEventDice.value = emergencyEventRes.sysDictDataList;
+  };
+  const getEmergencyEvent = (emergencyType: string) => {
+    return emergencyEventDice.value.find((item) => item.itemCode === emergencyType)?.itemValue;
+  };
+  // 应急物资类型
+  const emergencySupplyDice = ref<SysDictDataDetail[]>([]);
+  const getEmergencySupplyDict = async () => {
+    const emergencySupplyRes = await queryDictTypeDetail(DICT_CODE.EMERGENCY_SUPPLY);
+    emergencySupplyDice.value = emergencySupplyRes.sysDictDataList;
+  };
+  const getEmergencySupply = (emergencySupplyType: string) => {
+    return emergencySupplyDice.value.find((item) => item.itemCode === emergencySupplyType)?.itemValue;
+  };
+  const getEmergencyStatus = (status: number) => {
+    return EMERGENCY_SUPPLY_STATUS_OPTIONS.find((item) => item.value === status)?.label;
+  };
+  return {
+    emergencyEventDice,
+    getEmergencyEventDict,
+    getEmergencyEvent,
+    emergencySupplyDice,
+    getEmergencySupplyDict,
+    getEmergencySupply,
+    getEmergencyStatus,
+  };
+};

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

@@ -0,0 +1,3 @@
+.el-select {
+  --el-select-width: 200px !important;
+}

+ 4 - 0
src/views/emergency/src/constant.ts

@@ -0,0 +1,4 @@
+//管理权限
+export const EMERGENCY_PERMISSIONS = {
+  SUPPLY_LIST: 'emergency_business_module:supplies_list',
+};

+ 5 - 5
src/views/system/dictionary/components/AddDict.vue

@@ -2,15 +2,15 @@
   <el-drawer :model-value="true" title="新建字典" @close="handleClose" :size="600">
     <el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" class="add-dict-form">
       <el-form-item label="字典名称" prop="dictName">
-        <el-input v-model="formData.dictName" />
+        <el-input v-model="formData.dictName" placeholder="请输入字典名称" />
       </el-form-item>
 
       <el-form-item label="字典编码" prop="dictCode">
-        <el-input v-model="formData.dictCode" />
+        <el-input v-model="formData.dictCode" placeholder="请输入字典编码" />
       </el-form-item>
 
       <el-form-item label="字典分类" prop="dictType">
-        <el-select v-model="formData.dictType" placeholder="请选择">
+        <el-select v-model="formData.dictType" placeholder="请选择字典分类">
           <el-option
             v-for="(item, index) in dictionaryTypeOptions"
             :key="index"
@@ -51,7 +51,7 @@
               >
                 <el-input
                   v-model="item.itemValue"
-                  placeholder="请输入"
+                  placeholder="请输入字典项值"
                   type="textarea"
                   show-word-limit
                   maxlength="500"
@@ -64,7 +64,7 @@
               >
                 <el-input
                   v-model="item.itemCode"
-                  placeholder="请输入"
+                  placeholder="请输入字典项编码"
                   type="textarea"
                   show-word-limit
                   maxlength="500"

+ 6 - 2
src/views/system/dictionary/dictionary.vue

@@ -8,7 +8,7 @@
         <el-button type="primary" @click="handleAddDialogShow" :icon="Plus">新增字典项</el-button>
       </div>
 
-      <el-table v-loading="loading" :data="dataSource" style="width: 100%; margin-top: 16px">
+      <el-table v-loading="loading" :data="dataSource" style="width: 100%; margin-top: 16px" :max-height="'calc(100vh - 300px)'">
         <el-table-column prop="dictName" label="字典名称" width="360" />
         <el-table-column prop="dictCode" label="字典编码" width="360" />
         <el-table-column prop="description" label="字典描述" width="680" />
@@ -55,7 +55,7 @@
 
 <script lang="ts" setup>
   import { ref, onMounted, computed } from 'vue';
-  import { ElMessage, ElMessageBox } from 'element-plus';
+  import { ElMessage } from 'element-plus';
   import { DEFAULT_PAGINATION_LAYOUT, PAGE_SIZE_CONFIG } from '@/constant/pagination';
   import { Plus } from '@element-plus/icons-vue';
   import AddDict from './components/AddDict.vue';
@@ -127,12 +127,16 @@
   // 提交表单
   async function handleSubmit(formData: SaveDictParams) {
     if (!addDictRef.value) return;
+    let operate = '';
     if (formData.dictId) {
       await updateDictionary(formData);
+      operate = '编辑';
     } else {
       await createDictionary(formData);
+      operate = '新增';
     }
     dialogVisible.value = false;
+    ElMessage.success(`${operate}字典成功`);
     getDataSource();
   }