Bladeren bron

feat: 添加需求物资表单和校验

ai0197 4 maanden geleden
bovenliggende
commit
45d433148e

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

@@ -183,3 +183,12 @@ export interface ReceiveSupplyRequestDetailForm {
   detailId: number; // 需求物资ID
   planId: number; // 申领计划ID
 }
+
+export type AddSupplyRequestSubForm = Pick<SupplyRequestDetailList, 'id'> &
+  Partial<Omit<SupplyRequestDetailList, 'id'>>;
+
+export interface AddSupplyRequestForm {
+  info: Partial<SupplyRequestDetailInfo>;
+  detailList: AddSupplyRequestSubForm[];
+}
+export interface UpdateSupplyRequestForm extends SupplyRequestDetailItem {}

+ 0 - 1
src/views/emergency/emergency-supplies/PageSupplyRequest.vue

@@ -172,7 +172,6 @@
   const handleCreateRequest = () => {
     supplyRequestFormRef.value?.openAddDialog();
   };
-
   // 查看详情
   const handleViewDetail = (id: number) => {
     router.push({

+ 5 - 1
src/views/emergency/emergency-supplies/PageSupplyRequestDetail.vue

@@ -80,6 +80,8 @@
     </div>
     <!-- 领用弹窗 -->
     <ReceiveSupplyDialog ref="receiveSupplyDialogRef" @success="handleClaimSuccess" />
+    <!-- 添加物资弹窗 -->
+    <AddSuppliesDrawer ref="addSupplyDrawerRef" />
   </div>
 </template>
 
@@ -101,6 +103,7 @@
   import ReceiveSupplyDialog from './src/components/ReceiveSupplyDialog.vue';
   import { useUserInfoHook } from '@/hooks/useUserInfoHook';
   import { EMERGENCY_PERMISSIONS } from '@/views/emergency/src/constant';
+  import AddSuppliesDrawer from './src/components/AddSuppliesDrawer.vue';
 
   const { permissions } = useUserInfoHook();
   const supplyRequestManagePermission = ref<Boolean>(false);
@@ -128,6 +131,7 @@
 
   const loading = ref(false);
   const tableData = ref<TableRowData[]>([]);
+  const addSupplyDrawerRef = ref<InstanceType<typeof AddSuppliesDrawer>>();
 
   // 领用弹窗相关
   const receiveSupplyDialogRef = ref<InstanceType<typeof ReceiveSupplyDialog>>();
@@ -206,7 +210,7 @@
   // 添加需求物资
   const handleAddMaterial = () => {
     // TODO: 打开添加物资的对话框
-    ElMessage.info('添加需求物资功能待实现');
+    addSupplyDrawerRef.value?.openDrawer();
   };
 
   // 下载采购记录

+ 177 - 0
src/views/emergency/emergency-supplies/src/components/AddSuppliesDrawer.vue

@@ -0,0 +1,177 @@
+<template>
+  <el-drawer
+    v-model="showDrawer"
+    direction="rtl"
+    title="添加需求物资"
+    size="50%"
+    :close-on-click-modal="false"
+    destroy-on-close
+  >
+    <el-form ref="formRef" :model="formData" label-width="auto" class="add-supply-form">
+      <el-form-item
+        label="物资名称:"
+        prop="info.supplyName"
+        :rules="[{ required: true, message: '请输入物资名称', trigger: 'blur' }]"
+      >
+        <el-input v-model="formData.info.supplyName" placeholder="请输入物资名称" />
+      </el-form-item>
+      <el-form-item
+        label="规格:"
+        prop="info.specs"
+        :rules="[{ required: true, message: '请输入规格', trigger: 'blur' }]"
+      >
+        <el-input v-model="formData.info.specs" placeholder="请输入规格" />
+      </el-form-item>
+      <el-form-item
+        label="单价(元):"
+        prop="info.unitPrice"
+        :rules="[{ required: true, message: '请输入单价', trigger: 'blur' }]"
+      >
+        <el-input v-model.number="formData.info.unitPrice" placeholder="请输入单价" type="number" min="0" />
+      </el-form-item>
+      <el-form-item label="小计:" prop="info.subtotal">
+        <el-input v-model="formData.info.subtotal" placeholder="请输入小计" type="textarea" rows: 3, />
+      </el-form-item>
+      <el-form-item label="需求详情:" v-if="deptTree">
+        <AddSuppliesSubForm
+          ref="subFormRef"
+          v-for="(item, index) in formData.detailList"
+          :key="item.id"
+          :init-data="item"
+          :dept-tree="deptTree"
+          @close-sub-form="onCloseSubForm(item.id)"
+        />
+      </el-form-item>
+      <el-form-item>
+        <div class="add-supply-form-btns">
+          <el-button @click="addDetail">新增</el-button>
+        </div>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="showDrawer = false">取消</el-button>
+      <el-button type="primary" @click="handleSubmit"> 提交 </el-button>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup lang="ts">
+  import { ElDrawer, ElForm, ElMessage } from 'element-plus';
+  import { ref, reactive, onMounted, useTemplateRef } from 'vue';
+  import type { AddSupplyRequestForm, SupplyRequestDetailList } from '@/types/emergency-supplier';
+  import AddSuppliesSubForm from './AddSuppliesSubForm.vue';
+
+  import type { DeptTree } from '@/types/dept/type';
+  import { getAllDepartments } from '@/api/auth/dept';
+
+  const formRef = ref<InstanceType<typeof ElForm>>();
+  const subFormRefs = useTemplateRef('subFormRef');
+
+  const showDrawer = ref(false);
+
+  const lastDetailId = ref(0);
+
+  // 获取部门树
+  const deptTree = ref<DeptTree[]>();
+  const getDeptTreeData = async () => {
+    const res = await getAllDepartments();
+    deptTree.value = res[0].children;
+  };
+
+  // 表单数据
+  const formData = reactive<AddSupplyRequestForm>({
+    info: {},
+    detailList: [
+      {
+        id: lastDetailId.value,
+      },
+    ],
+  });
+
+  // 清理表单数据
+  const clearFormData = () => {
+    lastDetailId.value = 0;
+    formData.info = {};
+    formData.detailList = [
+      {
+        id: lastDetailId.value,
+      },
+    ];
+  };
+
+  // 打开需求列表&数据初始化
+  const openDrawer = () => {
+    // 创建时清理为初始化
+    clearFormData();
+    showDrawer.value = true;
+  };
+
+  // 表单需求详情加一项
+  const addDetail = () => {
+    lastDetailId.value += 1;
+    formData.detailList.push({
+      id: lastDetailId.value,
+    });
+  };
+
+  // 删除一项需求详情
+  const onCloseSubForm = (id: number) => {
+    if (formData.detailList.length === 1) {
+      ElMessage.warning('至少一条需求详情');
+      return;
+    }
+    formData.detailList = formData.detailList.filter((item) => item.id !== id);
+  };
+
+  // 表单校验
+  const formValidate = async () => {
+    if (!formRef.value) return;
+    if (!subFormRefs.value) return;
+    const subFormsValidateResultList = await Promise.all(subFormRefs.value.map((item) => item?.subFormValidate()));
+    const isSubFormsValidateResult = subFormsValidateResultList.every((item) => item);
+    if (!isSubFormsValidateResult) return;
+    return await formRef.value.validate();
+  };
+
+  // 提交表单
+  const handleSubmit = async () => {
+    const res = await formValidate();
+    if (!res) return;
+  };
+
+  onMounted(() => {
+    getDeptTreeData();
+  });
+
+  defineExpose({
+    openDrawer,
+  });
+</script>
+
+<style scoped>
+  .el-form {
+    display: flex;
+    flex-direction: column;
+    width: auto;
+    height: 100%;
+    gap: 24px;
+  }
+  .el-form-item {
+    margin-bottom: 0;
+  }
+  .add-supply-form-btns {
+    padding-left: 88px;
+  }
+
+  :deep(.el-form-item__label) {
+    padding: 0;
+  }
+
+  :deep(.el-form-item__content) {
+    gap: 16px;
+  }
+
+  :deep(.el-textarea__inner) {
+    padding-bottom: 20px;
+  }
+</style>

+ 115 - 0
src/views/emergency/emergency-supplies/src/components/AddSuppliesSubForm.vue

@@ -0,0 +1,115 @@
+<template>
+  <div class="add-supply-sub-form">
+    <div class="sub-form-title">
+      <img class="delete-supply" src="@/assets/icons/delete.png" alt="" @click="emits('closeSubForm')" />
+    </div>
+    <el-form ref="subFormRef" :model="subFormData" label-width="auto" class="add-supply-sub-form">
+      <el-form-item
+        label="需求部门:"
+        prop="deptId"
+        :rules="[{ required: true, message: '请选择需求部门', trigger: 'change' }]"
+      >
+        <el-cascader
+          ref="cascaderRef"
+          popper-class="cascader-popper--custom"
+          v-model="subFormData.deptId"
+          :options="deptTree"
+          :props="cascaderProp"
+          :show-all-levels="false"
+          placeholder="请选择需求部门"
+          filterable
+          @change="handleChangeDept"
+        />
+      </el-form-item>
+      <el-form-item
+        label="数量:"
+        prop="quantity"
+        :rules="[{ required: true, message: '请输入数量', trigger: 'blur' }]"
+      >
+        <el-input v-model.number="subFormData.quantity" placeholder="请输入数量" type="number" min="0" />
+      </el-form-item>
+      <el-form-item label="尺寸明细:" prop="sizeDetail">
+        <el-input v-model="subFormData.sizeDetail" placeholder="请输入尺寸明细" />
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { ElForm } from 'element-plus';
+  import { ref } from 'vue';
+  import type { AddSupplyRequestSubForm } from '@/types/emergency-supplier';
+  import type { DeptTree } from '@/types/dept/type';
+
+  const props = defineProps<{
+    initData: AddSupplyRequestSubForm;
+    deptTree: DeptTree[];
+  }>();
+
+  const emits = defineEmits<{
+    (e: 'closeSubForm'): void;
+  }>();
+
+  const cascaderRef = ref();
+  const cascaderProp = {
+    checkStrictly: true,
+    expandTrigger: 'hover',
+    value: 'id',
+    label: 'deptName',
+    emitPath: false,
+  };
+  const handleChangeDept = () => {
+    const deptInfo = cascaderRef.value?.getCheckedNodes();
+    subFormData.value.deptName = deptInfo[0].label;
+  };
+
+  const subFormRef = ref<InstanceType<typeof ElForm>>();
+  const subFormData = ref<AddSupplyRequestSubForm>(props.initData);
+
+  const subFormValidate = async () => {
+    return new Promise((resolve) => {
+      subFormRef.value?.validate((valid) => {
+        resolve(valid);
+      });
+    });
+  };
+
+  defineExpose({
+    subFormValidate,
+  });
+</script>
+
+<style scoped>
+  .add-supply-sub-form {
+    width: 100%;
+    padding: 10px;
+    border-radius: 8px;
+    background: #f0f2f5;
+  }
+  .sub-form-title {
+    text-align: end;
+    padding: 0 10px;
+  }
+  .delete-supply {
+    cursor: pointer;
+    width: 16px;
+  }
+
+  .el-form {
+    display: flex;
+    flex-direction: column;
+    width: auto;
+    height: 100%;
+    gap: 16px;
+  }
+  .el-form-item {
+    margin-bottom: 0;
+  }
+
+  :deep(.el-form-item__label) {
+    padding: 0;
+  }
+  :deep(.el-cascader) {
+    width: 100%;
+  }
+</style>