diff --git a/antis-ncc-admin/src/views/extend/storeDashboard/index.vue b/antis-ncc-admin/src/views/extend/storeDashboard/index.vue index 46c85fb..cbdb8e9 100644 --- a/antis-ncc-admin/src/views/extend/storeDashboard/index.vue +++ b/antis-ncc-admin/src/views/extend/storeDashboard/index.vue @@ -92,18 +92,9 @@ - + - - -
- - 每日运营数据趋势 -
-
-
-
- +
@@ -221,15 +212,15 @@ + }} + }} + }} @@ -526,7 +517,6 @@ export default { ], trendChart: null, categoryChart: null, - dailyChart: null, compareChart: null, stackedChart: null, funnelChart: null, @@ -570,7 +560,6 @@ export default { beforeDestroy() { if (this.trendChart) this.trendChart.dispose() if (this.categoryChart) this.categoryChart.dispose() - if (this.dailyChart) this.dailyChart.dispose() if (this.compareChart) this.compareChart.dispose() if (this.stackedChart) this.stackedChart.dispose() if (this.funnelChart) this.funnelChart.dispose() @@ -586,7 +575,6 @@ export default { this.$nextTick(() => { this.renderTrendChart() this.renderCategoryChart() - this.renderDailyChart() this.renderCompareChart() this.renderStackedChart() this.renderFunnelChart() @@ -639,28 +627,6 @@ export default { } this.categoryChart.setOption(option) }, - renderDailyChart() { - if (!this.$refs.dailyChart) return - this.dailyChart = echarts.init(this.$refs.dailyChart) - const option = { - tooltip: { trigger: 'axis', axisPointer: { type: 'cross' } }, - legend: { data: ['开单业绩', '消耗业绩', '人头数', '人次', '项目数'], top: 10 }, - grid: { left: '60px', right: '80px', top: '50px', bottom: '60px', containLabel: false }, - xAxis: { type: 'category', data: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30'], axisLabel: { rotate: 45, interval: 2, fontSize: 11 } }, - yAxis: [ - { type: 'value', name: '业绩', position: 'left', axisLabel: { formatter: value => value >= 10000 ? '¥' + (value / 10000).toFixed(1) + '万' : '¥' + value }, splitLine: { lineStyle: { type: 'dashed', color: '#E4E7ED' } } }, - { type: 'value', name: '数量', position: 'right', splitLine: { show: false } } - ], - series: [ - { name: '开单业绩', type: 'bar', yAxisIndex: 0, data: [45680, 52890, 48960, 56890, 49860, 59860, 62890, 55860, 51860, 59860, 52890, 48960, 56890, 49860, 59860, 62890, 55860, 51860, 59860, 52890, 48960, 56890, 49860, 59860, 62890, 55860, 51860, 59860, 52890, 48960], itemStyle: { color: '#409EFF' }, barWidth: '30%' }, - { name: '消耗业绩', type: 'bar', yAxisIndex: 0, data: [32890, 38960, 35280, 41250, 36580, 43280, 45680, 40250, 37580, 43280, 38960, 35280, 41250, 36580, 43280, 45680, 40250, 37580, 43280, 38960, 35280, 41250, 36580, 43280, 45680, 40250, 37580, 43280, 38960, 35280], itemStyle: { color: '#67C23A' }, barWidth: '30%' }, - { name: '人头数', type: 'line', yAxisIndex: 1, data: [45, 52, 48, 56, 49, 58, 62, 55, 51, 59, 52, 48, 56, 49, 58, 62, 55, 51, 59, 52, 48, 56, 49, 58, 62, 55, 51, 59, 52, 48], itemStyle: { color: '#F56C6C' }, lineStyle: { width: 2 }, symbol: 'circle', symbolSize: 6 }, - { name: '人次', type: 'line', yAxisIndex: 1, data: [128, 145, 132, 156, 138, 162, 178, 152, 142, 165, 145, 132, 156, 138, 162, 178, 152, 142, 165, 145, 132, 156, 138, 162, 178, 152, 142, 165, 145, 132], itemStyle: { color: '#E6A23C' }, lineStyle: { width: 2 }, symbol: 'circle', symbolSize: 6 }, - { name: '项目数', type: 'line', yAxisIndex: 1, data: [256, 289, 268, 312, 278, 325, 356, 304, 284, 330, 289, 268, 312, 278, 325, 356, 304, 284, 330, 289, 268, 312, 278, 325, 356, 304, 284, 330, 289, 268], itemStyle: { color: '#909399' }, lineStyle: { width: 2 }, symbol: 'circle', symbolSize: 6 } - ] - } - this.dailyChart.setOption(option) - }, renderCompareChart() { if (!this.$refs.compareChart) return this.compareChart = echarts.init(this.$refs.compareChart) @@ -873,7 +839,6 @@ export default { handleResize() { if (this.trendChart) this.trendChart.resize() if (this.categoryChart) this.categoryChart.resize() - if (this.dailyChart) this.dailyChart.resize() if (this.compareChart) this.compareChart.resize() if (this.stackedChart) this.stackedChart.resize() if (this.funnelChart) this.funnelChart.resize() @@ -1159,6 +1124,7 @@ export default { grid-template-columns: 1fr 400px; gap: 20px; margin-bottom: 20px; + align-items: start; .content-left { display: flex; diff --git a/antis-ncc-admin/src/views/statisticsList/form21.vue b/antis-ncc-admin/src/views/statisticsList/form21.vue index 2c440f8..54b8fff 100644 --- a/antis-ncc-admin/src/views/statisticsList/form21.vue +++ b/antis-ncc-admin/src/views/statisticsList/form21.vue @@ -270,6 +270,17 @@ + + + + + + public string itemCategory { get; set; } + + /// + /// 健康师账号 + /// + public string healthCoachId { get; set; } + + /// + /// 健康师姓名 + /// + public string healthCoachName { get; set; } + + /// + /// 健康师业绩 + /// + public decimal healthCoachPerformance { get; set; } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs index 6731e6a..f2c9210 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs @@ -27,6 +27,7 @@ using NCC.Extend.Entitys.lq_hytk_jksyj; using NCC.Extend.Entitys.lq_hytk_kjbsyj; using NCC.Extend.Entitys.lq_hytk_mx; using NCC.Extend.Entitys.lq_kd_pxmx; +using NCC.Extend.Entitys.lq_kd_jksyj; using NCC.Extend.Entitys.lq_xmzl; using NCC.Extend.Entitys.lq_khxx; using NCC.Extend.Entitys.lq_mdxx; @@ -915,7 +916,43 @@ namespace NCC.Extend.LqHytkHytk memberDict = members.ToDictionary(x => x.Id, x => x.Sjh ?? ""); } - // 5. 组装数据 + // 5. 批量查询健康师业绩信息 + var billingItemIds = mxList.Select(x => x.BillingItemId).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList(); + var healthCoachDict = new Dictionary(); + if (billingItemIds.Any()) + { + // 通过开单品项明细ID查询开单品项明细,获取开单编号和品项明细ID + var pxmxList = await _db.Queryable() + .Where(x => billingItemIds.Contains(x.Id)) + .Select(x => new { x.Id, x.Glkdbh }) + .ToListAsync(); + + if (pxmxList.Any()) + { + var glkdbhList = pxmxList.Select(x => x.Glkdbh).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList(); + var pxmxIdList = pxmxList.Select(x => x.Id).Distinct().ToList(); + + // 通过开单编号和品项明细ID查询健康师业绩 + var jksyjList = await _db.Queryable() + .Where(x => glkdbhList.Contains(x.Glkdbh) && pxmxIdList.Contains(x.Kdpxid) && x.IsEffective == 1) + .Select(x => new { x.Glkdbh, x.Kdpxid, x.Jkszh, x.Jksxm, x.Jksyj }) + .ToListAsync(); + + // 建立开单品项明细ID到健康师信息的映射 + foreach (var jksyj in jksyjList) + { + // 找到对应的开单品项明细ID + var pxmxId = pxmxList.FirstOrDefault(x => x.Glkdbh == jksyj.Glkdbh && x.Id == jksyj.Kdpxid)?.Id; + if (!string.IsNullOrEmpty(pxmxId)) + { + var jksyjValue = decimal.TryParse(jksyj.Jksyj, out var perf) ? perf : 0; + healthCoachDict[pxmxId] = (jksyj.Jkszh ?? "", jksyj.Jksxm ?? "", jksyjValue); + } + } + } + } + + // 6. 组装数据 var resultList = new List(); foreach (var mx in mxList) { @@ -936,6 +973,11 @@ namespace NCC.Extend.LqHytkHytk var memberId = mx.MemberId ?? (refundInfo?.Hy); var refundTime = mx.Tksj ?? refundInfo?.Tksj; + // 获取健康师信息 + var healthCoachInfo = !string.IsNullOrEmpty(mx.BillingItemId) && healthCoachDict.ContainsKey(mx.BillingItemId) + ? healthCoachDict[mx.BillingItemId] + : (Id: "", Name: "", Performance: 0m); + resultList.Add(new RefundDetailListOutput { storeId = refundInfo?.Md, @@ -952,11 +994,14 @@ namespace NCC.Extend.LqHytkHytk performanceType = mx.PerformanceType, beautyType = mx.BeautyType, sourceType = mx.SourceType, - itemCategory = mx.ItemCategory + itemCategory = mx.ItemCategory, + healthCoachId = healthCoachInfo.Id, + healthCoachName = healthCoachInfo.Name, + healthCoachPerformance = healthCoachInfo.Performance }); } - // 6. 排序 + // 7. 排序 var sidx = string.IsNullOrEmpty(input.sidx) ? "refundTime" : input.sidx; var sort = string.IsNullOrEmpty(input.sort) ? "desc" : input.sort; @@ -969,7 +1014,7 @@ namespace NCC.Extend.LqHytkHytk resultList = resultList.OrderBy(x => GetPropertyValue(x, sidx)).ToList(); } - // 7. 分页 + // 8. 分页 var total = resultList.Count; var skip = (input.currentPage - 1) * input.pageSize; var pagedList = resultList.Skip(skip).Take(input.pageSize).ToList(); @@ -1069,7 +1114,43 @@ namespace NCC.Extend.LqHytkHytk memberDict = members.ToDictionary(x => x.Id, x => x.Sjh ?? ""); } - // 5. 组装数据 + // 5. 批量查询健康师业绩信息 + var billingItemIds = mxList.Select(x => x.BillingItemId).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList(); + var healthCoachDict = new Dictionary(); + if (billingItemIds.Any()) + { + // 通过开单品项明细ID查询开单品项明细,获取开单编号和品项明细ID + var pxmxList = await _db.Queryable() + .Where(x => billingItemIds.Contains(x.Id)) + .Select(x => new { x.Id, x.Glkdbh }) + .ToListAsync(); + + if (pxmxList.Any()) + { + var glkdbhList = pxmxList.Select(x => x.Glkdbh).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList(); + var pxmxIdList = pxmxList.Select(x => x.Id).Distinct().ToList(); + + // 通过开单编号和品项明细ID查询健康师业绩 + var jksyjList = await _db.Queryable() + .Where(x => glkdbhList.Contains(x.Glkdbh) && pxmxIdList.Contains(x.Kdpxid) && x.IsEffective == 1) + .Select(x => new { x.Glkdbh, x.Kdpxid, x.Jkszh, x.Jksxm, x.Jksyj }) + .ToListAsync(); + + // 建立开单品项明细ID到健康师信息的映射 + foreach (var jksyj in jksyjList) + { + // 找到对应的开单品项明细ID + var pxmxId = pxmxList.FirstOrDefault(x => x.Glkdbh == jksyj.Glkdbh && x.Id == jksyj.Kdpxid)?.Id; + if (!string.IsNullOrEmpty(pxmxId)) + { + var jksyjValue = decimal.TryParse(jksyj.Jksyj, out var perf) ? perf : 0; + healthCoachDict[pxmxId] = (jksyj.Jkszh ?? "", jksyj.Jksxm ?? "", jksyjValue); + } + } + } + } + + // 6. 组装数据 var resultList = new List(); foreach (var mx in mxList) { @@ -1090,6 +1171,11 @@ namespace NCC.Extend.LqHytkHytk var memberId = mx.MemberId ?? (refundInfo?.Hy); var refundTime = mx.Tksj ?? refundInfo?.Tksj; + // 获取健康师信息 + var healthCoachInfo = !string.IsNullOrEmpty(mx.BillingItemId) && healthCoachDict.ContainsKey(mx.BillingItemId) + ? healthCoachDict[mx.BillingItemId] + : (Id: "", Name: "", Performance: 0m); + resultList.Add(new RefundDetailListOutput { storeId = refundInfo?.Md, @@ -1106,11 +1192,14 @@ namespace NCC.Extend.LqHytkHytk performanceType = mx.PerformanceType, beautyType = mx.BeautyType, sourceType = mx.SourceType, - itemCategory = mx.ItemCategory + itemCategory = mx.ItemCategory, + healthCoachId = healthCoachInfo.Id, + healthCoachName = healthCoachInfo.Name, + healthCoachPerformance = healthCoachInfo.Performance }); } - // 6. 排序 + // 7. 排序 var sidx = string.IsNullOrEmpty(input.sidx) ? "refundTime" : input.sidx; var sort = string.IsNullOrEmpty(input.sort) ? "desc" : input.sort;