Commit a510c633fc1bab44bd18eaeacd2fe712316d3c0e

Authored by 李宇
2 parents f7aed489 77631543

Merge branch 'master' of http://39.98.150.180/antissoft/lvqianmeiye_ERP

antis-ncc-admin/src/views/extend/storeDashboard/index.vue
@@ -92,18 +92,9 @@ @@ -92,18 +92,9 @@
92 </el-col> 92 </el-col>
93 </el-row> 93 </el-row>
94 94
95 - <!-- 第二行:每日运营数据趋势 + 门店综合能力雷达图 --> 95 + <!-- 第二行:门店综合能力雷达图 -->
96 <el-row :gutter="16" class="chart-row"> 96 <el-row :gutter="16" class="chart-row">
97 - <el-col :span="16">  
98 - <el-card class="chart-card" shadow="hover">  
99 - <div slot="header" class="card-header">  
100 - <i class="el-icon-date"></i>  
101 - <span>每日运营数据趋势</span>  
102 - </div>  
103 - <div ref="dailyChart" class="chart-container"></div>  
104 - </el-card>  
105 - </el-col>  
106 - <el-col :span="8"> 97 + <el-col :span="24">
107 <el-card class="chart-card" shadow="hover"> 98 <el-card class="chart-card" shadow="hover">
108 <div slot="header" class="card-header"> 99 <div slot="header" class="card-header">
109 <i class="el-icon-aim"></i> 100 <i class="el-icon-aim"></i>
@@ -182,7 +173,8 @@ @@ -182,7 +173,8 @@
182 <el-table :data="topBillingItems" size="small" border stripe> 173 <el-table :data="topBillingItems" size="small" border stripe>
183 <el-table-column type="index" label="排名" width="60" align="center"> 174 <el-table-column type="index" label="排名" width="60" align="center">
184 <template slot-scope="scope"> 175 <template slot-scope="scope">
185 - <el-tag v-if="scope.$index < 3" :type="['danger', 'warning', 'success'][scope.$index]" size="mini"> 176 + <el-tag v-if="scope.$index < 3"
  177 + :type="['danger', 'warning', 'success'][scope.$index]" size="mini">
186 {{ scope.$index + 1 }} 178 {{ scope.$index + 1 }}
187 </el-tag> 179 </el-tag>
188 <span v-else>{{ scope.$index + 1 }}</span> 180 <span v-else>{{ scope.$index + 1 }}</span>
@@ -191,13 +183,15 @@ @@ -191,13 +183,15 @@
191 <el-table-column prop="itemName" label="品项名称" min-width="180" /> 183 <el-table-column prop="itemName" label="品项名称" min-width="180" />
192 <el-table-column prop="billingAmount" label="开单金额" width="140" align="right"> 184 <el-table-column prop="billingAmount" label="开单金额" width="140" align="right">
193 <template slot-scope="scope"> 185 <template slot-scope="scope">
194 - <span style="font-weight: 600; color: #67C23A;">¥{{ formatMoney(scope.row.billingAmount) }}</span> 186 + <span style="font-weight: 600; color: #67C23A;">¥{{
  187 + formatMoney(scope.row.billingAmount) }}</span>
195 </template> 188 </template>
196 </el-table-column> 189 </el-table-column>
197 <el-table-column prop="billingCount" label="开单次数" width="100" align="center" /> 190 <el-table-column prop="billingCount" label="开单次数" width="100" align="center" />
198 <el-table-column prop="category" label="分类" width="80" align="center"> 191 <el-table-column prop="category" label="分类" width="80" align="center">
199 <template slot-scope="scope"> 192 <template slot-scope="scope">
200 - <el-tag size="mini" :type="getCategoryType(scope.row.category)">{{ scope.row.category }}</el-tag> 193 + <el-tag size="mini" :type="getCategoryType(scope.row.category)">{{
  194 + scope.row.category }}</el-tag>
