Commit 189ad8f683f9fe588b2430ac034600d8cba2fb3d

Authored by 李宇
2 parents 0f14a621 28ad29c0

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

antis-ncc-admin/src/views/extend/annualSummary/dashboard/index.vue
@@ -119,7 +119,8 @@ @@ -119,7 +119,8 @@
119 </div> 119 </div>
120 <NCC-table v-loading="trendTableLoading" :data="trendTableData" border stripe style="width: 100%"> 120 <NCC-table v-loading="trendTableLoading" :data="trendTableData" border stripe style="width: 100%">
121 <el-table-column v-for="col in trendTableColumns" :key="col.prop" :prop="col.prop" :label="col.label" 121 <el-table-column v-for="col in trendTableColumns" :key="col.prop" :prop="col.prop" :label="col.label"
122 - :width="col.width" :align="col.align || 'center'"> 122 + :width="col.width" :align="col.align || 'center'" :sortable="col.sortable || false"
  123 + :sort-method="col.sortMethod || undefined">
123 <template slot-scope="scope"> 124 <template slot-scope="scope">
124 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> 125 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span>
125 <span v-else>{{ scope.row[col.prop] || '0' }}</span> 126 <span v-else>{{ scope.row[col.prop] || '0' }}</span>
@@ -150,7 +151,8 @@ @@ -150,7 +151,8 @@
150 <NCC-table v-loading="performanceTableLoading" :data="performanceTableData" border stripe 151 <NCC-table v-loading="performanceTableLoading" :data="performanceTableData" border stripe
151 style="width: 100%"> 152 style="width: 100%">
152 <el-table-column v-for="col in performanceTableColumns" :key="col.prop" :prop="col.prop" 153 <el-table-column v-for="col in performanceTableColumns" :key="col.prop" :prop="col.prop"
153 - :label="col.label" :width="col.width" :align="col.align || 'center'"> 154 + :label="col.label" :width="col.width" :align="col.align || 'center'" :sortable="col.sortable || false"
  155 + :sort-method="col.sortMethod || undefined">
154 <template slot-scope="scope"> 156 <template slot-scope="scope">
155 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> 157 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span>
156 <span v-else>{{ scope.row[col.prop] || '0' }}</span> 158 <span v-else>{{ scope.row[col.prop] || '0' }}</span>
@@ -180,7 +182,8 @@ @@ -180,7 +182,8 @@
180 </div> 182 </div>
181 <NCC-table v-loading="consumeTableLoading" :data="consumeTableData" border stripe style="width: 100%"> 183 <NCC-table v-loading="consumeTableLoading" :data="consumeTableData" border stripe style="width: 100%">
182 <el-table-column v-for="col in consumeTableColumns" :key="col.prop" :prop="col.prop" :label="col.label" 184 <el-table-column v-for="col in consumeTableColumns" :key="col.prop" :prop="col.prop" :label="col.label"
183 - :width="col.width" :align="col.align || 'center'"> 185 + :width="col.width" :align="col.align || 'center'" :sortable="col.sortable || false"
  186 + :sort-method="col.sortMethod || undefined">
184 <template slot-scope="scope"> 187 <template slot-scope="scope">
185 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> 188 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span>
186 <span v-else>{{ scope.row[col.prop] || '0' }}</span> 189 <span v-else>{{ scope.row[col.prop] || '0' }}</span>
@@ -210,7 +213,8 @@ @@ -210,7 +213,8 @@
210 </div> 213 </div>
211 <NCC-table v-loading="headCountTableLoading" :data="headCountTableData" border stripe style="width: 100%"> 214 <NCC-table v-loading="headCountTableLoading" :data="headCountTableData" border stripe style="width: 100%">
212 <el-table-column v-for="col in headCountTableColumns" :key="col.prop" :prop="col.prop" 215 <el-table-column v-for="col in headCountTableColumns" :key="col.prop" :prop="col.prop"
213 - :label="col.label" :width="col.width" :align="col.align || 'center'"> 216 + :label="col.label" :width="col.width" :align="col.align || 'center'" :sortable="col.sortable || false"
  217 + :sort-method="col.sortMethod || undefined">
