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,25 +1233,47 @@ export default {
1233 1233
1234 <style lang="scss" scoped> 1234 <style lang="scss" scoped>
1235 .financial-report-container { 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 min-height: calc(100vh - 84px); 1238 min-height: calc(100vh - 84px);
1239 max-width: 100%; 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 .search-card { 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 &:hover { 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 .search-form { 1279 .search-form {
@@ -1278,28 +1300,34 @@ export default { @@ -1278,28 +1300,34 @@ export default {
1278 } 1300 }
1279 1301
1280 ::v-deep .el-button { 1302 ::v-deep .el-button {
1281 - border-radius: 6px; 1303 + border-radius: 8px;
1282 font-weight: 500; 1304 font-weight: 500;
1283 - transition: all 0.2s ease; 1305 + transition: all 0.3s ease;
1284 padding: 4px 12px; 1306 padding: 4px 12px;
1285 height: 26px; 1307 height: 26px;
1286 font-size: 13px; 1308 font-size: 13px;
1287 1309
1288 &.el-button--primary { 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 &:hover { 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 &:not(.el-button--primary) { 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 &:hover { 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,18 +1336,19 @@ export default {
1308 1336
1309 // 统计卡片区域 1337 // 统计卡片区域
1310 .stat-cards-section { 1338 .stat-cards-section {
1311 - margin-bottom: 12px; 1339 + margin-bottom: 16px;
1312 1340
1313 .stat-card { 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 display: flex; 1346 display: flex;
1318 align-items: center; 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 cursor: pointer; 1350 cursor: pointer;
1322 - border: 1px solid #e2e8f0; 1351 + border: 1px solid rgba(144, 147, 153, 0.15);
1323 height: 100%; 1352 height: 100%;
1324 position: relative; 1353 position: relative;
1325 overflow: hidden; 1354 overflow: hidden;
@@ -1328,40 +1357,64 @@ export default { @@ -1328,40 +1357,64 @@ export default {
1328 content: ''; 1357 content: '';
1329 position: absolute; 1358 position: absolute;
1330 top: 0; 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 &:hover { 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 &::before { 1371 &::before {
1345 - opacity: 1; 1372 + left: 100%;
1346 } 1373 }
1347 } 1374 }
1348 1375
1349 .stat-icon { 1376 .stat-icon {
1350 - width: 44px;  
1351 - height: 44px;  
1352 - border-radius: 8px; 1377 + width: 56px;
  1378 + height: 56px;
  1379 + border-radius: 12px;
1353 display: flex; 1380 display: flex;
1354 align-items: center; 1381 align-items: center;
1355 justify-content: center; 1382 justify-content: center;
1356 - margin-right: 12px;  
1357 - font-size: 22px; 1383 + margin-right: 16px;
  1384 + font-size: 24px;
1358 flex-shrink: 0; 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 &:hover .stat-icon { 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 .stat-content { 1420 .stat-content {
@@ -1369,19 +1422,22 @@ export default { @@ -1369,19 +1422,22 @@ export default {
1369 min-width: 0; 1422 min-width: 0;
1370 1423
1371 .stat-label { 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 font-weight: 500; 1428 font-weight: 500;
1376 line-height: 1.3; 1429 line-height: 1.3;
1377 letter-spacing: 0.01em; 1430 letter-spacing: 0.01em;
1378 } 1431 }
1379 1432
1380 .stat-value { 1433 .stat-value {
1381 - font-size: 22px; 1434 + font-size: 24px;
1382 font-weight: 700; 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 white-space: nowrap; 1441 white-space: nowrap;
1386 overflow: hidden; 1442 overflow: hidden;
1387 text-overflow: ellipsis; 1443 text-overflow: ellipsis;
@@ -1391,7 +1447,7 @@ export default { @@ -1391,7 +1447,7 @@ export default {
1391 1447
1392 .stat-meta { 1448 .stat-meta {
1393 font-size: 12px; 1449 font-size: 12px;
1394 - color: #94a3b8; 1450 + color: #909399;
1395 line-height: 1.3; 1451 line-height: 1.3;
1396 font-weight: 400; 1452 font-weight: 400;
1397 } 1453 }
@@ -1399,130 +1455,203 @@ export default { @@ -1399,130 +1455,203 @@ export default {
1399 1455
1400 &.income-card { 1456 &.income-card {
1401 .stat-icon { 1457 .stat-icon {
1402 - background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%); 1458 + background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
1403 color: #fff; 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 &.channel-card { 1463 &.channel-card {
1412 .stat-icon { 1464 .stat-icon {
1413 - background: linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%); 1465 + background: linear-gradient(135deg, #a855f7 0%, #9333ea 100%);
1414 color: #fff; 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 &.payable-card { 1470 &.payable-card {
1423 .stat-icon { 1471 .stat-icon {
1424 - background: linear-gradient(135deg, #f97316 0%, #fb923c 100%); 1472 + background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
1425 color: #fff; 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 &.receivable-card { 1477 &.receivable-card {
1434 .stat-icon { 1478 .stat-icon {
1435 - background: linear-gradient(135deg, #10b981 0%, #34d399 100%); 1479 + background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
1436 color: #fff; 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 .charts-section { 1487 .charts-section {
1448 - margin-bottom: 12px; 1488 + margin-bottom: 16px;
1449 1489
1450 .chart-card { 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 overflow: hidden; 1497 overflow: hidden;
1457 1498
1458 &:hover { 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 .chart-header { 1515 .chart-header {
1464 display: flex; 1516 display: flex;
1465 align-items: center; 1517 align-items: center;
1466 justify-content: space-between; 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 .chart-title { 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 display: flex; 1532 display: flex;
1478 align-items: center; 1533 align-items: center;
1479 - gap: 6px; 1534 + gap: 12px;
1480 letter-spacing: -0.01em; 1535 letter-spacing: -0.01em;
1481 - height: 20px;  
1482 - line-height: 20px; 1536 + height: auto;
  1537 + line-height: 1.5;
1483 1538
1484 i { 1539 i {
1485 - font-size: 14px;  
1486 - color: #2563eb;  
1487 - width: 18px;  
1488 - height: 18px; 1540 + width: 32px;
  1541 + height: 32px;
1489 display: flex; 1542 display: flex;
1490 align-items: center; 1543 align-items: center;
1491 justify-content: center; 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 .chart-container { 1615 .chart-container {
1499 width: 100%; 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 .table-card { 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 width: 100%; 1632 width: 100%;
1515 overflow: hidden; 1633 overflow: hidden;
1516 1634
1517 &:hover { 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 .table-filters { 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 margin-top: 0; 1655 margin-top: 0;
1527 1656
1528 .filter-form { 1657 .filter-form {
@@ -1567,105 +1696,147 @@ export default { @@ -1567,105 +1696,147 @@ export default {
1567 display: flex; 1696 display: flex;
1568 align-items: center; 1697 align-items: center;
1569 justify-content: space-between; 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 .table-title { 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 display: flex; 1712 display: flex;
1581 align-items: center; 1713 align-items: center;
1582 - gap: 6px; 1714 + gap: 12px;
1583 letter-spacing: -0.01em; 1715 letter-spacing: -0.01em;
1584 flex-shrink: 0; 1716 flex-shrink: 0;
1585 - height: 20px;  
1586 - line-height: 20px; 1717 + height: auto;
  1718 + line-height: 1.5;
1587 1719
1588 i { 1720 i {
1589 - font-size: 14px;  
1590 - color: #2563eb;  
1591 - width: 18px;  
1592 - height: 18px; 1721 + width: 32px;
  1722 + height: 32px;
1593 display: flex; 1723 display: flex;
1594 align-items: center; 1724 align-items: center;
1595 justify-content: center; 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 .table-tabs { 1759 .table-tabs {
1602 flex: 1; 1760 flex: 1;
1603 - margin-left: 12px; 1761 + margin-left: 16px;
1604 1762
1605 ::v-deep .el-tabs__header { 1763 ::v-deep .el-tabs__header {
1606 margin: 0; 1764 margin: 0;
1607 - height: 20px;  
1608 } 1765 }
1609 1766
1610 ::v-deep .el-tabs__nav-wrap { 1767 ::v-deep .el-tabs__nav-wrap {
1611 - height: 20px;  
1612 -  
1613 &::after { 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 ::v-deep .el-tabs__item { 1774 ::v-deep .el-tabs__item {
1624 font-weight: 500; 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 &.is-active { 1785 &.is-active {
1635 - color: #2563eb; 1786 + color: #3b82f6;
1636 font-weight: 600; 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 &:hover:not(.is-active) { 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 ::v-deep .el-tabs__active-bar { 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 .table-wrapper { 1805 .table-wrapper {
1655 width: 100%; 1806 width: 100%;
1656 - padding: 8px 12px; 1807 + padding: 0;
1657 overflow-x: auto; 1808 overflow-x: auto;
1658 overflow-y: hidden; 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 .data-table { 1830 .data-table {
1661 width: 100% !important; 1831 width: 100% !important;
1662 min-width: 100%; 1832 min-width: 100%;
1663 1833
1664 ::v-deep .el-table { 1834 ::v-deep .el-table {
1665 width: 100% !important; 1835 width: 100% !important;
1666 - font-size: 13px;  
1667 - border-radius: 6px; 1836 + font-size: 14px;
  1837 + border-radius: 8px;
1668 overflow: hidden; 1838 overflow: hidden;
  1839 + border: 1px solid rgba(144, 147, 153, 0.2);
1669 1840
1670 .el-table__header-wrapper { 1841 .el-table__header-wrapper {
1671 width: 100% !important; 1842 width: 100% !important;
@@ -1677,18 +1848,17 @@ export default { @@ -1677,18 +1848,17 @@ export default {
1677 1848
1678 .el-table__header { 1849 .el-table__header {
1679 width: 100% !important; 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 th { 1853 th {
1683 - background: #f8fafc;  
1684 - color: #475569; 1854 + background: transparent;
  1855 + color: #303133;
1685 font-weight: 600; 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 text-align: left; 1859 text-align: left;
1689 - font-size: 12px; 1860 + font-size: 13px;
1690 letter-spacing: 0.01em; 1861 letter-spacing: 0.01em;
1691 - text-transform: uppercase;  
1692 } 1862 }
1693 } 1863 }
1694 1864
@@ -1697,20 +1867,21 @@ export default { @@ -1697,20 +1867,21 @@ export default {
1697 1867
1698 tr { 1868 tr {
1699 width: 100% !important; 1869 width: 100% !important;
1700 - transition: background-color 0.15s ease; 1870 + transition: all 0.3s ease;
1701 1871
1702 &:hover { 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 td { 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 text-align: left; 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,7 +1889,7 @@ export default {
1718 width: 100% !important; 1889 width: 100% !important;
1719 1890
1720 &:nth-child(even) { 1891 &:nth-child(even) {
1721 - background-color: #fafbfc; 1892 + background-color: rgba(248, 249, 250, 0.3);
1722 } 1893 }
1723 1894
1724 &:last-child td { 1895 &:last-child td {
@@ -1745,25 +1916,25 @@ export default { @@ -1745,25 +1916,25 @@ export default {
1745 // 响应式适配 1916 // 响应式适配
1746 @media (max-width: 1400px) { 1917 @media (max-width: 1400px) {
1747 .financial-report-container { 1918 .financial-report-container {
1748 - padding: 28px; 1919 + padding: 16px;
1749 } 1920 }
1750 } 1921 }
1751 1922
1752 @media (max-width: 1200px) { 1923 @media (max-width: 1200px) {
1753 .financial-report-container { 1924 .financial-report-container {
1754 - padding: 24px; 1925 + padding: 16px;
1755 1926
1756 .stat-cards-section { 1927 .stat-cards-section {
1757 .stat-card { 1928 .stat-card {
1758 .stat-icon { 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 .stat-value { 1936 .stat-value {
1766 - font-size: 26px; 1937 + font-size: 22px;
1767 } 1938 }
1768 } 1939 }
1769 } 1940 }
@@ -1781,17 +1952,17 @@ export default { @@ -1781,17 +1952,17 @@ export default {
1781 .financial-report-container { 1952 .financial-report-container {
1782 .stat-cards-section { 1953 .stat-cards-section {
1783 .stat-card { 1954 .stat-card {
1784 - padding: 24px; 1955 + padding: 16px 20px;
1785 1956
1786 .stat-icon { 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 .stat-value { 1964 .stat-value {
1794 - font-size: 24px; 1965 + font-size: 22px;
1795 } 1966 }
1796 } 1967 }
1797 } 1968 }
@@ -1803,9 +1974,9 @@ export default { @@ -1803,9 +1974,9 @@ export default {
1803 padding: 16px; 1974 padding: 16px;
1804 1975
1805 .search-card { 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 .search-form { 1981 .search-form {
1811 ::v-deep .el-form-item { 1982 ::v-deep .el-form-item {
@@ -1842,12 +2013,12 @@ export default { @@ -1842,12 +2013,12 @@ export default {
1842 } 2013 }
1843 2014
1844 .stat-card { 2015 .stat-card {
1845 - padding: 20px; 2016 + padding: 16px 20px;
1846 2017
1847 .stat-icon { 2018 .stat-icon {
1848 width: 56px; 2019 width: 56px;
1849 height: 56px; 2020 height: 56px;
1850 - font-size: 28px; 2021 + font-size: 24px;
1851 margin-right: 16px; 2022 margin-right: 16px;
1852 } 2023 }
1853 2024
@@ -1884,18 +2055,18 @@ export default { @@ -1884,18 +2055,18 @@ export default {
1884 } 2055 }
1885 2056
1886 .chart-card { 2057 .chart-card {
1887 - border-radius: 10px; 2058 + border-radius: 12px;
1888 2059
1889 .chart-header { 2060 .chart-header {
1890 - padding: 10px 16px; 2061 + padding: 16px 20px;
1891 2062
1892 .chart-title { 2063 .chart-title {
1893 - font-size: 13px; 2064 + font-size: 15px;
1894 2065
1895 i { 2066 i {
1896 font-size: 16px; 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,14 +2074,14 @@ export default {
1903 .chart-container { 2074 .chart-container {
1904 height: 300px; 2075 height: 300px;
1905 min-height: 300px; 2076 min-height: 300px;
1906 - padding: 4px 4px; 2077 + padding: 0;
1907 } 2078 }
1908 } 2079 }
1909 } 2080 }
1910 2081
1911 .table-card { 2082 .table-card {
1912 .table-filters { 2083 .table-filters {
1913 - padding: 10px 16px; 2084 + padding: 14px 20px;
1914 2085
1915 .filter-form { 2086 .filter-form {
1916 ::v-deep .el-form-item { 2087 ::v-deep .el-form-item {
@@ -1928,16 +2099,16 @@ export default { @@ -1928,16 +2099,16 @@ export default {
1928 .table-header { 2099 .table-header {
1929 flex-direction: column; 2100 flex-direction: column;
1930 align-items: flex-start; 2101 align-items: flex-start;
1931 - gap: 8px;  
1932 - padding: 8px 16px; 2102 + gap: 12px;
  2103 + padding: 0;
1933 2104
1934 .table-title { 2105 .table-title {
1935 - font-size: 13px; 2106 + font-size: 15px;
1936 2107
1937 i { 2108 i {
1938 font-size: 16px; 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,17 +2117,17 @@ export default {
1946 margin-left: 0; 2117 margin-left: 0;
1947 2118
1948 ::v-deep .el-tabs__item { 2119 ::v-deep .el-tabs__item {
1949 - padding: 0 12px; 2120 + padding: 0 16px;
1950 height: 32px; 2121 height: 32px;
1951 line-height: 32px; 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 .table-wrapper { 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,6 +602,11 @@ namespace NCC.Extend
602 salary.NewCustomerConversionRate = extraData.NewCustomerConversionRate; 602 salary.NewCustomerConversionRate = extraData.NewCustomerConversionRate;
603 salary.NewCustomerPerformance = extraData.NewCustomerPerformance; 603 salary.NewCustomerPerformance = extraData.NewCustomerPerformance;
604 salary.UpgradePerformance = extraData.UpgradePerformance; 604 salary.UpgradePerformance = extraData.UpgradePerformance;
  605 +
  606 + // 调整总业绩:加上其他业绩加,减去其他业绩减
  607 + // 确保后续计算(包括金三角战队业绩)使用的是调整后的总业绩
  608 + salary.TotalPerformance += salary.OtherPerformanceAdd;
  609 + salary.TotalPerformance -= salary.OtherPerformanceSubtract;
605 } 610 }
606 611
607 // 2.1.2 计算实际基础业绩和实际合作业绩 612 // 2.1.2 计算实际基础业绩和实际合作业绩