201 </template> 195 </template>
202 </el-table-column> 196 </el-table-column>
203 </el-table> 197 </el-table>
@@ -217,13 +211,16 @@ @@ -217,13 +211,16 @@
217 <el-table-column type="index" label="排名" width="60" align="center" /> 211 <el-table-column type="index" label="排名" width="60" align="center" />
218 <el-table-column prop="name" label="健康师姓名" min-width="120" /> 212 <el-table-column prop="name" label="健康师姓名" min-width="120" />
219 <el-table-column prop="billingPerformance" label="开单业绩" width="120" align="right"> 213 <el-table-column prop="billingPerformance" label="开单业绩" width="120" align="right">
220 - <template slot-scope="scope">¥{{ formatMoney(scope.row.billingPerformance) }}</template> 214 + <template slot-scope="scope">¥{{ formatMoney(scope.row.billingPerformance)
  215 + }}</template>
221 </el-table-column> 216 </el-table-column>
222 <el-table-column prop="consumePerformance" label="消耗业绩" width="120" align="right"> 217 <el-table-column prop="consumePerformance" label="消耗业绩" width="120" align="right">
223 - <template slot-scope="scope">¥{{ formatMoney(scope.row.consumePerformance) }}</template> 218 + <template slot-scope="scope">¥{{ formatMoney(scope.row.consumePerformance)
  219 + }}</template>
224 </el-table-column> 220 </el-table-column>
225 <el-table-column prop="totalPerformance" label="总业绩" width="120" align="right"> 221 <el-table-column prop="totalPerformance" label="总业绩" width="120" align="right">
226 - <template slot-scope="scope">¥{{ formatMoney(scope.row.totalPerformance) }}</template> 222 + <template slot-scope="scope">¥{{ formatMoney(scope.row.totalPerformance)
  223 + }}</template>
227 </el-table-column> 224 </el-table-column>
228 </el-table> 225 </el-table>
229 </el-card> 226 </el-card>
@@ -239,7 +236,8 @@ @@ -239,7 +236,8 @@
239 <el-table-column prop="itemName" label="品项名称" min-width="150" /> 236 <el-table-column prop="itemName" label="品项名称" min-width="150" />
240 <el-table-column prop="consumeAmount" label="消耗金额" width="120" align="right"> 237 <el-table-column prop="consumeAmount" label="消耗金额" width="120" align="right">
241 <template slot-scope="scope"> 238 <template slot-scope="scope">
242 - <span style="font-weight: 600; color: #409EFF;">¥{{ formatMoney(scope.row.consumeAmount) }}</span> 239 + <span style="font-weight: 600; color: #409EFF;">¥{{
  240 + formatMoney(scope.row.consumeAmount) }}</span>
243 </template> 241 </template>
244 </el-table-column> 242 </el-table-column>
245 <el-table-column prop="category" label="分类" width="80" /> 243 <el-table-column prop="category" label="分类" width="80" />
@@ -340,7 +338,8 @@ @@ -340,7 +338,8 @@
340 <span class="rank-number">{{ comparison.performanceRanking }}</span> 338 <span class="rank-number">{{ comparison.performanceRanking }}</span>
341 <span class="rank-total">/ {{ comparison.totalStoreCount }}</span> 339 <span class="rank-total">/ {{ comparison.totalStoreCount }}</span>
342 </div> 340 </div>
343 - <div class="ranking-badge" :class="getRankingClass(comparison.performanceRanking, comparison.totalStoreCount)"> 341 + <div class="ranking-badge"
  342 + :class="getRankingClass(comparison.performanceRanking, comparison.totalStoreCount)">
344 {{ getRankingText(comparison.performanceRanking, comparison.totalStoreCount) }} 343 {{ getRankingText(comparison.performanceRanking, comparison.totalStoreCount) }}
345 </div> 344 </div>
346 </div> 345 </div>
@@ -410,7 +409,8 @@ @@ -410,7 +409,8 @@
410 <span class="progress-label">{{ metric.label }}</span> 409 <span class="progress-label">{{ metric.label }}</span>
411 <span class="progress-value">{{ metric.value }}%</span> 410 <span class="progress-value">{{ metric.value }}%</span>
412 </div> 411 </div>
413 - <el-progress :percentage="metric.value" :color="metric.color" :stroke-width="8"></el-progress> 412 + <el-progress :percentage="metric.value" :color="metric.color"
  413 + :stroke-width="8"></el-progress>