214 <template slot-scope="scope"> 218 <template slot-scope="scope">
215 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> 219 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span>
216 <span v-else>{{ scope.row[col.prop] || '0' }}</span> 220 <span v-else>{{ scope.row[col.prop] || '0' }}</span>
@@ -241,7 +245,8 @@ @@ -241,7 +245,8 @@
241 <NCC-table v-loading="personTimeTableLoading" :data="personTimeTableData" border stripe 245 <NCC-table v-loading="personTimeTableLoading" :data="personTimeTableData" border stripe
242 style="width: 100%"> 246 style="width: 100%">
243 <el-table-column v-for="col in personTimeTableColumns" :key="col.prop" :prop="col.prop" 247 <el-table-column v-for="col in personTimeTableColumns" :key="col.prop" :prop="col.prop"
244 - :label="col.label" :width="col.width" :align="col.align || 'center'"> 248 + :label="col.label" :width="col.width" :align="col.align || 'center'" :sortable="col.sortable || false"
  249 + :sort-method="col.sortMethod || undefined">
245 <template slot-scope="scope"> 250 <template slot-scope="scope">
246 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> 251 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span>
247 <span v-else>{{ scope.row[col.prop] || '0' }}</span> 252 <span v-else>{{ scope.row[col.prop] || '0' }}</span>
@@ -272,7 +277,8 @@ @@ -272,7 +277,8 @@
272 <NCC-table v-loading="projectCountTableLoading" :data="projectCountTableData" border stripe 277 <NCC-table v-loading="projectCountTableLoading" :data="projectCountTableData" border stripe
273 style="width: 100%"> 278 style="width: 100%">
274 <el-table-column v-for="col in projectCountTableColumns" :key="col.prop" :prop="col.prop" 279 <el-table-column v-for="col in projectCountTableColumns" :key="col.prop" :prop="col.prop"
275 - :label="col.label" :width="col.width" :align="col.align || 'center'"> 280 + :label="col.label" :width="col.width" :align="col.align || 'center'" :sortable="col.sortable || false"
  281 + :sort-method="col.sortMethod || undefined">
276 <template slot-scope="scope"> 282 <template slot-scope="scope">
277 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> 283 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span>
278 <span v-else>{{ scope.row[col.prop] || '0' }}</span> 284 <span v-else>{{ scope.row[col.prop] || '0' }}</span>
@@ -340,7 +346,7 @@ @@ -340,7 +346,7 @@
340 <NCC-table v-loading="storeIndicatorTableLoading" :data="storeIndicatorTableData" border stripe 346 <NCC-table v-loading="storeIndicatorTableLoading" :data="storeIndicatorTableData" border stripe
341 style="width: 100%"> 347 style="width: 100%">
342 <el-table-column v-for="col in storeIndicatorTableColumns" :key="col.prop" :prop="col.prop" 348 <el-table-column v-for="col in storeIndicatorTableColumns" :key="col.prop" :prop="col.prop"
343 - :label="col.label"> 349 + :label="col.label" :sortable="col.sortable || false" :sort-method="col.sortMethod || undefined">
344 <template slot-scope="scope"> 350 <template slot-scope="scope">
345 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> 351 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span>
346 <span v-else>{{ scope.row[col.prop] || '0' }}</span> 352 <span v-else>{{ scope.row[col.prop] || '0' }}</span>
@@ -408,7 +414,7 @@ @@ -408,7 +414,7 @@
408 <NCC-table v-loading="buIndicatorTableLoading" :data="buIndicatorTableData" border stripe 414 <NCC-table v-loading="buIndicatorTableLoading" :data="buIndicatorTableData" border stripe
409 style="width: 100%"> 415 style="width: 100%">
410 <el-table-column v-for="col in buIndicatorTableColumns" :key="col.prop" :prop="col.prop" 416 <el-table-column v-for="col in buIndicatorTableColumns" :key="col.prop" :prop="col.prop"
411 - :label="col.label"> 417 + :label="col.label" :sortable="col.sortable || false" :sort-method="col.sortMethod || undefined">
412 <template slot-scope="scope"> 418 <template slot-scope="scope">
413 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> 419 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span>
414 <span v-else>{{ scope.row[col.prop] || '0' }}</span> 420 <span v-else>{{ scope.row[col.prop] || '0' }}</span>
@@ -431,7 +437,8 @@ @@ -431,7 +437,8 @@
431 <NCC-table v-loading="buSummaryTableLoading" :data="buSummaryTableData" border stripe style="width: 100%" 437 <NCC-table v-loading="buSummaryTableLoading" :data="buSummaryTableData" border stripe style="width: 100%"
432 :height="null" class="bu-summary-table"> 438 :height="null" class="bu-summary-table">
433 <el-table-column v-for="col in buSummaryTableColumns" :key="col.prop" :prop="col.prop" :label="col.label" 439 <el-table-column v-for="col in buSummaryTableColumns" :key="col.prop" :prop="col.prop" :label="col.label"
434 - :width="col.width" :align="col.align || 'center'"> 440 + :width="col.width" :align="col.align || 'center'" :sortable="col.sortable || false"
  441 + :sort-method="col.sortMethod || undefined">
