|
|
@@ -0,0 +1,369 @@
|
|
|
+const _Http = getApp().globalData.http;
|
|
|
+
|
|
|
+Page({
|
|
|
+ data: {
|
|
|
+ quarterMap: {
|
|
|
+ 1: "一",
|
|
|
+ 2: "二",
|
|
|
+ 3: "三",
|
|
|
+ 4: "四"
|
|
|
+ },
|
|
|
+ monthsCopy: []
|
|
|
+ },
|
|
|
+ onLoad(options) {
|
|
|
+ this.setData({
|
|
|
+ currentYear: new Date().getFullYear(),
|
|
|
+ currentMonth: new Date().getMonth() + 1,
|
|
|
+ currentQuarter: Math.ceil((new Date().getMonth() + 1) / 3),
|
|
|
+ months: wx.getStorageSync('siteP').statistics_months
|
|
|
+ })
|
|
|
+ this.getAreaList()
|
|
|
+ _Http.basic({
|
|
|
+ "id": "2025103010165903",
|
|
|
+ "content": {}
|
|
|
+ }).then(res => {
|
|
|
+ if (res.code != 1) return wx.showToast({
|
|
|
+ title: res.msg,
|
|
|
+ icon: "none"
|
|
|
+ });
|
|
|
+ this.setData({
|
|
|
+ currentUser: res.data.map(v => {
|
|
|
+ v.key = v.areaname + (v.name ? '(' + v.name + ")" : '')
|
|
|
+ return v
|
|
|
+ })[0]
|
|
|
+ })
|
|
|
+ // 查询月目标
|
|
|
+ this.queryMonthlyTarget()
|
|
|
+ // 重新季目标
|
|
|
+ this.queryQuarterlyTarget()
|
|
|
+ // 查询总指标
|
|
|
+ this.queryOverallTarget()
|
|
|
+ })
|
|
|
+ this.getAreaList();
|
|
|
+ },
|
|
|
+
|
|
|
+ //获取当前业务员区域及其下属区域
|
|
|
+ getAreaList() {
|
|
|
+ _Http.basic({
|
|
|
+ "id": "2025103009445603",
|
|
|
+ "content": {
|
|
|
+ pageSize: 9999
|
|
|
+ }
|
|
|
+ }).then(res => {
|
|
|
+ if (res.code != 1) return wx.showToast({
|
|
|
+ title: res.msg,
|
|
|
+ icon: "none"
|
|
|
+ });
|
|
|
+ this.setData({
|
|
|
+ areaList: res.data.map(v => {
|
|
|
+ v.key = v.areaname + (v.name ? '(' + v.name + ")" : '')
|
|
|
+ return v
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 查询业务员月度目标
|
|
|
+ queryMonthlyTarget() {
|
|
|
+ let that = this;
|
|
|
+ _Http.basic({
|
|
|
+ "id": "2025103010192003",
|
|
|
+ "content": {
|
|
|
+ "sa_saleareaid": this.data.currentUser.sa_saleareaid,
|
|
|
+ "year": this.data.currentYear,
|
|
|
+ "month": this.data.currentMonth
|
|
|
+ }
|
|
|
+ }).then(res => {
|
|
|
+ console.log("业务员月度目标", res)
|
|
|
+ if (res.code != 1) return wx.showToast({
|
|
|
+ title: res.msg,
|
|
|
+ icon: "none"
|
|
|
+ });
|
|
|
+ this.setData({
|
|
|
+ monthlyMetrics: calculateMonthlyMetrics(res)
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ function calculateMonthlyMetrics(res) {
|
|
|
+ const data = res?.data || {};
|
|
|
+
|
|
|
+ // ===============================
|
|
|
+ // 🔹 基础字段(接口已提供)
|
|
|
+ // ===============================
|
|
|
+ const rw_month = data.rw_month || 0; // 月度任务(万)
|
|
|
+ const previousexceed = data.previousexceed || 0; // 上月完成额超出部分(1月为0)
|
|
|
+ const gccompletedamount = data.gccompletedamount || 0; // GC工程完成额
|
|
|
+ const gccompletedamountexceed = data.gccompletedamountexceed || 0; // GC工程超出部分
|
|
|
+ const zzcompletedamount = data.zzcompletedamount || 0; // 整装工程完成额
|
|
|
+ const zzcompletedamountexceed = data.zzcompletedamountexceed || 0; // 整装工程超出部分
|
|
|
+
|
|
|
+ // ===============================
|
|
|
+ // ⚠️ 缺失字段(需要后端或其他接口提供)
|
|
|
+ // ===============================
|
|
|
+ const cashbackamount = data.cashbackamount || 0; // ⚠️ 现金账户回款(缺少)
|
|
|
+ const advancepaymentamount = data.advancepaymentamount || 0; // ⚠️ 活动预存账户回款(缺少)
|
|
|
+ const rebateamount = data.rebateamount || 0; // ⚠️ 返利(缺少)
|
|
|
+
|
|
|
+ // ===============================
|
|
|
+ // 🔹 中间计算项
|
|
|
+ // ===============================
|
|
|
+ // 回款完成额
|
|
|
+ const paymentCompleted = cashbackamount + advancepaymentamount + rebateamount;
|
|
|
+
|
|
|
+ // 实际完成额
|
|
|
+ const actualcompletedamount =
|
|
|
+ paymentCompleted + gccompletedamount + zzcompletedamount;
|
|
|
+
|
|
|
+ // 实际完成百分比
|
|
|
+ const actualcompletedpercentage =
|
|
|
+ rw_month > 0 ? (actualcompletedamount / rw_month) * 100 : 0;
|
|
|
+
|
|
|
+ // 完成额超出100%部分
|
|
|
+ const completedamountexceed100 =
|
|
|
+ paymentCompleted + previousexceed + gccompletedamount + zzcompletedamount - rw_month;
|
|
|
+
|
|
|
+ // 若为负则取0
|
|
|
+ const completedamountexceed100_fixed =
|
|
|
+ completedamountexceed100 > 0 ? completedamountexceed100 : 0;
|
|
|
+
|
|
|
+ // ===============================
|
|
|
+ // 🔹 返回完整结果(金额类统一格式化)
|
|
|
+ // ===============================
|
|
|
+ return {
|
|
|
+ // ---- 原始字段 ----
|
|
|
+ rw_month: that.CNY(rw_month), // 月度任务额(万)
|
|
|
+ previousexceed: that.CNY(previousexceed), // 上月超出额
|
|
|
+ gccompletedamount: that.CNY(gccompletedamount), // GC工程完成额
|
|
|
+ gccompletedamountexceed: that.CNY(gccompletedamountexceed), // GC工程超出部分
|
|
|
+ zzcompletedamount: that.CNY(zzcompletedamount), // 整装工程完成额
|
|
|
+ zzcompletedamountexceed: that.CNY(zzcompletedamountexceed), // 整装工程超出部分
|
|
|
+
|
|
|
+ // ---- 缺少但定义字段 ----
|
|
|
+ cashbackamount: that.CNY(cashbackamount), // ⚠️ 现金账户回款
|
|
|
+ advancepaymentamount: that.CNY(advancepaymentamount), // ⚠️ 活动预存账户回款
|
|
|
+ rebateamount: that.CNY(rebateamount), // ⚠️ 返利
|
|
|
+
|
|
|
+ // ---- 计算结果 ----
|
|
|
+ paymentCompleted: that.CNY(paymentCompleted), // 回款完成额
|
|
|
+ actualcompletedamount: that.CNY(actualcompletedamount), // 实际完成额
|
|
|
+ actualcompletedpercentage: actualcompletedpercentage.toFixed(2) + '%', // 实际完成百分比(保留两位小数)
|
|
|
+ completedamountexceed100: that.CNY(completedamountexceed100_fixed), // 完成额超出100%部分
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 查询业务员季度目标
|
|
|
+ queryQuarterlyTarget() {
|
|
|
+ let that = this;
|
|
|
+ _Http.basic({
|
|
|
+ "id": "2025103010193903",
|
|
|
+ "version": 1,
|
|
|
+ "content": {
|
|
|
+ "sa_saleareaid": this.data.currentUser.sa_saleareaid,
|
|
|
+ "year": this.data.currentYear
|
|
|
+ }
|
|
|
+ }).then(res => {
|
|
|
+ console.log("业务员季度目标", res);
|
|
|
+ if (res.code != 1) return wx.showToast({
|
|
|
+ title: res.msg,
|
|
|
+ icon: "none"
|
|
|
+ });
|
|
|
+ this.setData({
|
|
|
+ quarterlyMetrics: calculateQuarterlyMetrics(res)
|
|
|
+ });
|
|
|
+ console.log("季度", this.data.quarterlyMetrics)
|
|
|
+ });
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 季度指标计算函数
|
|
|
+ * 根据接口返回的 res.data 自动计算核心指标,并格式化金额
|
|
|
+ */
|
|
|
+ function calculateQuarterlyMetrics(res) {
|
|
|
+ const data = res?.data || {};
|
|
|
+
|
|
|
+ // ===============================
|
|
|
+ // 🔹 基础字段(接口已提供)
|
|
|
+ // ===============================
|
|
|
+ const rw_quarter = data.rw_quarter || 0; // 季度任务额(万)= 当季各月度任务额总计
|
|
|
+ const previousexceed = data.previousexceed || 0; // 上季完成额超出部分
|
|
|
+ const gccompletedamount = data.gccompletedamount || 0; // GC工程完成额(季度累计)
|
|
|
+ const zzcompletedamount = data.zzcompletedamount || 0; // 整装工程完成额(季度累计)
|
|
|
+ const actualcompletedamount = data.actualcompletedamount || 0; // 实际完成额(季度实际回款+GC+整装)
|
|
|
+ const actualcompletedpercentage = data.actualcompletedpercentage || 0; // 实际完成百分比(季度原始值)
|
|
|
+ const completedamount = data.completedamount || 0; // 完成额(未超出部分)
|
|
|
+
|
|
|
+ // ===============================
|
|
|
+ // ⚠️ 缺失字段(需后端补充)
|
|
|
+ // ===============================
|
|
|
+ const paymentCompleted = data.paymentCompleted || 0; // ⚠️ 季度回款完成额(当季各月度回款完成额总计)
|
|
|
+ // 若后端没提供,可暂用 actualcompletedamount - gc - zz 近似估算:
|
|
|
+ const estimatedPaymentCompleted = paymentCompleted || (actualcompletedamount - gccompletedamount - zzcompletedamount);
|
|
|
+
|
|
|
+ // ===============================
|
|
|
+ // 🔹 计算逻辑
|
|
|
+ // ===============================
|
|
|
+ // 季度完成额 = 回款完成额 + 上季超出额 + GC + 整装
|
|
|
+ const quarterCompletedAmount =
|
|
|
+ estimatedPaymentCompleted + previousexceed + gccompletedamount + zzcompletedamount;
|
|
|
+
|
|
|
+ // 季度百分比 = 季度完成额 / 季度任务额 * 100
|
|
|
+ const quarterPercentage =
|
|
|
+ rw_quarter > 0 ? (quarterCompletedAmount / rw_quarter) * 100 : 0;
|
|
|
+
|
|
|
+ // ===============================
|
|
|
+ // 🔹 返回完整结果(金额格式化)
|
|
|
+ // ===============================
|
|
|
+ return {
|
|
|
+ // ---- 原始字段 ----
|
|
|
+ rw_quarter: that.CNY(rw_quarter), // 季度任务额(万)
|
|
|
+ previousexceed: that.CNY(previousexceed), // 上季完成额超出部分
|
|
|
+ gccompletedamount: that.CNY(gccompletedamount), // GC工程完成额
|
|
|
+ zzcompletedamount: that.CNY(zzcompletedamount), // 整装工程完成额
|
|
|
+ actualcompletedamount: that.CNY(actualcompletedamount), // 实际完成额
|
|
|
+ completedamount: that.CNY(completedamount), // 完成额(未超出部分)
|
|
|
+
|
|
|
+ // ---- 缺失但定义字段 ----
|
|
|
+ paymentCompleted: that.CNY(estimatedPaymentCompleted), // ⚠️ 季度回款完成额(若后端未返回则估算)
|
|
|
+
|
|
|
+ // ---- 计算结果 ----
|
|
|
+ quarterCompletedAmount: that.CNY(quarterCompletedAmount), // 季度完成额
|
|
|
+ quarterPercentage: quarterPercentage.toFixed(2) + '%', // 季度完成百分比
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 查询业务员总指标
|
|
|
+ queryOverallTarget() {
|
|
|
+ let that = this;
|
|
|
+ _Http.basic({
|
|
|
+ "id": "2025103010195403",
|
|
|
+ "version": 1,
|
|
|
+ "content": {
|
|
|
+ "sa_saleareaid": this.data.currentUser.sa_saleareaid,
|
|
|
+ "year": this.data.currentYear,
|
|
|
+ "months": this.data.months // 默认或用户选择的月份区间
|
|
|
+ }
|
|
|
+ }).then(res => {
|
|
|
+ console.log("业务员总指标", res);
|
|
|
+ if (res.code != 1) return wx.showToast({
|
|
|
+ title: res.msg,
|
|
|
+ icon: "none"
|
|
|
+ });
|
|
|
+ this.setData({
|
|
|
+ overallMetrics: calculateOverallMetrics(res)
|
|
|
+ })
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 总指标计算函数
|
|
|
+ * 根据接口返回 res.data 计算核心指标并格式化金额
|
|
|
+ */
|
|
|
+ function calculateOverallMetrics(res) {
|
|
|
+ const data = res?.data || {};
|
|
|
+
|
|
|
+ // ===============================
|
|
|
+ // 🔹 基础字段(接口已提供)
|
|
|
+ // ===============================
|
|
|
+ const rw_all = data.rw_all || 0; // 总任务额(万)
|
|
|
+ const gccompletedamount = data.gccompletedamount || 0; // GC工程完成额
|
|
|
+ const zzcompletedamount = data.zzcompletedamount || 0; // 整装工程完成额
|
|
|
+ const actualcompletedamount = data.actualcompletedamount || 0; // 实际完成额
|
|
|
+ const actualcompletedpercentage = data.actualcompletedpercentage || 0; // 实际完成百分比
|
|
|
+ const completedamount = data.completedamount || 0; // 完成额(未超出部分)
|
|
|
+ const differenceamount = data.differenceamount || 0; // 差额(目标与实际差距)
|
|
|
+
|
|
|
+ // ===============================
|
|
|
+ // ⚠️ 缺失字段(需后端补充)
|
|
|
+ // ===============================
|
|
|
+ const paymentCompleted = data.paymentCompleted || 0; // ⚠️ 回款完成额(区间累计)
|
|
|
+ const estimatedPaymentCompleted =
|
|
|
+ paymentCompleted || (actualcompletedamount - gccompletedamount - zzcompletedamount);
|
|
|
+
|
|
|
+ // ===============================
|
|
|
+ // 🔹 计算逻辑
|
|
|
+ // ===============================
|
|
|
+ const totalCompletedAmount = estimatedPaymentCompleted + gccompletedamount + zzcompletedamount;
|
|
|
+ const totalPercentage = rw_all > 0 ? (totalCompletedAmount / rw_all) * 100 : 0;
|
|
|
+
|
|
|
+ // 距70%差额(百分比形式)
|
|
|
+ const differenceTo70 = totalPercentage < 70 ? (70 - totalPercentage) : 0;
|
|
|
+
|
|
|
+ // ===============================
|
|
|
+ // 🔹 返回结果(金额格式化 + 百分比两位小数)
|
|
|
+ // ===============================
|
|
|
+ return {
|
|
|
+ rw_all: that.CNY(rw_all),
|
|
|
+ gccompletedamount: that.CNY(gccompletedamount),
|
|
|
+ zzcompletedamount: that.CNY(zzcompletedamount),
|
|
|
+ actualcompletedamount: that.CNY(actualcompletedamount),
|
|
|
+ completedamount: that.CNY(completedamount),
|
|
|
+ differenceamount: that.CNY(differenceamount),
|
|
|
+
|
|
|
+ paymentCompleted: that.CNY(estimatedPaymentCompleted),
|
|
|
+
|
|
|
+ totalCompletedAmount: that.CNY(totalCompletedAmount),
|
|
|
+ totalPercentage: totalPercentage.toFixed(2) + '%', // 总完成百分比
|
|
|
+ differenceTo70: differenceTo70.toFixed(2) + '%', // 距70%差额(百分比)
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
+ CNY(value) {
|
|
|
+ if (value === null || value === undefined || isNaN(value)) return '0';
|
|
|
+ let num = parseFloat(value).toFixed(2);
|
|
|
+ num = num.replace(/\.?0+$/, '');
|
|
|
+ const parts = num.split('.');
|
|
|
+ parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
|
+ return parts.join('.');
|
|
|
+ },
|
|
|
+ // 切换月
|
|
|
+ changeDate(e) {
|
|
|
+ let value = e.detail.value.split("-")
|
|
|
+ this.setData({
|
|
|
+ currentYear: value[0],
|
|
|
+ currentMonth: value[1],
|
|
|
+ currentQuarter: Math.ceil((value[1] - 0 + 1) / 3)
|
|
|
+ })
|
|
|
+ this.queryMonthlyTarget();
|
|
|
+ this.queryQuarterlyTarget();
|
|
|
+ },
|
|
|
+ // 切换区域
|
|
|
+ changeSalearea(e) {
|
|
|
+ let index = e.detail.value;
|
|
|
+ this.setData({
|
|
|
+ currentUser: this.data.areaList[index]
|
|
|
+ })
|
|
|
+ this.queryMonthlyTarget();
|
|
|
+ this.queryQuarterlyTarget();
|
|
|
+ this.queryOverallTarget();
|
|
|
+ },
|
|
|
+ // 选择月
|
|
|
+ selectedOption(e) {
|
|
|
+ let {
|
|
|
+ index
|
|
|
+ } = e.currentTarget.dataset,
|
|
|
+ monthsCopy = this.data.monthsCopy;
|
|
|
+ if (monthsCopy.includes(index)) {
|
|
|
+ monthsCopy = monthsCopy.filter(v => v != index)
|
|
|
+ } else {
|
|
|
+ monthsCopy.push(index)
|
|
|
+ monthsCopy.sort((a, b) => a - b)
|
|
|
+ }
|
|
|
+ this.setData({
|
|
|
+ monthsCopy
|
|
|
+ })
|
|
|
+ },
|
|
|
+ onClose() {
|
|
|
+ this.setData({
|
|
|
+ monthsCopy: []
|
|
|
+ })
|
|
|
+ },
|
|
|
+ onConfirm() {
|
|
|
+ this.setData({
|
|
|
+ months: this.data.monthsCopy
|
|
|
+ })
|
|
|
+ this.queryOverallTarget();
|
|
|
+ },
|
|
|
+ openDialog() {
|
|
|
+ this.setData({
|
|
|
+ monthsCopy: this.data.months
|
|
|
+ })
|
|
|
+ }
|
|
|
+})
|