Commit 189ad8f683f9fe588b2430ac034600d8cba2fb3d
Merge branch 'master' of http://39.98.150.180/antissoft/lvqianmeiye_ERP
Showing
2 changed files
with
120 additions
and
20 deletions
antis-ncc-admin/src/views/extend/annualSummary/dashboard/index.vue
| ... | ... | @@ -119,7 +119,8 @@ |
| 119 | 119 | </div> |
| 120 | 120 | <NCC-table v-loading="trendTableLoading" :data="trendTableData" border stripe style="width: 100%"> |
| 121 | 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 | 124 | <template slot-scope="scope"> |
| 124 | 125 | <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> |
| 125 | 126 | <span v-else>{{ scope.row[col.prop] || '0' }}</span> |
| ... | ... | @@ -150,7 +151,8 @@ |
| 150 | 151 | <NCC-table v-loading="performanceTableLoading" :data="performanceTableData" border stripe |
| 151 | 152 | style="width: 100%"> |
| 152 | 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 | 156 | <template slot-scope="scope"> |
| 155 | 157 | <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> |
| 156 | 158 | <span v-else>{{ scope.row[col.prop] || '0' }}</span> |
| ... | ... | @@ -180,7 +182,8 @@ |
| 180 | 182 | </div> |
| 181 | 183 | <NCC-table v-loading="consumeTableLoading" :data="consumeTableData" border stripe style="width: 100%"> |
| 182 | 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 | 187 | <template slot-scope="scope"> |
| 185 | 188 | <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> |
| 186 | 189 | <span v-else>{{ scope.row[col.prop] || '0' }}</span> |
| ... | ... | @@ -210,7 +213,8 @@ |
| 210 | 213 | </div> |
| 211 | 214 | <NCC-table v-loading="headCountTableLoading" :data="headCountTableData" border stripe style="width: 100%"> |
| 212 | 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 | 218 | <template slot-scope="scope"> |
| 215 | 219 | <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> |
| 216 | 220 | <span v-else>{{ scope.row[col.prop] || '0' }}</span> |
| ... | ... | @@ -241,7 +245,8 @@ |
| 241 | 245 | <NCC-table v-loading="personTimeTableLoading" :data="personTimeTableData" border stripe |
| 242 | 246 | style="width: 100%"> |
| 243 | 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 | 250 | <template slot-scope="scope"> |
| 246 | 251 | <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> |
| 247 | 252 | <span v-else>{{ scope.row[col.prop] || '0' }}</span> |
| ... | ... | @@ -272,7 +277,8 @@ |
| 272 | 277 | <NCC-table v-loading="projectCountTableLoading" :data="projectCountTableData" border stripe |
| 273 | 278 | style="width: 100%"> |
| 274 | 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 | 282 | <template slot-scope="scope"> |
| 277 | 283 | <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> |
| 278 | 284 | <span v-else>{{ scope.row[col.prop] || '0' }}</span> |
| ... | ... | @@ -340,7 +346,7 @@ |
| 340 | 346 | <NCC-table v-loading="storeIndicatorTableLoading" :data="storeIndicatorTableData" border stripe |
| 341 | 347 | style="width: 100%"> |
| 342 | 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 | 350 | <template slot-scope="scope"> |
| 345 | 351 | <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> |
| 346 | 352 | <span v-else>{{ scope.row[col.prop] || '0' }}</span> |
| ... | ... | @@ -408,7 +414,7 @@ |
| 408 | 414 | <NCC-table v-loading="buIndicatorTableLoading" :data="buIndicatorTableData" border stripe |
| 409 | 415 | style="width: 100%"> |
| 410 | 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 | 418 | <template slot-scope="scope"> |
| 413 | 419 | <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> |
| 414 | 420 | <span v-else>{{ scope.row[col.prop] || '0' }}</span> |
| ... | ... | @@ -431,7 +437,8 @@ |
| 431 | 437 | <NCC-table v-loading="buSummaryTableLoading" :data="buSummaryTableData" border stripe style="width: 100%" |
| 432 | 438 | :height="null" class="bu-summary-table"> |
| 433 | 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 | 442 | <template slot-scope="scope"> |
| 436 | 443 | <span v-if="col.formatter" v-html="col.formatter(scope.row)"></span> |
| 437 | 444 | <span v-else>{{ scope.row[col.prop] || '0' }}</span> |
| ... | ... | @@ -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 | 1240 | buildTrendTableColumns(data) { |
| 1208 | 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 | 1246 | for (let i = 1; i <= 12; i++) { |
| ... | ... | @@ -1216,6 +1249,8 @@ export default { |
| 1216 | 1249 | prop: `month${i}`, |
| 1217 | 1250 | width: 100, |
| 1218 | 1251 | align: 'right', |
| 1252 | + sortable: 'custom', | |
| 1253 | + sortMethod: this.getNumberSortMethod(`month${i}`), | |
| 1219 | 1254 | formatter: (row) => { |
| 1220 | 1255 | return row[`month${i}`] ? Number(row[`month${i}`]).toLocaleString() : '0' |
| 1221 | 1256 | } |
| ... | ... | @@ -1228,6 +1263,8 @@ export default { |
| 1228 | 1263 | prop: 'totalCurrentYear', |
| 1229 | 1264 | width: 120, |
| 1230 | 1265 | align: 'right', |
| 1266 | + sortable: 'custom', | |
| 1267 | + sortMethod: this.getNumberSortMethod('totalCurrentYear'), | |
| 1231 | 1268 | formatter: (row) => { |
| 1232 | 1269 | return row.totalCurrentYear ? Number(row.totalCurrentYear).toLocaleString() : '0' |
| 1233 | 1270 | } |
| ... | ... | @@ -1237,6 +1274,8 @@ export default { |
| 1237 | 1274 | prop: 'totalLastYear', |
| 1238 | 1275 | width: 120, |
| 1239 | 1276 | align: 'right', |
| 1277 | + sortable: 'custom', | |
| 1278 | + sortMethod: this.getNumberSortMethod('totalLastYear'), | |
| 1240 | 1279 | formatter: (row) => { |
| 1241 | 1280 | return row.totalLastYear ? Number(row.totalLastYear).toLocaleString() : '0' |
| 1242 | 1281 | } |
| ... | ... | @@ -1246,6 +1285,8 @@ export default { |
| 1246 | 1285 | prop: 'growthRate', |
| 1247 | 1286 | width: 100, |
| 1248 | 1287 | align: 'right', |
| 1288 | + sortable: 'custom', | |
| 1289 | + sortMethod: this.getGrowthRateSortMethod('growthRate'), | |
| 1249 | 1290 | formatter: (row) => { |
| 1250 | 1291 | const rate = parseFloat(row.growthRate) || 0 |
| 1251 | 1292 | const color = rate >= 0 ? '#67C23A' : '#F56C6C' |
| ... | ... | @@ -1259,8 +1300,8 @@ export default { |
| 1259 | 1300 | // 构建月度统计表格列 |
| 1260 | 1301 | buildMonthlyStatTableColumns(data, name) { |
| 1261 | 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 | 1307 | for (let i = 1; i <= 12; i++) { |
| ... | ... | @@ -1269,6 +1310,8 @@ export default { |
| 1269 | 1310 | prop: `month${i}`, |
| 1270 | 1311 | width: 100, |
| 1271 | 1312 | align: 'right', |
| 1313 | + sortable: 'custom', | |
| 1314 | + sortMethod: this.getNumberSortMethod(`month${i}`), | |
| 1272 | 1315 | formatter: (row) => { |
| 1273 | 1316 | const value = row[`month${i}`] || 0 |
| 1274 | 1317 | if (name === '业绩' || name === '消耗') { |
| ... | ... | @@ -1285,6 +1328,8 @@ export default { |
| 1285 | 1328 | prop: 'totalCurrentYear', |
| 1286 | 1329 | width: 120, |
| 1287 | 1330 | align: 'right', |
| 1331 | + sortable: 'custom', | |
| 1332 | + sortMethod: this.getNumberSortMethod('totalCurrentYear'), | |
| 1288 | 1333 | formatter: (row) => { |
| 1289 | 1334 | const value = row.totalCurrentYear || 0 |
| 1290 | 1335 | if (name === '业绩' || name === '消耗') { |
| ... | ... | @@ -1298,6 +1343,8 @@ export default { |
| 1298 | 1343 | prop: 'totalLastYear', |
| 1299 | 1344 | width: 120, |
| 1300 | 1345 | align: 'right', |
| 1346 | + sortable: 'custom', | |
| 1347 | + sortMethod: this.getNumberSortMethod('totalLastYear'), | |
| 1301 | 1348 | formatter: (row) => { |
| 1302 | 1349 | const value = row.totalLastYear || 0 |
| 1303 | 1350 | if (name === '业绩' || name === '消耗') { |
| ... | ... | @@ -1311,6 +1358,8 @@ export default { |
| 1311 | 1358 | prop: 'growthRate', |
| 1312 | 1359 | width: 100, |
| 1313 | 1360 | align: 'right', |
| 1361 | + sortable: 'custom', | |
| 1362 | + sortMethod: this.getGrowthRateSortMethod('growthRate'), | |
| 1314 | 1363 | formatter: (row) => { |
| 1315 | 1364 | const rate = parseFloat(row.growthRate) || 0 |
| 1316 | 1365 | const color = rate >= 0 ? '#67C23A' : '#F56C6C' |
| ... | ... | @@ -1340,13 +1389,15 @@ export default { |
| 1340 | 1389 | // 构建门店指标表格列 |
| 1341 | 1390 | buildStoreIndicatorTableColumns() { |
| 1342 | 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 | 1395 | label: '本年数值', |
| 1347 | 1396 | prop: 'currentYearValue', |
| 1348 | 1397 | width: 120, |
| 1349 | 1398 | align: 'right', |
| 1399 | + sortable: 'custom', | |
| 1400 | + sortMethod: this.getNumberSortMethod('currentYearValue'), | |
| 1350 | 1401 | formatter: (row) => { |
| 1351 | 1402 | return Number(row.currentYearValue || 0).toLocaleString() |
| 1352 | 1403 | } |
| ... | ... | @@ -1356,6 +1407,8 @@ export default { |
| 1356 | 1407 | prop: 'lastYearValue', |
| 1357 | 1408 | width: 120, |
| 1358 | 1409 | align: 'right', |
| 1410 | + sortable: 'custom', | |
| 1411 | + sortMethod: this.getNumberSortMethod('lastYearValue'), | |
| 1359 | 1412 | formatter: (row) => { |
| 1360 | 1413 | return Number(row.lastYearValue || 0).toLocaleString() |
| 1361 | 1414 | } |
| ... | ... | @@ -1365,6 +1418,8 @@ export default { |
| 1365 | 1418 | prop: 'growthRate', |
| 1366 | 1419 | width: 100, |
| 1367 | 1420 | align: 'right', |
| 1421 | + sortable: 'custom', | |
| 1422 | + sortMethod: this.getGrowthRateSortMethod('growthRate'), | |
| 1368 | 1423 | formatter: (row) => { |
| 1369 | 1424 | const rate = parseFloat(row.growthRate) || 0 |
| 1370 | 1425 | const color = rate >= 0 ? '#67C23A' : '#F56C6C' |
| ... | ... | @@ -1376,12 +1431,14 @@ export default { |
| 1376 | 1431 | // 构建事业部指标表格列 |
| 1377 | 1432 | buildBuIndicatorTableColumns() { |
| 1378 | 1433 | this.buIndicatorTableColumns = [ |
| 1379 | - { label: '事业部', prop: 'businessUnitName', width: 200, align: 'left' }, | |
| 1434 | + { label: '事业部', prop: 'businessUnitName', width: 200, align: 'left', sortable: true }, | |
| 1380 | 1435 | { |
| 1381 | 1436 | label: '本年数值', |
| 1382 | 1437 | prop: 'currentYearValue', |
| 1383 | 1438 | width: 150, |
| 1384 | 1439 | align: 'right', |
| 1440 | + sortable: 'custom', | |
| 1441 | + sortMethod: this.getNumberSortMethod('currentYearValue'), | |
| 1385 | 1442 | formatter: (row) => { |
| 1386 | 1443 | return Number(row.currentYearValue || 0).toLocaleString() |
| 1387 | 1444 | } |
| ... | ... | @@ -1391,6 +1448,8 @@ export default { |
| 1391 | 1448 | prop: 'lastYearValue', |
| 1392 | 1449 | width: 150, |
| 1393 | 1450 | align: 'right', |
| 1451 | + sortable: 'custom', | |
| 1452 | + sortMethod: this.getNumberSortMethod('lastYearValue'), | |
| 1394 | 1453 | formatter: (row) => { |
| 1395 | 1454 | return Number(row.lastYearValue || 0).toLocaleString() |
| 1396 | 1455 | } |
| ... | ... | @@ -1400,6 +1459,8 @@ export default { |
| 1400 | 1459 | prop: 'growthRate', |
| 1401 | 1460 | width: 120, |
| 1402 | 1461 | align: 'right', |
| 1462 | + sortable: 'custom', | |
| 1463 | + sortMethod: this.getGrowthRateSortMethod('growthRate'), | |
| 1403 | 1464 | formatter: (row) => { |
| 1404 | 1465 | const rate = parseFloat(row.growthRate) || 0 |
| 1405 | 1466 | const color = rate >= 0 ? '#67C23A' : '#F56C6C' |
| ... | ... | @@ -1411,13 +1472,15 @@ export default { |
| 1411 | 1472 | // 构建事业部汇总表格列 |
| 1412 | 1473 | buildBuSummaryTableColumns() { |
| 1413 | 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 | 1478 | label: '本年业绩', |
| 1418 | 1479 | prop: 'currentPerformance', |
| 1419 | 1480 | width: 120, |
| 1420 | 1481 | align: 'right', |
| 1482 | + sortable: 'custom', | |
| 1483 | + sortMethod: this.getNumberSortMethod('currentPerformance'), | |
| 1421 | 1484 | formatter: (row) => { |
| 1422 | 1485 | return `¥${Number(row.currentPerformance || 0).toLocaleString()}` |
| 1423 | 1486 | } |
| ... | ... | @@ -1427,6 +1490,8 @@ export default { |
| 1427 | 1490 | prop: 'lastPerformance', |
| 1428 | 1491 | width: 120, |
| 1429 | 1492 | align: 'right', |
| 1493 | + sortable: 'custom', | |
| 1494 | + sortMethod: this.getNumberSortMethod('lastPerformance'), | |
| 1430 | 1495 | formatter: (row) => { |
| 1431 | 1496 | return `¥${Number(row.lastPerformance || 0).toLocaleString()}` |
| 1432 | 1497 | } |
| ... | ... | @@ -1436,6 +1501,8 @@ export default { |
| 1436 | 1501 | prop: 'performanceGrowthRate', |
| 1437 | 1502 | width: 110, |
| 1438 | 1503 | align: 'right', |
| 1504 | + sortable: 'custom', | |
| 1505 | + sortMethod: this.getGrowthRateStringSortMethod('performanceGrowthRate'), | |
| 1439 | 1506 | formatter: (row) => { |
| 1440 | 1507 | const rate = row.performanceGrowthRate || '0%' |
| 1441 | 1508 | const numRate = parseFloat(rate) || 0 |
| ... | ... | @@ -1448,6 +1515,8 @@ export default { |
| 1448 | 1515 | prop: 'currentConsume', |
| 1449 | 1516 | width: 120, |
| 1450 | 1517 | align: 'right', |
| 1518 | + sortable: 'custom', | |
| 1519 | + sortMethod: this.getNumberSortMethod('currentConsume'), | |
| 1451 | 1520 | formatter: (row) => { |
| 1452 | 1521 | return `¥${Number(row.currentConsume || 0).toLocaleString()}` |
| 1453 | 1522 | } |
| ... | ... | @@ -1457,6 +1526,8 @@ export default { |
| 1457 | 1526 | prop: 'lastConsume', |
| 1458 | 1527 | width: 120, |
| 1459 | 1528 | align: 'right', |
| 1529 | + sortable: 'custom', | |
| 1530 | + sortMethod: this.getNumberSortMethod('lastConsume'), | |
| 1460 | 1531 | formatter: (row) => { |
| 1461 | 1532 | return `¥${Number(row.lastConsume || 0).toLocaleString()}` |
| 1462 | 1533 | } |
| ... | ... | @@ -1466,6 +1537,8 @@ export default { |
| 1466 | 1537 | prop: 'consumeGrowthRate', |
| 1467 | 1538 | width: 110, |
| 1468 | 1539 | align: 'right', |
| 1540 | + sortable: 'custom', | |
| 1541 | + sortMethod: this.getGrowthRateStringSortMethod('consumeGrowthRate'), | |
| 1469 | 1542 | formatter: (row) => { |
| 1470 | 1543 | const rate = row.consumeGrowthRate || '0%' |
| 1471 | 1544 | const numRate = parseFloat(rate) || 0 |
| ... | ... | @@ -1478,6 +1551,8 @@ export default { |
| 1478 | 1551 | prop: 'currentHeadCount', |
| 1479 | 1552 | width: 100, |
| 1480 | 1553 | align: 'right', |
| 1554 | + sortable: 'custom', | |
| 1555 | + sortMethod: this.getNumberSortMethod('currentHeadCount'), | |
| 1481 | 1556 | formatter: (row) => { |
| 1482 | 1557 | return Number(row.currentHeadCount || 0).toLocaleString() |
| 1483 | 1558 | } |
| ... | ... | @@ -1487,6 +1562,8 @@ export default { |
| 1487 | 1562 | prop: 'lastHeadCount', |
| 1488 | 1563 | width: 100, |
| 1489 | 1564 | align: 'right', |
| 1565 | + sortable: 'custom', | |
| 1566 | + sortMethod: this.getNumberSortMethod('lastHeadCount'), | |
| 1490 | 1567 | formatter: (row) => { |
| 1491 | 1568 | return Number(row.lastHeadCount || 0).toLocaleString() |
| 1492 | 1569 | } |
| ... | ... | @@ -1496,6 +1573,8 @@ export default { |
| 1496 | 1573 | prop: 'headCountGrowthRate', |
| 1497 | 1574 | width: 110, |
| 1498 | 1575 | align: 'right', |
| 1576 | + sortable: 'custom', | |
| 1577 | + sortMethod: this.getGrowthRateStringSortMethod('headCountGrowthRate'), | |
| 1499 | 1578 | formatter: (row) => { |
| 1500 | 1579 | const rate = row.headCountGrowthRate || '0%' |
| 1501 | 1580 | const numRate = parseFloat(rate) || 0 |
| ... | ... | @@ -1508,6 +1587,8 @@ export default { |
| 1508 | 1587 | prop: 'currentPersonTime', |
| 1509 | 1588 | width: 100, |
| 1510 | 1589 | align: 'right', |
| 1590 | + sortable: 'custom', | |
| 1591 | + sortMethod: this.getNumberSortMethod('currentPersonTime'), | |
| 1511 | 1592 | formatter: (row) => { |
| 1512 | 1593 | return Number(row.currentPersonTime || 0).toLocaleString() |
| 1513 | 1594 | } |
| ... | ... | @@ -1517,6 +1598,8 @@ export default { |
| 1517 | 1598 | prop: 'lastPersonTime', |
| 1518 | 1599 | width: 100, |
| 1519 | 1600 | align: 'right', |
| 1601 | + sortable: 'custom', | |
| 1602 | + sortMethod: this.getNumberSortMethod('lastPersonTime'), | |
| 1520 | 1603 | formatter: (row) => { |
| 1521 | 1604 | return Number(row.lastPersonTime || 0).toLocaleString() |
| 1522 | 1605 | } |
| ... | ... | @@ -1526,6 +1609,8 @@ export default { |
| 1526 | 1609 | prop: 'personTimeGrowthRate', |
| 1527 | 1610 | width: 110, |
| 1528 | 1611 | align: 'right', |
| 1612 | + sortable: 'custom', | |
| 1613 | + sortMethod: this.getGrowthRateStringSortMethod('personTimeGrowthRate'), | |
| 1529 | 1614 | formatter: (row) => { |
| 1530 | 1615 | const rate = row.personTimeGrowthRate || '0%' |
| 1531 | 1616 | const numRate = parseFloat(rate) || 0 |
| ... | ... | @@ -1538,6 +1623,8 @@ export default { |
| 1538 | 1623 | prop: 'currentProjectCount', |
| 1539 | 1624 | width: 100, |
| 1540 | 1625 | align: 'right', |
| 1626 | + sortable: 'custom', | |
| 1627 | + sortMethod: this.getNumberSortMethod('currentProjectCount'), | |
| 1541 | 1628 | formatter: (row) => { |
| 1542 | 1629 | return Number(row.currentProjectCount || 0).toLocaleString() |
| 1543 | 1630 | } |
| ... | ... | @@ -1547,6 +1634,8 @@ export default { |
| 1547 | 1634 | prop: 'lastProjectCount', |
| 1548 | 1635 | width: 100, |
| 1549 | 1636 | align: 'right', |
| 1637 | + sortable: 'custom', | |
| 1638 | + sortMethod: this.getNumberSortMethod('lastProjectCount'), | |
| 1550 | 1639 | formatter: (row) => { |
| 1551 | 1640 | return Number(row.lastProjectCount || 0).toLocaleString() |
| 1552 | 1641 | } |
| ... | ... | @@ -1556,6 +1645,8 @@ export default { |
| 1556 | 1645 | prop: 'projectCountGrowthRate', |
| 1557 | 1646 | width: 110, |
| 1558 | 1647 | align: 'right', |
| 1648 | + sortable: 'custom', | |
| 1649 | + sortMethod: this.getGrowthRateStringSortMethod('projectCountGrowthRate'), | |
| 1559 | 1650 | formatter: (row) => { |
| 1560 | 1651 | const rate = row.projectCountGrowthRate || '0%' |
| 1561 | 1652 | const numRate = parseFloat(rate) || 0 | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqAnnualSummaryService.cs
| ... | ... | @@ -985,8 +985,17 @@ namespace NCC.Extend |
| 985 | 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 | 999 | .OrderBy(x => x.BusinessUnitName) |
| 991 | 1000 | .ThenBy(x => x.StoreName) |
| 992 | 1001 | .ToList(); | ... | ... |