435 <template slot-scope="scope"> 442 <template slot-scope="scope">
436 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> 443 <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span>
437 <span v-else>{{ scope.row[col.prop] || '0' }}</span> 444 <span v-else>{{ scope.row[col.prop] || '0' }}</span>
@@ -1203,11 +1210,37 @@ export default { @@ -1203,11 +1210,37 @@ export default {
1203 } 1210 }
1204 }) 1211 })
1205 }, 1212 },
  1213 + // 数字排序方法(返回一个排序函数)
  1214 + getNumberSortMethod(prop) {
  1215 + return (a, b) => {
  1216 + const valA = parseFloat(a[prop]) || 0
  1217 + const valB = parseFloat(b[prop]) || 0
  1218 + return valA - valB
  1219 + }
  1220 + },
  1221 + // 增长率排序方法(处理百分比,返回一个排序函数)
  1222 + getGrowthRateSortMethod(prop) {
  1223 + return (a, b) => {
  1224 + const valA = parseFloat(a[prop]) || 0
  1225 + const valB = parseFloat(b[prop]) || 0
  1226 + return valA - valB
  1227 + }
  1228 + },
  1229 + // 增长率排序方法(处理百分比字符串,返回一个排序函数)
  1230 + getGrowthRateStringSortMethod(prop) {
  1231 + return (a, b) => {
  1232 + const rateA = a[prop] || '0%'
  1233 + const rateB = b[prop] || '0%'
  1234 + const valA = parseFloat(rateA.toString().replace('%', '')) || 0
  1235 + const valB = parseFloat(rateB.toString().replace('%', '')) || 0
  1236 + return valA - valB
  1237 + }
  1238 + },
