|
|
@@ -317,9 +317,43 @@
|
|
|
<el-table-column prop="device_code" label="设备编号" align="center" />
|
|
|
<!-- <el-table-column prop="device_type" label="设备分类" align="center" /> -->
|
|
|
<el-table-column prop="device_name" label="设备名称" align="center" />
|
|
|
- <el-table-column prop="borrow_count" label="借用数量" align="center" width="150">
|
|
|
+ <el-table-column label="已归还数量" width="110" align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ row.returned_quantity ?? 0 }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ v-if="showUnreturnedReturnTableColumns"
|
|
|
+ label="未归还可还"
|
|
|
+ width="110"
|
|
|
+ align="center"
|
|
|
+ >
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ row.available_quantity ?? 0 }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ v-if="showUnreturnedReturnTableColumns"
|
|
|
+ prop="borrow_count"
|
|
|
+ label="归还数量"
|
|
|
+ align="center"
|
|
|
+ width="150"
|
|
|
+ >
|
|
|
<template #default="{ row }">
|
|
|
- <el-input-number v-model="row.borrow_count" :min="1" :max="row.available_quantity" size="small" :disabled="true" />
|
|
|
+ <el-input-number
|
|
|
+ v-if="!isView && isReturnLinePendingReturn(row)"
|
|
|
+ v-model="row.borrow_count"
|
|
|
+ :min="0"
|
|
|
+ :max="(row.available_quantity ?? 0) > 0 ? (row.available_quantity ?? 0) : 0"
|
|
|
+ :disabled="(row.available_quantity ?? 0) <= 0"
|
|
|
+ size="small"
|
|
|
+ @change="() => clampReturnBorrowCount(row)"
|
|
|
+ />
|
|
|
+ <span
|
|
|
+ v-else-if="isView && isReturnLinePendingReturn(row)"
|
|
|
+ class="return-cell-text"
|
|
|
+ >{{ row.borrow_count ?? 0 }}</span>
|
|
|
+ <span v-else class="return-cell-placeholder">—</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="brand" label="品牌" align="center" />
|
|
|
@@ -553,7 +587,12 @@ interface DeviceListItem {
|
|
|
data: string;
|
|
|
}>;
|
|
|
device_specification?: string;
|
|
|
- available_quantity?:number;
|
|
|
+ /** 归还页签:可归还上限,来自 items.pending_quantity */
|
|
|
+ available_quantity?: number;
|
|
|
+ /** 截止当前已在库登记归还的数量,来自 items.returned_quantity */
|
|
|
+ returned_quantity?: number;
|
|
|
+ problem_records?: any[];
|
|
|
+ damage_type?: number;
|
|
|
}
|
|
|
|
|
|
interface FormItem {
|
|
|
@@ -879,13 +918,81 @@ const displayReturnRemark = computed({
|
|
|
}
|
|
|
});
|
|
|
|
|
|
-// 统一判定设备是否已归还
|
|
|
+/** 从借用单明细行解析待归还数量:优先用 pending_quantity,缺省时用借出-已还推算(与后端 items 一致,避免硬编码) */
|
|
|
+function getPendingUnreturnedFromItem(item: any): number {
|
|
|
+ if (item == null) return 0;
|
|
|
+ const raw = item.pending_quantity;
|
|
|
+ if (raw !== undefined && raw !== null && String(raw) !== '') {
|
|
|
+ const n = Math.floor(Number(raw));
|
|
|
+ if (!Number.isNaN(n)) return Math.max(0, n);
|
|
|
+ }
|
|
|
+ const borrowed = Number(item.borrowed_quantity) || 0;
|
|
|
+ const returned = Number(item.returned_quantity) || 0;
|
|
|
+ return Math.max(0, borrowed - returned);
|
|
|
+}
|
|
|
+
|
|
|
+/** 将 form.items 单行映射为归还列表行:上限为待归还;归还数量由扫码/手工录入,从 0 起算 */
|
|
|
+function mapFormItemToReturnDeviceListRow(item: any): DeviceListItem {
|
|
|
+ const pending = getPendingUnreturnedFromItem(item);
|
|
|
+ return {
|
|
|
+ device_no: item.device,
|
|
|
+ device_code: item.device_code,
|
|
|
+ device_type: item.remark,
|
|
|
+ device_name: item.device_name,
|
|
|
+ borrow_count: 0,
|
|
|
+ brand: item.brand || item.device_brand || '',
|
|
|
+ model: item.device_specification,
|
|
|
+ warehouse: item.location || item.device_storage_location || '',
|
|
|
+ problem_records: item.problem_records,
|
|
|
+ return_status: item.return_status,
|
|
|
+ return_time: item.return_times,
|
|
|
+ available_quantity: pending,
|
|
|
+ returned_quantity: Math.max(0, Number(item.returned_quantity) || 0)
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+function clampReturnBorrowCount(row: DeviceListItem) {
|
|
|
+ const max = row.available_quantity ?? 0;
|
|
|
+ if (max <= 0) {
|
|
|
+ row.borrow_count = 0;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let n = Number(row.borrow_count) || 0;
|
|
|
+ if (n < 0) n = 0;
|
|
|
+ if (n > max) n = max;
|
|
|
+ row.borrow_count = n;
|
|
|
+}
|
|
|
+
|
|
|
+/** 是否仍有待归还(有未归还可还):用于表格列在「只展示已归还」与「展示待还+本次归还」间切换 */
|
|
|
+function isReturnLinePendingReturn(row: DeviceListItem) {
|
|
|
+ return (Number(row.available_quantity) || 0) > 0;
|
|
|
+}
|
|
|
+
|
|
|
+/** 扫码命中列表中的设备时:归还数量 +1,不超过待归还数 available_quantity */
|
|
|
+function applyReturnScanIncrement(row: DeviceListItem): boolean {
|
|
|
+ const cap = row.available_quantity ?? 0;
|
|
|
+ if (cap <= 0) {
|
|
|
+ ElMessage.warning('该设备无待归还数量');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const current = Number(row.borrow_count) || 0;
|
|
|
+ if (current >= cap) {
|
|
|
+ ElMessage.warning('该设备归还数量已达待归还上限');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ row.borrow_count = current + 1;
|
|
|
+ if (row.borrow_count >= cap) {
|
|
|
+ row.is_return = true;
|
|
|
+ row.return_time = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+// 统一判定「该明细是否已把本次可归还数记满」:用于选设备白名单/全部完成判断(不依赖硬编码业务状态值)
|
|
|
const isDeviceReturned = (device: any) => {
|
|
|
- if (device?.is_return === true) return true;
|
|
|
- const rs = device?.return_status;
|
|
|
- if (rs && (rs.value === 2 || rs.label === '已归还')) return true;
|
|
|
- if (device?.status === '已归还') return true;
|
|
|
- return false;
|
|
|
+ const cap = Number(device?.available_quantity) || 0;
|
|
|
+ if (cap <= 0) return true;
|
|
|
+ return (Number(device?.borrow_count) || 0) >= cap;
|
|
|
};
|
|
|
|
|
|
// 过滤未归还设备的 device_no 列表,用于设备选择弹窗的排除
|
|
|
@@ -898,6 +1005,11 @@ const unreturnedDeviceIds = computed(() =>
|
|
|
// 是否全部已归还(仅在归还页签生效)
|
|
|
const allReturned = computed(() => unreturnedDeviceIds.value.length === 0);
|
|
|
|
|
|
+/** 列表中是否仍有「待归还」行:为 false 时整表隐藏「未归还可还」「归还数量」两列(仅保留已归还数量等) */
|
|
|
+const showUnreturnedReturnTableColumns = computed(() =>
|
|
|
+ returnDeviceList.value.some((d) => (Number(d.available_quantity) || 0) > 0)
|
|
|
+);
|
|
|
+
|
|
|
//审批步骤
|
|
|
const steps = ref<any[]>([]);
|
|
|
// 仓库映射(id -> name)
|
|
|
@@ -1948,19 +2060,6 @@ const handleScanSearch = async (event?: Event) => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-const normalizeReturnStatus = (status?: { value?: number | string; label?: string }) => {
|
|
|
- const candidate = status?.value;
|
|
|
- const numericValue =
|
|
|
- candidate === undefined || candidate === null || candidate === ''
|
|
|
- ? 2
|
|
|
- : Number(candidate);
|
|
|
-
|
|
|
- return {
|
|
|
- value: Number.isNaN(numericValue) ? 2 : numericValue,
|
|
|
- label: status?.label || '已归还'
|
|
|
- };
|
|
|
-};
|
|
|
-
|
|
|
// 处理归还流程RFID标签数组,逐个检索并提交
|
|
|
const processReturnRfidTagArray = async () => {
|
|
|
if (returnRfidTagArray.value.length === 0 || isProcessingReturnTagArray.value) return;
|
|
|
@@ -2064,15 +2163,13 @@ const processReturnRfidTagArray = async () => {
|
|
|
|
|
|
if (res.data && res.data.length > 0) {
|
|
|
const device = res.data[0];
|
|
|
- const normalizedStatus = normalizeReturnStatus(device.return_status);
|
|
|
-
|
|
|
// 检查是否已存在
|
|
|
const existingDeviceIndex = returnDeviceList.value.findIndex(d => d.device_no === device.id);
|
|
|
if (existingDeviceIndex !== -1) {
|
|
|
- // 如果设备已存在,更新其状态
|
|
|
- returnDeviceList.value[existingDeviceIndex].return_status = normalizedStatus;
|
|
|
- returnDeviceList.value[existingDeviceIndex].is_return = true;
|
|
|
- returnDeviceList.value[existingDeviceIndex].return_time = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
|
|
+ const row = returnDeviceList.value[existingDeviceIndex];
|
|
|
+ if (!applyReturnScanIncrement(row)) {
|
|
|
+ return { success: false, code, message: '归还数量未增加(已达待归还上限或无待还)' };
|
|
|
+ }
|
|
|
return { success: true, code };
|
|
|
} else {
|
|
|
// 设备不存在于归还列表中
|
|
|
@@ -2127,17 +2224,17 @@ const processReturnRfidTagArray = async () => {
|
|
|
|
|
|
if (uniqueCodes.length > 1) {
|
|
|
if (successCount > 0 && failCount === 0) {
|
|
|
- ElMessage.success(`标签 ${trimmedTag}: 成功更新 ${successCount} 个设备状态为已归还`);
|
|
|
+ ElMessage.success(`标签 ${trimmedTag}: 成功增加 ${successCount} 个设备的归还数量`);
|
|
|
} else if (successCount > 0 && failCount > 0) {
|
|
|
- ElMessage.warning(`标签 ${trimmedTag}: 成功更新 ${successCount} 个设备状态,失败 ${failCount} 个`);
|
|
|
+ ElMessage.warning(`标签 ${trimmedTag}: 成功增加 ${successCount} 个设备的归还数量,失败 ${failCount} 个`);
|
|
|
if (errorMessages.length > 0) {
|
|
|
console.warn('[processReturnRfidTagArray] 批量处理错误详情:', errorMessages.slice(0, 3));
|
|
|
}
|
|
|
} else if (failCount > 0) {
|
|
|
- ElMessage.error(`标签 ${trimmedTag}: 更新失败,共 ${failCount} 个设备编号`);
|
|
|
+ ElMessage.error(`标签 ${trimmedTag}: 处理失败,共 ${failCount} 个设备编号`);
|
|
|
}
|
|
|
} else if (successCount > 0) {
|
|
|
- ElMessage.success(`标签 ${trimmedTag}: 设备状态已更新为已归还`);
|
|
|
+ ElMessage.success(`标签 ${trimmedTag}: 已增加 1 个归还数量`);
|
|
|
} else if (failCount > 0 && errorMessages.length > 0) {
|
|
|
ElMessage.warning(`标签 ${trimmedTag}: ${errorMessages[0]}`);
|
|
|
}
|
|
|
@@ -2715,15 +2812,12 @@ const handleReturnScanSearch = async (event?: Event) => {
|
|
|
|
|
|
if (res.data && res.data.length > 0) {
|
|
|
const device = res.data[0];
|
|
|
- const normalizedStatus = normalizeReturnStatus(device.return_status);
|
|
|
-
|
|
|
- // 检查是否已存在
|
|
|
const existingDeviceIndex = returnDeviceList.value.findIndex(d => d.device_no === device.id);
|
|
|
if (existingDeviceIndex !== -1) {
|
|
|
- // 如果设备已存在,更新其状态
|
|
|
- returnDeviceList.value[existingDeviceIndex].return_status = normalizedStatus;
|
|
|
- returnDeviceList.value[existingDeviceIndex].is_return = true;
|
|
|
- returnDeviceList.value[existingDeviceIndex].return_time = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
|
|
+ const row = returnDeviceList.value[existingDeviceIndex];
|
|
|
+ if (!applyReturnScanIncrement(row)) {
|
|
|
+ return { success: false, code, message: '归还数量未增加(已达待归还上限或无待还)' };
|
|
|
+ }
|
|
|
return { success: true, code };
|
|
|
} else {
|
|
|
// 设备不存在于归还列表中
|
|
|
@@ -2767,18 +2861,18 @@ const handleReturnScanSearch = async (event?: Event) => {
|
|
|
// 显示批量处理结果
|
|
|
if (uniqueCodes.length > 1) {
|
|
|
if (successCount > 0 && failCount === 0) {
|
|
|
- ElMessage.success(`成功更新 ${successCount} 个设备状态为已归还`);
|
|
|
+ ElMessage.success(`成功增加 ${successCount} 个设备的归还数量`);
|
|
|
} else if (successCount > 0 && failCount > 0) {
|
|
|
- ElMessage.warning(`成功更新 ${successCount} 个设备状态,失败 ${failCount} 个`);
|
|
|
+ ElMessage.warning(`成功增加 ${successCount} 个设备的归还数量,失败 ${failCount} 个`);
|
|
|
// 只显示前3个错误信息,避免消息过多
|
|
|
if (errorMessages.length > 0) {
|
|
|
console.warn('批量处理错误详情:', errorMessages.slice(0, 3));
|
|
|
}
|
|
|
} else if (failCount > 0) {
|
|
|
- ElMessage.error(`更新失败,共 ${failCount} 个设备编号`);
|
|
|
+ ElMessage.error(`处理失败,共 ${failCount} 个设备编号`);
|
|
|
}
|
|
|
} else if (successCount > 0) {
|
|
|
- ElMessage.success('设备状态已更新为已归还');
|
|
|
+ ElMessage.success('已增加 1 个归还数量');
|
|
|
} else if (failCount > 0 && errorMessages.length > 0) {
|
|
|
ElMessage.warning(errorMessages[0]);
|
|
|
}
|
|
|
@@ -2936,17 +3030,24 @@ function onDeviceSelected(devices: Device[]) {
|
|
|
}))
|
|
|
);
|
|
|
}else if(activeName.value === 'third'){
|
|
|
- // 在添加前检查每个设备是否已存在
|
|
|
+ // 在添加前检查每个设备是否已存在;手动选设备:将本次归还数量记满至「待归还」上限
|
|
|
devices.forEach(d => {
|
|
|
const existingDeviceIndex = returnDeviceList.value.findIndex(item => item.device_no === d.id);
|
|
|
if (existingDeviceIndex !== -1) {
|
|
|
- // 如果设备已存在,更新其状态
|
|
|
- returnDeviceList.value[existingDeviceIndex].return_status.value = 2;
|
|
|
- returnDeviceList.value[existingDeviceIndex].return_status.label = '已归还';
|
|
|
- returnDeviceList.value[existingDeviceIndex].is_return = true;
|
|
|
- returnDeviceList.value[existingDeviceIndex].return_time = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
|
|
- returnDeviceList.value[existingDeviceIndex].brand = d.brand || '';
|
|
|
- ElMessage.success(`设备 ${d.category_name} 状态已更新为已归还`);
|
|
|
+ const row = returnDeviceList.value[existingDeviceIndex];
|
|
|
+ const cap = row.available_quantity ?? 0;
|
|
|
+ if (cap <= 0) {
|
|
|
+ ElMessage.warning('该设备无待归还数量');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ row.borrow_count = cap;
|
|
|
+ row.is_return = true;
|
|
|
+ row.return_time = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
|
|
+ row.brand = d.brand || row.brand || '';
|
|
|
+ if (row.return_status) {
|
|
|
+ row.return_status = { value: 2, label: '已归还' };
|
|
|
+ }
|
|
|
+ ElMessage.success(`已将该设备本次归还记为 ${cap} 件`);
|
|
|
} else {
|
|
|
// 如果设备不存在,添加新记录
|
|
|
/* returnDeviceList.value.push({
|
|
|
@@ -3168,22 +3269,9 @@ watch(() => props.modelValue, async (val) => {
|
|
|
|
|
|
// 同步 form.items 到 returnDeviceList
|
|
|
if (form.value.items && form.value.items.length > 0) {
|
|
|
- returnDeviceList.value = form.value.items
|
|
|
- .filter(item => item.device !== null)
|
|
|
- .map(item => ({
|
|
|
- device_no: item.device,
|
|
|
- device_code: item.device_code,
|
|
|
- device_type: item.remark,
|
|
|
- device_name: item.device_name,
|
|
|
- borrow_count: item.quantity,
|
|
|
- brand: item.brand ||item.device_brand || '',
|
|
|
- model: item.device_specification,
|
|
|
- warehouse: item.location,
|
|
|
- problem_records: item.problem_records,
|
|
|
- /* status: '未归还' */
|
|
|
- return_status:item.return_status,
|
|
|
- return_time:item.return_times
|
|
|
- }));
|
|
|
+ returnDeviceList.value = (form.value.items as any[])
|
|
|
+ .filter((item) => item.device !== null)
|
|
|
+ .map(mapFormItemToReturnDeviceListRow);
|
|
|
}
|
|
|
// 同步 form.records 到 returnAbnormalList
|
|
|
if (form.value.records && form.value.records.length > 0) {
|
|
|
@@ -3192,7 +3280,7 @@ watch(() => props.modelValue, async (val) => {
|
|
|
application_no: form.value.application_no,
|
|
|
operator_name: form.value.app_user_borrower?.name||form.value.external_borrower_name||'',
|
|
|
user_code: form.value.borrower_info?.user_code || form.value.app_user_borrower?.user_code||'',
|
|
|
- emergency_phone: form.value.external_borrower_phone || form.value.app_user_borrower?.mobile||'',
|
|
|
+ emergency_phone: form.value.app_user_borrower?.mobile||form.value.external_borrower_phone || '',
|
|
|
type: '损坏',
|
|
|
condition: form.value.borrower_damage_count || 0,
|
|
|
create_time: dayjs().format('YYYY-MM-DD HH:mm:ss')
|
|
|
@@ -3203,7 +3291,7 @@ watch(() => props.modelValue, async (val) => {
|
|
|
application_no: form.value.application_no,
|
|
|
operator_name: form.value.app_user_borrower?.name||form.value.external_borrower_name||'',
|
|
|
user_code: form.value.borrower_info?.user_code || form.value.app_user_borrower?.user_code||'',
|
|
|
- emergency_phone: form.value.external_borrower_phone || form.value.app_user_borrower?.mobile||'',
|
|
|
+ emergency_phone: form.value.app_user_borrower?.mobile||form.value.external_borrower_phone || '',
|
|
|
type: '逾期',
|
|
|
condition: form.value.borrower_overdue_count || 0, // 逾期数量设为1
|
|
|
create_time: dayjs().format('YYYY-MM-DD HH:mm:ss')
|
|
|
@@ -3256,20 +3344,9 @@ watch(() => props.modelValue, async (val) => {
|
|
|
|
|
|
// 同步 form.items 到 returnDeviceList
|
|
|
if (form.value.items && form.value.items.length > 0) {
|
|
|
- returnDeviceList.value = form.value.items
|
|
|
- .filter(item => item.device !== null)
|
|
|
- .map(item => ({
|
|
|
- device_no: item.device,
|
|
|
- device_type: item.remark,
|
|
|
- device_name: item.device_name,
|
|
|
- borrow_count: item.quantity,
|
|
|
- brand: item.brand ||item.device_brand || '',
|
|
|
- model: item.device_specification,
|
|
|
- warehouse: item.location,
|
|
|
- problem_records: item.problem_records,
|
|
|
- return_status:item.return_status,
|
|
|
- return_time:item.return_times
|
|
|
- }));
|
|
|
+ returnDeviceList.value = (form.value.items as any[])
|
|
|
+ .filter((item) => item.device !== null)
|
|
|
+ .map(mapFormItemToReturnDeviceListRow);
|
|
|
}
|
|
|
|
|
|
// 处理附件回显 (编辑模式)
|
|
|
@@ -3498,19 +3575,29 @@ function onSubmit() {
|
|
|
}
|
|
|
});
|
|
|
} else {
|
|
|
- // 归还逻辑修改
|
|
|
- // 使用所有设备列表而不是选中的设备
|
|
|
- const allDevices = returnDeviceList.value
|
|
|
- .filter(item => item.is_return === true) // 只选择 return_status 为 2 的设备
|
|
|
- .map(item => ({
|
|
|
+ // 归还:按每行「归还数量」提交,须大于 0 且不超过待归还
|
|
|
+ const toReturn = returnDeviceList.value.filter(
|
|
|
+ (item) => (Number(item.borrow_count) || 0) > 0
|
|
|
+ );
|
|
|
+ if (toReturn.length === 0) {
|
|
|
+ ElMessage.warning('请通过扫码/输入填写归还数量,或从手动归还中确认设备');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const over = toReturn.find(
|
|
|
+ (item) => (Number(item.borrow_count) || 0) > (Number(item.available_quantity) || 0)
|
|
|
+ );
|
|
|
+ if (over) {
|
|
|
+ ElMessage.error('存在归还数量超过待归还数量,请检查');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const allDevices = toReturn.map((item) => ({
|
|
|
device: item.device_no,
|
|
|
quantity: item.borrow_count,
|
|
|
remark: returnRemark.value,
|
|
|
device_id: Number(item.device_no) || 0,
|
|
|
- // 添加异常相关字段
|
|
|
- condition: item.condition, // 异常说明
|
|
|
- damage_type:item.damage_type,
|
|
|
- photo_urls: item.photos || [], // 异常照片
|
|
|
+ condition: item.condition,
|
|
|
+ damage_type: item.damage_type,
|
|
|
+ photo_urls: item.photos || [],
|
|
|
}));
|
|
|
|
|
|
const submitData = {
|
|
|
@@ -3618,6 +3705,12 @@ onBeforeUnmount(() => {
|
|
|
height: 178px;
|
|
|
display: block;
|
|
|
}
|
|
|
+ .return-cell-placeholder {
|
|
|
+ color: #c0c4cc;
|
|
|
+ }
|
|
|
+ .return-cell-text {
|
|
|
+ color: #606266;
|
|
|
+ }
|
|
|
.device-code-input {
|
|
|
padding: 8px 12px;
|
|
|
font-size: 14px;
|