| | |
| | | <template> |
| | | <el-dialog |
| | | v-model="visible" |
| | | :title="isEdit ? '编辑设备领用' : '新增设备领用'" |
| | | :title=" |
| | | isReturnMode ? '设备归还' : isEdit ? '编辑设备领用' : '新增设备领用' |
| | | " |
| | | width="600px" |
| | | @close="handleClose" |
| | | > |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="150px"> |
| | | <el-form-item label="领用人" prop="userId"> |
| | | <el-select v-model="form.userId" placeholder="请选择"> |
| | | <el-select |
| | | v-model="form.userId" |
| | | placeholder="请选择" |
| | | :disabled="isViewMode || isReturnMode" |
| | | @change="getEquipment" |
| | | > |
| | | <el-option |
| | | v-for="item in userList" |
| | | :key="item.userId" |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="设备名称" prop="equipmentId"> |
| | | <el-select v-model="form.equipmentId" placeholder="请选择"> |
| | | <el-select |
| | | v-model="form.equipmentId" |
| | | placeholder="请选择" |
| | | :disabled="isViewMode || isReturnMode" |
| | | > |
| | | <el-option |
| | | v-for="item in equipmentList" |
| | | :key="item.id" |
| | |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="设备库存" prop="equipmentStock"> |
| | | <el-form-item label="是否为消耗品" prop="isConsumables"> |
| | | <el-select |
| | | :model-value="currentConsumables" |
| | | placeholder="请选择是否为耗材类型" |
| | | :disabled="true" |
| | | > |
| | | <el-option label="是" :value="true" /> |
| | | <el-option label="否" :value="false" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item |
| | | label="设备库存" |
| | | prop="equipmentStock" |
| | | v-if="!isReturnMode && formData.status !== 2" |
| | | > |
| | | <el-input |
| | | :value=" |
| | | equipmentList.find((item) => item.id == form.equipmentId) |
| | |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="领用数量" prop="usageQuantity"> |
| | | <el-form-item label="已使用数量" prop="usedQuantity" v-if="isReturnMode"> |
| | | <el-input |
| | | :value="formData.usageQuantity" |
| | | disabled |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item |
| | | label="已归还数量" |
| | | prop="returnedQuantity" |
| | | v-if="isReturnMode" |
| | | > |
| | | <el-input |
| | | :value="formData.totalReturnNo || 0" |
| | | disabled |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item |
| | | label="领用数量" |
| | | prop="usageQuantity" |
| | | v-if="!isReturnMode && formData.status !== 2" |
| | | > |
| | | <el-input-number |
| | | v-model="form.usageQuantity" |
| | | :min="1" |
| | | :max="maxQuantity || 999" |
| | | style="width: 100%" |
| | | :disabled="isViewMode" |
| | | /> |
| | | <span |
| | | v-if="maxQuantity !== null" |
| | |
| | | >(最多{{ maxQuantity }}台)</span |
| | | > |
| | | </el-form-item> |
| | | <el-form-item label="使用状态" prop="equipmentStatus"> |
| | | <el-select v-model="form.equipmentStatus" placeholder="请选择"> |
| | | <el-option label="启用" :value="1" /> |
| | | <el-option label="禁用" :value="0" /> |
| | | <el-option label="维修中" :value="2" /> |
| | | <el-option label="报废" :value="3" /> |
| | | <el-option label="待领用" :value="4" /> |
| | | </el-select> |
| | | <el-form-item |
| | | label="本次归还数量" |
| | | prop="returnQuantity" |
| | | v-if="isReturnMode" |
| | | > |
| | | <el-input-number |
| | | v-model="form.returnQuantity" |
| | | :min="1" |
| | | :max="Math.max(1, remainingReturnQuantity)" |
| | | style="width: 100%" |
| | | :disabled="remainingReturnQuantity <= 0" |
| | | /> |
| | | <span |
| | | style="color: #999; font-size: 12px; margin-left: 8px" |
| | | v-if="remainingReturnQuantity > 0" |
| | | >(最多{{ remainingReturnQuantity }}台)</span |
| | | > |
| | | <span style="color: #67c23a; font-size: 12px; margin-left: 8px" v-else |
| | | >(已全部归还)</span |
| | | > |
| | | <!-- 归还完成提示 --> |
| | | <div |
| | | v-if=" |
| | | remainingReturnQuantity > 0 && |
| | | form.returnQuantity === remainingReturnQuantity |
| | | " |
| | | style="color: #67c23a; font-size: 12px; margin-top: 4px" |
| | | > |
| | | 💡 提示:本次归还后将完成全部归还 |
| | | </div> |
| | | </el-form-item> |
| | | <el-form-item label="使用开始时间" prop="usageStartTime"> |
| | | <!-- 使用开始时间 - 只在非归还模式显示 --> |
| | | <el-form-item |
| | | label="使用开始时间" |
| | | prop="usageStartTime" |
| | | v-if="!isReturnMode" |
| | | > |
| | | <el-date-picker |
| | | v-model="form.usageStartTime" |
| | | type="datetime" |
| | |
| | | style="width: 100%" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | :disabled="isViewMode" |
| | | /> |
| | | </el-form-item> |
| | | <!-- <el-form-item label="使用结束时间" prop="usageEndTime"> |
| | | |
| | | <!-- 归还结束时间 - 只在归还模式显示 --> |
| | | <el-form-item label="归还时间" prop="returnTime" v-if="isReturnMode"> |
| | | <el-date-picker |
| | | v-model="form.usageEndTime" |
| | | v-model="form.returnTime" |
| | | type="datetime" |
| | | placeholder="选择结束时间" |
| | | placeholder="选择归还时间" |
| | | style="width: 100%" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | /> |
| | | </el-form-item> --> |
| | | </el-form-item> |
| | | <el-form-item label="备注" prop="remarks"> |
| | | <el-input |
| | | v-model="form.remarks" |
| | | type="textarea" |
| | | placeholder="请输入备注" |
| | | :disabled="isViewMode" |
| | | /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="handleClose">取消</el-button> |
| | | <el-button type="primary" @click="handleSubmit">确定</el-button> |
| | | <el-button type="primary" @click="debouncedSubmit" v-if="!isViewMode" |
| | | >确定</el-button |
| | | > |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, watch, computed, onMounted } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { getEquipmentList } from "@/api/publicApi/index.js"; |
| | | import { addOrEditUsageRecord } from "@/api/equipment/requisition/index.js"; |
| | | |
| | | import useUserStore from "@/store/modules/user"; |
| | | |
| | | onMounted(() => {}); |
| | | const userStore = useUserStore(); |
| | | let userList = ref([]); |
| | | userStore.getUserList().then((res) => { |
| | |
| | | }); |
| | | // 获取设备列表 |
| | | const equipmentList = ref([]); |
| | | getEquipmentList().then((res) => { |
| | | equipmentList.value = res.data; |
| | | }); |
| | | // 获取最新数据 |
| | | const getEquipment = async () => { |
| | | try { |
| | | await getEquipmentList().then((res) => { |
| | | equipmentList.value = res.data; |
| | | }); |
| | | } catch (error) { |
| | | ElMessage.error("获取设备列表失败"); |
| | | } |
| | | }; |
| | | const props = defineProps({ |
| | | modelValue: Boolean, |
| | | formData: { |
| | | type: Object, |
| | | default: () => ({}), |
| | | }, |
| | | addOrEdit: { |
| | | type: String, |
| | | default: "add", |
| | | }, |
| | | }); |
| | | |
| | | // 默认表单初始值 |
| | | const defaultForm = { |
| | | userId: "", |
| | | equipmentId: "", |
| | | usageQuantity: 1, |
| | | usageStartTime: "", |
| | | returnQuantity: 1, |
| | | returnTime: "", |
| | | remarks: "", |
| | | }; |
| | | const form = ref({ ...defaultForm }); |
| | | |
| | | const currentConsumables = computed(() => { |
| | | const eq = equipmentList.value.find(item => item.id == form.value.equipmentId); |
| | | return eq ? !!eq.isConsumables : false; |
| | | }); |
| | | const maxQuantity = computed(() => { |
| | | if (!form.value.equipmentId) return 0; |
| | |
| | | set: (v) => emit("update:modelValue", v), |
| | | }); |
| | | |
| | | // 监听设备选择变化 |
| | | watch( |
| | | () => form.value.equipmentId, |
| | | (newId) => { |
| | | if (newId) { |
| | | const eq = equipmentList.value.find(item => item.id == newId); |
| | | } |
| | | } |
| | | ); |
| | | const isViewMode = computed( |
| | | () => props.addOrEdit === "view" || props.addOrEdit === "viewRow" |
| | | ); |
| | | |
| | | // 判断是否为归还模式 |
| | | const isReturnMode = computed(() => props.addOrEdit === "return"); |
| | | |
| | | // 计算剩余可归还数量 |
| | | const remainingReturnQuantity = computed(() => { |
| | | if (!isReturnMode.value || !props.formData.usageQuantity) return 0; |
| | | |
| | | const totalUsageQuantity = props.formData.usageQuantity || 0; // 总使用数量 |
| | | const alreadyReturnedQuantity = props.formData.totalReturnNo || 0; // 已归还数量 |
| | | const remaining = totalUsageQuantity - alreadyReturnedQuantity; // 剩余可归还数量 |
| | | |
| | | return Math.max(0, remaining); // 确保不为负数 |
| | | }); |
| | | |
| | | const isEdit = computed(() => !!props.formData?.id); |
| | | const formRef = ref(); |
| | | |
| | | // 默认表单初始值 |
| | | const defaultForm = { |
| | | userId: "", |
| | | equipmentId: "", |
| | | usageQuantity: 1, |
| | | equipmentStatus: 1, |
| | | usageStartTime: "", |
| | | remarks: "" |
| | | // 获取当前日期(YYYY-MM-DD格式) |
| | | const getCurrentDate = () => { |
| | | const now = new Date(); |
| | | const year = now.getFullYear(); |
| | | const month = String(now.getMonth() + 1).padStart(2, "0"); |
| | | const day = String(now.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | }; |
| | | const form = ref({ ...defaultForm }); |
| | | |
| | | // 确保初始化时获取设备列表 |
| | | onMounted(() => { |
| | | getEquipment(); |
| | | }); |
| | | |
| | | watch( |
| | | () => props.formData, |
| | | (val) => { |
| | | if (val && Object.keys(val).length > 0) { |
| | | form.value = { ...defaultForm, ...val }; |
| | | form.value = { ...val }; |
| | | |
| | | // 归还模式初始化 |
| | | if (isReturnMode.value) { |
| | | form.value.returnTime = getCurrentDate(); |
| | | const maxReturnQuantity = remainingReturnQuantity.value; |
| | | form.value.returnQuantity = |
| | | maxReturnQuantity > 0 ? Math.min(1, maxReturnQuantity) : 0; |
| | | } |
| | | } else { |
| | | // 新建时重置为初始值,防止脏数据 |
| | | form.value = { ...defaultForm }; |
| | | } |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | |
| | | const rules = { |
| | | userId: [{ required: true, message: "请输入领用人", trigger: "blur" }], |
| | | equipmentId: [{ required: true, message: "请输入设备ID", trigger: "blur" }], |
| | | usageQuantity: [ |
| | | { required: true, message: "请输入领用数量", trigger: "blur" }, |
| | | { type: "number", min: 1, message: "至少领用1台", trigger: "blur" }, |
| | | { |
| | | validator: (rule, value, callback) => { |
| | | if (maxQuantity.value !== null && value > maxQuantity.value) { |
| | | callback(new Error("领用数量不能大于设备数量")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | trigger: "blur", |
| | | }, |
| | | ], |
| | | equipmentStatus: [ |
| | | { required: true, message: "请选择使用状态", trigger: "change" }, |
| | | ], |
| | | usageStartTime: [ |
| | | { required: true, message: "请选择开始时间", trigger: "change" }, |
| | | ], |
| | | }; |
| | | const rules = computed(() => { |
| | | const baseRules = { |
| | | userId: [{ required: true, message: "请输入领用人", trigger: "blur" }], |
| | | equipmentId: [{ required: true, message: "请输入设备ID", trigger: "blur" }], |
| | | }; |
| | | |
| | | if (isReturnMode.value) { |
| | | // 归还模式的验证规则 |
| | | return { |
| | | ...baseRules, |
| | | returnQuantity: [ |
| | | { required: true, message: "请输入归还数量", trigger: "blur" }, |
| | | { type: "number", min: 1, message: "至少归还1台", trigger: "blur" }, |
| | | { |
| | | validator: (rule, value, callback) => { |
| | | const remaining = remainingReturnQuantity.value; |
| | | if (remaining <= 0) { |
| | | callback(new Error("已全部归还,无法继续归还")); |
| | | } else if (value > remaining) { |
| | | callback( |
| | | new Error(`归还数量不能大于剩余可归还数量(${remaining}台)`) |
| | | ); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | trigger: "blur", |
| | | }, |
| | | ], |
| | | returnTime: [ |
| | | { required: true, message: "请选择归还时间", trigger: "change" }, |
| | | ], |
| | | }; |
| | | } else { |
| | | // 新增/编辑模式的验证规则 |
| | | return { |
| | | ...baseRules, |
| | | usageQuantity: [ |
| | | { required: true, message: "请输入领用数量", trigger: "blur" }, |
| | | { type: "number", min: 1, message: "至少领用1台", trigger: "blur" }, |
| | | { |
| | | validator: (rule, value, callback) => { |
| | | if (maxQuantity.value !== null && value > maxQuantity.value) { |
| | | callback(new Error("领用数量不能大于设备数量")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | trigger: "blur", |
| | | }, |
| | | ], |
| | | usageStartTime: [ |
| | | { required: true, message: "请选择开始时间", trigger: "change" }, |
| | | ], |
| | | }; |
| | | } |
| | | }); |
| | | |
| | | function handleClose() { |
| | | emit("update:modelValue", false); |
| | | } |
| | | |
| | | // 通用防抖函数 |
| | | function debounce(fn, delay = 800) { |
| | | let timer = null; |
| | | return function (...args) { |
| | | if (timer) clearTimeout(timer); |
| | | timer = setTimeout(() => { |
| | | fn.apply(this, args); |
| | | timer = null; |
| | | }, delay); |
| | | }; |
| | | } |
| | | |
| | | // 防抖后的提交方法 |
| | | const debouncedSubmit = debounce(handleSubmit, 800); |
| | | |
| | | function handleSubmit() { |
| | | formRef.value.validate((valid) => { |
| | | formRef.value.validate(async (valid) => { |
| | | if (!valid) return; |
| | | let res = addOrEditUsageRecord(form.value); |
| | | emit("submit", { ...form.value }); |
| | | handleClose(); |
| | | |
| | | let submitData = { ...form.value }; |
| | | |
| | | // 归还模式处理 |
| | | if (isReturnMode.value) { |
| | | const currentReturnQuantity = form.value.returnQuantity; |
| | | const totalUsageQuantity = props.formData.usageQuantity; |
| | | const alreadyReturnedQuantity = props.formData.totalReturnNo || 0; |
| | | const newTotalReturnedQuantity = |
| | | alreadyReturnedQuantity + currentReturnQuantity; |
| | | |
| | | // 判断是否全部归还完成 |
| | | let equipmentStatus = 2; // 默认为部分归还 |
| | | let isFullyReturned = newTotalReturnedQuantity >= totalUsageQuantity; |
| | | |
| | | if (isFullyReturned) { |
| | | equipmentStatus = 3; // 全部归还完成 |
| | | |
| | | // 全部归还时的确认提示 |
| | | try { |
| | | await ElMessageBox.confirm( |
| | | `确认将设备"${ |
| | | props.formData.equipmentName || "未知设备" |
| | | }"全部归还吗?归还后设备状态将变为"已归还"。`, |
| | | "确认全部归还", |
| | | { |
| | | confirmButtonText: "确认归还", |
| | | cancelButtonText: "取消", |
| | | type: "success", |
| | | } |
| | | ); |
| | | } catch (error) { |
| | | if (error === "cancel") { |
| | | ElMessage.info("已取消归还操作"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | console.log("设备归还完成:", { |
| | | 设备名称: props.formData.equipmentName, |
| | | 总使用数量: totalUsageQuantity, |
| | | 新的归还总数: newTotalReturnedQuantity, |
| | | 状态: "已全部归还", |
| | | }); |
| | | } else { |
| | | console.log("设备部分归还:", { |
| | | 设备名称: props.formData.equipmentName, |
| | | 总使用数量: totalUsageQuantity, |
| | | 已归还数量: newTotalReturnedQuantity, |
| | | 剩余未归还: totalUsageQuantity - newTotalReturnedQuantity, |
| | | 状态: "部分归还", |
| | | }); |
| | | } |
| | | |
| | | submitData = { |
| | | ...props.formData, |
| | | totalReturnNo: newTotalReturnedQuantity, |
| | | returnQuantity: currentReturnQuantity, |
| | | returnTime: form.value.returnTime, |
| | | equipmentStatus: equipmentStatus, |
| | | remarks: form.value.remarks, |
| | | usageQuantity: totalUsageQuantity, |
| | | }; |
| | | } |
| | | |
| | | try { |
| | | let { code, data } = await addOrEditUsageRecord(submitData); |
| | | if (code !== 200) { |
| | | ElMessage.error(data.msg || "操作失败"); |
| | | return; |
| | | } |
| | | if (code == 200 && data == 1) { |
| | | emit("submit", submitData); |
| | | } |
| | | handleClose(); |
| | | } catch (error) { |
| | | console.error("提交失败:", error); |
| | | ElMessage.error("操作失败,请稍后再试"); |
| | | } |
| | | }); |
| | | } |
| | | </script> |