维修记录重复及价格计算优化
This commit is contained in:
parent
87deb0ceab
commit
8408fb9bac
|
|
@ -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)
|
||||
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'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
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) {
|
||||
item.repairNum = formattedValue < 0 ? 0 : formattedValue;
|
||||
|
||||
// 计算当前所有项的总和
|
||||
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 = currentTotalRepairNum.value - maxRepairNum.value;
|
||||
// 从当前修改的项中减去超出的部分
|
||||
item.repairNum = Math.max(0, item.repairNum - excess);
|
||||
|
||||
// 计算超出的部分
|
||||
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);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
Loading…
Reference in New Issue