Commit 207c283a8564fdfa55ecab7ec7e89110a45813ef

Authored by “wangming”
1 parent db08ff8c

优化财务报表页面UI样式,修复健康师薪酬计算:额外数据整合到总业绩和金三角战队业绩

antis-ncc-admin/src/views/extend/financialReport/index.vue
... ... @@ -1233,25 +1233,47 @@ export default {
1233 1233  
1234 1234 <style lang="scss" scoped>
1235 1235 .financial-report-container {
1236   - padding: 32px;
1237   - background: #f8fafc;
  1236 + padding: 16px;
  1237 + background: linear-gradient(135deg, #f5f7fa 0%, #e8ecf1 50%, #f0f4f8 100%);
1238 1238 min-height: calc(100vh - 84px);
1239 1239 max-width: 100%;
1240   - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  1240 + overflow-y: auto;
  1241 + overflow-x: hidden;
  1242 +
  1243 + // 自定义滚动条样式
  1244 + &::-webkit-scrollbar {
  1245 + width: 8px;
  1246 + }
  1247 +
  1248 + &::-webkit-scrollbar-track {
  1249 + background: rgba(144, 147, 153, 0.1);
  1250 + border-radius: 4px;
  1251 + }
  1252 +
  1253 + &::-webkit-scrollbar-thumb {
  1254 + background: rgba(144, 147, 153, 0.3);
  1255 + border-radius: 4px;
  1256 + transition: background 0.3s ease;
  1257 +
  1258 + &:hover {
  1259 + background: rgba(144, 147, 153, 0.5);
  1260 + }
  1261 + }
1241 1262  
1242 1263 // 筛选卡片
1243 1264 .search-card {
1244   - margin-bottom: 12px;
1245   - border-radius: 8px;
1246   - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
1247   - background: #ffffff;
1248   - border: 1px solid #e2e8f0;
1249   - transition: all 0.2s ease;
1250   - padding: 8px 12px;
  1265 + margin-bottom: 16px;
  1266 + border-radius: 12px;
  1267 + background: linear-gradient(135deg, rgba(255, 255, 255, 0.95) 0%, rgba(255, 255, 255, 0.9) 100%);
  1268 + backdrop-filter: blur(10px);
  1269 + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08), 0 2px 8px rgba(0, 0, 0, 0.04);
  1270 + border: 1px solid rgba(144, 147, 153, 0.15);
  1271 + transition: all 0.3s ease;
  1272 + padding: 14px 18px;
1251 1273  
1252 1274 &:hover {
1253   - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
1254   - border-color: #cbd5e1;
  1275 + box-shadow: 0 6px 24px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.06);
  1276 + transform: translateY(-1px);
1255 1277 }
1256 1278  
1257 1279 .search-form {
... ... @@ -1278,28 +1300,34 @@ export default {
1278 1300 }
1279 1301  
1280 1302 ::v-deep .el-button {
1281   - border-radius: 6px;
  1303 + border-radius: 8px;
1282 1304 font-weight: 500;
1283   - transition: all 0.2s ease;
  1305 + transition: all 0.3s ease;
1284 1306 padding: 4px 12px;
1285 1307 height: 26px;
1286 1308 font-size: 13px;
1287 1309  
1288 1310 &.el-button--primary {
1289   - background-color: #2563eb;
1290   - border-color: #2563eb;
  1311 + background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
  1312 + border: none;
  1313 + box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
1291 1314  
1292 1315 &:hover {
1293   - background-color: #1d4ed8;
1294   - border-color: #1d4ed8;
1295   - box-shadow: 0 2px 4px rgba(37, 99, 235, 0.3);
  1316 + background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%);
  1317 + transform: translateY(-2px);
  1318 + box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
1296 1319 }
1297 1320 }
1298 1321  
1299 1322 &:not(.el-button--primary) {
  1323 + background: rgba(255, 255, 255, 0.9);
  1324 + border-color: rgba(144, 147, 153, 0.3);
  1325 + color: #606266;
  1326 +
1300 1327 &:hover {
1301   - background-color: #f1f5f9;
1302   - border-color: #cbd5e1;
  1328 + background: rgba(255, 255, 255, 1);
  1329 + border-color: rgba(144, 147, 153, 0.5);
  1330 + transform: translateY(-1px);
1303 1331 }
1304 1332 }
1305 1333 }
... ... @@ -1308,18 +1336,19 @@ export default {
1308 1336  
1309 1337 // 统计卡片区域
1310 1338 .stat-cards-section {
1311   - margin-bottom: 12px;
  1339 + margin-bottom: 16px;
1312 1340  
1313 1341 .stat-card {
1314   - background: #ffffff;
1315   - border-radius: 8px;
1316   - padding: 12px 14px;
  1342 + background: linear-gradient(135deg, rgba(255, 255, 255, 0.98) 0%, rgba(255, 255, 255, 0.95) 100%);
  1343 + backdrop-filter: blur(10px);
  1344 + border-radius: 12px;
  1345 + padding: 16px 20px;
1317 1346 display: flex;
1318 1347 align-items: center;
1319   - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
1320   - transition: all 0.2s ease;
  1348 + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08), 0 2px 8px rgba(0, 0, 0, 0.04);
  1349 + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
1321 1350 cursor: pointer;
1322   - border: 1px solid #e2e8f0;
  1351 + border: 1px solid rgba(144, 147, 153, 0.15);
1323 1352 height: 100%;
1324 1353 position: relative;
1325 1354 overflow: hidden;
... ... @@ -1328,40 +1357,64 @@ export default {
1328 1357 content: '';
1329 1358 position: absolute;
1330 1359 top: 0;
1331   - left: 0;
1332   - right: 0;
1333   - height: 2px;
1334   - background: linear-gradient(90deg, transparent 0%, rgba(37, 99, 235, 0.2) 50%, transparent 100%);
1335   - opacity: 0;
1336   - transition: opacity 0.2s ease;
  1360 + left: -100%;
  1361 + width: 100%;
  1362 + height: 100%;
  1363 + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
  1364 + transition: left 0.5s ease;
1337 1365 }
1338 1366  
1339 1367 &:hover {
1340   - transform: translateY(-2px);
1341   - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.08);
1342   - border-color: #cbd5e1;
  1368 + transform: translateY(-4px);
  1369 + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 4px 16px rgba(0, 0, 0, 0.06);
1343 1370  
1344 1371 &::before {
1345   - opacity: 1;
  1372 + left: 100%;
1346 1373 }
1347 1374 }
1348 1375  
1349 1376 .stat-icon {
1350   - width: 44px;
1351   - height: 44px;
1352   - border-radius: 8px;
  1377 + width: 56px;
  1378 + height: 56px;
  1379 + border-radius: 12px;
1353 1380 display: flex;
1354 1381 align-items: center;
1355 1382 justify-content: center;
1356   - margin-right: 12px;
1357   - font-size: 22px;
  1383 + margin-right: 16px;
  1384 + font-size: 24px;
1358 1385 flex-shrink: 0;
1359   - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
1360   - transition: transform 0.2s ease;
  1386 + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  1387 + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  1388 + position: relative;
  1389 + overflow: hidden;
  1390 +
  1391 + &::before {
  1392 + content: '';
  1393 + position: absolute;
  1394 + top: -50%;
  1395 + left: -50%;
  1396 + width: 200%;
  1397 + height: 200%;
  1398 + background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.3), transparent);
  1399 + transform: rotate(45deg);
  1400 + transition: all 0.6s ease;
  1401 + }
  1402 +
  1403 + i {
  1404 + position: relative;
  1405 + z-index: 1;
  1406 + filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
  1407 + }
1361 1408 }
1362 1409  
1363 1410 &:hover .stat-icon {
1364   - transform: scale(1.05);
  1411 + transform: scale(1.1) rotate(5deg);
  1412 + box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
  1413 +
  1414 + &::before {
  1415 + top: 50%;
  1416 + left: 50%;
  1417 + }
1365 1418 }
1366 1419  
1367 1420 .stat-content {
... ... @@ -1369,19 +1422,22 @@ export default {
1369 1422 min-width: 0;
1370 1423  
1371 1424 .stat-label {
1372   - font-size: 12px;
1373   - color: #64748b;
1374   - margin-bottom: 4px;
  1425 + font-size: 13px;
  1426 + color: #606266;
  1427 + margin-bottom: 8px;
1375 1428 font-weight: 500;
1376 1429 line-height: 1.3;
1377 1430 letter-spacing: 0.01em;
1378 1431 }
1379 1432  
1380 1433 .stat-value {
1381   - font-size: 22px;
  1434 + font-size: 24px;
1382 1435 font-weight: 700;
1383   - color: #1e293b;
1384   - margin-bottom: 2px;
  1436 + background: linear-gradient(135deg, #303133 0%, #606266 100%);
  1437 + -webkit-background-clip: text;
  1438 + -webkit-text-fill-color: transparent;
  1439 + background-clip: text;
  1440 + margin-bottom: 6px;
1385 1441 white-space: nowrap;
1386 1442 overflow: hidden;
1387 1443 text-overflow: ellipsis;
... ... @@ -1391,7 +1447,7 @@ export default {
1391 1447  
1392 1448 .stat-meta {
1393 1449 font-size: 12px;
1394   - color: #94a3b8;
  1450 + color: #909399;
1395 1451 line-height: 1.3;
1396 1452 font-weight: 400;
1397 1453 }
... ... @@ -1399,130 +1455,203 @@ export default {
1399 1455  
1400 1456 &.income-card {
1401 1457 .stat-icon {
1402   - background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%);
  1458 + background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
1403 1459 color: #fff;
1404 1460 }
1405   -
1406   - &:hover::before {
1407   - background: linear-gradient(90deg, transparent 0%, rgba(37, 99, 235, 0.3) 50%, transparent 100%);
1408   - }
1409 1461 }
1410 1462  
1411 1463 &.channel-card {
1412 1464 .stat-icon {
1413   - background: linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%);
  1465 + background: linear-gradient(135deg, #a855f7 0%, #9333ea 100%);
1414 1466 color: #fff;
1415 1467 }
1416   -
1417   - &:hover::before {
1418   - background: linear-gradient(90deg, transparent 0%, rgba(139, 92, 246, 0.3) 50%, transparent 100%);
1419   - }
1420 1468 }
1421 1469  
1422 1470 &.payable-card {
1423 1471 .stat-icon {
1424   - background: linear-gradient(135deg, #f97316 0%, #fb923c 100%);
  1472 + background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
1425 1473 color: #fff;
1426 1474 }
1427   -
1428   - &:hover::before {
1429   - background: linear-gradient(90deg, transparent 0%, rgba(249, 115, 22, 0.3) 50%, transparent 100%);
1430   - }
1431 1475 }
1432 1476  
1433 1477 &.receivable-card {
1434 1478 .stat-icon {
1435   - background: linear-gradient(135deg, #10b981 0%, #34d399 100%);
  1479 + background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
1436 1480 color: #fff;
1437 1481 }
1438   -
1439   - &:hover::before {
1440   - background: linear-gradient(90deg, transparent 0%, rgba(16, 185, 129, 0.3) 50%, transparent 100%);
1441   - }
1442 1482 }
1443 1483 }
1444 1484 }
1445 1485  
1446 1486 // 图表区域
1447 1487 .charts-section {
1448   - margin-bottom: 12px;
  1488 + margin-bottom: 16px;
1449 1489  
1450 1490 .chart-card {
1451   - border-radius: 8px;
1452   - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
1453   - background: #ffffff;
1454   - border: 1px solid #e2e8f0;
1455   - transition: all 0.2s ease;
  1491 + border-radius: 12px;
  1492 + background: linear-gradient(135deg, rgba(255, 255, 255, 0.98) 0%, rgba(255, 255, 255, 0.95) 100%);
  1493 + backdrop-filter: blur(10px);
  1494 + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08), 0 2px 8px rgba(0, 0, 0, 0.04);
  1495 + border: 1px solid rgba(144, 147, 153, 0.15);
  1496 + transition: all 0.3s ease;
1456 1497 overflow: hidden;
1457 1498  
1458 1499 &:hover {
1459   - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.08);
1460   - border-color: #cbd5e1;
  1500 + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 4px 16px rgba(0, 0, 0, 0.06);
  1501 + transform: translateY(-2px);
  1502 + }
  1503 +
  1504 + ::v-deep .el-card__header {
  1505 + padding: 16px 20px;
  1506 + background: linear-gradient(135deg, rgba(248, 249, 250, 0.8) 0%, rgba(240, 242, 245, 0.8) 100%);
  1507 + border-bottom: 2px solid rgba(144, 147, 153, 0.2);
  1508 + border-radius: 12px 12px 0 0;
  1509 + }
  1510 +
  1511 + ::v-deep .el-card__body {
  1512 + padding: 20px;
1461 1513 }
1462 1514  
1463 1515 .chart-header {
1464 1516 display: flex;
1465 1517 align-items: center;
1466 1518 justify-content: space-between;
1467   - padding: 6px 12px;
1468   - border-bottom: 1px solid #f1f5f9;
1469   - background: #ffffff;
1470   - min-height: 32px;
1471   - height: 32px;
  1519 + padding: 0;
  1520 + border-bottom: none;
  1521 + background: transparent;
  1522 + min-height: auto;
  1523 + height: auto;
1472 1524  
1473 1525 .chart-title {
1474   - font-size: 13px;
1475   - font-weight: 600;
1476   - color: #1e293b;
  1526 + font-size: 15px;
  1527 + font-weight: 700;
  1528 + background: linear-gradient(135deg, #303133 0%, #606266 100%);
  1529 + -webkit-background-clip: text;
  1530 + -webkit-text-fill-color: transparent;
  1531 + background-clip: text;
1477 1532 display: flex;
1478 1533 align-items: center;
1479   - gap: 6px;
  1534 + gap: 12px;
1480 1535 letter-spacing: -0.01em;
1481   - height: 20px;
1482   - line-height: 20px;
  1536 + height: auto;
  1537 + line-height: 1.5;
1483 1538  
1484 1539 i {
1485   - font-size: 14px;
1486   - color: #2563eb;
1487   - width: 18px;
1488   - height: 18px;
  1540 + width: 32px;
  1541 + height: 32px;
1489 1542 display: flex;
1490 1543 align-items: center;
1491 1544 justify-content: center;
1492   - background: rgba(37, 99, 235, 0.1);
1493   - border-radius: 4px;
  1545 + border-radius: 8px;
  1546 + font-size: 16px;
  1547 + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  1548 + position: relative;
  1549 + overflow: hidden;
  1550 + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  1551 +
  1552 + &::before {
  1553 + content: '';
  1554 + position: absolute;
  1555 + top: 0;
  1556 + left: -100%;
  1557 + width: 100%;
  1558 + height: 100%;
  1559 + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
  1560 + transition: left 0.5s ease;
  1561 + }
  1562 +
  1563 + &.el-icon-data-line {
  1564 + background: linear-gradient(135deg, rgba(59, 130, 246, 0.15) 0%, rgba(37, 99, 235, 0.15) 100%);
  1565 + color: #3b82f6;
  1566 + }
  1567 +
  1568 + &.el-icon-pie-chart {
  1569 + background: linear-gradient(135deg, rgba(168, 85, 247, 0.15) 0%, rgba(147, 51, 234, 0.15) 100%);
  1570 + color: #a855f7;
  1571 + }
  1572 +
  1573 + &.el-icon-shopping-bag-1 {
  1574 + background: linear-gradient(135deg, rgba(245, 158, 11, 0.15) 0%, rgba(217, 119, 6, 0.15) 100%);
  1575 + color: #f59e0b;
  1576 + }
  1577 +
  1578 + &.el-icon-wallet {
  1579 + background: linear-gradient(135deg, rgba(34, 197, 94, 0.15) 0%, rgba(21, 128, 61, 0.15) 100%);
  1580 + color: #22c55e;
  1581 + }
  1582 +
  1583 + &:hover {
  1584 + transform: scale(1.1) rotate(5deg);
  1585 + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  1586 +
  1587 + &::before {
  1588 + left: 100%;
  1589 + }
  1590 +
  1591 + &.el-icon-data-line {
  1592 + background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
  1593 + color: #fff;
  1594 + }
  1595 +
  1596 + &.el-icon-pie-chart {
  1597 + background: linear-gradient(135deg, #a855f7 0%, #9333ea 100%);
  1598 + color: #fff;
  1599 + }
  1600 +
  1601 + &.el-icon-shopping-bag-1 {
  1602 + background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
  1603 + color: #fff;
  1604 + }
  1605 +
  1606 + &.el-icon-wallet {
  1607 + background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
  1608 + color: #fff;
  1609 + }
  1610 + }
1494 1611 }
1495 1612 }
1496 1613 }
1497 1614  
1498 1615 .chart-container {
1499 1616 width: 100%;
1500   - height: 280px;
1501   - min-height: 280px;
1502   - padding: 8px 12px;
  1617 + height: 360px;
  1618 + min-height: 360px;
  1619 + padding: 0;
1503 1620 }
1504 1621 }
1505 1622 }
1506 1623  
1507 1624 // 表格卡片
1508 1625 .table-card {
1509   - border-radius: 8px;
1510   - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
1511   - background: #ffffff;
1512   - border: 1px solid #e2e8f0;
1513   - transition: all 0.2s ease;
  1626 + border-radius: 12px;
  1627 + background: linear-gradient(135deg, rgba(255, 255, 255, 0.98) 0%, rgba(255, 255, 255, 0.95) 100%);
  1628 + backdrop-filter: blur(10px);
  1629 + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08), 0 2px 8px rgba(0, 0, 0, 0.04);
  1630 + border: 1px solid rgba(144, 147, 153, 0.15);
  1631 + transition: all 0.3s ease;
1514 1632 width: 100%;
1515 1633 overflow: hidden;
1516 1634  
1517 1635 &:hover {
1518   - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.08);
1519   - border-color: #cbd5e1;
  1636 + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 4px 16px rgba(0, 0, 0, 0.06);
  1637 + transform: translateY(-2px);
  1638 + }
  1639 +
  1640 + ::v-deep .el-card__header {
  1641 + padding: 16px 20px;
  1642 + background: linear-gradient(135deg, rgba(248, 249, 250, 0.8) 0%, rgba(240, 242, 245, 0.8) 100%);
  1643 + border-bottom: 2px solid rgba(144, 147, 153, 0.2);
  1644 + border-radius: 12px 12px 0 0;
  1645 + }
  1646 +
  1647 + ::v-deep .el-card__body {
  1648 + padding: 20px;
1520 1649 }
1521 1650  
1522 1651 .table-filters {
1523   - padding: 6px 12px;
1524   - background: #f8fafc;
1525   - border-bottom: 1px solid #e2e8f0;
  1652 + padding: 14px 20px;
  1653 + background: linear-gradient(135deg, rgba(248, 249, 250, 0.8) 0%, rgba(240, 242, 245, 0.8) 100%);
  1654 + border-bottom: 2px solid rgba(144, 147, 153, 0.2);
1526 1655 margin-top: 0;
1527 1656  
1528 1657 .filter-form {
... ... @@ -1567,105 +1696,147 @@ export default {
1567 1696 display: flex;
1568 1697 align-items: center;
1569 1698 justify-content: space-between;
1570   - padding: 6px 12px;
1571   - border-bottom: 1px solid #f1f5f9;
1572   - background: #ffffff;
1573   - min-height: 32px;
1574   - height: 32px;
  1699 + padding: 0;
  1700 + border-bottom: none;
  1701 + background: transparent;
  1702 + min-height: auto;
  1703 + height: auto;
1575 1704  
1576 1705 .table-title {
1577   - font-size: 13px;
1578   - font-weight: 600;
1579   - color: #1e293b;
  1706 + font-size: 15px;
  1707 + font-weight: 700;
  1708 + background: linear-gradient(135deg, #303133 0%, #606266 100%);
  1709 + -webkit-background-clip: text;
  1710 + -webkit-text-fill-color: transparent;
  1711 + background-clip: text;
1580 1712 display: flex;
1581 1713 align-items: center;
1582   - gap: 6px;
  1714 + gap: 12px;
1583 1715 letter-spacing: -0.01em;
1584 1716 flex-shrink: 0;
1585   - height: 20px;
1586   - line-height: 20px;
  1717 + height: auto;
  1718 + line-height: 1.5;
1587 1719  
1588 1720 i {
1589   - font-size: 14px;
1590   - color: #2563eb;
1591   - width: 18px;
1592   - height: 18px;
  1721 + width: 32px;
  1722 + height: 32px;
1593 1723 display: flex;
1594 1724 align-items: center;
1595 1725 justify-content: center;
1596   - background: rgba(37, 99, 235, 0.1);
1597   - border-radius: 4px;
  1726 + border-radius: 8px;
  1727 + font-size: 16px;
  1728 + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  1729 + position: relative;
  1730 + overflow: hidden;
  1731 + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  1732 + background: linear-gradient(135deg, rgba(59, 130, 246, 0.15) 0%, rgba(37, 99, 235, 0.15) 100%);
  1733 + color: #3b82f6;
  1734 +
  1735 + &::before {
  1736 + content: '';
  1737 + position: absolute;
  1738 + top: 0;
  1739 + left: -100%;
  1740 + width: 100%;
  1741 + height: 100%;
  1742 + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
  1743 + transition: left 0.5s ease;
  1744 + }
  1745 +
  1746 + &:hover {
  1747 + transform: scale(1.1) rotate(5deg);
  1748 + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  1749 + background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
  1750 + color: #fff;
  1751 +
  1752 + &::before {
  1753 + left: 100%;
  1754 + }
  1755 + }
1598 1756 }
1599 1757 }
1600 1758  
1601 1759 .table-tabs {
1602 1760 flex: 1;
1603   - margin-left: 12px;
  1761 + margin-left: 16px;
1604 1762  
1605 1763 ::v-deep .el-tabs__header {
1606 1764 margin: 0;
1607   - height: 20px;
1608 1765 }
1609 1766  
1610 1767 ::v-deep .el-tabs__nav-wrap {
1611   - height: 20px;
1612   -
1613 1768 &::after {
1614   - background-color: #e2e8f0;
1615   - height: 1px;
  1769 + background-color: rgba(144, 147, 153, 0.2);
  1770 + height: 2px;
1616 1771 }
1617 1772 }
1618 1773  
1619   - ::v-deep .el-tabs__nav {
1620   - height: 20px;
1621   - }
1622   -
1623 1774 ::v-deep .el-tabs__item {
1624 1775 font-weight: 500;
1625   - color: #64748b;
1626   - padding: 0 10px;
1627   - height: 20px;
1628   - line-height: 20px;
1629   - font-size: 13px;
1630   - transition: all 0.2s ease;
1631   - border-radius: 0;
1632   - margin-right: 2px;
  1776 + color: #606266;
  1777 + padding: 0 16px;
  1778 + height: 32px;
  1779 + line-height: 32px;
  1780 + font-size: 14px;
  1781 + transition: all 0.3s ease;
  1782 + border-radius: 6px;
  1783 + margin-right: 4px;
1633 1784  
1634 1785 &.is-active {
1635   - color: #2563eb;
  1786 + color: #3b82f6;
1636 1787 font-weight: 600;
1637   - background-color: rgba(37, 99, 235, 0.05);
  1788 + background: linear-gradient(135deg, rgba(59, 130, 246, 0.1) 0%, rgba(37, 99, 235, 0.1) 100%);
1638 1789 }
1639 1790  
1640 1791 &:hover:not(.is-active) {
1641   - color: #2563eb;
1642   - background-color: rgba(37, 99, 235, 0.03);
  1792 + color: #3b82f6;
  1793 + background: rgba(59, 130, 246, 0.05);
1643 1794 }
1644 1795 }
1645 1796  
1646 1797 ::v-deep .el-tabs__active-bar {
1647   - background-color: #2563eb;
1648   - height: 2px;
1649   - border-radius: 0;
  1798 + background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
  1799 + height: 3px;
  1800 + border-radius: 2px;
1650 1801 }
1651 1802 }
1652 1803 }
1653 1804  
1654 1805 .table-wrapper {
1655 1806 width: 100%;
1656   - padding: 8px 12px;
  1807 + padding: 0;
1657 1808 overflow-x: auto;
1658 1809 overflow-y: hidden;
1659 1810  
  1811 + &::-webkit-scrollbar {
  1812 + height: 8px;
  1813 + }
  1814 +
  1815 + &::-webkit-scrollbar-track {
  1816 + background: rgba(144, 147, 153, 0.1);
  1817 + border-radius: 4px;
  1818 + }
  1819 +
  1820 + &::-webkit-scrollbar-thumb {
  1821 + background: rgba(144, 147, 153, 0.3);
  1822 + border-radius: 4px;
  1823 + transition: background 0.3s ease;
  1824 +
  1825 + &:hover {
  1826 + background: rgba(144, 147, 153, 0.5);
  1827 + }
  1828 + }
  1829 +
1660 1830 .data-table {
1661 1831 width: 100% !important;
1662 1832 min-width: 100%;
1663 1833  
1664 1834 ::v-deep .el-table {
1665 1835 width: 100% !important;
1666   - font-size: 13px;
1667   - border-radius: 6px;
  1836 + font-size: 14px;
  1837 + border-radius: 8px;
1668 1838 overflow: hidden;
  1839 + border: 1px solid rgba(144, 147, 153, 0.2);
1669 1840  
1670 1841 .el-table__header-wrapper {
1671 1842 width: 100% !important;
... ... @@ -1677,18 +1848,17 @@ export default {
1677 1848  
1678 1849 .el-table__header {
1679 1850 width: 100% !important;
1680   - background: #f8fafc;
  1851 + background: linear-gradient(135deg, rgba(248, 249, 250, 0.9) 0%, rgba(240, 242, 245, 0.9) 100%);
1681 1852  
1682 1853 th {
1683   - background: #f8fafc;
1684   - color: #475569;
  1854 + background: transparent;
  1855 + color: #303133;
1685 1856 font-weight: 600;
1686   - border-bottom: 1px solid #e2e8f0;
1687   - padding: 8px 10px;
  1857 + border-bottom: 2px solid rgba(144, 147, 153, 0.2);
  1858 + padding: 12px 16px;
1688 1859 text-align: left;
1689   - font-size: 12px;
  1860 + font-size: 13px;
1690 1861 letter-spacing: 0.01em;
1691   - text-transform: uppercase;
1692 1862 }
1693 1863 }
1694 1864  
... ... @@ -1697,20 +1867,21 @@ export default {
1697 1867  
1698 1868 tr {
1699 1869 width: 100% !important;
1700   - transition: background-color 0.15s ease;
  1870 + transition: all 0.3s ease;
1701 1871  
1702 1872 &:hover {
1703   - background-color: #f8fafc !important;
  1873 + background: linear-gradient(135deg, rgba(248, 249, 250, 0.5) 0%, rgba(240, 242, 245, 0.5) 100%) !important;
  1874 + transform: translateX(2px);
1704 1875 }
1705 1876 }
1706 1877  
1707 1878 td {
1708   - border-bottom: 1px solid #f1f5f9;
1709   - padding: 8px 10px;
1710   - color: #1e293b;
  1879 + border-bottom: 1px solid rgba(144, 147, 153, 0.15);
  1880 + padding: 12px 16px;
  1881 + color: #303133;
1711 1882 text-align: left;
1712   - font-size: 13px;
1713   - line-height: 1.4;
  1883 + font-size: 14px;
  1884 + line-height: 1.5;
1714 1885 }
1715 1886 }
1716 1887  
... ... @@ -1718,7 +1889,7 @@ export default {
1718 1889 width: 100% !important;
1719 1890  
1720 1891 &:nth-child(even) {
1721   - background-color: #fafbfc;
  1892 + background-color: rgba(248, 249, 250, 0.3);
1722 1893 }
1723 1894  
1724 1895 &:last-child td {
... ... @@ -1745,25 +1916,25 @@ export default {
1745 1916 // 响应式适配
1746 1917 @media (max-width: 1400px) {
1747 1918 .financial-report-container {
1748   - padding: 28px;
  1919 + padding: 16px;
1749 1920 }
1750 1921 }
1751 1922  
1752 1923 @media (max-width: 1200px) {
1753 1924 .financial-report-container {
1754   - padding: 24px;
  1925 + padding: 16px;
1755 1926  
1756 1927 .stat-cards-section {
1757 1928 .stat-card {
1758 1929 .stat-icon {
1759   - width: 64px;
1760   - height: 64px;
1761   - font-size: 32px;
1762   - margin-right: 20px;
  1930 + width: 56px;
  1931 + height: 56px;
  1932 + font-size: 24px;
  1933 + margin-right: 16px;
1763 1934 }
1764 1935  
1765 1936 .stat-value {
1766   - font-size: 26px;
  1937 + font-size: 22px;
1767 1938 }
1768 1939 }
1769 1940 }
... ... @@ -1781,17 +1952,17 @@ export default {
1781 1952 .financial-report-container {
1782 1953 .stat-cards-section {
1783 1954 .stat-card {
1784   - padding: 24px;
  1955 + padding: 16px 20px;
1785 1956  
1786 1957 .stat-icon {
1787   - width: 60px;
1788   - height: 60px;
1789   - font-size: 30px;
1790   - margin-right: 18px;
  1958 + width: 56px;
  1959 + height: 56px;
  1960 + font-size: 24px;
  1961 + margin-right: 16px;
1791 1962 }
1792 1963  
1793 1964 .stat-value {
1794   - font-size: 24px;
  1965 + font-size: 22px;
1795 1966 }
1796 1967 }
1797 1968 }
... ... @@ -1803,9 +1974,9 @@ export default {
1803 1974 padding: 16px;
1804 1975  
1805 1976 .search-card {
1806   - padding: 12px 16px;
1807   - margin-bottom: 20px;
1808   - border-radius: 10px;
  1977 + padding: 14px 18px;
  1978 + margin-bottom: 16px;
  1979 + border-radius: 12px;
1809 1980  
1810 1981 .search-form {
1811 1982 ::v-deep .el-form-item {
... ... @@ -1842,12 +2013,12 @@ export default {
1842 2013 }
1843 2014  
1844 2015 .stat-card {
1845   - padding: 20px;
  2016 + padding: 16px 20px;
1846 2017  
1847 2018 .stat-icon {
1848 2019 width: 56px;
1849 2020 height: 56px;
1850   - font-size: 28px;
  2021 + font-size: 24px;
1851 2022 margin-right: 16px;
1852 2023 }
1853 2024  
... ... @@ -1884,18 +2055,18 @@ export default {
1884 2055 }
1885 2056  
1886 2057 .chart-card {
1887   - border-radius: 10px;
  2058 + border-radius: 12px;
1888 2059  
1889 2060 .chart-header {
1890   - padding: 10px 16px;
  2061 + padding: 16px 20px;
1891 2062  
1892 2063 .chart-title {
1893   - font-size: 13px;
  2064 + font-size: 15px;
1894 2065  
1895 2066 i {
1896 2067 font-size: 16px;
1897   - width: 20px;
1898   - height: 20px;
  2068 + width: 32px;
  2069 + height: 32px;
1899 2070 }
1900 2071 }
1901 2072 }
... ... @@ -1903,14 +2074,14 @@ export default {
1903 2074 .chart-container {
1904 2075 height: 300px;
1905 2076 min-height: 300px;
1906   - padding: 4px 4px;
  2077 + padding: 0;
1907 2078 }
1908 2079 }
1909 2080 }
1910 2081  
1911 2082 .table-card {
1912 2083 .table-filters {
1913   - padding: 10px 16px;
  2084 + padding: 14px 20px;
1914 2085  
1915 2086 .filter-form {
1916 2087 ::v-deep .el-form-item {
... ... @@ -1928,16 +2099,16 @@ export default {
1928 2099 .table-header {
1929 2100 flex-direction: column;
1930 2101 align-items: flex-start;
1931   - gap: 8px;
1932   - padding: 8px 16px;
  2102 + gap: 12px;
  2103 + padding: 0;
1933 2104  
1934 2105 .table-title {
1935   - font-size: 13px;
  2106 + font-size: 15px;
1936 2107  
1937 2108 i {
1938 2109 font-size: 16px;
1939   - width: 20px;
1940   - height: 20px;
  2110 + width: 32px;
  2111 + height: 32px;
1941 2112 }
1942 2113 }
1943 2114  
... ... @@ -1946,17 +2117,17 @@ export default {
1946 2117 margin-left: 0;
1947 2118  
1948 2119 ::v-deep .el-tabs__item {
1949   - padding: 0 12px;
  2120 + padding: 0 16px;
1950 2121 height: 32px;
1951 2122 line-height: 32px;
1952   - font-size: 12px;
1953   - margin-right: 2px;
  2123 + font-size: 14px;
  2124 + margin-right: 4px;
1954 2125 }
1955 2126 }
1956 2127 }
1957 2128  
1958 2129 .table-wrapper {
1959   - padding: 12px 16px;
  2130 + padding: 0;
1960 2131 }
1961 2132 }
1962 2133 }
... ...
docs/健康师薪酬计算规则梳理-额外数据与金三角战队业绩整合逻辑.md 0 → 100644
  1 +# 健康师薪酬计算规则梳理 - 额外数据与金三角战队业绩整合逻辑
  2 +
  3 +## 一、核心问题
  4 +
  5 +健康师的额外数据(`lq_salary_extra_calculation` 表)会影响健康师的业绩计算,变动后的业绩需要整合到金三角战队业绩中。
  6 +
  7 +## 二、数据流程梳理
  8 +
  9 +### 2.1 数据来源
  10 +
  11 +#### 1. 基础业绩数据
  12 +- **表名**: `lq_kd_jksyj` (健康师业绩表)
  13 +- **字段**:
  14 + - `jkszh`: 健康师账号/ID
  15 + - `jksyj`: 健康师业绩(字符串类型,需转换)
  16 + - `PerformanceType`: 业绩类型("基础业绩" 或 "合作业绩")
  17 + - `yjsj`: 业绩时间
  18 + - `glkdbh`: 关联开单编号
  19 +
  20 +#### 2. 额外计算数据
  21 +- **表名**: `lq_salary_extra_calculation` (健康师工资额外计算表)
  22 +- **关键字段**:
  23 + - `F_EmployeeId`: 健康师ID
  24 + - `F_Year`: 年份
  25 + - `F_Month`: 月份
  26 + - `F_BaseRewardPerformance`: 基础奖励业绩(需从基础业绩中扣除)
  27 + - `F_CooperationRewardPerformance`: 合作奖励业绩(需从合作业绩中扣除)
  28 + - `F_OtherPerformanceAdd`: **其他业绩加**(需加到总业绩中)
  29 + - `F_OtherPerformanceSubtract`: **其他业绩减**(需从总业绩中扣除)
  30 + - `F_NewCustomerPerformance`: 新客业绩(可能被额外数据覆盖)
  31 + - `F_UpgradePerformance`: 升单业绩(可能被额外数据覆盖)
  32 +
  33 +#### 3. 退款数据
  34 +- **表名**: `lq_hytk_jksyj` (退款健康师业绩表)
  35 +- **作用**: 从总业绩中扣除退款金额
  36 +
  37 +#### 4. 金三角战队数据
  38 +- **表名**: `lq_jinsanjiao_user` (金三角用户表)
  39 +- **表名**: `lq_ycsd_jsj` (金三角基础信息表)
  40 +- **作用**: 确定健康师所属的战队
  41 +
  42 +### 2.2 当前计算流程(代码位置:`LqSalaryService.cs` 的 `CalculateHealthCoachSalary` 方法)
  43 +
  44 +#### 步骤1: 计算基础业绩数据(第563-591行)
  45 +
  46 +```csharp
  47 +// 2.1 计算个人业绩
  48 +var myPerf = performanceData.Where(x => x.Jks == empId).ToList();
  49 +salary.BasePerformance = myPerf.Where(x => (x.PerformanceType ?? "").Trim() == "基础业绩")
  50 + .Sum(x => decimal.Parse(x.Jksyj ?? "0"));
  51 +salary.CooperationPerformance = myPerf.Where(x => (x.PerformanceType ?? "").Trim() == "合作业绩")
  52 + .Sum(x => decimal.Parse(x.Jksyj ?? "0"));
  53 +salary.TotalPerformance = myPerf.Sum(x => decimal.Parse(x.Jksyj ?? "0")); // 第567行
  54 +
  55 +// 扣除退款
  56 +var myRefunds = refundList.Where(x => x.Jks == empId).ToList();
  57 +if (myRefunds.Any())
  58 +{
  59 + decimal totalRefund = myRefunds.Sum(x => x.Jksyj ?? 0);
  60 + salary.TotalPerformance -= totalRefund; // 第584行
  61 + salary.BasePerformance -= baseRefund;
  62 + salary.CooperationPerformance -= cooperationRefund;
  63 +}
  64 +
  65 +// 新客与升单业绩(从开单记录中统计)
  66 +salary.NewCustomerPerformance = myPerf.Where(x => string.Equals(x.Sfskdd, "是"))
  67 + .Sum(x => decimal.Parse(x.Jksyj ?? "0"));
  68 +salary.UpgradePerformance = myPerf.Where(x => string.Equals(x.Sfskdd, "否"))
  69 + .Sum(x => decimal.Parse(x.Jksyj ?? "0"));
  70 +```
  71 +
  72 +**当前问题**:
  73 +- `TotalPerformance` 只统计了开单业绩并扣除了退款
  74 +- **没有加上 `OtherPerformanceAdd`**
  75 +- **没有减去 `OtherPerformanceSubtract`**
  76 +
  77 +#### 步骤2: 填充额外计算数据(第593-605行)
  78 +
  79 +```csharp
  80 +// 2.1.1 填充额外计算数据
  81 +if (extraCalculationDict.ContainsKey(empId))
  82 +{
  83 + var extraData = extraCalculationDict[empId];
  84 + salary.BaseRewardPerformance = extraData.BaseRewardPerformance;
  85 + salary.CooperationRewardPerformance = extraData.CooperationRewardPerformance;
  86 + salary.OtherPerformanceAdd = extraData.OtherPerformanceAdd; // 第599行
  87 + salary.OtherPerformanceSubtract = extraData.OtherPerformanceSubtract; // 第600行
  88 + salary.UpgradeCustomerCount = extraData.UpgradeCustomerCount;
  89 + salary.NewCustomerConversionRate = extraData.NewCustomerConversionRate;
  90 + salary.NewCustomerPerformance = extraData.NewCustomerPerformance; // 可能覆盖之前的值
  91 + salary.UpgradePerformance = extraData.UpgradePerformance; // 可能覆盖之前的值
  92 +}
  93 +```
  94 +
  95 +**说明**:
  96 +- 额外数据被填充到工资统计对象中
  97 +- `NewCustomerPerformance` 和 `UpgradePerformance` 可能被额外数据覆盖
  98 +
  99 +#### 步骤3: 计算实际基础业绩和实际合作业绩(第607-636行)
  100 +
  101 +```csharp
  102 +// 2.1.2 计算实际基础业绩和实际合作业绩
  103 +// 实际基础业绩 = 基础业绩 - 基础奖励业绩 + 其他业绩加 - 其他业绩减
  104 +decimal actualBasePerformance = salary.BasePerformance
  105 + - salary.BaseRewardPerformance
  106 + + salary.OtherPerformanceAdd // 第615行:只影响实际基础业绩
  107 + - salary.OtherPerformanceSubtract; // 第616行:只影响实际基础业绩
  108 +
  109 +// 新店额外调整:根据阶段扣除新客业绩或升单业绩
  110 +if (isNewStore)
  111 +{
  112 + if (newStoreStage == 1)
  113 + {
  114 + actualBasePerformance -= salary.NewCustomerPerformance;
  115 + }
  116 + else if (newStoreStage == 2)
  117 + {
  118 + actualBasePerformance -= salary.UpgradePerformance;
  119 + }
  120 +}
  121 +
  122 +salary.ActualBasePerformance = actualBasePerformance;
  123 +
  124 +// 实际合作业绩 = 合作业绩 - 合作奖励业绩
  125 +salary.ActualCooperationPerformance = salary.CooperationPerformance - salary.CooperationRewardPerformance;
  126 +```
  127 +
  128 +**当前问题**:
  129 +- `OtherPerformanceAdd` 和 `OtherPerformanceSubtract` **只用于计算 `ActualBasePerformance`**
  130 +- **没有用于调整 `TotalPerformance`**
  131 +
  132 +#### 步骤4: 计算金三角战队业绩(第700-753行)
  133 +
  134 +```csharp
  135 +// 3. 处理战队逻辑 (考勤规则)
  136 +// 规则:若出勤天数 < 20天,则该健康师不计入战队,按单人计算。
  137 +
  138 +// 按战队分组
  139 +var teamGroups = employeeStats.Values
  140 + .Where(x => !string.IsNullOrEmpty(x.GoldTriangleId))
  141 + .GroupBy(x => x.GoldTriangleId)
  142 + .ToList();
  143 +
  144 +foreach (var group in teamGroups)
  145 +{
  146 + var validMembers = new List<LqSalaryStatisticsEntity>();
  147 + var invalidMembers = new List<LqSalaryStatisticsEntity>();
  148 +
  149 + foreach (var member in group)
  150 + {
  151 + if (member.WorkingDays >= 20)
  152 + {
  153 + validMembers.Add(member);
  154 + }
  155 + else
  156 + {
  157 + invalidMembers.Add(member);
  158 + }
  159 + }
  160 +
  161 + // 对于无效成员,移除战队标识,视为单人
  162 + foreach (var member in invalidMembers)
  163 + {
  164 + member.GoldTriangleId = null;
  165 + member.GoldTriangleTeam = "个人";
  166 + member.Position = "健康师";
  167 + }
  168 +
  169 + // 计算有效战队的总业绩和总消耗
  170 + var teamTotalPerformance = validMembers.Sum(x => x.TotalPerformance); // 第735行
  171 + var teamTotalConsumption = validMembers.Sum(x => x.Consumption);
  172 +
  173 + // 更新有效成员的战队业绩和战队总消耗
  174 + foreach (var member in validMembers)
  175 + {
  176 + member.TeamPerformance = teamTotalPerformance; // 第741行
  177 + member.TeamTotalConsumption = teamTotalConsumption;
  178 + }
  179 +}
  180 +
  181 +// 补充处理:对于没有战队ID的(个人,或被剔除的),战队业绩等于个人总业绩
  182 +foreach (var salary in employeeStats.Values)
  183 +{
  184 + if (string.IsNullOrEmpty(salary.GoldTriangleId))
  185 + {
  186 + salary.TeamPerformance = salary.TotalPerformance; // 第751行
  187 + }
  188 +}
  189 +```
  190 +
  191 +**当前问题**:
  192 +- 第735行计算战队总业绩时,使用的是 `x.TotalPerformance`
  193 +- 但 `TotalPerformance` **没有包含额外数据的调整**(`OtherPerformanceAdd` 和 `OtherPerformanceSubtract`)
  194 +- 因此,**金三角战队业绩没有整合变动后的业绩**
  195 +
  196 +## 三、问题分析
  197 +
  198 +### 3.1 核心问题
  199 +
  200 +1. **总业绩未包含额外数据调整**
  201 + - `TotalPerformance` 只统计了开单业绩并扣除了退款
  202 + - 没有加上 `OtherPerformanceAdd`
  203 + - 没有减去 `OtherPerformanceSubtract`
  204 +
  205 +2. **金三角战队业绩计算不准确**
  206 + - 战队业绩 = 所有有效成员的总业绩之和
  207 + - 但使用的是未调整的 `TotalPerformance`
  208 + - 导致额外数据的变动没有反映到战队业绩中
  209 +
  210 +### 3.2 影响范围
  211 +
  212 +1. **健康师个人总业绩**: 不准确(缺少额外数据调整)
  213 +2. **金三角战队业绩**: 不准确(基于不准确的个人总业绩)
  214 +3. **提成计算**: 可能受影响(如果提成计算依赖 `TotalPerformance`)
  215 +4. **业绩占比**: 不准确(个人业绩占比 = 个人总业绩 / 战队总业绩)
  216 +
  217 +## 四、解决方案建议
  218 +
  219 +### 4.1 方案一:在计算总业绩时直接加上额外数据调整
  220 +
  221 +**修改位置**: `LqSalaryService.cs` 第567-605行
  222 +
  223 +**修改逻辑**:
  224 +```csharp
  225 +// 2.1 计算个人业绩
  226 +var myPerf = performanceData.Where(x => x.Jks == empId).ToList();
  227 +salary.BasePerformance = myPerf.Where(x => (x.PerformanceType ?? "").Trim() == "基础业绩")
  228 + .Sum(x => decimal.Parse(x.Jksyj ?? "0"));
  229 +salary.CooperationPerformance = myPerf.Where(x => (x.PerformanceType ?? "").Trim() == "合作业绩")
  230 + .Sum(x => decimal.Parse(x.Jksyj ?? "0"));
  231 +salary.TotalPerformance = myPerf.Sum(x => decimal.Parse(x.Jksyj ?? "0"));
  232 +
  233 +// 扣除退款
  234 +var myRefunds = refundList.Where(x => x.Jks == empId).ToList();
  235 +if (myRefunds.Any())
  236 +{
  237 + decimal totalRefund = myRefunds.Sum(x => x.Jksyj ?? 0);
  238 + salary.TotalPerformance -= totalRefund;
  239 + salary.BasePerformance -= baseRefund;
  240 + salary.CooperationPerformance -= cooperationRefund;
  241 +}
  242 +
  243 +// 新客与升单业绩(从开单记录中统计)
  244 +salary.NewCustomerPerformance = myPerf.Where(x => string.Equals(x.Sfskdd, "是"))
  245 + .Sum(x => decimal.Parse(x.Jksyj ?? "0"));
  246 +salary.UpgradePerformance = myPerf.Where(x => string.Equals(x.Sfskdd, "否"))
  247 + .Sum(x => decimal.Parse(x.Jksyj ?? "0"));
  248 +
  249 +// 2.1.1 填充额外计算数据
  250 +if (extraCalculationDict.ContainsKey(empId))
  251 +{
  252 + var extraData = extraCalculationDict[empId];
  253 + salary.BaseRewardPerformance = extraData.BaseRewardPerformance;
  254 + salary.CooperationRewardPerformance = extraData.CooperationRewardPerformance;
  255 + salary.OtherPerformanceAdd = extraData.OtherPerformanceAdd;
  256 + salary.OtherPerformanceSubtract = extraData.OtherPerformanceSubtract;
  257 + salary.UpgradeCustomerCount = extraData.UpgradeCustomerCount;
  258 + salary.NewCustomerConversionRate = extraData.NewCustomerConversionRate;
  259 + salary.NewCustomerPerformance = extraData.NewCustomerPerformance;
  260 + salary.UpgradePerformance = extraData.UpgradePerformance;
  261 +
  262 + // 【新增】调整总业绩:加上其他业绩加,减去其他业绩减
  263 + salary.TotalPerformance += salary.OtherPerformanceAdd;
  264 + salary.TotalPerformance -= salary.OtherPerformanceSubtract;
  265 +}
  266 +```
  267 +
  268 +**优点**:
  269 +- 简单直接,在填充额外数据后立即调整总业绩
  270 +- 确保后续所有使用 `TotalPerformance` 的地方都能获取到调整后的值
  271 +
  272 +**缺点**:
  273 +- 需要确认 `OtherPerformanceAdd` 和 `OtherPerformanceSubtract` 是否应该影响总业绩
  274 +- 需要确认是否应该影响基础业绩或合作业绩
  275 +
  276 +### 4.2 方案二:在计算战队业绩前调整总业绩
  277 +
  278 +**修改位置**: `LqSalaryService.cs` 第700-753行
  279 +
  280 +**修改逻辑**:
  281 +```csharp
  282 +// 3. 处理战队逻辑 (考勤规则)
  283 +// 规则:若出勤天数 < 20天,则该健康师不计入战队,按单人计算。
  284 +
  285 +// 【新增】在计算战队业绩前,先调整所有健康师的总业绩(加上额外数据)
  286 +foreach (var salary in employeeStats.Values)
  287 +{
  288 + salary.TotalPerformance += salary.OtherPerformanceAdd;
  289 + salary.TotalPerformance -= salary.OtherPerformanceSubtract;
  290 +}
  291 +
  292 +// 按战队分组
  293 +var teamGroups = employeeStats.Values
  294 + .Where(x => !string.IsNullOrEmpty(x.GoldTriangleId))
  295 + .GroupBy(x => x.GoldTriangleId)
  296 + .ToList();
  297 +
  298 +// ... 后续逻辑不变
  299 +```
  300 +
  301 +**优点**:
  302 +- 集中处理,逻辑清晰
  303 +- 确保在计算战队业绩前,所有成员的总业绩都已调整
  304 +
  305 +**缺点**:
  306 +- 如果其他地方也使用 `TotalPerformance`,可能也需要调整
  307 +
  308 +### 4.3 方案三:使用调整后的总业绩字段
  309 +
  310 +**修改逻辑**:
  311 +- 保持 `TotalPerformance` 不变(原始总业绩)
  312 +- 新增 `AdjustedTotalPerformance` 字段(调整后的总业绩)
  313 +- 在计算战队业绩时使用 `AdjustedTotalPerformance`
  314 +
  315 +**优点**:
  316 +- 保留原始数据,便于追溯
  317 +- 明确区分原始业绩和调整后业绩
  318 +
  319 +**缺点**:
  320 +- 需要修改数据库表结构
  321 +- 需要修改所有使用总业绩的地方
  322 +
  323 +## 五、推荐方案
  324 +
  325 +**推荐使用方案一**,原因:
  326 +1. 逻辑简单,在填充额外数据后立即调整总业绩
  327 +2. 确保后续所有使用 `TotalPerformance` 的地方都能获取到调整后的值
  328 +3. 不需要修改数据库表结构
  329 +4. 符合业务逻辑:额外数据应该影响总业绩
  330 +
  331 +## 六、需要确认的问题
  332 +
  333 +1. **`OtherPerformanceAdd` 和 `OtherPerformanceSubtract` 是否应该影响总业绩?**
  334 + - 当前代码中,这两个字段只影响 `ActualBasePerformance`
  335 + - 需要确认业务规则:是否应该同时影响 `TotalPerformance`
  336 +
  337 +2. **额外数据中的 `NewCustomerPerformance` 和 `UpgradePerformance` 是否应该覆盖从开单记录中统计的值?**
  338 + - 当前代码中,如果存在额外数据,会覆盖之前统计的值
  339 + - 需要确认业务规则:是覆盖还是累加?
  340 +
  341 +3. **额外数据是否应该影响基础业绩或合作业绩?**
  342 + - 当前代码中,`OtherPerformanceAdd` 和 `OtherPerformanceSubtract` 只影响 `ActualBasePerformance`
  343 + - 需要确认:是否应该同时调整 `BasePerformance` 或 `CooperationPerformance`?
  344 +
  345 +4. **金三角战队业绩的计算时机**
  346 + - 当前在计算战队业绩时,使用的是 `TotalPerformance`
  347 + - 如果 `TotalPerformance` 没有包含额外数据调整,战队业绩就不准确
  348 + - 需要确认:是否应该在计算战队业绩前,先调整所有成员的总业绩?
  349 +
  350 +## 七、代码修改建议
  351 +
  352 +### 7.1 修改位置
  353 +
  354 +**文件**: `netcore/src/Modularity/Extend/NCC.Extend/LqSalaryService.cs`
  355 +**方法**: `CalculateHealthCoachSalary`
  356 +**位置**: 第593-605行(填充额外计算数据后)
  357 +
  358 +### 7.2 修改内容
  359 +
  360 +在填充额外计算数据后,立即调整总业绩:
  361 +
  362 +```csharp
  363 +// 2.1.1 填充额外计算数据
  364 +if (extraCalculationDict.ContainsKey(empId))
  365 +{
  366 + var extraData = extraCalculationDict[empId];
  367 + salary.BaseRewardPerformance = extraData.BaseRewardPerformance;
  368 + salary.CooperationRewardPerformance = extraData.CooperationRewardPerformance;
  369 + salary.OtherPerformanceAdd = extraData.OtherPerformanceAdd;
  370 + salary.OtherPerformanceSubtract = extraData.OtherPerformanceSubtract;
  371 + salary.UpgradeCustomerCount = extraData.UpgradeCustomerCount;
  372 + salary.NewCustomerConversionRate = extraData.NewCustomerConversionRate;
  373 + salary.NewCustomerPerformance = extraData.NewCustomerPerformance;
  374 + salary.UpgradePerformance = extraData.UpgradePerformance;
  375 +
  376 + // 【新增】调整总业绩:加上其他业绩加,减去其他业绩减
  377 + // 注意:这里调整的是总业绩,确保后续计算(包括战队业绩)使用的是调整后的值
  378 + salary.TotalPerformance += salary.OtherPerformanceAdd;
  379 + salary.TotalPerformance -= salary.OtherPerformanceSubtract;
  380 +}
  381 +```
  382 +
  383 +### 7.3 影响分析
  384 +
  385 +**修改后的影响**:
  386 +1. ✅ 健康师个人总业绩包含额外数据调整
  387 +2. ✅ 金三角战队业绩 = 所有有效成员的调整后总业绩之和
  388 +3. ✅ 提成计算(如果依赖 `TotalPerformance`)会使用调整后的值
  389 +4. ✅ 业绩占比计算会使用调整后的值
  390 +
  391 +**需要注意**:
  392 +- 确保 `OtherPerformanceAdd` 和 `OtherPerformanceSubtract` 的值是正确的
  393 +- 确保额外数据表(`lq_salary_extra_calculation`)的数据是准确的
  394 +- 如果后续有其他地方也使用 `TotalPerformance`,需要确认是否应该使用调整后的值
  395 +
  396 +## 八、测试建议
  397 +
  398 +1. **单元测试**:
  399 + - 测试额外数据为0时,总业绩不变
  400 + - 测试 `OtherPerformanceAdd > 0` 时,总业绩增加
  401 + - 测试 `OtherPerformanceSubtract > 0` 时,总业绩减少
  402 + - 测试两者同时存在时的计算
  403 +
  404 +2. **集成测试**:
  405 + - 测试单个健康师的额外数据调整后,总业绩是否正确
  406 + - 测试战队中多个成员都有额外数据时,战队总业绩是否正确
  407 + - 测试战队中部分成员有额外数据时,战队总业绩是否正确
  408 +
  409 +3. **数据验证**:
  410 + - 对比修改前后的计算结果
  411 + - 验证金三角战队业绩是否包含额外数据调整
  412 + - 验证业绩占比计算是否正确
  413 +
  414 +---
  415 +
  416 +**文档版本**: v1.0
  417 +**创建日期**: 2026-01-09
  418 +**适用范围**: 健康师薪酬计算 - 额外数据与金三角战队业绩整合
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqSalaryService.cs
... ... @@ -602,6 +602,11 @@ namespace NCC.Extend
602 602 salary.NewCustomerConversionRate = extraData.NewCustomerConversionRate;
603 603 salary.NewCustomerPerformance = extraData.NewCustomerPerformance;
604 604 salary.UpgradePerformance = extraData.UpgradePerformance;
  605 +
  606 + // 调整总业绩:加上其他业绩加,减去其他业绩减
  607 + // 确保后续计算(包括金三角战队业绩)使用的是调整后的总业绩
  608 + salary.TotalPerformance += salary.OtherPerformanceAdd;
  609 + salary.TotalPerformance -= salary.OtherPerformanceSubtract;
605 610 }
606 611  
607 612 // 2.1.2 计算实际基础业绩和实际合作业绩
... ...