diff --git a/frontend/src/views/Analytics.vue b/frontend/src/views/Analytics.vue index db7637f..69fd29d 100644 --- a/frontend/src/views/Analytics.vue +++ b/frontend/src/views/Analytics.vue @@ -566,41 +566,41 @@ const efficiencyTableData = computed(() => [ // 表格列定义 const userColumns = [ - { title: '排名', key: 'rank', width: 60 }, + { title: '排名', key: 'rank', width: 80, align: 'center' }, { title: '用户名', dataIndex: 'userName', key: 'userName' }, { title: '部门', dataIndex: 'deptName', key: 'deptName' }, - { title: '发起数', dataIndex: 'totalDemands', key: 'totalDemands', sorter: (a: any, b: any) => a.totalDemands - b.totalDemands }, - { title: '完成数', dataIndex: 'completedDemands', key: 'completedDemands' }, - { title: '总积分', dataIndex: 'totalScore', key: 'totalScore' }, - { title: '完成率', key: 'completionRate', width: 150 } + { title: '发起数', dataIndex: 'totalDemands', key: 'totalDemands', sorter: (a: any, b: any) => a.totalDemands - b.totalDemands, align: 'center' }, + { title: '完成数', dataIndex: 'completedDemands', key: 'completedDemands', align: 'center' }, + { title: '总积分', dataIndex: 'totalScore', key: 'totalScore', align: 'center' }, + { title: '完成率', key: 'completionRate', width: 150, align: 'center' } ] const designerColumns = [ - { title: '排名', key: 'rank', width: 60 }, + { title: '排名', key: 'rank', width: 80, align: 'center' }, { title: '设计师', dataIndex: 'realName', key: 'realName' }, { title: '部门', dataIndex: 'deptName', key: 'deptName' }, - { title: '接单量', dataIndex: 'receivedCount', key: 'receivedCount', sorter: (a: any, b: any) => a.receivedCount - b.receivedCount }, - { title: '完成量', dataIndex: 'completedCount', key: 'completedCount' }, - { title: '完成率', dataIndex: 'completionRate', key: 'completionRate', customRender: ({ text }: any) => text + '%' }, - { title: '准时率', key: 'onTimeRate' }, - { title: '评分', key: 'avgRating', width: 140 } + { title: '接单量', dataIndex: 'receivedCount', key: 'receivedCount', sorter: (a: any, b: any) => a.receivedCount - b.receivedCount, align: 'center' }, + { title: '完成量', dataIndex: 'completedCount', key: 'completedCount', align: 'center' }, + { title: '完成率', dataIndex: 'completionRate', key: 'completionRate', customRender: ({ text }: any) => text + '%', align: 'center' }, + { title: '准时率', key: 'onTimeRate', align: 'center' }, + { title: '评分', key: 'avgRating', width: 140, align: 'center' } ] const efficiencyColumns = [ { title: '指标', dataIndex: 'metric', key: 'metric' }, - { title: '本周', dataIndex: 'week', key: 'week' }, - { title: '上周', dataIndex: 'lastWeek', key: 'lastWeek' }, - { title: '环比', key: 'change' }, - { title: '本月', dataIndex: 'month', key: 'month' }, - { title: '目标', dataIndex: 'target', key: 'target' } + { title: '本周', dataIndex: 'week', key: 'week', align: 'right' }, + { title: '上周', dataIndex: 'lastWeek', key: 'lastWeek', align: 'right' }, + { title: '环比', key: 'change', align: 'right' }, + { title: '本月', dataIndex: 'month', key: 'month', align: 'right' }, + { title: '目标', dataIndex: 'target', key: 'target', align: 'right' } ] const warningColumns = [ - { title: '级别', key: 'level', width: 80 }, + { title: '级别', key: 'level', width: 100, align: 'center' }, { title: '任务名称', dataIndex: 'taskTitle', key: 'taskTitle', ellipsis: true }, - { title: '处理人', dataIndex: 'receiverName', key: 'receiverName' }, + { title: '处理人', dataIndex: 'receiverName', key: 'receiverName', align: 'center' }, { title: '预警原因', dataIndex: 'warningReason', key: 'warningReason' }, - { title: '操作', key: 'action', width: 140 } + { title: '操作', key: 'action', width: 140, align: 'center' } ] // 方法 @@ -867,16 +867,18 @@ onMounted(() => { .stat-card { background: $bg-card; - border: 1px solid $border-primary; border-radius: $radius-lg; - padding: $space-md; + padding: $space-lg; display: flex; gap: $space-md; transition: all $transition-base $ease-out; + border: 1px solid rgba(255, 255, 255, 0.03); + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); &:hover { - border-color: $brand-primary; - box-shadow: $shadow-base; + transform: translateY(-2px); + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); + border-color: rgba($brand-primary, 0.3); } .stat-icon { @@ -886,6 +888,8 @@ onMounted(() => { align-items: center; justify-content: center; flex-shrink: 0; + background: rgba($brand-primary, 0.1); + border-radius: 12px; } .stat-content { @@ -895,35 +899,41 @@ onMounted(() => { .stat-label { font-size: $font-size-sm; color: $text-secondary; - margin-bottom: 4px; + margin-bottom: 8px; } .stat-value { - font-size: $font-size-xl; - font-weight: $font-weight-bold; + font-size: 28px; + font-weight: 700; color: $text-primary; + line-height: 1; } } } .tabs-section { :deep(.ant-tabs-nav) { - margin-bottom: $space-lg; + margin-bottom: $space-xl; .ant-tabs-tab { color: $text-secondary; + padding: 12px 0; + transition: all 0.3s; &:hover { - color: $brand-primary; + color: $text-primary; } &.ant-tabs-tab-active .ant-tabs-tab-btn { color: $brand-primary; + font-weight: 600; } } .ant-tabs-ink-bar { background: $brand-primary; + height: 3px; + border-radius: 3px; } } } @@ -934,42 +944,53 @@ onMounted(() => { .chart-card, .table-card { background: $bg-card; - border: 1px solid $border-primary; border-radius: $radius-lg; - padding: $space-lg; + padding: $space-xl; + border: 1px solid rgba(255, 255, 255, 0.03); + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); + margin-bottom: 24px; .chart-title { - font-size: $font-size-base; - font-weight: $font-weight-semibold; + font-size: $font-size-lg; + font-weight: 600; color: $text-primary; - margin-bottom: $space-md; + margin-bottom: $space-lg; + display: flex; + align-items: center; + gap: 8px; .count-badge { + font-size: $font-size-sm; font-weight: normal; color: $text-secondary; + background: rgba(255, 255, 255, 0.05); + padding: 2px 8px; + border-radius: 10px; } } } .mini-stat-card { - background: $bg-tertiary; + background: $bg-card; border-radius: $radius-md; - padding: $space-md; + padding: $space-lg; text-align: center; + border: 1px solid rgba(255, 255, 255, 0.03); &.warning { - border: 1px solid $color-warning; + border: 1px solid rgba($color-warning, 0.3); + background: rgba($color-warning, 0.05); } .mini-stat-label { font-size: $font-size-sm; color: $text-secondary; - margin-bottom: 4px; + margin-bottom: 8px; } .mini-stat-value { - font-size: $font-size-xl; - font-weight: $font-weight-bold; + font-size: 24px; + font-weight: 700; color: $text-primary; } } @@ -978,27 +999,34 @@ onMounted(() => { display: inline-flex; align-items: center; justify-content: center; - width: 28px; - height: 28px; + width: 24px; + height: 24px; border-radius: 50%; - font-weight: $font-weight-bold; - font-size: $font-size-sm; - background: $bg-tertiary; + font-weight: 700; + font-size: 12px; + background: rgba(255, 255, 255, 0.05); color: $text-secondary; + border: 1px solid rgba(255, 255, 255, 0.1); &.rank-1 { - background: rgba(#FFD700, 0.2); - color: #FFD700; + background: linear-gradient(135deg, #FFD700 0%, #FFA500 100%); + color: #fff; + border: none; + box-shadow: 0 2px 4px rgba(255, 215, 0, 0.3); } &.rank-2 { - background: rgba(#C0C0C0, 0.2); - color: #C0C0C0; + background: linear-gradient(135deg, #E0E0E0 0%, #A0A0A0 100%); + color: #fff; + border: none; + box-shadow: 0 2px 4px rgba(192, 192, 192, 0.3); } &.rank-3 { - background: rgba(#CD7F32, 0.2); - color: #CD7F32; + background: linear-gradient(135deg, #CD7F32 0%, #8B4513 100%); + color: #fff; + border: none; + box-shadow: 0 2px 4px rgba(205, 127, 50, 0.3); } } @@ -1009,9 +1037,9 @@ onMounted(() => { // 流程图样式 .process-flow-card { background: $bg-card; - border: 1px solid $border-primary; border-radius: $radius-lg; padding: $space-xl; + border: 1px solid rgba(255, 255, 255, 0.03); } .process-flow { @@ -1019,39 +1047,50 @@ onMounted(() => { align-items: center; justify-content: center; flex-wrap: wrap; - gap: $space-sm; - margin: $space-xl 0; + gap: $space-lg; + margin: 40px 0; } .process-step { display: flex; flex-direction: column; align-items: center; - gap: 4px; + gap: 8px; + position: relative; .step-name { font-size: $font-size-sm; color: $text-primary; - padding: $space-sm $space-md; - background: $bg-tertiary; - border-radius: $radius-md; + padding: 8px 16px; + background: rgba(255, 255, 255, 0.05); + border-radius: 20px; + border: 1px solid rgba(255, 255, 255, 0.1); } .step-time { - font-size: $font-size-xs; + font-size: 13px; color: $brand-primary; - font-weight: $font-weight-bold; + font-weight: 600; } .step-arrow { - color: $text-tertiary; - font-size: $font-size-lg; + color: rgba(255, 255, 255, 0.2); + font-size: 20px; + position: absolute; + right: -24px; + top: 50%; + transform: translateY(-50%); + } + + &:last-child .step-arrow { + display: none; } &.bottleneck { .step-name { - background: rgba($color-warning, 0.2); - border: 1px solid $color-warning; + background: rgba($color-warning, 0.1); + border-color: rgba($color-warning, 0.3); + color: $color-warning; } } } @@ -1059,9 +1098,13 @@ onMounted(() => { .process-summary { text-align: center; color: $text-secondary; + margin-top: $space-lg; + padding-top: $space-lg; + border-top: 1px solid rgba(255, 255, 255, 0.05); strong { color: $text-primary; + font-size: 16px; } .bottleneck-info { @@ -1072,76 +1115,110 @@ onMounted(() => { // 预警卡片样式 .warning-stat-card { - background: $bg-tertiary; - border-radius: $radius-md; + background: $bg-card; + border-radius: $radius-lg; padding: $space-lg; text-align: center; cursor: pointer; transition: all $transition-base; + border: 1px solid rgba(255, 255, 255, 0.03); + position: relative; + overflow: hidden; &:hover { transform: translateY(-2px); - box-shadow: $shadow-base; + box-shadow: 0 8px 12px rgba(0, 0, 0, 0.2); } - &.urgent { border: 1px solid $color-error; } - &.warning { border: 1px solid $color-warning; } - &.normal { border: 1px solid $color-success; } - &.all { border: 1px solid $brand-primary; } + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 4px; + height: 100%; + } + + &.urgent::before { background: $color-error; } + &.warning::before { background: $color-warning; } + &.normal::before { background: $color-success; } + &.all::before { background: $brand-primary; } .warning-icon { - font-size: 24px; - margin-bottom: $space-xs; + font-size: 28px; + margin-bottom: 12px; + opacity: 0.8; } .warning-label { font-size: $font-size-sm; color: $text-secondary; + margin-bottom: 4px; } .warning-count { - font-size: $font-size-2xl; - font-weight: $font-weight-bold; + font-size: 32px; + font-weight: 700; color: $text-primary; } } .level-badge { - padding: 2px 8px; - border-radius: $radius-sm; - font-size: $font-size-xs; + padding: 4px 10px; + border-radius: 4px; + font-size: 12px; + font-weight: 500; &.urgent { - background: rgba($color-error, 0.1); - color: $color-error; + background: rgba($color-error, 0.15); + color: lighten($color-error, 10%); + border: 1px solid rgba($color-error, 0.2); } &.warning { - background: rgba($color-warning, 0.1); - color: $color-warning; + background: rgba($color-warning, 0.15); + color: lighten($color-warning, 10%); + border: 1px solid rgba($color-warning, 0.2); } } // Ant Design 深色主题覆盖 :deep(.ant-table) { background: transparent !important; + color: $text-primary; - .ant-table-thead > tr > th { - background: $bg-tertiary !important; - border-color: $border-color !important; - color: $text-primary !important; + // 移除边框 + .ant-table-container { + border: none !important; } - .ant-table-tbody > tr { - &:hover > td { - background: $bg-tertiary !important; - } + .ant-table-thead > tr > th { + background: transparent !important; + border-bottom: 1px solid rgba(255, 255, 255, 0.05) !important; + color: $text-secondary !important; + font-weight: 500; + padding: 16px; - > td { - border-color: $border-color !important; - color: $text-primary !important; + &::before { + display: none !important; // 移除表头分割线 } } + + .ant-table-tbody > tr > td { + border-bottom: 1px solid rgba(255, 255, 255, 0.02) !important; + padding: 16px; + color: $text-primary; + transition: background 0.3s; + } + + .ant-table-tbody > tr:hover > td { + background: rgba(255, 255, 255, 0.03) !important; + } + + // 移除所有垂直边框 + .ant-table-cell { + border-right: none !important; + } } :deep(.ant-tabs) { @@ -1151,14 +1228,20 @@ onMounted(() => { :deep(.ant-select) { .ant-select-selector { background: $bg-tertiary !important; - border-color: $border-color !important; + border-color: rgba(255, 255, 255, 0.1) !important; color: $text-primary !important; + border-radius: 6px !important; + } + + .ant-select-arrow { + color: $text-secondary !important; } } :deep(.ant-picker) { background: $bg-tertiary !important; - border-color: $border-color !important; + border-color: rgba(255, 255, 255, 0.1) !important; + border-radius: 6px !important; .ant-picker-input > input { color: $text-primary !important; @@ -1169,7 +1252,14 @@ onMounted(() => { } } +:deep(.ant-btn) { + border-radius: 6px; +} + :deep(.ant-rate) { + font-size: 14px; + color: rgba(255, 255, 255, 0.1); + .ant-rate-star-full .ant-rate-star-second { color: #FFD700 !important; }