维修记录重复及价格计算优化
This commit is contained in:
parent
87deb0ceab
commit
8408fb9bac
|
|
@ -431,9 +431,13 @@ const saveCode = () => {
|
||||||
}
|
}
|
||||||
//维修完成请求
|
//维修完成请求
|
||||||
const saveCodeApi = async () => {
|
const saveCodeApi = async () => {
|
||||||
|
uni.showLoading({
|
||||||
|
title: '提交中...',
|
||||||
|
mask: true
|
||||||
|
})
|
||||||
|
try {
|
||||||
//请求接口
|
//请求接口
|
||||||
rowData.value.repairDeviceList = queryParams.value.selectedDevices
|
rowData.value.repairDeviceList = queryParams.value.selectedDevices
|
||||||
console.log("llllllllllllllll",queryParams.value)
|
|
||||||
// 遍历所有设备列表项,为每一项设置相同的值
|
// 遍历所有设备列表项,为每一项设置相同的值
|
||||||
for (let i = 0; i < rowData.value.repairDeviceList.length; i++) {
|
for (let i = 0; i < rowData.value.repairDeviceList.length; i++) {
|
||||||
// 设置维修人员信息
|
// 设置维修人员信息
|
||||||
|
|
@ -462,15 +466,30 @@ const saveCodeApi = async () => {
|
||||||
rowData.value.repairDeviceList[i].repairType = 1;
|
rowData.value.repairDeviceList[i].repairType = 1;
|
||||||
}
|
}
|
||||||
console.log(rowData.value.repairDeviceList)
|
console.log(rowData.value.repairDeviceList)
|
||||||
saveLossAssessmentRow(rowData.value.repairDeviceList).then(async (response) => {
|
const response = await saveLossAssessmentRow(rowData.value.repairDeviceList)
|
||||||
console.log("uuuuuuuuuuu",response)
|
// 隐藏Loading
|
||||||
|
uni.hideLoading()
|
||||||
if (response.code == 200) {
|
if (response.code == 200) {
|
||||||
uni.showToast({ title: '定损成功', icon: 'none' })
|
uni.showToast({ title: '定损成功', icon: 'none' })
|
||||||
uni.navigateBack({
|
uni.navigateBack({
|
||||||
delta: 2, // 返回到已存在的页面
|
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'
|
import PreviewImg from '@/components/PreviewImg/index.vue'
|
||||||
// const query = defineProps() // 获取上级页面传递的路由参数
|
// const query = defineProps() // 获取上级页面传递的路由参数
|
||||||
// const queryParams = JSON.parse(query.queryParams)
|
// 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 queryParams = ref({})
|
||||||
const rowData = ref({})
|
const rowData = ref({})
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
|
|
@ -429,6 +506,53 @@ const deleteImage2 = (index) => {
|
||||||
fileData.value.fileList.splice(index, 1)
|
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 () => {
|
const saveNumAll = async () => {
|
||||||
|
|
@ -445,6 +569,16 @@ const saveNumAll = async () => {
|
||||||
// uni.showToast({ title: '存在配件数量为 0 的项,请检查!', icon: 'none' })
|
// uni.showToast({ title: '存在配件数量为 0 的项,请检查!', icon: 'none' })
|
||||||
// }
|
// }
|
||||||
else {
|
else {
|
||||||
|
// 验证配件数据
|
||||||
|
if (!validateParts()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.showLoading({
|
||||||
|
title: '提交中...',
|
||||||
|
mask: true
|
||||||
|
})
|
||||||
|
try {
|
||||||
//维修人员
|
//维修人员
|
||||||
rowData.value.repairDeviceList[0].repairList=[
|
rowData.value.repairDeviceList[0].repairList=[
|
||||||
{
|
{
|
||||||
|
|
@ -464,61 +598,135 @@ const saveNumAll = async () => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
console.log("yyyyyyyyyy",rowData.value)
|
console.log("yyyyyyyyyy",rowData.value)
|
||||||
saveLossAssessmentRow(rowData.value.repairDeviceList).then(async (response) => {
|
const response = await saveLossAssessmentRow(rowData.value.repairDeviceList)
|
||||||
console.log("yxxxxxyyyy",response)
|
// 隐藏Loading
|
||||||
if (response.code === 200) {
|
uni.hideLoading()
|
||||||
|
if (response.code == 200) {
|
||||||
uni.showToast({ title: '定损成功', icon: 'none' })
|
uni.showToast({ title: '定损成功', icon: 'none' })
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.navigateBack({
|
uni.navigateBack({
|
||||||
delta: 1, // 返回到已存在的页面
|
delta: 1, // 返回到已存在的页面
|
||||||
})
|
})
|
||||||
}, 1000)
|
}, 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(() => {
|
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(() => {
|
const currentTotalRepairNum = computed(() => {
|
||||||
let total = 0;
|
return partItems.value.reduce((sum, item) => {
|
||||||
partItems.value.forEach(item => {
|
return floatUtils.add(sum, item.repairNum || 0);
|
||||||
total += Number(item.repairNum) || 0;
|
}, 0);
|
||||||
});
|
|
||||||
return total;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// 数量框change事件
|
// 数量框change事件
|
||||||
const repairCheckNum1 = (index) => {
|
const repairCheckNum1 = (index) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const item = partItems.value[index];
|
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({
|
uni.showToast({
|
||||||
title: '已达到当前物资最大定损数量!',
|
title: '已达到当前物资最大定损数量!',
|
||||||
icon: 'none',
|
icon: 'none',
|
||||||
});
|
});
|
||||||
// 计算需要减少的数量
|
|
||||||
const excess = currentTotalRepairNum.value - maxRepairNum.value;
|
// 计算超出的部分
|
||||||
// 从当前修改的项中减去超出的部分
|
const excess = floatUtils.subtract(currentTotal, maxNum);
|
||||||
item.repairNum = Math.max(0, item.repairNum - excess);
|
|
||||||
|
// 从当前项中减去超出的部分
|
||||||
|
const newValue = floatUtils.format(
|
||||||
|
floatUtils.subtract(item.repairNum, excess)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 确保新值不会变成负数
|
||||||
|
item.repairNum = Math.max(0, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重新计算费用合计
|
// 重新计算费用合计
|
||||||
calculateCostAll();
|
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);
|
}, 500);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -744,6 +744,55 @@ const saveNumAll = async () => {
|
||||||
return
|
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 = [
|
rowData.value.repairDeviceList[0].repairList = [
|
||||||
{ repairer: repairPerson.value }
|
{ repairer: repairPerson.value }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue