|
@@ -181,6 +181,263 @@ export default {
|
|
|
if (!d) return ''
|
|
if (!d) return ''
|
|
|
return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0')
|
|
return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0')
|
|
|
},
|
|
},
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制团队成长曲线
|
|
|
|
|
+ drawGrowthCurve(data) {
|
|
|
|
|
+ var labels = data.labels || []
|
|
|
|
|
+ var dataValues = data.data || []
|
|
|
|
|
+
|
|
|
|
|
+ if (!labels || labels.length === 0) return
|
|
|
|
|
+
|
|
|
|
|
+ uni.createCanvasContext('growthCurveCanvas', this)
|
|
|
|
|
+ var ctx = uni.getCanvasContext('growthCurveCanvas', this)
|
|
|
|
|
+
|
|
|
|
|
+ if (!ctx) return
|
|
|
|
|
+
|
|
|
|
|
+ ctx.clearRect(0, 0, 320, 200)
|
|
|
|
|
+
|
|
|
|
|
+ var canvasWidth = 320
|
|
|
|
|
+ var canvasHeight = 200
|
|
|
|
|
+ var padding = 40
|
|
|
|
|
+ var chartWidth = canvasWidth - padding * 2
|
|
|
|
|
+ var chartHeight = canvasHeight - padding * 2
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制坐标轴
|
|
|
|
|
+ ctx.setStrokeStyle('#C0C0C0')
|
|
|
|
|
+ ctx.setLineWidth(1)
|
|
|
|
|
+ ctx.beginPath()
|
|
|
|
|
+ ctx.moveTo(padding, padding)
|
|
|
|
|
+ ctx.lineTo(padding, canvasHeight - padding)
|
|
|
|
|
+ ctx.lineTo(canvasWidth - padding, canvasHeight - padding)
|
|
|
|
|
+ ctx.stroke()
|
|
|
|
|
+ ctx.closePath()
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制X轴刻度和标签
|
|
|
|
|
+ ctx.setFontSize(12)
|
|
|
|
|
+ for (var i = 0; i < labels.length; i++) {
|
|
|
|
|
+ var x = padding + (i * (chartWidth / (labels.length - 1))) || padding
|
|
|
|
|
+ ctx.beginPath()
|
|
|
|
|
+ ctx.moveTo(x, canvasHeight - padding)
|
|
|
|
|
+ ctx.lineTo(x, canvasHeight - padding + 5)
|
|
|
|
|
+ ctx.stroke()
|
|
|
|
|
+ ctx.fillText(labels[i], x - ctx.measureText(labels[i]).width / 2, canvasHeight - padding + 20)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制Y轴刻度
|
|
|
|
|
+ var maxValue = Math.max(...dataValues) || 1
|
|
|
|
|
+ var stepHeight = chartHeight / 5
|
|
|
|
|
+ for (var i = 0; i <= 5; i++) {
|
|
|
|
|
+ var y = canvasHeight - padding - i * stepHeight
|
|
|
|
|
+ ctx.beginPath()
|
|
|
|
|
+ ctx.moveTo(padding, y)
|
|
|
|
|
+ ctx.lineTo(padding - 5, y)
|
|
|
|
|
+ ctx.stroke()
|
|
|
|
|
+ ctx.fillText(String(Math.round(maxValue * (5 - i) / 5)), padding - 30, y + 4)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制折线图
|
|
|
|
|
+ if (dataValues.length > 1) {
|
|
|
|
|
+ ctx.setStrokeStyle('#F97316')
|
|
|
|
|
+ ctx.setLineWidth(2)
|
|
|
|
|
+ ctx.beginPath()
|
|
|
|
|
+
|
|
|
|
|
+ for (var i = 0; i < dataValues.length; i++) {
|
|
|
|
|
+ var x = padding + (i * (chartWidth / (dataValues.length - 1)))
|
|
|
|
|
+ var y = canvasHeight - padding - (dataValues[i] / maxValue) * chartHeight
|
|
|
|
|
+ if (i === 0) {
|
|
|
|
|
+ ctx.moveTo(x, y)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ctx.lineTo(x, y)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ctx.stroke()
|
|
|
|
|
+ ctx.closePath()
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制填充区域
|
|
|
|
|
+ ctx.setFillStyle('rgba(249, 115, 22, 0.2)')
|
|
|
|
|
+ ctx.beginPath()
|
|
|
|
|
+ ctx.moveTo(padding, canvasHeight - padding)
|
|
|
|
|
+ for (var i = 0; i < dataValues.length; i++) {
|
|
|
|
|
+ var x = padding + (i * (chartWidth / (dataValues.length - 1)))
|
|
|
|
|
+ var y = canvasHeight - padding - (dataValues[i] / maxValue) * chartHeight
|
|
|
|
|
+ ctx.lineTo(x, y)
|
|
|
|
|
+ }
|
|
|
|
|
+ ctx.lineTo(canvasWidth - padding, canvasHeight - padding)
|
|
|
|
|
+ ctx.closePath()
|
|
|
|
|
+ ctx.fill()
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制所有成员消费曲线
|
|
|
|
|
+ drawMembersConsumptionCurve(data) {
|
|
|
|
|
+ var labels = data.labels || []
|
|
|
|
|
+ var dataValues = data.data || []
|
|
|
|
|
+
|
|
|
|
|
+ if (!labels || labels.length === 0) return
|
|
|
|
|
+
|
|
|
|
|
+ uni.createCanvasContext('membersConsumptionCanvas', this)
|
|
|
|
|
+ var ctx = uni.getCanvasContext('membersConsumptionCanvas', this)
|
|
|
|
|
+
|
|
|
|
|
+ if (!ctx) return
|
|
|
|
|
+
|
|
|
|
|
+ ctx.clearRect(0, 0, 320, 200)
|
|
|
|
|
+
|
|
|
|
|
+ var canvasWidth = 320
|
|
|
|
|
+ var canvasHeight = 200
|
|
|
|
|
+ var padding = 40
|
|
|
|
|
+ var chartWidth = canvasWidth - padding * 2
|
|
|
|
|
+ var chartHeight = canvasHeight - padding * 2
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制坐标轴
|
|
|
|
|
+ ctx.setStrokeStyle('#C0C0C0')
|
|
|
|
|
+ ctx.setLineWidth(1)
|
|
|
|
|
+ ctx.beginPath()
|
|
|
|
|
+ ctx.moveTo(padding, padding)
|
|
|
|
|
+ ctx.lineTo(padding, canvasHeight - padding)
|
|
|
|
|
+ ctx.lineTo(canvasWidth - padding, canvasHeight - padding)
|
|
|
|
|
+ ctx.stroke()
|
|
|
|
|
+ ctx.closePath()
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制X轴刻度
|
|
|
|
|
+ ctx.setFontSize(12)
|
|
|
|
|
+ for (var i = 0; i < labels.length; i++) {
|
|
|
|
|
+ var x = padding + (i * (chartWidth / (labels.length - 1))) || padding
|
|
|
|
|
+ ctx.beginPath()
|
|
|
|
|
+ ctx.moveTo(x, canvasHeight - padding)
|
|
|
|
|
+ ctx.lineTo(x, canvasHeight - padding + 5)
|
|
|
|
|
+ ctx.stroke()
|
|
|
|
|
+ ctx.fillText(labels[i], x - ctx.measureText(labels[i]).width / 2, canvasHeight - padding + 20)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制Y轴刻度(金额)
|
|
|
|
|
+ var maxVal = Math.max(...dataValues) || 1
|
|
|
|
|
+ var stepHeight = chartHeight / 5
|
|
|
|
|
+ for (var i = 0; i <= 5; i++) {
|
|
|
|
|
+ var y = canvasHeight - padding - i * stepHeight
|
|
|
|
|
+ ctx.beginPath()
|
|
|
|
|
+ ctx.moveTo(padding, y)
|
|
|
|
|
+ ctx.lineTo(padding - 5, y)
|
|
|
|
|
+ ctx.stroke()
|
|
|
|
|
+ ctx.fillText('¥' + Math.round(maxVal * (5 - i) / 5 / 100), padding - 30, y + 4)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制折线图
|
|
|
|
|
+ if (dataValues.length > 1) {
|
|
|
|
|
+ ctx.setStrokeStyle('#0EA5E9')
|
|
|
|
|
+ ctx.setLineWidth(2)
|
|
|
|
|
+ ctx.beginPath()
|
|
|
|
|
+
|
|
|
|
|
+ for (var i = 0; i < dataValues.length; i++) {
|
|
|
|
|
+ var x = padding + (i * (chartWidth / (dataValues.length - 1)))
|
|
|
|
|
+ var y = canvasHeight - padding - (dataValues[i] / maxVal) * chartHeight
|
|
|
|
|
+ if (i === 0) {
|
|
|
|
|
+ ctx.moveTo(x, y)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ctx.lineTo(x, y)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ctx.stroke()
|
|
|
|
|
+ ctx.closePath()
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制填充区域
|
|
|
|
|
+ ctx.setFillStyle('rgba(14, 165, 233, 0.2)')
|
|
|
|
|
+ ctx.beginPath()
|
|
|
|
|
+ ctx.moveTo(padding, canvasHeight - padding)
|
|
|
|
|
+ for (var i = 0; i < dataValues.length; i++) {
|
|
|
|
|
+ var x = padding + (i * (chartWidth / (dataValues.length - 1)))
|
|
|
|
|
+ var y = canvasHeight - padding - (dataValues[i] / maxVal) * chartHeight
|
|
|
|
|
+ ctx.lineTo(x, y)
|
|
|
|
|
+ }
|
|
|
|
|
+ ctx.lineTo(canvasWidth - padding, canvasHeight - padding)
|
|
|
|
|
+ ctx.closePath()
|
|
|
|
|
+ ctx.fill()
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制L1直推团队消费曲线
|
|
|
|
|
+ drawL1ConsumptionCurve(data) {
|
|
|
|
|
+ var labels = data.labels || []
|
|
|
|
|
+ var dataValues = data.data || []
|
|
|
|
|
+
|
|
|
|
|
+ if (!labels || labels.length === 0) return
|
|
|
|
|
+
|
|
|
|
|
+ uni.createCanvasContext('l1ConsumptionCanvas', this)
|
|
|
|
|
+ var ctx = uni.getCanvasContext('l1ConsumptionCanvas', this)
|
|
|
|
|
+
|
|
|
|
|
+ if (!ctx) return
|
|
|
|
|
+
|
|
|
|
|
+ ctx.clearRect(0, 0, 320, 200)
|
|
|
|
|
+
|
|
|
|
|
+ var canvasWidth = 320
|
|
|
|
|
+ var canvasHeight = 200
|
|
|
|
|
+ var padding = 40
|
|
|
|
|
+ var chartWidth = canvasWidth - padding * 2
|
|
|
|
|
+ var chartHeight = canvasHeight - padding * 2
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制坐标轴
|
|
|
|
|
+ ctx.setStrokeStyle('#C0C0C0')
|
|
|
|
|
+ ctx.setLineWidth(1)
|
|
|
|
|
+ ctx.beginPath()
|
|
|
|
|
+ ctx.moveTo(padding, padding)
|
|
|
|
|
+ ctx.lineTo(padding, canvasHeight - padding)
|
|
|
|
|
+ ctx.lineTo(canvasWidth - padding, canvasHeight - padding)
|
|
|
|
|
+ ctx.stroke()
|
|
|
|
|
+ ctx.closePath()
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制X轴刻度
|
|
|
|
|
+ ctx.setFontSize(12)
|
|
|
|
|
+ for (var i = 0; i < labels.length; i++) {
|
|
|
|
|
+ var x = padding + (i * (chartWidth / (labels.length - 1))) || padding
|
|
|
|
|
+ ctx.beginPath()
|
|
|
|
|
+ ctx.moveTo(x, canvasHeight - padding)
|
|
|
|
|
+ ctx.lineTo(x, canvasHeight - padding + 5)
|
|
|
|
|
+ ctx.stroke()
|
|
|
|
|
+ ctx.fillText(labels[i], x - ctx.measureText(labels[i]).width / 2, canvasHeight - padding + 20)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制Y轴刻度
|
|
|
|
|
+ var maxValue = Math.max(...dataValues) || 1
|
|
|
|
|
+ var stepHeight = chartHeight / 5
|
|
|
|
|
+ for (var i = 0; i <= 5; i++) {
|
|
|
|
|
+ var y = canvasHeight - padding - i * stepHeight
|
|
|
|
|
+ ctx.beginPath()
|
|
|
|
|
+ ctx.moveTo(padding, y)
|
|
|
|
|
+ ctx.lineTo(padding - 5, y)
|
|
|
|
|
+ ctx.stroke()
|
|
|
|
|
+ ctx.fillText(String(Math.round(maxValue * (5 - i) / 5)), padding - 30, y + 4)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制折线图 - 使用暖橙色
|
|
|
|
|
+ ctx.setStrokeStyle('#F97316')
|
|
|
|
|
+ ctx.setLineWidth(2)
|
|
|
|
|
+ ctx.beginPath()
|
|
|
|
|
+
|
|
|
|
|
+ for (var i = 0; i < dataValues.length; i++) {
|
|
|
|
|
+ var x = padding + (i * (chartWidth / (dataValues.length - 1)))
|
|
|
|
|
+ var y = canvasHeight - padding - (dataValues[i] / maxValue) * chartHeight
|
|
|
|
|
+ if (i === 0) {
|
|
|
|
|
+ ctx.moveTo(x, y)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ctx.lineTo(x, y)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ctx.stroke()
|
|
|
|
|
+ ctx.closePath()
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制填充区域
|
|
|
|
|
+ ctx.setFillStyle('rgba(249, 115, 22, 0.2)')
|
|
|
|
|
+ ctx.beginPath()
|
|
|
|
|
+ ctx.moveTo(padding, canvasHeight - padding)
|
|
|
|
|
+ for (var i = 0; i < dataValues.length; i++) {
|
|
|
|
|
+ var x = padding + (i * (chartWidth / (dataValues.length - 1)))
|
|
|
|
|
+ var y = canvasHeight - padding - (dataValues[i] / maxValue) * chartHeight
|
|
|
|
|
+ ctx.lineTo(x, y)
|
|
|
|
|
+ }
|
|
|
|
|
+ ctx.lineTo(canvasWidth - padding, canvasHeight - padding)
|
|
|
|
|
+ ctx.closePath()
|
|
|
|
|
+ ctx.fill()
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
async loadCurveData() {
|
|
async loadCurveData() {
|
|
|
try {
|
|
try {
|
|
|
// 获取团队成长曲线数据(12个月)
|
|
// 获取团队成长曲线数据(12个月)
|