diff --git a/frontend/src/pages/Dashboard/Dashboard.css b/frontend/src/pages/Dashboard/Dashboard.css index 1a4fce1..96b8d59 100644 --- a/frontend/src/pages/Dashboard/Dashboard.css +++ b/frontend/src/pages/Dashboard/Dashboard.css @@ -34,6 +34,33 @@ justify-content: center; color: var(--color-primary-green); font-size: 12px; + position: relative; + overflow: hidden; +} + +.banner-placeholder-gradient { + position: absolute; + inset: 0; + background: linear-gradient(135deg, #6b8e6b 0%, #a8c89a 50%, #d4e6b5 100%); +} + +.change-cover-btn { + position: absolute; + bottom: 6px; + right: 6px; + z-index: 2; +} + +.placeholder-label { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 2; + color: rgba(255,255,255,0.85); + font-size: 13px; + font-weight: 600; + letter-spacing: 2px; } /* KPI Cards */ diff --git a/frontend/src/pages/Dashboard/Dashboard.jsx b/frontend/src/pages/Dashboard/Dashboard.jsx index 7ce3d6f..d0751c5 100644 --- a/frontend/src/pages/Dashboard/Dashboard.jsx +++ b/frontend/src/pages/Dashboard/Dashboard.jsx @@ -1,32 +1,30 @@ -import { Row, Col, Card, Avatar, Tooltip } from 'antd' +import { useState, useEffect } from 'react' +import { Row, Col, Card, Avatar, Tooltip, Button } from 'antd' import { BarChartOutlined, EyeOutlined, CalendarOutlined, FireOutlined, + PictureOutlined, } from '@ant-design/icons' +import useAuthStore from '../../stores/authStore' +import { listEpisodes } from '../../services/episodeService' +import { listTargets } from '../../services/yearlyTargetService' import './Dashboard.css' -// 假数据:近 9 期收视(基础目标 0.6,摸高目标 0.9) -const fakeEpisodes = [ - { id: 1, title: '第 1247 期 现代防空反导大对决', editor: 'simonkoson', share: 0.72 }, - { id: 2, title: '第 1246 期 深海暗战', editor: 'simonkoson', share: 0.85 }, - { id: 3, title: '第 1245 期 隐形战场', editor: 'simonkoson', share: 0.94 }, - { id: 4, title: '第 1244 期 无人机革命', editor: 'simonkoson', share: 0.65 }, - { id: 5, title: '第 1243 期 核潜艇传奇', editor: 'simonkoson', share: 0.58 }, - { id: 6, title: '第 1242 期 电子战风暴', editor: 'simonkoson', share: 0.88 }, - { id: 7, title: '第 1241 期 太空博弈', editor: 'simonkoson', share: 0.91 }, - { id: 8, title: '第 1240 期 装甲对决', editor: 'simonkoson', share: 0.67 }, - { id: 9, title: '第 1239 期 隐身战机', editor: 'simonkoson', share: 0.55 }, -] - -const BASE_TARGET = 0.6 -const STRETCH_TARGET = 0.9 - -function getBarColor(share) { - if (share > STRETCH_TARGET) return '#cf1322' // 红=优秀 - if (share >= BASE_TARGET) return '#6b8e6b' // 蓝=达标 - return '#d4a017' // 绿=待提升 +/** + * 收视份额颜色判定(极易写反,禁止凭直觉): + * audience_share > stretch_target → 🔴 红(优秀) + * base_target ≤ audience_share ≤ stretch_target → 🔵 蓝(达标) + * audience_share < base_target → 🟢 绿(待提升) + * 判色取该期 air_date 所属年份的 yearly_targets 行(不是当前年)。 + */ +function getShareColor(share, targets, airYear) { + const target = targets.find(t => t.year === airYear) + if (!target) return '#999' + if (share > target.stretch_target) return '#cf1322' // 红=优秀 + if (share >= target.base_target) return '#6b8e6b' // 蓝=达标 + return '#d4a017' // 绿=待提升 } function getBarHeight(share) { @@ -38,16 +36,63 @@ function getShortTitle(title) { } function Dashboard() { + const { user } = useAuthStore() + const [episodes, setEpisodes] = useState([]) + const [targets, setTargets] = useState([]) + const [loading, setLoading] = useState(true) + + useEffect(() => { + Promise.all([ + listEpisodes(limit = 9), + listTargets(), + ]).then(([epData, tgtData]) => { + // 按 air_date 倒序取前 9 + const sorted = (epData || []).sort((a, b) => new Date(b.air_date) - new Date(a.air_date)).slice(0, 9) + setEpisodes(sorted) + setTargets(tgtData || []) + setLoading(false) + }).catch(() => { + setLoading(false) + }) + }, []) + + // 显示最近有份额数据的期次(最多9个,不够用真实数据补位) + const hasShare = episodes.filter(e => e.audience_share != null) + const displayEpisodes = hasShare.length >= 5 ? hasShare.slice(0, 9) : episodes.slice(0, Math.max(9, hasShare.length || 5)) + + const bestEpisode = [...displayEpisodes].filter(e => e.audience_share != null).sort((a, b) => b.audience_share - a.audience_share)[0] + + const showChangeCoverBtn = user?.role === 'zhipianren' || user?.role === 'zebian' + return (
第 1245 期 隐形战场 · 收视份额 0.94
+ {bestEpisode ? ( ++ 第 {bestEpisode.episode_number} 期 {bestEpisode.program_name} · + 收视份额 {bestEpisode.audience_share} +
+ ) : ( +暂无收视数据
+ )}模块 H · Phase 4c 实施
- 热点雷达将在 Phase 4c 开发,作为编导个人首页的核心功能 +热点雷达 · Phase 4c
+ 编导个人首页核心功能,Phase 4c 实施模块 F · Phase 4b 实施
- 甘特图排期将在 Phase 4b 开发,使用 frappe-gantt 实现拖拽排期 +排播计划 · Phase 4b
+ 甘特图排期使用 frappe-gantt 实现,Phase 4b 开发