Sfoglia il codice sorgente

feat: 物资清单添加物资报废和导出物资报废清单

wyf 4 mesi fa
parent
commit
36d9813c33

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

@@ -118,3 +118,29 @@ export const saveInventoryTask = (taskName: string, endTime: string) => {
     data: { taskName, endTime },
   });
 };
+/**
+ * 物资报废
+ */
+export const discardEmergencySupply = (supplyId: number, quantity: number) => {
+  return http.request({
+    url: '/emergencySupplies/scrapEmergencySupplies',
+    method: 'post',
+    data: { supplyId, quantity },
+  });
+};
+/**
+ * 导出物资报废记录
+ */
+export const exportDiscardRecord = (startTime: string, endTime: string) => {
+  return http.request(
+    {
+      url: '/emergencySupplies/exportSuppliesScrapRecord',
+      method: 'post',
+      data: { startTime, endTime },
+      responseType: 'blob',
+    },
+    {
+      isTransformResponse: false,
+    },
+  );
+};

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

@@ -52,6 +52,13 @@ export interface InventoryTaskForm {
   endTime: string;
 }
 
+export interface ExportDiscardForm {
+  discardTime: Date[];
+}
+export interface DiscardSuppliesForm {
+  quantity: number | null;
+}
+
 export interface AddEmergencyItemForm
   extends Omit<
     EmergencySupplyListResponse,

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

@@ -25,6 +25,17 @@
             </template>
             发起盘点
           </el-button>
+          <el-button
+            type="primary"
+            class="search-table-container--button"
+            v-if="emergencySupplyPermissions"
+            @click="handleExportDiscarded"
+          >
+            <template #icon>
+              <SvgIcon iconName="inventory-check" />
+            </template>
+            导出报废记录
+          </el-button>
           <BasicSearch
             :searchConfig="SUPPLY_LIST_SEARCH_CONFIG"
             :searchData="searchData"
@@ -101,6 +112,7 @@
             <div class="action-container--div">
               <ActionButton text="查看" @click="handleViewDetail(scope.row.id)" />
               <ActionButton text="编辑" v-if="emergencySupplyPermissions" @click="handleEditSupply(scope.row.id)" />
+              <ActionButton text="报废" @click="handleOpenDiscard(scope.row)" />
               <ActionButton
                 text="删除"
                 v-if="emergencySupplyPermissions"
@@ -116,6 +128,8 @@
     </div>
   </div>
   <InventoryTask ref="inventoryTaskRef" />
+  <ExportDiscardedRecords ref="ExportDiscardedRecordsRef" />
+  <DiscardSupplies ref="DiscardSuppliesRef" @refresh-list="getTableData" />
 </template>
 
 <script setup lang="ts">
@@ -129,6 +143,8 @@
   import BasicTable from '@/components/BasicTable.vue';
   import ActionButton from '@/components/ActionButton.vue';
   import InventoryTask from './src/components/InventoryTask.vue';
+  import ExportDiscardedRecords from './src/components/ExportDiscardedRecords.vue';
+  import DiscardSupplies from './src/components/DiscardSupplies.vue';
   import {
     SUPPLY_LIST_SEARCH_CONFIG,
     SUPPLY_LIST_TABLE_COLUMNS,
@@ -226,10 +242,16 @@
   };
 
   const inventoryTaskRef = ref<InstanceType<typeof InventoryTask>>();
+  const ExportDiscardedRecordsRef = ref<InstanceType<typeof ExportDiscardedRecords>>();
+  const DiscardSuppliesRef = ref<InstanceType<typeof DiscardSupplies>>();
   const handleInventory = () => {
     inventoryTaskRef.value?.openDialog();
   };
 
+  const handleExportDiscarded = () => {
+    ExportDiscardedRecordsRef.value?.openDialog();
+  };
+
   const defaultRouterName = 'emergency-list-info';
   const handleAddSupply = () => {
     router.push({
@@ -247,6 +269,10 @@
       },
     });
   };
