diff --git a/src/pages/repair/equipAssessment/batch-repair.vue b/src/pages/repair/equipAssessment/batch-repair.vue index 344013f..36550d6 100644 --- a/src/pages/repair/equipAssessment/batch-repair.vue +++ b/src/pages/repair/equipAssessment/batch-repair.vue @@ -431,9 +431,13 @@ const saveCode = () => { } //维修完成请求 const saveCodeApi = async () => { + uni.showLoading({ + title: '提交中...', + mask: true + }) + try { //请求接口 rowData.value.repairDeviceList = queryParams.value.selectedDevices - console.log("llllllllllllllll",queryParams.value) // 遍历所有设备列表项,为每一项设置相同的值 for (let i = 0; i < rowData.value.repairDeviceList.length; i++) { // 设置维修人员信息 @@ -462,15 +466,30 @@ const saveCodeApi = async () => { rowData.value.repairDeviceList[i].repairType = 1; } console.log(rowData.value.repairDeviceList) - saveLossAssessmentRow(rowData.value.repairDeviceList).then(async (response) => { - console.log("uuuuuuuuuuu",response) - if (response.code == 200) { - uni.showToast({ title: '定损成功', icon: 'none' }) - uni.navigateBack({ - delta: 2, // 返回到已存在的页面 - }) - } - }) + const response = await saveLossAssessmentRow(rowData.value.repairDeviceList) + // 隐藏Loading + uni.hideLoading() + if (response.code == 200) { + uni.showToast({ title: '定损成功', icon: 'none' }) + uni.navigateBack({ + delta: 2, // 返回到已存在的页面 + }) + } else { + uni.showToast({ + title: response.msg || '提交失败', + icon: 'none' + }) + } + } catch (error) { + // 隐藏Loading + uni.hideLoading() + + console.error('定损提交失败:', error) + uni.showToast({ + title: '网络错误,请重试', + icon: 'none' + }) + } } diff --git a/src/pages/repair/equipAssessment/num-operate.vue b/src/pages/repair/equipAssessment/num-operate.vue index 32a494e..a5e184e 100644 --- a/src/pages/repair/equipAssessment/num-operate.vue +++ b/src/pages/repair/equipAssessment/num-operate.vue @@ -226,6 +226,83 @@ import { decryptWithSM4, encryptWithSM4, hashWithSM3AndSalt } from '@/utils/sm' import PreviewImg from '@/components/PreviewImg/index.vue' // const query = defineProps() // 获取上级页面传递的路由参数 // const queryParams = JSON.parse(query.queryParams) + +// 浮点数运算辅助函数 +const floatUtils = { + // 加法,避免精度问题 + add: (...nums) => { + return parseFloat(nums.reduce((sum, num) => { + const value = Number(num || 0); + if (isNaN(value)) return sum; + return parseFloat((sum + value).toFixed(6)); + }, 0).toFixed(6)); + }, + + // 减法,避免精度问题 + subtract: (a, b) => { + const aVal = Number(a || 0); + const bVal = Number(b || 0); + if (isNaN(aVal) || isNaN(bVal)) return 0; + return parseFloat((aVal - bVal).toFixed(6)); + }, + + // 比较是否相等(考虑浮点数误差) + isEqual: (a, b) => { + const aVal = Number(a); + const bVal = Number(b); + if (isNaN(aVal) || isNaN(bVal)) return false; + return Math.abs(aVal - bVal) < 1e-10; + }, + + // 格式化数字,避免极小值 + format: (num) => { + const value = Number(num); + if (isNaN(value)) return 0; + const formatted = parseFloat(value.toFixed(6)); + return Math.abs(formatted) < 1e-10 ? 0 : formatted; + }, + + // 乘法,避免精度问题 + multiply: (a, b) => { + const aVal = Number(a || 0); + const bVal = Number(b || 0); + if (isNaN(aVal) || isNaN(bVal)) return 0; + return parseFloat((aVal * bVal).toFixed(6)); + }, + + // 检查数值是否为空或0 + isEmptyOrZero: (num) => { + const value = Number(num); + if (isNaN(value)) return true; + return Math.abs(value) < 1e-10; + }, + + // 检查数值是否为空 + isEmpty: (num) => { + // 检查是否为 null 或 undefined + if (num === null || num === undefined) { + return true; + } + + // 检查是否为空字符串 + if (typeof num === 'string' && num.trim() === '') { + return true; + } + + // 转换为数字 + const value = Number(num); + + // 检查是否为 NaN + if (isNaN(value)) { + return true; + } + + // 检查是否为 0(根据需求,0 可能视为空或非空) + // 这里返回 false,因为 0 是一个有效的数字值 + return false; + }, +}; + const queryParams = ref({}) const rowData = ref({}) onLoad((options) => { @@ -429,6 +506,53 @@ const deleteImage2 = (index) => { fileData.value.fileList.splice(index, 1) } +// 验证配件数据 +const validateParts = () => { + let isValid = true; + let errorMessage = ""; + + for (let i = 0; i < partItems.value.length; i++) { + const item = partItems.value[i]; + + // 检查配件单价不为空时,配件数量不能为空或0 + const partPrice = floatUtils.format(item.partPrice); + const partNum = floatUtils.format(item.partNum); + + // 如果配件单价有值(不为0) + if (!floatUtils.isEmptyOrZero(partPrice)) { + // 配件数量为空或0 + if (floatUtils.isEmptyOrZero(partNum)) { + isValid = false; + errorMessage = `第${i + 1}行配件单价已填写,请填写配件数量!`; + break; + } + } + + // 如果配件数量有值(不为0) + if (!floatUtils.isEmptyOrZero(partNum)) { + // 配件单价为空或0 + if (floatUtils.isEmpty(partPrice)) { + isValid = false; + errorMessage = `第${i + 1}行配件数量已填写,请填写配件单价!`; + break; + } + } + + // // 检查配件类型是否选择(如果配件数量或单价有值) + // if ((!floatUtils.isEmptyOrZero(partNum) || !floatUtils.isEmptyOrZero(partPrice)) && !item.partId) { + // isValid = false; + // errorMessage = `第${i + 1}行请选择配件类型!`; + // break; + // } + } + + if (!isValid) { + uni.showToast({ title: errorMessage, icon: 'none' }); + } + + return isValid; +} + //数量维修保存 const saveNumAll = async () => { @@ -445,6 +569,16 @@ const saveNumAll = async () => { // uni.showToast({ title: '存在配件数量为 0 的项,请检查!', icon: 'none' }) // } else { + // 验证配件数据 + if (!validateParts()) { + return; + } + + uni.showLoading({ + title: '提交中...', + mask: true + }) + try { //维修人员 rowData.value.repairDeviceList[0].repairList=[ { @@ -464,61 +598,135 @@ const saveNumAll = async () => { }) } console.log("yyyyyyyyyy",rowData.value) - saveLossAssessmentRow(rowData.value.repairDeviceList).then(async (response) => { - console.log("yxxxxxyyyy",response) - if (response.code === 200) { - uni.showToast({ title: '定损成功', icon: 'none' }) - setTimeout(() => { - uni.navigateBack({ - delta: 1, // 返回到已存在的页面 - }) - }, 1000) - } - }) + const response = await saveLossAssessmentRow(rowData.value.repairDeviceList) + // 隐藏Loading + uni.hideLoading() + if (response.code == 200) { + uni.showToast({ title: '定损成功', icon: 'none' }) + setTimeout(() => { + uni.navigateBack({ + delta: 1, // 返回到已存在的页面 + }) + }, 1000) + } else { + uni.showToast({ + title: response.msg || '提交失败', + icon: 'none' + }) + } + // saveLossAssessmentRow(rowData.value.repairDeviceList).then(async (response) => { + // console.log("yxxxxxyyyy",response) + // if (response.code === 200) { + // uni.showToast({ title: '定损成功', icon: 'none' }) + // setTimeout(() => { + // uni.navigateBack({ + // delta: 1, // 返回到已存在的页面 + // }) + // }, 1000) + // } + // }) + } catch (error) { + // 隐藏Loading + uni.hideLoading() + + console.error('定损提交失败:', error) + uni.showToast({ + title: '网络错误,请重试', + icon: 'none' + }) + } } } // 计算可使用的最大定损数量 +// const maxRepairNum = computed(() => { +// return queryParams.value.typeRepairNum - queryParams.value.typeRepairedNum - queryParams.value.typeScrapNum; +// }); + const maxRepairNum = computed(() => { - return queryParams.value.typeRepairNum - queryParams.value.typeRepairedNum - queryParams.value.typeScrapNum; + const total = floatUtils.subtract( + queryParams.value.typeRepairNum, + floatUtils.add(queryParams.value.typeRepairedNum, queryParams.value.typeScrapNum) + ); + return floatUtils.format(total); }); // 计算当前所有定损数量之和 +// const currentTotalRepairNum = computed(() => { +// let total = 0; +// partItems.value.forEach(item => { +// total += Number(item.repairNum) || 0; +// }); +// return total; +// }); + const currentTotalRepairNum = computed(() => { - let total = 0; - partItems.value.forEach(item => { - total += Number(item.repairNum) || 0; - }); - return total; + return partItems.value.reduce((sum, item) => { + return floatUtils.add(sum, item.repairNum || 0); + }, 0); }); + // 数量框change事件 const repairCheckNum1 = (index) => { setTimeout(() => { const item = partItems.value[index]; - if (queryParams.value.unitValue === 1) { - item.repairNum = Number(String(item.repairNum).replace(/[^\d.]/g, '')); - } else { - item.repairNum = Number(String(item.repairNum).replace(/[^\d]/g, '')); - } - if (Number(item.repairNum) < 0) { - item.repairNum = 0; - } + // 使用辅助函数格式化输入值 + const originalValue = item.repairNum; + const cleanedValue = Number(String(originalValue).replace(/[^\d.]/g, '')); + const formattedValue = floatUtils.format(cleanedValue); - if (currentTotalRepairNum.value > maxRepairNum.value) { - uni.showToast({ - title: '已达到当前物资最大定损数量!', - icon: 'none', - }); - // 计算需要减少的数量 - const excess = currentTotalRepairNum.value - maxRepairNum.value; - // 从当前修改的项中减去超出的部分 - item.repairNum = Math.max(0, item.repairNum - excess); - } + item.repairNum = formattedValue < 0 ? 0 : formattedValue; - // 重新计算费用合计 - calculateCostAll(); + // 计算当前所有项的总和 + const currentTotal = partItems.value.reduce((sum, it, idx) => { + const value = idx === index ? item.repairNum : (it.repairNum || 0); + return floatUtils.add(sum, value); + }, 0); + + const maxNum = maxRepairNum.value; + if (currentTotal > maxNum && !floatUtils.isEqual(currentTotal, maxNum)) { + uni.showToast({ + title: '已达到当前物资最大定损数量!', + icon: 'none', + }); + + // 计算超出的部分 + const excess = floatUtils.subtract(currentTotal, maxNum); + + // 从当前项中减去超出的部分 + const newValue = floatUtils.format( + floatUtils.subtract(item.repairNum, excess) + ); + + // 确保新值不会变成负数 + item.repairNum = Math.max(0, newValue); + } + + // 重新计算费用合计 + calculateCostAll(); + + + + // item.repairNum = Number(String(item.repairNum).replace(/[^\d.]/g, '')); + // if (Number(item.repairNum) < 0) { + // item.repairNum = 0; + // } + // + // if (currentTotalRepairNum.value > maxRepairNum.value) { + // uni.showToast({ + // title: '已达到当前物资最大定损数量!', + // icon: 'none', + // }); + // // 计算需要减少的数量 + // const excess = currentTotalRepairNum.value - maxRepairNum.value; + // // 从当前修改的项中减去超出的部分 + // item.repairNum = Math.max(0, item.repairNum - excess); + // } + // + // // 重新计算费用合计 + // calculateCostAll(); }, 500); }; diff --git a/src/pages/repair/repairManage/num-operate.vue b/src/pages/repair/repairManage/num-operate.vue index 5ebb15f..8e2c5e9 100644 --- a/src/pages/repair/repairManage/num-operate.vue +++ b/src/pages/repair/repairManage/num-operate.vue @@ -744,6 +744,55 @@ const saveNumAll = async () => { return } + // ======= 新增:配件校验逻辑 ======= + // 1. 校验内部维修配件:配件不为空时,数量必须大于0 + let isPartValid = true; + for (let i = 0; i < partItems.value.length; i++) { + const item = partItems.value[i]; + // 修复点:先转为字符串再去空格,避免非字符串类型调用trim()报错 + const partIdStr = String(item.partId || ''); + // 判断配件是否不为空(先转字符串去空格,再判断是否非空) + const isPartNotEmpty = partIdStr.trim() !== ''; + // 配件数量(转数字,空值默认0) + const partNum = Number(item.partNum) || 0; + + // 校验规则:配件不为空 → 数量必须大于0 + if (isPartNotEmpty && partNum <= 0) { + uni.showToast({ title: `内部维修第${i+1}个配件数量必须大于0!`, icon: 'none' }) + isPartValid = false; + break; // 发现错误立即终止循环 + } + } +// 内部维修配件校验失败,直接返回 + if (!isPartValid) { + loading.value = false; + return; + } + + // 2. 校验返厂维修配件:配件不为空时,数量必须大于0 + let isMidPartValid = true; + for (let i = 0; i < partItemsMiddle.value.length; i++) { + const item = partItemsMiddle.value[i]; + // 优化点:同样先转为字符串再去空格,提升健壮性 + const partNameStr = String(item.partName || ''); + // 判断配件是否不为空 + const isPartNotEmpty = partNameStr.trim() !== ''; + // 配件数量(转数字,空值默认0) + const partNum = Number(item.partNum) || 0; + + // 校验规则:配件不为空 → 数量必须大于0 + if (isPartNotEmpty && partNum <= 0) { + uni.showToast({ title: `返厂维修第${i+1}个配件数量必须大于0!`, icon: 'none' }) + isMidPartValid = false; + break; // 发现错误立即终止循环 + } + } +// 返厂维修配件校验失败,直接返回 + if (!isMidPartValid) { + loading.value = false; + return; + } + // ======= 数据组装 ======= rowData.value.repairDeviceList[0].repairList = [ { repairer: repairPerson.value }