1206 // 构建趋势表格列 1239 // 构建趋势表格列
1207 buildTrendTableColumns(data) { 1240 buildTrendTableColumns(data) {
1208 const columns = [ 1241 const columns = [
1209 - { label: '事业部', prop: 'businessUnitName', width: 120, align: 'left' },  
1210 - { label: '门店', prop: 'storeName', align: 'left' } 1242 + { label: '事业部', prop: 'businessUnitName', width: 120, align: 'left', sortable: true },
  1243 + { label: '门店', prop: 'storeName', align: 'left', sortable: true }
1211 ] 1244 ]
1212 1245
1213 for (let i = 1; i <= 12; i++) { 1246 for (let i = 1; i <= 12; i++) {
@@ -1216,6 +1249,8 @@ export default { @@ -1216,6 +1249,8 @@ export default {
1216 prop: `month${i}`, 1249 prop: `month${i}`,
1217 width: 100, 1250 width: 100,
1218 align: 'right', 1251 align: 'right',
  1252 + sortable: 'custom',
  1253 + sortMethod: this.getNumberSortMethod(`month${i}`),
1219 formatter: (row) => { 1254 formatter: (row) => {
1220 return row[`month${i}`] ? Number(row[`month${i}`]).toLocaleString() : '0' 1255 return row[`month${i}`] ? Number(row[`month${i}`]).toLocaleString() : '0'
1221 } 1256 }
@@ -1228,6 +1263,8 @@ export default { @@ -1228,6 +1263,8 @@ export default {
1228 prop: 'totalCurrentYear', 1263 prop: 'totalCurrentYear',
1229 width: 120, 1264 width: 120,
1230 align: 'right', 1265 align: 'right',
  1266 + sortable: 'custom',
  1267 + sortMethod: this.getNumberSortMethod('totalCurrentYear'),
1231 formatter: (row) => { 1268 formatter: (row) => {
1232 return row.totalCurrentYear ? Number(row.totalCurrentYear).toLocaleString() : '0' 1269 return row.totalCurrentYear ? Number(row.totalCurrentYear).toLocaleString() : '0'
1233 } 1270 }
@@ -1237,6 +1274,8 @@ export default { @@ -1237,6 +1274,8 @@ export default {
1237 prop: 'totalLastYear', 1274 prop: 'totalLastYear',
1238 width: 120, 1275 width: 120,
1239 align: 'right', 1276 align: 'right',
  1277 + sortable: 'custom',
  1278 + sortMethod: this.getNumberSortMethod('totalLastYear'),
1240 formatter: (row) => { 1279 formatter: (row) => {
1241 return row.totalLastYear ? Number(row.totalLastYear).toLocaleString() : '0' 1280 return row.totalLastYear ? Number(row.totalLastYear).toLocaleString() : '0'
1242 } 1281 }
@@ -1246,6 +1285,8 @@ export default { @@ -1246,6 +1285,8 @@ export default {
1246 prop: 'growthRate', 1285 prop: 'growthRate',
1247 width: 100, 1286 width: 100,
1248 align: 'right', 1287 align: 'right',
  1288 + sortable: 'custom',
  1289 + sortMethod: this.getGrowthRateSortMethod('growthRate'),
1249 formatter: (row) => { 1290 formatter: (row) => {
1250 const rate = parseFloat(row.growthRate) || 0 1291 const rate = parseFloat(row.growthRate) || 0
1251 const color = rate >= 0 ? '#67C23A' : '#F56C6C' 1292 const color = rate >= 0 ? '#67C23A' : '#F56C6C'
@@ -1259,8 +1300,8 @@ export default { @@ -1259,8 +1300,8 @@ export default {
1259 // 构建月度统计表格列 1300 // 构建月度统计表格列
1260 buildMonthlyStatTableColumns(data, name) { 1301 buildMonthlyStatTableColumns(data, name) {
1261 const columns = [ 1302 const columns = [
1262 - { label: '事业部', prop: 'businessUnitName', width: 120, align: 'left' },  
1263 - { label: '门店', prop: 'storeName', align: 'left' } 1303 + { label: '事业部', prop: 'businessUnitName', width: 120, align: 'left', sortable: true },
  1304 + { label: '门店', prop: 'storeName', align: 'left', sortable: true }
1264 ] 1305 ]
1265 1306
1266 for (let i = 1; i <= 12; i++) { 1307 for (let i = 1; i <= 12; i++) {
@@ -1269,6 +1310,8 @@ export default { @@ -1269,6 +1310,8 @@ export default {
1269 prop: `month${i}`, 1310 prop: `month${i}`,
1270 width: 100, 1311 width: 100,
1271 align: 'right', 1312 align: 'right',
  1313 + sortable: 'custom',
  1314 + sortMethod: this.getNumberSortMethod(`month${i}`),
1272 formatter: (row) => { 1315 formatter: (row) => {
1273 const value = row[`month${i}`] || 0 1316 const value = row[`month${i}`] || 0
1274 if (name === '业绩' || name === '消耗') { 1317 if (name === '业绩' || name === '消耗') {
@@ -1285,6 +1328,8 @@ export default { @@ -1285,6 +1328,8 @@ export default {
1285 prop: 'totalCurrentYear', 1328 prop: 'totalCurrentYear',
1286 width: 120, 1329 width: 120,
1287 align: 'right', 1330 align: 'right',
  1331 + sortable: 'custom',
  1332 + sortMethod: this.getNumberSortMethod('totalCurrentYear'),
1288 formatter: (row) => { 1333 formatter: (row) => {
1289 const value = row.totalCurrentYear || 0 1334 const value = row.totalCurrentYear || 0
1290 if (name === '业绩' || name === '消耗') { 1335 if (name === '业绩' || name === '消耗') {
@@ -1298,6 +1343,8 @@ export default { @@ -1298,6 +1343,8 @@ export default {
1298 prop: 'totalLastYear', 1343 prop: 'totalLastYear',
1299 width: 120, 1344 width: 120,
1300 align: 'right', 1345 align: 'right',
  1346 + sortable: 'custom',
  1347 + sortMethod: this.getNumberSortMethod('totalLastYear'),
1301 formatter: (row) => { 1348 formatter: (row) => {
1302 const value = row.totalLastYear || 0 1349 const value = row.totalLastYear || 0
1303 if (name === '业绩' || name === '消耗') { 1350 if (name === '业绩' || name === '消耗') {
@@ -1311,6 +1358,8 @@ export default { @@ -1311,6 +1358,8 @@ export default {
1311 prop: 'growthRate', 1358 prop: 'growthRate',
1312 width: 100, 1359 width: 100,
1313 align: 'right', 1360 align: 'right',
  1361 + sortable: 'custom',
  1362 + sortMethod: this.getGrowthRateSortMethod('growthRate'),
1314 formatter: (row) => { 1363 formatter: (row) => {
1315 const rate = parseFloat(row.growthRate) || 0 1364 const rate = parseFloat(row.growthRate) || 0
1316 const color = rate >= 0 ? '#67C23A' : '#F56C6C' 1365 const color = rate >= 0 ? '#67C23A' : '#F56C6C'
@@ -1340,13 +1389,15 @@ export default { @@ -1340,13 +1389,15 @@ export default {
1340 // 构建门店指标表格列 1389 // 构建门店指标表格列
1341 buildStoreIndicatorTableColumns() { 1390 buildStoreIndicatorTableColumns() {
1342 this.storeIndicatorTableColumns = [ 1391 this.storeIndicatorTableColumns = [
1343 - { label: '事业部', prop: 'businessUnitName', width: 120, align: 'left' },  
1344 - { label: '门店', prop: 'storeName', align: 'left' }, 1392 + { label: '事业部', prop: 'businessUnitName', width: 120, align: 'left', sortable: true },
  1393 + { label: '门店', prop: 'storeName', align: 'left', sortable: true },
1345 { 1394 {
1346 label: '本年数值', 1395 label: '本年数值',
1347 prop: 'currentYearValue', 1396 prop: 'currentYearValue',
1348 width: 120, 1397 width: 120,
1349 align: 'right', 1398 align: 'right',
  1399 + sortable: 'custom',
  1400 + sortMethod: this.getNumberSortMethod('currentYearValue'),
1350 formatter: (row) => { 1401 formatter: (row) => {
1351 return Number(row.currentYearValue || 0).toLocaleString() 1402 return Number(row.currentYearValue || 0).toLocaleString()
1352 } 1403 }
@@ -1356,6 +1407,8 @@ export default { @@ -1356,6 +1407,8 @@ export default {
1356 prop: 'lastYearValue', 1407 prop: 'lastYearValue',
1357 width: 120, 1408 width: 120,
1358 align: 'right', 1409 align: 'right',
  1410 + sortable: 'custom',
  1411 + sortMethod: this.getNumberSortMethod('lastYearValue'),
1359 formatter: (row) => { 1412 formatter: (row) => {
1360 return Number(row.lastYearValue || 0).toLocaleString() 1413 return Number(row.lastYearValue || 0).toLocaleString()
1361 } 1414 }
@@ -1365,6 +1418,8 @@ export default { @@ -1365,6 +1418,8 @@ export default {
1365 prop: 'growthRate', 1418 prop: 'growthRate',
1366 width: 100, 1419 width: 100,
1367 align: 'right', 1420 align: 'right',
  1421 + sortable: 'custom',
  1422 + sortMethod: this.getGrowthRateSortMethod('growthRate'),
1368 formatter: (row) => { 1423 formatter: (row) => {
1369 const rate = parseFloat(row.growthRate) || 0 1424 const rate = parseFloat(row.growthRate) || 0
1370 const color = rate >= 0 ? '#67C23A' : '#F56C6C' 1425 const color = rate >= 0 ? '#67C23A' : '#F56C6C'
@@ -1376,12 +1431,14 @@ export default { @@ -1376,12 +1431,14 @@ export default {
1376 // 构建事业部指标表格列 1431 // 构建事业部指标表格列
1377 buildBuIndicatorTableColumns() { 1432 buildBuIndicatorTableColumns() {
1378 this.buIndicatorTableColumns = [ 1433 this.buIndicatorTableColumns = [
1379 - { label: '事业部', prop: 'businessUnitName', width: 200, align: 'left' }, 1434 + { label: '事业部', prop: 'businessUnitName', width: 200, align: 'left', sortable: true },
1380 { 1435 {
1381 label: '本年数值', 1436 label: '本年数值',
1382 prop: 'currentYearValue', 1437 prop: 'currentYearValue',
1383 width: 150, 1438 width: 150,
1384 align: 'right', 1439 align: 'right',
  1440 + sortable: 'custom',
  1441 + sortMethod: this.getNumberSortMethod('currentYearValue'),
1385 formatter: (row) => { 1442 formatter: (row) => {
1386 return Number(row.currentYearValue || 0).toLocaleString() 1443 return Number(row.currentYearValue || 0).toLocaleString()
1387 } 1444 }
@@ -1391,6 +1448,8 @@ export default { @@ -1391,6 +1448,8 @@ export default {
1391 prop: 'lastYearValue', 1448 prop: 'lastYearValue',
1392 width: 150, 1449 width: 150,
1393 align: 'right', 1450 align: 'right',
  1451 + sortable: 'custom',
  1452 + sortMethod: this.getNumberSortMethod('lastYearValue'),
1394 formatter: (row) => { 1453 formatter: (row) => {
1395 return Number(row.lastYearValue || 0).toLocaleString() 1454 return Number(row.lastYearValue || 0).toLocaleString()
1396 } 1455 }
@@ -1400,6 +1459,8 @@ export default { @@ -1400,6 +1459,8 @@ export default {
1400 prop: 'growthRate', 1459 prop: 'growthRate',
1401 width: 120, 1460 width: 120,
1402 align: 'right', 1461 align: 'right',
  1462 + sortable: 'custom',
  1463 + sortMethod: this.getGrowthRateSortMethod('growthRate'),
1403 formatter: (row) => { 1464 formatter: (row) => {
1404 const rate = parseFloat(row.growthRate) || 0 1465 const rate = parseFloat(row.growthRate) || 0
1405 const color = rate >= 0 ? '#67C23A' : '#F56C6C' 1466 const color = rate >= 0 ? '#67C23A' : '#F56C6C'
@@ -1411,13 +1472,15 @@ export default { @@ -1411,13 +1472,15 @@ export default {
1411 // 构建事业部汇总表格列 1472 // 构建事业部汇总表格列
1412 buildBuSummaryTableColumns() { 1473 buildBuSummaryTableColumns() {
1413 this.buSummaryTableColumns = [ 1474 this.buSummaryTableColumns = [
1414 - { label: '事业部', prop: 'businessUnitName', width: 120, align: 'left' },  
1415 - { label: '门店', prop: 'storeName', align: 'left' }, 1475 + { label: '事业部', prop: 'businessUnitName', width: 120, align: 'left', sortable: true },
  1476 + { label: '门店', prop: 'storeName', align: 'left', sortable: true },
1416 { 1477 {
1417 label: '本年业绩', 1478 label: '本年业绩',
1418 prop: 'currentPerformance', 1479 prop: 'currentPerformance',
1419 width: 120, 1480 width: 120,
1420 align: 'right', 1481 align: 'right',
  1482 + sortable: 'custom',
  1483 + sortMethod: this.getNumberSortMethod('currentPerformance'),
1421 formatter: (row) => { 1484 formatter: (row) => {
1422 return `¥${Number(row.currentPerformance || 0).toLocaleString()}` 1485 return `¥${Number(row.currentPerformance || 0).toLocaleString()}`
1423 } 1486 }
@@ -1427,6 +1490,8 @@ export default { @@ -1427,6 +1490,8 @@ export default {
1427 prop: 'lastPerformance', 1490 prop: 'lastPerformance',
1428 width: 120, 1491 width: 120,
1429 align: 'right', 1492 align: 'right',
  1493 + sortable: 'custom',
  1494 + sortMethod: this.getNumberSortMethod('lastPerformance'),
1430 formatter: (row) => { 1495 formatter: (row) => {
1431 return `¥${Number(row.lastPerformance || 0).toLocaleString()}` 1496 return `¥${Number(row.lastPerformance || 0).toLocaleString()}`
1432 } 1497 }
@@ -1436,6 +1501,8 @@ export default { @@ -1436,6 +1501,8 @@ export default {
1436 prop: 'performanceGrowthRate', 1501 prop: 'performanceGrowthRate',
1437 width: 110, 1502 width: 110,
1438 align: 'right', 1503 align: 'right',
  1504 + sortable: 'custom',
  1505 + sortMethod: this.getGrowthRateStringSortMethod('performanceGrowthRate'),
1439 formatter: (row) => { 1506 formatter: (row) => {
1440 const rate = row.performanceGrowthRate || '0%' 1507 const rate = row.performanceGrowthRate || '0%'
1441 const numRate = parseFloat(rate) || 0 1508 const numRate = parseFloat(rate) || 0
@@ -1448,6 +1515,8 @@ export default { @@ -1448,6 +1515,8 @@ export default {
1448 prop: 'currentConsume', 1515 prop: 'currentConsume',
1449 width: 120, 1516 width: 120,
1450 align: 'right', 1517 align: 'right',
  1518 + sortable: 'custom',
  1519 + sortMethod: this.getNumberSortMethod('currentConsume'),
1451 formatter: (row) => { 1520 formatter: (row) => {
1452 return `¥${Number(row.currentConsume || 0).toLocaleString()}` 1521 return `¥${Number(row.currentConsume || 0).toLocaleString()}`
1453 } 1522 }
@@ -1457,6 +1526,8 @@ export default { @@ -1457,6 +1526,8 @@ export default {
1457 prop: 'lastConsume', 1526 prop: 'lastConsume',
1458 width: 120, 1527 width: 120,
1459 align: 'right', 1528 align: 'right',
  1529 + sortable: 'custom',
  1530 + sortMethod: this.getNumberSortMethod('lastConsume'),
1460 formatter: (row) => { 1531 formatter: (row) => {
1461 return `¥${Number(row.lastConsume || 0).toLocaleString()}` 1532 return `¥${Number(row.lastConsume || 0).toLocaleString()}`
1462 } 1533 }
@@ -1466,6 +1537,8 @@ export default { @@ -1466,6 +1537,8 @@ export default {
1466 prop: 'consumeGrowthRate', 1537 prop: 'consumeGrowthRate',
1467 width: 110, 1538 width: 110,
1468 align: 'right', 1539 align: 'right',
  1540 + sortable: 'custom',
  1541 + sortMethod: this.getGrowthRateStringSortMethod('consumeGrowthRate'),
1469 formatter: (row) => { 1542 formatter: (row) => {
1470 const rate = row.consumeGrowthRate || '0%' 1543 const rate = row.consumeGrowthRate || '0%'
1471 const numRate = parseFloat(rate) || 0 1544 const numRate = parseFloat(rate) || 0
@@ -1478,6 +1551,8 @@ export default { @@ -1478,6 +1551,8 @@ export default {
1478 prop: 'currentHeadCount', 1551 prop: 'currentHeadCount',
1479 width: 100, 1552 width: 100,
1480 align: 'right', 1553 align: 'right',
  1554 + sortable: 'custom',
  1555 + sortMethod: this.getNumberSortMethod('currentHeadCount'),
1481 formatter: (row) => { 1556 formatter: (row) => {
1482 return Number(row.currentHeadCount || 0).toLocaleString() 1557 return Number(row.currentHeadCount || 0).toLocaleString()
1483 } 1558 }
@@ -1487,6 +1562,8 @@ export default { @@ -1487,6 +1562,8 @@ export default {
1487 prop: 'lastHeadCount', 1562 prop: 'lastHeadCount',
1488 width: 100, 1563 width: 100,
1489 align: 'right', 1564 align: 'right',
  1565 + sortable: 'custom',
  1566 + sortMethod: this.getNumberSortMethod('lastHeadCount'),
1490 formatter: (row) => { 1567 formatter: (row) => {
1491 return Number(row.lastHeadCount || 0).toLocaleString() 1568 return Number(row.lastHeadCount || 0).toLocaleString()
1492 } 1569 }
@@ -1496,6 +1573,8 @@ export default { @@ -1496,6 +1573,8 @@ export default {
1496 prop: 'headCountGrowthRate', 1573 prop: 'headCountGrowthRate',
1497 width: 110, 1574 width: 110,
1498 align: 'right', 1575 align: 'right',
  1576 + sortable: 'custom',
  1577 + sortMethod: this.getGrowthRateStringSortMethod('headCountGrowthRate'),
1499 formatter: (row) => { 1578 formatter: (row) => {
1500 const rate = row.headCountGrowthRate || '0%' 1579 const rate = row.headCountGrowthRate || '0%'
1501 const numRate = parseFloat(rate) || 0 1580 const numRate = parseFloat(rate) || 0
@@ -1508,6 +1587,8 @@ export default { @@ -1508,6 +1587,8 @@ export default {
1508 prop: 'currentPersonTime', 1587 prop: 'currentPersonTime',
1509 width: 100, 1588 width: 100,
1510 align: 'right', 1589 align: 'right',
  1590 + sortable: 'custom',
  1591 + sortMethod: this.getNumberSortMethod('currentPersonTime'),
1511 formatter: (row) => { 1592 formatter: (row) => {
1512 return Number(row.currentPersonTime || 0).toLocaleString() 1593 return Number(row.currentPersonTime || 0).toLocaleString()
1513 } 1594 }
@@ -1517,6 +1598,8 @@ export default { @@ -1517,6 +1598,8 @@ export default {
1517 prop: 'lastPersonTime', 1598 prop: 'lastPersonTime',
1518 width: 100, 1599 width: 100,
1519 align: 'right', 1600 align: 'right',
  1601 + sortable: 'custom',
  1602 + sortMethod: this.getNumberSortMethod('lastPersonTime'),
1520 formatter: (row) => { 1603 formatter: (row) => {
1521 return Number(row.lastPersonTime || 0).toLocaleString() 1604 return Number(row.lastPersonTime || 0).toLocaleString()
1522 } 1605 }
@@ -1526,6 +1609,8 @@ export default { @@ -1526,6 +1609,8 @@ export default {
1526 prop: 'personTimeGrowthRate', 1609 prop: 'personTimeGrowthRate',
1527 width: 110, 1610 width: 110,
1528 align: 'right', 1611 align: 'right',
  1612 + sortable: 'custom',
  1613 + sortMethod: this.getGrowthRateStringSortMethod('personTimeGrowthRate'),
1529 formatter: (row) => { 1614 formatter: (row) => {
1530 const rate = row.personTimeGrowthRate || '0%' 1615 const rate = row.personTimeGrowthRate || '0%'
1531 const numRate = parseFloat(rate) || 0 1616 const numRate = parseFloat(rate) || 0
@@ -1538,6 +1623,8 @@ export default { @@ -1538,6 +1623,8 @@ export default {
1538 prop: 'currentProjectCount', 1623 prop: 'currentProjectCount',
1539 width: 100, 1624 width: 100,
1540 align: 'right', 1625 align: 'right',
  1626 + sortable: 'custom',
  1627 + sortMethod: this.getNumberSortMethod('currentProjectCount'),
1541 formatter: (row) => { 1628 formatter: (row) => {
1542 return Number(row.currentProjectCount || 0).toLocaleString() 1629 return Number(row.currentProjectCount || 0).toLocaleString()
1543 } 1630 }
@@ -1547,6 +1634,8 @@ export default { @@ -1547,6 +1634,8 @@ export default {
1547 prop: 'lastProjectCount', 1634 prop: 'lastProjectCount',
1548 width: 100, 1635 width: 100,
1549 align: 'right', 1636 align: 'right',
  1637 + sortable: 'custom',
  1638 + sortMethod: this.getNumberSortMethod('lastProjectCount'),
1550 formatter: (row) => { 1639 formatter: (row) => {
1551 return Number(row.lastProjectCount || 0).toLocaleString() 1640 return Number(row.lastProjectCount || 0).toLocaleString()
1552 } 1641 }
@@ -1556,6 +1645,8 @@ export default { @@ -1556,6 +1645,8 @@ export default {
1556 prop: 'projectCountGrowthRate', 1645 prop: 'projectCountGrowthRate',
1557 width: 110, 1646 width: 110,
1558 align: 'right', 1647 align: 'right',
  1648 + sortable: 'custom',
  1649 + sortMethod: this.getGrowthRateStringSortMethod('projectCountGrowthRate'),
1559 formatter: (row) => { 1650 formatter: (row) => {
1560 const rate = row.projectCountGrowthRate || '0%' 1651 const rate = row.projectCountGrowthRate || '0%'
1561 const numRate = parseFloat(rate) || 0 1652 const numRate = parseFloat(rate) || 0
netcore/src/Modularity/Extend/NCC.Extend/LqAnnualSummaryService.cs
@@ -985,8 +985,17 @@ namespace NCC.Extend @@ -985,8 +985,17 @@ namespace NCC.Extend
985 .ToListAsync(); 985 .ToListAsync();
986 986
987 // 整理所有门店 (包括今年有数据和去年有数据的) 987 // 整理所有门店 (包括今年有数据和去年有数据的)
988 - var allStores = currentYearData.Select(x => new { x.StoreId, x.StoreName, x.BusinessUnitName, x.BusinessUnitId })  
989 - .Distinct() 988 + // 按门店ID去重,确保每个门店只出现一次
  989 + // 如果同一门店有多个事业部,取第一个(通常应该只有一个)
  990 + var allStores = currentYearData
  991 + .GroupBy(x => x.StoreId)
  992 + .Select(g => new
  993 + {
  994 + StoreId = g.Key,
  995 + StoreName = g.First().StoreName,
  996 + BusinessUnitName = g.First().BusinessUnitName,
  997 + BusinessUnitId = g.First().BusinessUnitId
  998 + })
990 .OrderBy(x => x.BusinessUnitName) 999 .OrderBy(x => x.BusinessUnitName)
991 .ThenBy(x => x.StoreName) 1000 .ThenBy(x => x.StoreName)
992 .ToList(); 1001 .ToList();