+
+  const handleOpenDiscard = (item: EmergencySupplyListResponse) => {
+    DiscardSuppliesRef.value?.openDialog(item);
+  };
   const handleViewDetail = (id: number) => {
     router.push({
       name: 'emergency-list-detail',

+ 103 - 0
src/views/emergency/emergency-supplies/src/components/DiscardSupplies.vue

@@ -0,0 +1,103 @@
+<template>
+  <BasicDialog ref="basicDialogRef" title="报废" @refresh="refreshFromData">
+    <template #form>
+      <BasicForm
+        ref="basicFormRef"
+        :formData="ruleFormData"
+        :formRules="formRules"
+        :formConfig="ruleFormConfig"
+        style="margin-bottom: 15px"
+      >
+        <template #quantity>
+          <el-input
+            v-model.number="ruleFormData.quantity"
+            placeholder="请输入报废数量"
+            type="number"
+            min="1"
+            max="10"
+            step="1"
+          >
+          </el-input>
+        </template>
+      </BasicForm>
+      <div class="discard-note">最多可报废数量:{{ supply?.currentQuantity }}</div>
+    </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 { ElMessage } from 'element-plus';
+  import BasicDialog from '@/components/BasicDialog.vue';
+  import BasicForm from '@/components/BasicForm.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';
+
+  const emit = defineEmits<{
+    (e: 'refreshList'): void;
+  }>();
+
+  const basicDialogRef = ref<InstanceType<typeof BasicDialog>>();
+  const basicFormRef = ref<InstanceType<typeof BasicForm>>();
+  const { ruleFormConfig, ruleFormData, formRules } = useFormConfigHook<DiscardSuppliesForm>(
+    SUPPLIES_DISCARD_FROM_CONFIG,
+    SUPPLIES_DISCARD_FROM_DATA,
+    SUPPLIES_DISCARD_FROM_RULES,
+  );
+
+  const supply = ref<EmergencySupplyListResponse>();
+
+  const openDialog = (item: EmergencySupplyListResponse) => {
+    supply.value = item;
+    basicDialogRef.value?.openDialog();
+    (formRules.quantity as Array<any>).push({
+      validator: (_rule, value, callback) => {
+        if (!supply.value) {
+          ElMessage.error('物资报废失败,请重新选择报废物资');
+          return callback(new Error('请重新选择报废物资'));
+        }
+        if (value == null) return callback(new Error('请输入报废数量'));
+        if (!Number.isInteger(value)) return callback(new Error('请输入正整数'));
+        if (value > supply.value?.currentQuantity) {
+          callback(new Error('超过数量上限'));
+        } else if (value <= 0) {
+          callback(new Error('数量不能小于1'));
+        } else {
+          callback();
+        }
+      },
+      trigger: 'blur',
+    });
+  };
+  const handleSumbit = async () => {
+    const validate = await basicFormRef.value?.validateForm();
+    if (!validate) return;
+    if (!supply.value) return;
+    try {
+      await discardEmergencySupply(supply.value.id, ruleFormData.quantity!);
+      ElMessage.success('物资报废成功');
+      emit('refreshList');
+      basicDialogRef.value?.closeDialog();
+    } catch (error) {
+      ElMessage.error('物资报废失败');
+    }
+  };
+  const refreshFromData = () => {
+    basicFormRef.value?.clearValidate();
+  };
+  defineExpose({
+    openDialog,
+  });
+</script>
+
+<style scoped lang="scss">
+  .discard-note {
+    padding-left: 80px;
+  }
+</style>

+ 81 - 0
src/views/emergency/emergency-supplies/src/components/ExportDiscardedRecords.vue

@@ -0,0 +1,81 @@
+<template>
+  <BasicDialog ref="basicDialogRef" title="导出报废记录" @refresh="refreshFromData">
+    <template #form>
+      <BasicForm
+        ref="basicFormRef"
+        :formData="ruleFormData"
+        :formRules="formRules"
+        :formConfig="ruleFormConfig"
+        style="margin-bottom: 15px"
+      >
+        <template #discardTime>
+          <el-date-picker
+            v-model="ruleFormData.discardTime"
+            type="daterange"
+            range-separator="至"
+            start-placeholder="请选择开始日期"
+            end-placeholder="请选择截止日期"
+            style="width: 100%"
+          ></el-date-picker>
+        </template>
+      </BasicForm>
+    </template>
+    <template #footer>
+      <el-button type="primary" @click="handleDownload">提交</el-button>
+      <el-button @click="basicDialogRef?.closeDialog">取消</el-button>
+    </template>
+  </BasicDialog>
+</template>
+
+<script setup lang="ts">
+  import { ref } from 'vue';
+  import { ElMessage } from 'element-plus';
+  import BasicDialog from '@/components/BasicDialog.vue';
+  import BasicForm from '@/components/BasicForm.vue';
+  import { useFormConfigHook } from '@/hooks/useFormConfigHook';
+  import { ExportDiscardForm } from '@/types/emergency-supplier';
+  import { exportDiscardRecord } from '@/api/emergency-supplier';
+  import { EXPORT_DISCARD_FROM_CONFIG, EXPORT_DISCARD_FROM_DATA, EXPORT_DISCARD_FROM_RULES } from '../config';
+  import { downloadFile } from '@/views/disaster/utils/download';
+  import dayjs from 'dayjs';
+
+  const basicDialogRef = ref<InstanceType<typeof BasicDialog>>();
+  const basicFormRef = ref<InstanceType<typeof BasicForm>>();
+  const { ruleFormConfig, ruleFormData, formRules } = useFormConfigHook<ExportDiscardForm>(
+    EXPORT_DISCARD_FROM_CONFIG,
+    EXPORT_DISCARD_FROM_DATA,
+    EXPORT_DISCARD_FROM_RULES,
+  );
+
+  const openDialog = () => {
+    basicDialogRef.value?.openDialog();
+  };
+  const handleDownload = async () => {
+    const validate = await basicFormRef.value?.validateForm();
+    if (!validate) return;
+
+    try {
+      const res = await exportDiscardRecord(
+        dayjs(ruleFormData.discardTime[0]).format('YYYY-MM-DD'),
+        dayjs(ruleFormData.discardTime[1]).add(1, 'day').format('YYYY-MM-DD'),
+      );
+      if (res.size === 0) return;
+      const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+      const url = window.URL.createObjectURL(blob);
+      downloadFile(url, '物资报废记录.xlsx');
+      ElMessage.success('导出报废记录成功');
+      basicDialogRef.value?.closeDialog();
+    } catch (e) {
+      ElMessage.error('下载失败');
+      console.log(e);
+    }
+  };
+  const refreshFromData = () => {
+    basicFormRef.value?.clearValidate();
+  };
+  defineExpose({
+    openDialog,
+  });
+</script>
+
+<style scoped lang="scss"></style>

+ 7 - 1
src/views/emergency/emergency-supplies/src/components/InventoryTask.vue

@@ -1,7 +1,13 @@
 <template>
   <BasicDialog ref="basicDialogRef" title="发起盘点任务" @refresh="refreshFromData">
     <template #form>
-      <BasicForm ref="basicFormRef" :formData="ruleFormData" :formRules="formRules" :formConfig="ruleFormConfig" />
+      <BasicForm
+        ref="basicFormRef"
+        :formData="ruleFormData"
+        :formRules="formRules"
+        :formConfig="ruleFormConfig"
+        style="margin-bottom: 15px"
+      />
     </template>
     <template #footer>
       <el-button type="primary" @click="handleSumbit">提交</el-button>

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

@@ -289,3 +289,41 @@ export const ADD_EMERGENCY_ITEM_RULES = {
 export const EDIT_EMERGENCY_ITEM_RULES = {
   ...BASIC_EMERGENCY_ITEM_RULES,
 };
+
+// 导出报废记录表单配置
+export const EXPORT_DISCARD_FROM_CONFIG: FormConfig[] = [
+  {
+    label: '报废时间段:',
+    prop: 'discardTime',
+    slot: 'discardTime',
+  },
+];
+
+// 导出报废记录数据
+export const EXPORT_DISCARD_FROM_DATA = {
+  discardTime: [],
+};
+
+// 导出报废记录规则
+export const EXPORT_DISCARD_FROM_RULES = {
+  discardTime: [{ required: true, message: '请输入报废时间段', trigger: 'change' }],
+};
+
+// 物资报废单数据
+export const SUPPLIES_DISCARD_FROM_CONFIG: FormConfig[] = [
+  {
+    label: '报废数量:',
+    prop: 'quantity',
+    slot: 'quantity',
+  },
+];
+
+// 物资报废单数据
+export const SUPPLIES_DISCARD_FROM_DATA = {
+  quantity: null,
+};
+
+// 物资报废单规则
+export const SUPPLIES_DISCARD_FROM_RULES = {
+  quantity: [{ required: true, message: '请输入报废数量', trigger: 'blur' }],
+};

+ 12 - 0
src/views/emergency/emergency-supplies/src/config/index.ts

@@ -23,6 +23,12 @@ import {
   EDIT_EMERGENCY_ITEM_RULES,
   VIEW_EMERGENCY_ITEM_DATA,
   VIEW_EMERGENCY_ITEM_FROM_CONFIG,
+  EXPORT_DISCARD_FROM_CONFIG,
+  EXPORT_DISCARD_FROM_DATA,
+  EXPORT_DISCARD_FROM_RULES,
+  SUPPLIES_DISCARD_FROM_CONFIG,
+  SUPPLIES_DISCARD_FROM_DATA,
+  SUPPLIES_DISCARD_FROM_RULES,
 } from './form';
 
 export {
@@ -49,4 +55,10 @@ export {
   INVENTORY_CHECK_TABLE_OPTIONS,
   INVENTORY_CHECK_TABLE_MAX_HEIGHT_DEFAULT,
   INVENTORY_CHECK_TABLE_MAX_HEIGHT_PERMISSION,
+  EXPORT_DISCARD_FROM_CONFIG,
+  EXPORT_DISCARD_FROM_DATA,
+  EXPORT_DISCARD_FROM_RULES,
+  SUPPLIES_DISCARD_FROM_CONFIG,
+  SUPPLIES_DISCARD_FROM_DATA,
+  SUPPLIES_DISCARD_FROM_RULES,
 };

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

@@ -31,11 +31,13 @@ export const EMERGENCY_SUPPLY_TABS = [
 enum CHANGE_TYPE {
   CHECK = 1,
   CHANGE,
+  DISCARD,
 }
 
 export const CHANGE_TYPE_MAP = {
   [CHANGE_TYPE.CHECK]: '物资盘点',
   [CHANGE_TYPE.CHANGE]: '数量变更',
+  [CHANGE_TYPE.DISCARD]: '报废',
 };
 
 export enum INVENTORY_RESULT {