|
@@ -0,0 +1,312 @@
|
|
|
+//超级订阅价格计算
|
|
|
+class Buyset {
|
|
|
+ constructor(areacount, cityArr = [], buyerCount, upgrade) {
|
|
|
+ this.areacount = areacount; //省份数量 -1 全国
|
|
|
+ this.citys = cityArr; //购买的城市数组
|
|
|
+ this.buyerclasscount = buyerCount; //行业数量
|
|
|
+ this.upgrade = upgrade; //是否是升级版的超级订阅
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+var Calculation = {
|
|
|
+ PriceRule: {
|
|
|
+ "old": {
|
|
|
+ "month": {
|
|
|
+ "oneCity_oneBuyerClass": 580,
|
|
|
+ "oneCity_allBuyerClass": 1800,
|
|
|
+ "oneProvince_oneBuyerClass": 1180,
|
|
|
+ "oneProvince_allBuyerClass": 3800,
|
|
|
+ "allProvince_oneBuyerClass": 11800,
|
|
|
+ "allProvince_allBuyerClass": 38800
|
|
|
+ },
|
|
|
+ "year": {
|
|
|
+ "oneCity_oneBuyerClass": 5800,
|
|
|
+ "oneCity_allBuyerClass": 18000,
|
|
|
+ "oneProvince_oneBuyerClass": 11800,
|
|
|
+ "oneProvince_allBuyerClass": 38000,
|
|
|
+ "allProvince_oneBuyerClass": 118000,
|
|
|
+ "allProvince_allBuyerClass": 388000
|
|
|
+ },
|
|
|
+ "cityPrice": 580,
|
|
|
+ "provincePrice": 1180,
|
|
|
+ "buyerClassPrice": 580,
|
|
|
+ "cityMaxCount": 2,
|
|
|
+ "provinceMaxCount": 9,
|
|
|
+ "buyerClassMaxCount": 3,
|
|
|
+ "monthMaxCount": 9
|
|
|
+ },
|
|
|
+ "new": {
|
|
|
+ "month": {
|
|
|
+ "oneProvince_allBuyerClass": 3800,
|
|
|
+ "allProvince_allBuyerClass": 59900
|
|
|
+ },
|
|
|
+ "year": {
|
|
|
+ "oneProvince_allBuyerClass": 38800,
|
|
|
+ "allProvince_allBuyerClass": 599900
|
|
|
+ },
|
|
|
+ "provincePrice": 3800,
|
|
|
+ "provinceMaxCount": 15,
|
|
|
+ "monthMaxCount": 9
|
|
|
+ },
|
|
|
+ "discount": 1
|
|
|
+ }, //套餐价格表
|
|
|
+ IsTrial: true, //是否时试用用户
|
|
|
+ OldBuyset: new Buyset(),//用户之前套餐
|
|
|
+ EndTime: 0, //会员到期时间
|
|
|
+ RenewList: [],
|
|
|
+ Init: (isTrial, oldBuyset, renewList, price, endTime) => { //首次购买时oldBuyset传入undefined
|
|
|
+ this.IsTrial = isTrial;
|
|
|
+ this.OldBuyset = oldBuyset;
|
|
|
+ this.RenewList = renewList;
|
|
|
+ this.EndTime = endTime;
|
|
|
+ this.PriceRule = price;
|
|
|
+ },
|
|
|
+ Check: (tmpBuyset, oldBuyset) => { //校验是否合法
|
|
|
+ if (!oldBuyset) {
|
|
|
+ oldBuyset = this.OldBuyset;
|
|
|
+ }
|
|
|
+ if (!oldBuyset) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ if (oldBuyset.upgrade === 1) { //升级后省份数量必须大于升级前的
|
|
|
+ return tmpBuyset.areacount > oldBuyset.areacount;
|
|
|
+ } else {
|
|
|
+ return tmpBuyset.areacount >= oldBuyset.areacount + oldBuyset.citys.length;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ //首次购买
|
|
|
+ //续费 newBuyset 传入undefined
|
|
|
+ GetTotal: (newBuyset, buyTime = [1, 2]) => { //newBuyset 用户选择的套餐;time[数量,单位(1:年,2月)]
|
|
|
+ if (newBuyset) {//首次购买
|
|
|
+ return this.getBuysetPrice(newBuyset, t)
|
|
|
+ }
|
|
|
+ return this.getBuysetPrice(this.OldBuyset, t) //续费
|
|
|
+ },
|
|
|
+ GetUpgradeDetail: (newBuyset = new Buyset(), buyTime = [1, 2]) => { //升级计价
|
|
|
+ let subtotail = []; //计价清单
|
|
|
+ let final_price = 0; //最终计算价格
|
|
|
+ let nowEndTime = this.EndTime;
|
|
|
+ //续费升级价格
|
|
|
+ if (this.renewList.length > 0) {
|
|
|
+ for (var i = renewList.length - 1; i >= 0; i--) {
|
|
|
+ let thisBuyset = renewList[i].o_buyset;
|
|
|
+ let thisStartTime = renewList[i].l_validtime;
|
|
|
+ let old = new Buyset(thisBuyset.areacount, thisBuyset.newcitys, thisBuyset.buyerclasscount, this.upgrade || 0)
|
|
|
+ var this_price = this.GetSubPrice(old, newBuyset, thisStartTime, nowEndTime);
|
|
|
+ if (this_price < 0) {
|
|
|
+ return [-2, []]
|
|
|
+ }
|
|
|
+ //清单数组
|
|
|
+ subtotail.push({
|
|
|
+ "buyset": old,
|
|
|
+ "startTime": thisStartTime,
|
|
|
+ "endTime": nowEndTime,
|
|
|
+ "price": this_price,
|
|
|
+ "type": 1
|
|
|
+ });
|
|
|
+ final_price = this.numAdd(final_price, this_price);
|
|
|
+ nowEndTime = thisStartTime;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //现在使用升级价格
|
|
|
+ var now_price = this.GetSubPrice(this.OldBuyset, newBuyset, new Date().getTime() / 1000, nowEndTime);
|
|
|
+ if (now_price < 0) {
|
|
|
+ return [-2, []]
|
|
|
+ }
|
|
|
+ //清单数组
|
|
|
+ subtotail.push({
|
|
|
+ "buyset": oldBuyset,
|
|
|
+ "startTime": new Date().getTime() / 1000,
|
|
|
+ "endTime": nowEndTime,
|
|
|
+ "price": now_price,
|
|
|
+ "type": 0
|
|
|
+ });
|
|
|
+ final_price = this.numAdd(final_price, now_price);
|
|
|
+ //新增续费升级价格
|
|
|
+ if (buyTime.length !== 0) {
|
|
|
+ var thisPrice = this.getBuysetPrice(newBuyset, t);
|
|
|
+ if (thisPrice < 0) {
|
|
|
+ return [-2, []]
|
|
|
+ }
|
|
|
+ console.log(newBuyset, t, "额外升级费用", thisPrice);
|
|
|
+ final_price = this.numAdd(final_price, thisPrice);
|
|
|
+ //清单数组
|
|
|
+ subtotail.push({
|
|
|
+ "buyset": newBuyset,
|
|
|
+ "startTime": endUnix,//xxx
|
|
|
+ "endTime": getVipEndDate(t[1], t[0], endUnix),
|
|
|
+ "price": thisPrice,
|
|
|
+ "type": 2
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return [final_price, subtotail]
|
|
|
+ },
|
|
|
+ GetSubPrice: (oldBuyset, newBuyset, start, end) => { //升级-计算套餐差价
|
|
|
+ if (this.check(newBuyset, oldBuyset)) {
|
|
|
+ return -1
|
|
|
+ }
|
|
|
+ let beforePrice = 0;
|
|
|
+ let newPrice = 0;
|
|
|
+ let t = this.getDateSub(start, end);
|
|
|
+
|
|
|
+ if (t[1] !== 0) {//月
|
|
|
+ beforePrice = this.numAdd(beforePrice, this.getBuysetPrice(oldBuyset, [t[1], 2]))
|
|
|
+ newPrice = this.numAdd(newPrice, this.getBuysetPrice(newBuyset, [t[1], 2]))
|
|
|
+ }
|
|
|
+ if (t[0] !== 0) {//年
|
|
|
+ beforePrice = this.numAdd(beforePrice, this.getBuysetPrice(oldBuyset, [t[0], 1]))
|
|
|
+ newPrice = this.numAdd(newPrice, this.getBuysetPrice(newBuyset, [t[0], 1]))
|
|
|
+ }
|
|
|
+ console.log("old ", oldBuyset, " \n new ", newBuyset, " \n 相差", t[0], "年 ", t[1], "个月\n price:", newPrice, "-", beforePrice, "=", (newPrice * 10000 - beforePrice * 10000) / 10000);
|
|
|
+ return (newPrice * 10000 - beforePrice * 10000) / 10000
|
|
|
+ },
|
|
|
+ getBuysetPrice: (vipbuyset = new Buyset(), t) => { //获取套餐价格
|
|
|
+ if (t.length !== 2) {
|
|
|
+ return -1
|
|
|
+ }
|
|
|
+ if (vipbuyset.upgrade === 0) { //旧版大会员价格计算
|
|
|
+ if (t[0] > this.PriceRule.old.monthMaxCount && t[1] === 2) t[0] = 10;//月份十个月以上价格一样
|
|
|
+ if (vipbuyset.areacount === -1) {//计算全国套餐价格
|
|
|
+ if (vipbuyset.buyerclasscount === 1) return this.getSetMealPrice_old(0, 1, t[1]) * t[0] / 100; //全国1行业套餐
|
|
|
+ if (vipbuyset.buyerclasscount === 0) return this.getSetMealPrice_old(0, 0, t[1]) * t[0] / 100; //全国全行业套餐
|
|
|
+ return this.getSetMealPrice_old(0, vipbuyset.buyerclasscount, t[1]) * t[0] / 100 //全国多行业套餐
|
|
|
+ }
|
|
|
+ let final_price = 0;//计算省份价格
|
|
|
+ for (var i in vipbuyset.citys) {
|
|
|
+ var thisPrice = 0;
|
|
|
+ if (vipbuyset.citys[i] === 1) {//单城市
|
|
|
+ thisPrice = this.getSetMealPrice_old(2, vipbuyset.buyerclasscount, t[1]) * t[0];
|
|
|
+ } else {//多城市
|
|
|
+ if (vipbuyset.buyerclasscount === 0 || vipbuyset.buyerclasscount === 1) {//多城市 单行业
|
|
|
+ if (vipbuyset.citys[i] > this.PriceRule.old.cityMaxCount) {
|
|
|
+ vipbuyset.areacount++;
|
|
|
+ } else {
|
|
|
+ thisPrice = vipbuyset.citys[i] * this.getSetMealPrice_old(2, vipbuyset.buyerclasscount, t[1]) * t[0];
|
|
|
+ }
|
|
|
+ } else {//多城市 多行业
|
|
|
+ if (vipbuyset.citys[i] > this.PriceRule.old.cityMaxCount) {
|
|
|
+ vipbuyset.areacount++;
|
|
|
+ } else {
|
|
|
+ thisPrice = this.getSetMealPrice_old(2, vipbuyset.buyerclasscount, t[1]) * vipbuyset.citys[i] * t[0];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ final_price += thisPrice;
|
|
|
+ }
|
|
|
+ final_price += vipbuyset.areacount * this.getSetMealPrice_old(1, vipbuyset.buyerclasscount, t[1]) * t[0];
|
|
|
+ return final_price / 100
|
|
|
+ } else {//新版大会员价格计算
|
|
|
+ pCount = vipbuyset.areacount
|
|
|
+ if (pCount > this.PriceRule.new.provinceMaxCount) {
|
|
|
+ pCount = -1
|
|
|
+ }
|
|
|
+ if (pCount === -1) {
|
|
|
+ pCount = 0
|
|
|
+ }
|
|
|
+ //当选择月份大于 按照全年计算
|
|
|
+ if (t[0] > this.PriceRule.new.monthMaxCount && t[1] === 2) { //月份十个月以上价格一样
|
|
|
+ count = 10
|
|
|
+ }
|
|
|
+ return this.getSetMealPrice_new(pCount, unit) * count //全国1行业套餐
|
|
|
+ }
|
|
|
+ },
|
|
|
+ getSetMealPrice_old: (c, iCount, u) => { //旧套餐价格计算
|
|
|
+ var t = u === 2; //是否是月单位
|
|
|
+ switch (c) {
|
|
|
+ case 0:
|
|
|
+ if (iCount === -1) {
|
|
|
+ if (t) return this.PriceRule.old.month.allProvince_allBuyerClass; //1月全国全行业
|
|
|
+ return this.PriceRule.old.year.allProvince_allBuyerClass; //1年全国全行业
|
|
|
+ } else {
|
|
|
+ if (t) return this.PriceRule.old.month.allProvince_oneBuyerClass * iCount; //1月全国icount个行业
|
|
|
+ return this.PriceRule.old.year.allProvince_oneBuyerClass * iCount; //1年全国icount个行业
|
|
|
+ }
|
|
|
+ case 1:
|
|
|
+ if (iCount === -1) {
|
|
|
+ if (t) return this.PriceRule.old.month.oneProvince_allBuyerClass; //1月1省全行业
|
|
|
+ return this.PriceRule.old.year.oneProvince_allBuyerClass //1年1省全行业
|
|
|
+ } else {
|
|
|
+ if (t) return this.PriceRule.old.month.oneProvince_oneBuyerClass * iCount; //1月1省icount个行业
|
|
|
+ return this.PriceRule.old.year.oneProvince_oneBuyerClass * iCount //1年1省icount个行业
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ if (iCount === -1) {
|
|
|
+ if (t) return this.PriceRule.old.month.oneCity_allBuyerClass; //1月1市全行业
|
|
|
+ return this.PriceRule.old.year.oneCity_allBuyerClass //1年1市全行业
|
|
|
+ } else {
|
|
|
+ if (t) return this.PriceRule.old.month.oneCity_oneBuyerClass * iCount; //1月1市icount个行业
|
|
|
+ return this.PriceRule.old.year.oneCity_oneBuyerClass * iCount //1年1市icount个行业
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ getSetMealPrice_new: (p, u) => { //新套餐价格计算 p省份格式,u时间单位
|
|
|
+ var t = u === 2 //是否是月单位
|
|
|
+ switch (p) {
|
|
|
+ case 0:
|
|
|
+ if (t) {
|
|
|
+ return this.PriceRule.new.month.allProvince_allBuyerClass // 1月全国全行业
|
|
|
+ }
|
|
|
+ return this.PriceRule.new.year.allProvince_allBuyerClass //1年全国全行业
|
|
|
+ case 1:
|
|
|
+ if (t) {
|
|
|
+ return this.PriceRule.new.month.oneProvince_allBuyerClass //1月1省全行业
|
|
|
+ }
|
|
|
+ return this.PriceRule.new.year.oneProvince_allBuyerClass //1年1省全行业
|
|
|
+ }
|
|
|
+ return -1
|
|
|
+ },
|
|
|
+ getDateSub: (start, end) => { //计算时间间隔差 [年个数, 月个数]
|
|
|
+ var startTime = new Date(start * 1000);
|
|
|
+ var endTime = new Date(end * 1000);
|
|
|
+
|
|
|
+ var startYear = startTime.getFullYear();
|
|
|
+ var startMonth = startTime.getMonth();
|
|
|
+ var startDay = startTime.getDate();
|
|
|
+
|
|
|
+ var endYear = endTime.getFullYear();
|
|
|
+ var endMonth = endTime.getMonth();
|
|
|
+ var endDay = endTime.getDate();
|
|
|
+
|
|
|
+ var finalMonthNum = 0;
|
|
|
+ var finalYearNum = 0;
|
|
|
+ if (startYear === endYear) {
|
|
|
+ if (startMonth === endMonth) {
|
|
|
+ finalMonthNum = 1;
|
|
|
+ } else {
|
|
|
+ if (endDay > startDay) {
|
|
|
+ finalMonthNum = endMonth - startMonth + 1;
|
|
|
+ } else {
|
|
|
+ finalMonthNum = endMonth - startMonth;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (startMonth === endMonth) {
|
|
|
+ if (endDay <= startDay) {
|
|
|
+ finalMonthNum = (endYear - startYear) * 12;
|
|
|
+ } else {
|
|
|
+ finalMonthNum = (endYear - startYear) * 12 + 1;
|
|
|
+ }
|
|
|
+ } else if (endMonth > startMonth) {
|
|
|
+ if (endDay <= startDay) {
|
|
|
+ finalMonthNum = (endYear - startYear) * 12 + (endMonth - startMonth);
|
|
|
+ } else {
|
|
|
+ finalMonthNum = (endYear - startYear) * 12 + (endMonth - startMonth) + 1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (endDay <= startDay) {
|
|
|
+ finalMonthNum = (endYear - startYear - 1) * 12 + (12 - startMonth + endMonth);
|
|
|
+ } else {
|
|
|
+ finalMonthNum = (endYear - startYear - 1) * 12 + (12 - startMonth + endMonth) + 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ finalYearNum = Math.floor(finalMonthNum / 12);
|
|
|
+ if (finalYearNum > 0) {
|
|
|
+ finalMonthNum = finalMonthNum - finalYearNum * 12
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return [finalYearNum, finalMonthNum]
|
|
|
+ },
|
|
|
+ numAdd: (num1, num2) => {
|
|
|
+ return (num1 * 10000 + num2 * 10000) / 10000
|
|
|
+ }
|
|
|
+}
|