414 </div> 414 </div>
415 </div> 415 </div>
416 </el-card> 416 </el-card>
@@ -517,7 +517,6 @@ export default { @@ -517,7 +517,6 @@ export default {
517 ], 517 ],
518 trendChart: null, 518 trendChart: null,
519 categoryChart: null, 519 categoryChart: null,
520 - dailyChart: null,  
521 compareChart: null, 520 compareChart: null,
522 stackedChart: null, 521 stackedChart: null,
523 funnelChart: null, 522 funnelChart: null,
@@ -561,7 +560,6 @@ export default { @@ -561,7 +560,6 @@ export default {
561 beforeDestroy() { 560 beforeDestroy() {
562 if (this.trendChart) this.trendChart.dispose() 561 if (this.trendChart) this.trendChart.dispose()
563 if (this.categoryChart) this.categoryChart.dispose() 562 if (this.categoryChart) this.categoryChart.dispose()
564 - if (this.dailyChart) this.dailyChart.dispose()  
565 if (this.compareChart) this.compareChart.dispose() 563 if (this.compareChart) this.compareChart.dispose()
566 if (this.stackedChart) this.stackedChart.dispose() 564 if (this.stackedChart) this.stackedChart.dispose()
567 if (this.funnelChart) this.funnelChart.dispose() 565 if (this.funnelChart) this.funnelChart.dispose()
@@ -577,7 +575,6 @@ export default { @@ -577,7 +575,6 @@ export default {
577 this.$nextTick(() => { 575 this.$nextTick(() => {
578 this.renderTrendChart() 576 this.renderTrendChart()
579 this.renderCategoryChart() 577 this.renderCategoryChart()
580 - this.renderDailyChart()  
581 this.renderCompareChart() 578 this.renderCompareChart()
582 this.renderStackedChart() 579 this.renderStackedChart()
583 this.renderFunnelChart() 580 this.renderFunnelChart()
@@ -630,28 +627,6 @@ export default { @@ -630,28 +627,6 @@ export default {
630 } 627 }
631 this.categoryChart.setOption(option) 628 this.categoryChart.setOption(option)
632 }, 629 },
633 - renderDailyChart() {  
634 - if (!this.$refs.dailyChart) return  
635 - this.dailyChart = echarts.init(this.$refs.dailyChart)  
636 - const option = {  
637 - tooltip: { trigger: 'axis', axisPointer: { type: 'cross' } },  
638 - legend: { data: ['开单业绩', '消耗业绩', '人头数', '人次', '项目数'], top: 10 },  
639 - grid: { left: '60px', right: '80px', top: '50px', bottom: '60px', containLabel: false },  
640 - 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 } },  
641 - yAxis: [  
642 - { type: 'value', name: '业绩', position: 'left', axisLabel: { formatter: value => value >= 10000 ? '¥' + (value / 10000).toFixed(1) + '万' : '¥' + value }, splitLine: { lineStyle: { type: 'dashed', color: '#E4E7ED' } } },  
643 - { type: 'value', name: '数量', position: 'right', splitLine: { show: false } }  
644 - ],  
645 - series: [  
646 - { 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%' },  
647 - { 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%' },  
648 - { 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 },  
649 - { 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 },  
650 - { 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 }  
651 - ]  
652 - }  
653 - this.dailyChart.setOption(option)  
654 - },  
655 renderCompareChart() { 630 renderCompareChart() {
656 if (!this.$refs.compareChart) return 631 if (!this.$refs.compareChart) return
657 this.compareChart = echarts.init(this.$refs.compareChart) 632 this.compareChart = echarts.init(this.$refs.compareChart)
@@ -864,7 +839,6 @@ export default { @@ -864,7 +839,6 @@ export default {
864 handleResize() { 839 handleResize() {
865 if (this.trendChart) this.trendChart.resize() 840 if (this.trendChart) this.trendChart.resize()
866 if (this.categoryChart) this.categoryChart.resize() 841 if (this.categoryChart) this.categoryChart.resize()
867 - if (this.dailyChart) this.dailyChart.resize()  
868 if (this.compareChart) this.compareChart.resize() 842 if (this.compareChart) this.compareChart.resize()
869 if (this.stackedChart) this.stackedChart.resize() 843 if (this.stackedChart) this.stackedChart.resize()
870 if (this.funnelChart) this.funnelChart.resize() 844 if (this.funnelChart) this.funnelChart.resize()
@@ -1150,6 +1124,7 @@ export default { @@ -1150,6 +1124,7 @@ export default {
1150 grid-template-columns: 1fr 400px; 1124 grid-template-columns: 1fr 400px;
1151 gap: 20px; 1125 gap: 20px;
1152 margin-bottom: 20px; 1126 margin-bottom: 20px;
  1127 + align-items: start;
1153 1128
1154 .content-left { 1129 .content-left {
1155 display: flex; 1130 display: flex;
antis-ncc-admin/src/views/statisticsList/form21.vue
@@ -270,6 +270,17 @@ @@ -270,6 +270,17 @@
270 </el-tag> 270 </el-tag>
271 </template> 271 </template>
272 </el-table-column> 272 </el-table-column>
  273 + <el-table-column prop="healthCoachName" label="健康师" min-width="120" sortable="custom">
  274 + <template slot-scope="scope">
  275 + <i class="el-icon-user-solid" style="margin-right: 4px; color: #F56C6C;"></i>
  276 + <span>{{ scope.row.healthCoachName || '无' }}</span>
  277 + </template>
  278 + </el-table-column>
  279 + <el-table-column prop="healthCoachPerformance" label="健康师业绩" min-width="130" sortable="custom">
  280 + <template slot-scope="scope">
  281 + <span class="amount-value">¥{{ formatMoney(scope.row.healthCoachPerformance) }}</span>
  282 + </template>
  283 + </el-table-column>
273 </NCC-table> 284 </NCC-table>
274 <pagination 285 <pagination
275 v-show="total > 0" 286 v-show="total > 0"
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/RefundDetailListOutput.cs
@@ -81,6 +81,21 @@ namespace NCC.Extend.Entitys.Dto.LqHytkHytk @@ -81,6 +81,21 @@ namespace NCC.Extend.Entitys.Dto.LqHytkHytk
81 /// 品项分类 81 /// 品项分类
82 /// </summary> 82 /// </summary>
83 public string itemCategory { get; set; } 83 public string itemCategory { get; set; }
  84 +
  85 + /// <summary>
  86 + /// 健康师账号
  87 + /// </summary>
  88 + public string healthCoachId { get; set; }
  89 +
  90 + /// <summary>
  91 + /// 健康师姓名
  92 + /// </summary>
  93 + public string healthCoachName { get; set; }
  94 +
  95 + /// <summary>
  96 + /// 健康师业绩
  97 + /// </summary>
  98 + public decimal healthCoachPerformance { get; set; }
84 } 99 }
85 } 100 }
86 101
netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs
@@ -27,6 +27,7 @@ using NCC.Extend.Entitys.lq_hytk_jksyj; @@ -27,6 +27,7 @@ using NCC.Extend.Entitys.lq_hytk_jksyj;
27 using NCC.Extend.Entitys.lq_hytk_kjbsyj; 27 using NCC.Extend.Entitys.lq_hytk_kjbsyj;
28 using NCC.Extend.Entitys.lq_hytk_mx; 28 using NCC.Extend.Entitys.lq_hytk_mx;
29 using NCC.Extend.Entitys.lq_kd_pxmx; 29 using NCC.Extend.Entitys.lq_kd_pxmx;
  30 +using NCC.Extend.Entitys.lq_kd_jksyj;
30 using NCC.Extend.Entitys.lq_xmzl; 31 using NCC.Extend.Entitys.lq_xmzl;
31 using NCC.Extend.Entitys.lq_khxx; 32 using NCC.Extend.Entitys.lq_khxx;
32 using NCC.Extend.Entitys.lq_mdxx; 33 using NCC.Extend.Entitys.lq_mdxx;
@@ -915,7 +916,43 @@ namespace NCC.Extend.LqHytkHytk @@ -915,7 +916,43 @@ namespace NCC.Extend.LqHytkHytk
915 memberDict = members.ToDictionary(x => x.Id, x => x.Sjh ?? ""); 916 memberDict = members.ToDictionary(x => x.Id, x => x.Sjh ?? "");
916 } 917 }
917 918
918 - // 5. 组装数据 919 + // 5. 批量查询健康师业绩信息
  920 + var billingItemIds = mxList.Select(x => x.BillingItemId).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList();
  921 + var healthCoachDict = new Dictionary<string, (string Id, string Name, decimal Performance)>();
  922 + if (billingItemIds.Any())
  923 + {
  924 + // 通过开单品项明细ID查询开单品项明细,获取开单编号和品项明细ID
  925 + var pxmxList = await _db.Queryable<LqKdPxmxEntity>()
  926 + .Where(x => billingItemIds.Contains(x.Id))
  927 + .Select(x => new { x.Id, x.Glkdbh })
  928 + .ToListAsync();
  929 +
  930 + if (pxmxList.Any())
  931 + {
  932 + var glkdbhList = pxmxList.Select(x => x.Glkdbh).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList();
  933 + var pxmxIdList = pxmxList.Select(x => x.Id).Distinct().ToList();
  934 +
  935 + // 通过开单编号和品项明细ID查询健康师业绩
  936 + var jksyjList = await _db.Queryable<LqKdJksyjEntity>()
  937 + .Where(x => glkdbhList.Contains(x.Glkdbh) && pxmxIdList.Contains(x.Kdpxid) && x.IsEffective == 1)
  938 + .Select(x => new { x.Glkdbh, x.Kdpxid, x.Jkszh, x.Jksxm, x.Jksyj })
  939 + .ToListAsync();
  940 +
  941 + // 建立开单品项明细ID到健康师信息的映射
  942 + foreach (var jksyj in jksyjList)
  943 + {
  944 + // 找到对应的开单品项明细ID
  945 + var pxmxId = pxmxList.FirstOrDefault(x => x.Glkdbh == jksyj.Glkdbh && x.Id == jksyj.Kdpxid)?.Id;
  946 + if (!string.IsNullOrEmpty(pxmxId))
  947 + {
  948 + var jksyjValue = decimal.TryParse(jksyj.Jksyj, out var perf) ? perf : 0;
  949 + healthCoachDict[pxmxId] = (jksyj.Jkszh ?? "", jksyj.Jksxm ?? "", jksyjValue);
  950 + }
  951 + }
  952 + }
  953 + }
  954 +
  955 + // 6. 组装数据
919 var resultList = new List<RefundDetailListOutput>(); 956 var resultList = new List<RefundDetailListOutput>();
920 foreach (var mx in mxList) 957 foreach (var mx in mxList)
921 { 958 {
@@ -936,6 +973,11 @@ namespace NCC.Extend.LqHytkHytk @@ -936,6 +973,11 @@ namespace NCC.Extend.LqHytkHytk
936 var memberId = mx.MemberId ?? (refundInfo?.Hy); 973 var memberId = mx.MemberId ?? (refundInfo?.Hy);
937 var refundTime = mx.Tksj ?? refundInfo?.Tksj; 974 var refundTime = mx.Tksj ?? refundInfo?.Tksj;
938 975
  976 + // 获取健康师信息
  977 + var healthCoachInfo = !string.IsNullOrEmpty(mx.BillingItemId) && healthCoachDict.ContainsKey(mx.BillingItemId)
  978 + ? healthCoachDict[mx.BillingItemId]
  979 + : (Id: "", Name: "", Performance: 0m);
  980 +
939 resultList.Add(new RefundDetailListOutput 981 resultList.Add(new RefundDetailListOutput
940 { 982 {
941 storeId = refundInfo?.Md, 983 storeId = refundInfo?.Md,
@@ -952,11 +994,14 @@ namespace NCC.Extend.LqHytkHytk @@ -952,11 +994,14 @@ namespace NCC.Extend.LqHytkHytk
952 performanceType = mx.PerformanceType, 994 performanceType = mx.PerformanceType,
953 beautyType = mx.BeautyType, 995 beautyType = mx.BeautyType,
954 sourceType = mx.SourceType, 996 sourceType = mx.SourceType,
955 - itemCategory = mx.ItemCategory 997 + itemCategory = mx.ItemCategory,
  998 + healthCoachId = healthCoachInfo.Id,
  999 + healthCoachName = healthCoachInfo.Name,
  1000 + healthCoachPerformance = healthCoachInfo.Performance
956 }); 1001 });
957 } 1002 }
958 1003
959 - // 6. 排序 1004 + // 7. 排序
960 var sidx = string.IsNullOrEmpty(input.sidx) ? "refundTime" : input.sidx; 1005 var sidx = string.IsNullOrEmpty(input.sidx) ? "refundTime" : input.sidx;
961 var sort = string.IsNullOrEmpty(input.sort) ? "desc" : input.sort; 1006 var sort = string.IsNullOrEmpty(input.sort) ? "desc" : input.sort;
962 1007
@@ -969,7 +1014,7 @@ namespace NCC.Extend.LqHytkHytk @@ -969,7 +1014,7 @@ namespace NCC.Extend.LqHytkHytk
969 resultList = resultList.OrderBy(x => GetPropertyValue(x, sidx)).ToList(); 1014 resultList = resultList.OrderBy(x => GetPropertyValue(x, sidx)).ToList();
970 } 1015 }
971 1016
972 - // 7. 分页 1017 + // 8. 分页
973 var total = resultList.Count; 1018 var total = resultList.Count;
974 var skip = (input.currentPage - 1) * input.pageSize; 1019 var skip = (input.currentPage - 1) * input.pageSize;
975 var pagedList = resultList.Skip(skip).Take(input.pageSize).ToList(); 1020 var pagedList = resultList.Skip(skip).Take(input.pageSize).ToList();
@@ -1069,7 +1114,43 @@ namespace NCC.Extend.LqHytkHytk @@ -1069,7 +1114,43 @@ namespace NCC.Extend.LqHytkHytk
1069 memberDict = members.ToDictionary(x => x.Id, x => x.Sjh ?? ""); 1114 memberDict = members.ToDictionary(x => x.Id, x => x.Sjh ?? "");
1070 } 1115 }
1071 1116
1072 - // 5. 组装数据 1117 + // 5. 批量查询健康师业绩信息
  1118 + var billingItemIds = mxList.Select(x => x.BillingItemId).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList();
  1119 + var healthCoachDict = new Dictionary<string, (string Id, string Name, decimal Performance)>();
  1120 + if (billingItemIds.Any())
  1121 + {
  1122 + // 通过开单品项明细ID查询开单品项明细,获取开单编号和品项明细ID
  1123 + var pxmxList = await _db.Queryable<LqKdPxmxEntity>()
  1124 + .Where(x => billingItemIds.Contains(x.Id))
  1125 + .Select(x => new { x.Id, x.Glkdbh })
  1126 + .ToListAsync();
  1127 +
  1128 + if (pxmxList.Any())
  1129 + {
  1130 + var glkdbhList = pxmxList.Select(x => x.Glkdbh).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList();
  1131 + var pxmxIdList = pxmxList.Select(x => x.Id).Distinct().ToList();
  1132 +
  1133 + // 通过开单编号和品项明细ID查询健康师业绩
  1134 + var jksyjList = await _db.Queryable<LqKdJksyjEntity>()
  1135 + .Where(x => glkdbhList.Contains(x.Glkdbh) && pxmxIdList.Contains(x.Kdpxid) && x.IsEffective == 1)
  1136 + .Select(x => new { x.Glkdbh, x.Kdpxid, x.Jkszh, x.Jksxm, x.Jksyj })
  1137 + .ToListAsync();
  1138 +
  1139 + // 建立开单品项明细ID到健康师信息的映射
  1140 + foreach (var jksyj in jksyjList)
  1141 + {
  1142 + // 找到对应的开单品项明细ID
  1143 + var pxmxId = pxmxList.FirstOrDefault(x => x.Glkdbh == jksyj.Glkdbh && x.Id == jksyj.Kdpxid)?.Id;
  1144 + if (!string.IsNullOrEmpty(pxmxId))
  1145 + {
  1146 + var jksyjValue = decimal.TryParse(jksyj.Jksyj, out var perf) ? perf : 0;
  1147 + healthCoachDict[pxmxId] = (jksyj.Jkszh ?? "", jksyj.Jksxm ?? "", jksyjValue);
  1148 + }
  1149 + }
  1150 + }
  1151 + }
  1152 +
  1153 + // 6. 组装数据
1073 var resultList = new List<RefundDetailListOutput>(); 1154 var resultList = new List<RefundDetailListOutput>();
1074 foreach (var mx in mxList) 1155 foreach (var mx in mxList)
1075 { 1156 {
@@ -1090,6 +1171,11 @@ namespace NCC.Extend.LqHytkHytk @@ -1090,6 +1171,11 @@ namespace NCC.Extend.LqHytkHytk
1090 var memberId = mx.MemberId ?? (refundInfo?.Hy); 1171 var memberId = mx.MemberId ?? (refundInfo?.Hy);
1091 var refundTime = mx.Tksj ?? refundInfo?.Tksj; 1172 var refundTime = mx.Tksj ?? refundInfo?.Tksj;
1092 1173
  1174 + // 获取健康师信息
  1175 + var healthCoachInfo = !string.IsNullOrEmpty(mx.BillingItemId) && healthCoachDict.ContainsKey(mx.BillingItemId)
  1176 + ? healthCoachDict[mx.BillingItemId]
  1177 + : (Id: "", Name: "", Performance: 0m);
  1178 +
1093 resultList.Add(new RefundDetailListOutput 1179 resultList.Add(new RefundDetailListOutput
1094 { 1180 {
1095 storeId = refundInfo?.Md, 1181 storeId = refundInfo?.Md,
@@ -1106,11 +1192,14 @@ namespace NCC.Extend.LqHytkHytk @@ -1106,11 +1192,14 @@ namespace NCC.Extend.LqHytkHytk
1106 performanceType = mx.PerformanceType, 1192 performanceType = mx.PerformanceType,
1107 beautyType = mx.BeautyType, 1193 beautyType = mx.BeautyType,
1108 sourceType = mx.SourceType, 1194 sourceType = mx.SourceType,
1109 - itemCategory = mx.ItemCategory 1195 + itemCategory = mx.ItemCategory,
  1196 + healthCoachId = healthCoachInfo.Id,
  1197 + healthCoachName = healthCoachInfo.Name,
  1198 + healthCoachPerformance = healthCoachInfo.Performance
1110 }); 1199 });
1111 } 1200 }
1112 1201
1113 - // 6. 排序 1202 + // 7. 排序
1114 var sidx = string.IsNullOrEmpty(input.sidx) ? "refundTime" : input.sidx; 1203 var sidx = string.IsNullOrEmpty(input.sidx) ? "refundTime" : input.sidx;
1115 var sort = string.IsNullOrEmpty(input.sort) ? "desc" : input.sort; 1204 var sort = string.IsNullOrEmpty(input.sort) ? "desc" : input.sort;
1116 1205