154 lines
5.7 KiB
JavaScript
Raw Permalink Normal View History

2026-07-27 11:28:33 +08:00
const BigNumber = require('bignumber.js');
exports.getPackageData = function (data, rest = {}) {
return {
...rest,
name: data.name.trim(),
cateId: typeof data.cateId === 'string' ? data.cateId : '',
desc: typeof data.desc === 'string' ? data.desc.trim() : '',
hasValidDays: typeof data.hasValidDays === 'boolean' ? data.hasValidDays : false,
validDays: typeof data.validDays === 'number' ? data.validDays : 0,
enableDiscount: typeof data.enableDiscount === 'boolean' ? data.enableDiscount : false,
minDiscount: typeof data.minDiscount === 'number' ? data.minDiscount : 10,
packageType: data.packageType,
packagePrice: data.packagePrice,
projectNumber: data.projectNumber,
projects: data.projects.map(i => ({
_id: i._id,
projectName: i.projectName,
projectCateId: i.projectCateId,
price: i.price,
number: i.number,
discount: i.discount,
required: i.required
}))
}
}
exports.verifyPakcage = function (data) {
if (typeof data.name !== 'string' || data.name.trim() === '') {
return '套餐名称不能为空'
}
if (data.name.trim().length > 50) {
return '套餐名称不能超过50个字符'
}
if (data.desc && typeof data.desc !== 'string') {
return '套餐描述必须是字符串'
}
if (typeof data.desc === 'string' && data.desc.trim().length > 500) {
return '套餐描述不能超过500个字符'
}
if (typeof data.hasValidDays !== 'boolean') {
return '是否有有效期设置不正确'
}
if (data.hasValidDays && (typeof data.validDays !== 'number' || !(data.validDays > 0)) || data.validDays % 1 !== 0) {
return '有效天数无效'
}
if (typeof data.enableDiscount !== 'boolean') {
return '启用折扣设置不正确'
}
if (data.enableDiscount && (typeof data.minDiscount !== 'number' || !(data.minDiscount > 0 && data.minDiscount <= 10))) {
return '最小折扣无效'
}
if (typeof data.cateId !== 'string' || data.cateId.trim() === '') {
return '套餐分类不能为空'
}
if (data.enableDiscount && !checkDecimal(data.minDiscount, 2)) {
return '最小折扣最多支持2为小数'
}
if (!['fixed', 'free'].includes(data.packageType)) {
return '套餐类型不正确'
}
if (data.packagePrice === 'free' && (typeof data.packagePrice !== 'number' || !(data.packagePrice > 0))) {
return '套餐价格无效'
}
if (data.packagePrice === 'free' && !checkDecimal(data.packagePrice, 2)) {
return '套餐价格最多支持2位小数'
}
const msg = verifyPackageItems(data.projects, data.packageType);
if (msg) return msg;
if (typeof data.projectNumber !== 'number' || !(data.projectNumber > 0) || !checkDecimal(data.projectNumber, 0)) {
return '套餐项目数量设置不正确'
}
}
function verifyPackageItems(projects, packageType) {
if (!Array.isArray(projects) || projects.length === 0) {
return '套餐项目不能为空'
}
if (packageType === 'fixed' && projects.some(i => !(i._id && typeof i.projectName === 'string' && i.projectName.trim() !== '' && i.price && i.number && i.discount))) return '套餐项目信息不完整'
for (let project of projects) {
const name = project.projectName.trim();
if (typeof project._id !== 'string' || project._id.trim() === '') {
return `${name}数据设置不正确`
}
if (typeof project.price !== 'number' || !(project.price > 0)) {
return `${name}价格设置不正确`
}
// if (checkDecimal(project.price, 2)) {
// return `${name}价格最多支持2位小数`
// }
if (typeof project.number !== 'number' || !(project.number > 0) || !checkDecimal(project.number, 0)) {
return `${name} 项目数量设置不正确`
}
if (packageType === 'fixed') {
if (typeof project.discount !== 'number' || !(project.discount > 0 && project.discount <= 10 && checkDecimal(project.discount, 2))) {
return `${name} 折扣设置不正确`
}
}
if (typeof project.required !== 'boolean') {
return `${name} 是否必选设置不正确`
}
}
}
/**
* 计算项目套餐价格
*/
exports.getPackageListWithPrice = function (packageList) {
if (!Array.isArray(packageList)) return [];
return packageList.map(p => {
const projectData = Array.isArray(p.packageProjects) ? p.packageProjects : [];
const _projects = Array.isArray(p.projects) ? p.projects : [];
let allProjectPrice = new BigNumber(0);
let count = 0;
const projects = _projects.map(i => {
const project = projectData.find(j => j._id === i._id);
let projectFee = 0
if (p.packageType === 'fixed') {
count += 1
const price = project && project.price >= 0 ? Number(project.price) : 0;
const discount = i.discount >= 0 ? Number(i.discount) : 10;
const number = i.number >= 0 ? Number(i.number) : 1;
projectFee = new BigNumber(price).multipliedBy(discount).dividedBy(10).multipliedBy(number).toNumber();
allProjectPrice = allProjectPrice.plus(projectFee);
}
return {
...i,
projectName: project ? project.projectName : i.projectName,
price: project ? project.price : i.price,
number: i.number,
discount: i.discount,
projectFee,
lowestDiscount: project ? project.lowestDiscount : '',
}
})
const { packageProjects, ...rest } = p;
return {
...rest,
projects,
count,
packagePrice: p.packageType === 'fixed' ? allProjectPrice.toNumber() : p.packagePrice,
}
})
}
function checkDecimal(num, len) {
if (typeof num !== 'number' || typeof len !== 'number' || !(len >= 0) || len % 1 !== 0) return false;
if (len === 0) return Number.isInteger(num);
return parseFloat(num.toFixed(len)) === num
}