- 仪表盘双色进度条(超100%蓝红分段)、工时损耗展示、chart tooltip增强 - 修复 Submissions.vue 延期原因字段始终显示的Bug - 修复 SPA catch-all 路由拦截 API 请求(去尾部斜杠) - seed_demo.py 重写:5项目/4类型/32里程碑/124提交,真实时间线 - 三阶段损耗计算(前期工时/制作秒数/后期工时) - ContentType 扩展为11种,里程碑增强(预估天数/开始日期/超期检测) - 更新 PRD 和项目总结文档 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
591 lines
31 KiB
Python
591 lines
31 KiB
Python
"""补充演示数据 - 只添加项目/提交/成本,不动用户和角色
|
||
展示场景:
|
||
1. 双色进度条(品牌方 TVC 进度>200%)
|
||
2. 工时损耗(分镜/剪辑里程碑超期)
|
||
3. 秒数损耗(测试提交 + 超产)
|
||
4. 四种项目类型 + 五个项目
|
||
5. 前期必须结束才有制作提交
|
||
6. 内部原创配有风格测试项目
|
||
7. owners / 制片 不提交
|
||
"""
|
||
from datetime import date, datetime, timedelta
|
||
from database import SessionLocal
|
||
from models import *
|
||
|
||
db = SessionLocal()
|
||
|
||
|
||
def get_user(username):
|
||
u = db.query(User).filter(User.username == username).first()
|
||
if not u:
|
||
print(f" [WARN] user '{username}' not found")
|
||
return u
|
||
|
||
|
||
def dt(d):
|
||
"""date → datetime(用于 completed_at)"""
|
||
return datetime.combine(d, datetime.min.time())
|
||
|
||
|
||
def seed_demo():
|
||
# 清除旧的项目相关数据(不动 users 和 roles)
|
||
db.query(SubmissionHistory).delete()
|
||
db.query(Submission).delete()
|
||
db.query(OutsourceCost).delete()
|
||
db.query(CostOverride).delete()
|
||
db.query(AIToolCost).delete()
|
||
db.query(OverheadCost).delete()
|
||
db.query(ProjectMilestone).delete()
|
||
db.query(Project).delete()
|
||
db.commit()
|
||
print("[1] Cleared old project data")
|
||
|
||
# ── 获取真实用户 ──
|
||
# owners / 制片:不提交任何东西
|
||
huhaonan = get_user("huhaonan") # owner/总导演
|
||
dengqingrui = get_user("dengqingrui") # owner/AI导演
|
||
qiushaohui = get_user("qiushaohui") # 制片
|
||
|
||
# 组长:可以提交
|
||
chenbaodan = get_user("chenbaodan") # 组长/动画制作
|
||
maruoqing = get_user("maruoqing") # 组长/AI导演
|
||
weichunli = get_user("weichunli") # 组长/AI导演
|
||
panziyan = get_user("panziyan") # 组长/剪辑
|
||
|
||
# 组员
|
||
daixiaoqian = get_user("daixiaoqian") # 动画制作
|
||
tanruping = get_user("tanruping") # 动画制作
|
||
zhengyiqing = get_user("zhengyiqing") # 动画制作
|
||
huangxuewen = get_user("huangxuewen") # 动画制作
|
||
liushiqi = get_user("liushiqi") # 动画制作
|
||
daiwei = get_user("daiwei") # 动画制作
|
||
huangrongying = get_user("huangrongying") # 编剧
|
||
jiahaozheng = get_user("jiahaozheng") # 剪辑
|
||
wangyansen = get_user("wangyansen") # 剪辑
|
||
huangqiuxia = get_user("huangqiuxia") # 动画制作
|
||
lijing = get_user("lijing") # 动画制作
|
||
yemeilian = get_user("yemeilian") # 动画制作
|
||
chenxuanying = get_user("chenxuanying") # 动画制作
|
||
|
||
today = date.today()
|
||
|
||
# ══════════════════════════════════════════════════════════════
|
||
# 项目 1: 品牌方 TVC 宣传片
|
||
# 客户正式 | 后期 | target=180s | 创建于 12/8
|
||
# 进度>200% → 双色进度条
|
||
# 分镜+剪辑超期 → waste_hours
|
||
# ══════════════════════════════════════════════════════════════
|
||
proj_tvc = Project(
|
||
name="品牌方 TVC 宣传片", project_type=ProjectType.CLIENT_FORMAL,
|
||
leader_id=maruoqing.id, current_phase=PhaseGroup.POST,
|
||
episode_duration_minutes=1, episode_count=3,
|
||
estimated_completion_date=date(2026, 2, 20),
|
||
contract_amount=50000,
|
||
created_at=dt(date(2025, 12, 8)),
|
||
)
|
||
|
||
# ══════════════════════════════════════════════════════════════
|
||
# 项目 2: 星际漫游 第一季
|
||
# 客户正式 | 制作中 | target=3900s | 创建于 12/22
|
||
# 进度~80% | 分镜微超期 → 少量 waste_hours
|
||
# ══════════════════════════════════════════════════════════════
|
||
proj_star = Project(
|
||
name="星际漫游 第一季", project_type=ProjectType.CLIENT_FORMAL,
|
||
leader_id=chenbaodan.id, current_phase=PhaseGroup.PRODUCTION,
|
||
episode_duration_minutes=5, episode_count=13,
|
||
estimated_completion_date=date(2026, 3, 30),
|
||
contract_amount=100000,
|
||
created_at=dt(date(2025, 12, 22)),
|
||
)
|
||
|
||
# ══════════════════════════════════════════════════════════════
|
||
# 项目 3: AI 短剧原创 S1
|
||
# 内部原创 | 制作中 | target=2880s | 创建于 1/6
|
||
# 进度~40% | 无超期 → waste_hours=0
|
||
# ══════════════════════════════════════════════════════════════
|
||
proj_orig = Project(
|
||
name="AI 短剧原创 S1", project_type=ProjectType.INTERNAL_ORIGINAL,
|
||
leader_id=weichunli.id, current_phase=PhaseGroup.PRODUCTION,
|
||
episode_duration_minutes=8, episode_count=6,
|
||
estimated_completion_date=date(2026, 4, 30),
|
||
created_at=dt(date(2026, 1, 6)),
|
||
)
|
||
|
||
# ══════════════════════════════════════════════════════════════
|
||
# 项目 4: 原创 S1 风格测试
|
||
# 内部测试 | 制作 | target=60s | 创建于 1/2
|
||
# 内部原创的配套测试项目 | 全 TEST → 高损耗率
|
||
# ══════════════════════════════════════════════════════════════
|
||
proj_orig_test = Project(
|
||
name="原创 S1 风格测试", project_type=ProjectType.INTERNAL_TEST,
|
||
leader_id=weichunli.id, current_phase=PhaseGroup.PRODUCTION,
|
||
episode_duration_minutes=1, episode_count=1,
|
||
created_at=dt(date(2026, 1, 2)),
|
||
)
|
||
|
||
# ══════════════════════════════════════════════════════════════
|
||
# 项目 5: 甲方风格测试
|
||
# 客户测试 | 前期 | target=60s | 创建于 1/27
|
||
# 早期阶段 | 策划案超期 → waste_hours
|
||
# ══════════════════════════════════════════════════════════════
|
||
proj_client_test = Project(
|
||
name="甲方风格测试", project_type=ProjectType.CLIENT_TEST,
|
||
leader_id=maruoqing.id, current_phase=PhaseGroup.PRE,
|
||
episode_duration_minutes=1, episode_count=1,
|
||
created_at=dt(date(2026, 1, 27)),
|
||
)
|
||
|
||
db.add_all([proj_tvc, proj_star, proj_orig, proj_orig_test, proj_client_test])
|
||
db.flush()
|
||
print("[2] Created 5 projects")
|
||
|
||
# ══════════════════════════════════════════════════════════════
|
||
# 里程碑
|
||
# ══════════════════════════════════════════════════════════════
|
||
milestones = []
|
||
|
||
# ── 品牌方 TVC 里程碑 ──
|
||
# 前期
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_tvc.id, name="策划案", phase=PhaseGroup.PRE, sort_order=1,
|
||
estimated_days=2, start_date=date(2025, 12, 8),
|
||
is_completed=1, completed_at=dt(date(2025, 12, 9)),
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_tvc.id, name="分镜", phase=PhaseGroup.PRE, sort_order=3,
|
||
estimated_days=2, start_date=date(2025, 12, 10),
|
||
is_completed=1, completed_at=dt(date(2025, 12, 15)), # 实际3天,超1天→8h
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_tvc.id, name="人设图", phase=PhaseGroup.PRE, sort_order=4,
|
||
estimated_days=2, start_date=date(2025, 12, 15),
|
||
is_completed=1, completed_at=dt(date(2025, 12, 16)),
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_tvc.id, name="场景图", phase=PhaseGroup.PRE, sort_order=5,
|
||
estimated_days=1, start_date=date(2025, 12, 17),
|
||
is_completed=1, completed_at=dt(date(2025, 12, 17)),
|
||
))
|
||
# 后期
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_tvc.id, name="配音", phase=PhaseGroup.POST, sort_order=1,
|
||
estimated_days=3, start_date=date(2026, 1, 27),
|
||
is_completed=1, completed_at=dt(date(2026, 1, 29)),
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_tvc.id, name="音效", phase=PhaseGroup.POST, sort_order=2,
|
||
estimated_days=2, start_date=date(2026, 1, 29),
|
||
is_completed=1, completed_at=dt(date(2026, 1, 30)),
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_tvc.id, name="修补镜头", phase=PhaseGroup.POST, sort_order=3,
|
||
estimated_days=2, start_date=date(2026, 1, 27),
|
||
is_completed=1, completed_at=dt(date(2026, 1, 28)),
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_tvc.id, name="剪辑", phase=PhaseGroup.POST, sort_order=4,
|
||
estimated_days=3, start_date=date(2026, 2, 3),
|
||
is_completed=0, # 进行中,多轮反馈导致超期 → waste_hours
|
||
))
|
||
|
||
# ── 星际漫游 里程碑 ──
|
||
# 前期
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_star.id, name="策划案", phase=PhaseGroup.PRE, sort_order=1,
|
||
estimated_days=3, start_date=date(2025, 12, 22),
|
||
is_completed=1, completed_at=dt(date(2025, 12, 23)),
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_star.id, name="剧本", phase=PhaseGroup.PRE, sort_order=2,
|
||
estimated_days=5, start_date=date(2025, 12, 24),
|
||
is_completed=1, completed_at=dt(date(2025, 12, 30)),
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_star.id, name="分镜", phase=PhaseGroup.PRE, sort_order=3,
|
||
estimated_days=3, start_date=date(2025, 12, 31),
|
||
is_completed=1, completed_at=dt(date(2026, 1, 7)), # 实际5天,超2天→16h
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_star.id, name="人设图", phase=PhaseGroup.PRE, sort_order=4,
|
||
estimated_days=2, start_date=date(2026, 1, 8),
|
||
is_completed=1, completed_at=dt(date(2026, 1, 9)),
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_star.id, name="场景图", phase=PhaseGroup.PRE, sort_order=5,
|
||
estimated_days=2, start_date=date(2026, 1, 10),
|
||
is_completed=1, completed_at=dt(date(2026, 1, 13)),
|
||
))
|
||
# 后期(未开始)
|
||
for name, order in [("配音", 1), ("音效", 2), ("修补镜头", 3), ("剪辑", 4)]:
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_star.id, name=name, phase=PhaseGroup.POST, sort_order=order,
|
||
))
|
||
|
||
# ── AI 短剧原创 里程碑 ──(全部按时)
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_orig.id, name="策划案", phase=PhaseGroup.PRE, sort_order=1,
|
||
estimated_days=2, start_date=date(2026, 1, 6),
|
||
is_completed=1, completed_at=dt(date(2026, 1, 7)),
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_orig.id, name="剧本", phase=PhaseGroup.PRE, sort_order=2,
|
||
estimated_days=5, start_date=date(2026, 1, 8),
|
||
is_completed=1, completed_at=dt(date(2026, 1, 14)),
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_orig.id, name="分镜", phase=PhaseGroup.PRE, sort_order=3,
|
||
estimated_days=3, start_date=date(2026, 1, 15),
|
||
is_completed=1, completed_at=dt(date(2026, 1, 17)),
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_orig.id, name="人设图", phase=PhaseGroup.PRE, sort_order=4,
|
||
estimated_days=2, start_date=date(2026, 1, 20),
|
||
is_completed=1, completed_at=dt(date(2026, 1, 21)),
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_orig.id, name="场景图", phase=PhaseGroup.PRE, sort_order=5,
|
||
estimated_days=1, start_date=date(2026, 1, 22),
|
||
is_completed=1, completed_at=dt(date(2026, 1, 22)),
|
||
))
|
||
for name, order in [("配音", 1), ("音效", 2), ("修补镜头", 3), ("剪辑", 4)]:
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_orig.id, name=name, phase=PhaseGroup.POST, sort_order=order,
|
||
))
|
||
|
||
# ── 原创风格测试 里程碑 ──
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_orig_test.id, name="策划案", phase=PhaseGroup.PRE, sort_order=1,
|
||
estimated_days=2, start_date=date(2026, 1, 2),
|
||
is_completed=1, completed_at=dt(date(2026, 1, 3)),
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_orig_test.id, name="人设图", phase=PhaseGroup.PRE, sort_order=4,
|
||
estimated_days=2, start_date=date(2026, 1, 6),
|
||
is_completed=1, completed_at=dt(date(2026, 1, 7)),
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_orig_test.id, name="剪辑", phase=PhaseGroup.POST, sort_order=4,
|
||
))
|
||
|
||
# ── 甲方风格测试 里程碑 ──
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_client_test.id, name="策划案", phase=PhaseGroup.PRE, sort_order=1,
|
||
estimated_days=3, start_date=date(2026, 1, 27),
|
||
is_completed=0, # 甲方反复修改,至今未定稿 → 超期 → waste_hours
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_client_test.id, name="人设图", phase=PhaseGroup.PRE, sort_order=4,
|
||
estimated_days=2, start_date=date(2026, 2, 3),
|
||
is_completed=0,
|
||
))
|
||
milestones.append(ProjectMilestone(
|
||
project_id=proj_client_test.id, name="剪辑", phase=PhaseGroup.POST, sort_order=4,
|
||
))
|
||
|
||
db.add_all(milestones)
|
||
db.flush()
|
||
print(f"[2.5] Created {len(milestones)} milestones")
|
||
|
||
# ══════════════════════════════════════════════════════════════
|
||
# 内容提交
|
||
# ══════════════════════════════════════════════════════════════
|
||
subs = []
|
||
|
||
def add(user, proj, phase, wt, ct, secs, d, desc, hours=None):
|
||
"""快捷添加提交"""
|
||
subs.append(Submission(
|
||
user_id=user.id, project_id=proj.id,
|
||
project_phase=phase, work_type=wt,
|
||
content_type=ct, total_seconds=secs,
|
||
duration_minutes=secs // 60 if secs else 0,
|
||
duration_seconds=secs % 60 if secs else 0,
|
||
hours_spent=hours, submit_to=SubmitTo.INTERNAL,
|
||
description=desc, submit_date=d,
|
||
))
|
||
|
||
PRE = PhaseGroup.PRE
|
||
PROD = PhaseGroup.PRODUCTION
|
||
POST = PhaseGroup.POST
|
||
PLAN = WorkType.PLAN
|
||
MFG = WorkType.PRODUCTION
|
||
TEST = WorkType.TEST
|
||
|
||
# ────────────────────────────────────────────
|
||
# 品牌方 TVC 宣传片 (target=180s, 创建 12/8)
|
||
# 前期: 12/8 - 12/18
|
||
# 制作: 12/22 - 1/10
|
||
# 后期: 1/27 - now
|
||
# ────────────────────────────────────────────
|
||
|
||
# 前期 - 策划案 (12/8-9)
|
||
add(huangrongying, proj_tvc, PRE, PLAN, ContentType.PLANNING, 0, date(2025, 12, 8), "TVC 策划案初稿", 4)
|
||
add(huangrongying, proj_tvc, PRE, PLAN, ContentType.PLANNING, 0, date(2025, 12, 9), "TVC 策划案定稿", 3)
|
||
|
||
# 前期 - 分镜 (12/10-15, 比预期多1天)
|
||
add(daixiaoqian, proj_tvc, PRE, PLAN, ContentType.STORYBOARD, 0, date(2025, 12, 10), "TVC 分镜初稿", 5)
|
||
add(daixiaoqian, proj_tvc, PRE, PLAN, ContentType.STORYBOARD, 0, date(2025, 12, 11), "TVC 分镜修改", 4)
|
||
add(daixiaoqian, proj_tvc, PRE, PLAN, ContentType.STORYBOARD, 0, date(2025, 12, 15), "TVC 分镜终稿", 3)
|
||
|
||
# 前期 - 人设图 (12/15-16)
|
||
add(huangxuewen, proj_tvc, PRE, PLAN, ContentType.CHARACTER_DESIGN, 0, date(2025, 12, 15), "TVC 人设图初稿", 5)
|
||
add(huangxuewen, proj_tvc, PRE, PLAN, ContentType.CHARACTER_DESIGN, 0, date(2025, 12, 16), "TVC 人设图定稿", 3)
|
||
|
||
# 前期 - 场景图 (12/17)
|
||
add(huangxuewen, proj_tvc, PRE, PLAN, ContentType.SCENE_DESIGN, 0, date(2025, 12, 17), "TVC 场景图", 4)
|
||
|
||
# 制作 - 马若情 (12/22 - 12/26 第一轮, 1/8-9 修改轮)
|
||
add(maruoqing, proj_tvc, PROD, TEST, ContentType.ANIMATION, 35, date(2025, 12, 22), "TVC 片段测试", 3)
|
||
add(maruoqing, proj_tvc, PROD, MFG, ContentType.ANIMATION, 70, date(2025, 12, 23), "TVC 第1集场景1", 4)
|
||
add(maruoqing, proj_tvc, PROD, MFG, ContentType.ANIMATION, 65, date(2025, 12, 24), "TVC 第1集场景2", 4)
|
||
add(maruoqing, proj_tvc, PROD, MFG, ContentType.ANIMATION, 75, date(2025, 12, 25), "TVC 第2集场景1", 4)
|
||
add(maruoqing, proj_tvc, PROD, MFG, ContentType.ANIMATION, 60, date(2025, 12, 26), "TVC 第2-3集", 4)
|
||
# 甲方反馈后修改
|
||
add(maruoqing, proj_tvc, PROD, MFG, ContentType.ANIMATION, 55, date(2026, 1, 8), "TVC 修改-第1集重做", 3)
|
||
add(maruoqing, proj_tvc, PROD, MFG, ContentType.ANIMATION, 50, date(2026, 1, 9), "TVC 修改-第3集调整", 3)
|
||
|
||
# 后期 - 修补镜头 (秒数,归入制作计算) 1/27-28
|
||
add(liushiqi, proj_tvc, POST, MFG, ContentType.SHOT_REPAIR, 25, date(2026, 1, 27), "TVC 修补镜头1", 1.5)
|
||
add(liushiqi, proj_tvc, POST, MFG, ContentType.SHOT_REPAIR, 30, date(2026, 1, 28), "TVC 修补镜头2", 1.5)
|
||
|
||
# 后期 - 配音 (1/27-29, 每天1集)
|
||
add(panziyan, proj_tvc, POST, MFG, ContentType.DUBBING, 0, date(2026, 1, 27), "TVC 第1集配音", 4)
|
||
add(panziyan, proj_tvc, POST, MFG, ContentType.DUBBING, 0, date(2026, 1, 28), "TVC 第2集配音", 4)
|
||
add(panziyan, proj_tvc, POST, MFG, ContentType.DUBBING, 0, date(2026, 1, 29), "TVC 第3集配音", 3)
|
||
|
||
# 后期 - 音效 (1/29-30)
|
||
add(panziyan, proj_tvc, POST, MFG, ContentType.SOUND_EFFECTS, 0, date(2026, 1, 29), "TVC 音效设计", 5)
|
||
add(panziyan, proj_tvc, POST, MFG, ContentType.SOUND_EFFECTS, 0, date(2026, 1, 30), "TVC 音效终混", 3)
|
||
|
||
# 后期 - 剪辑 (2/3-now, 多轮甲方反馈导致超期)
|
||
add(wangyansen, proj_tvc, POST, MFG, ContentType.EDITING, 0, date(2026, 2, 3), "TVC 第1-2集粗剪", 6)
|
||
add(wangyansen, proj_tvc, POST, MFG, ContentType.EDITING, 0, date(2026, 2, 4), "TVC 第3集粗剪+精剪", 5)
|
||
add(wangyansen, proj_tvc, POST, MFG, ContentType.EDITING, 0, date(2026, 2, 10), "TVC 甲方反馈后重剪", 5)
|
||
add(wangyansen, proj_tvc, POST, MFG, ContentType.EDITING, 0, date(2026, 2, 12), "TVC 第二轮反馈修改", 4)
|
||
|
||
# ────────────────────────────────────────────
|
||
# 星际漫游 第一季 (target=3900s, 创建 12/22)
|
||
# 前期: 12/22 - 1/13
|
||
# 制作: 1/14 - now
|
||
# ────────────────────────────────────────────
|
||
|
||
# 前期 - 策划案 (12/22-23)
|
||
add(huangrongying, proj_star, PRE, PLAN, ContentType.PLANNING, 0, date(2025, 12, 22), "星际漫游 世界观策划案", 4)
|
||
add(huangrongying, proj_star, PRE, PLAN, ContentType.PLANNING, 0, date(2025, 12, 23), "星际漫游 策划案终稿", 3)
|
||
|
||
# 前期 - 剧本 (12/24-30, 5个工作日)
|
||
for i, d in enumerate([date(2025, 12, 24), date(2025, 12, 25), date(2025, 12, 26),
|
||
date(2025, 12, 29), date(2025, 12, 30)]):
|
||
add(huangrongying, proj_star, PRE, PLAN, ContentType.SCRIPT, 0, d,
|
||
f"第{i*3+1}-{i*3+3}集剧本", 6)
|
||
|
||
# 前期 - 分镜 (12/31-1/7, 比预期多, 导致超期 → 16h waste)
|
||
for i, d in enumerate([date(2025, 12, 31), date(2026, 1, 2), date(2026, 1, 5),
|
||
date(2026, 1, 6), date(2026, 1, 7)]):
|
||
add(daixiaoqian, proj_star, PRE, PLAN, ContentType.STORYBOARD, 0, d,
|
||
f"第{i+1}批分镜({i*3+1}-{i*3+3}集)", 5)
|
||
|
||
# 前期 - 人设图 (1/8-9)
|
||
add(huangxuewen, proj_star, PRE, PLAN, ContentType.CHARACTER_DESIGN, 0, date(2026, 1, 8), "主要角色人设图", 5)
|
||
add(huangxuewen, proj_star, PRE, PLAN, ContentType.CHARACTER_DESIGN, 0, date(2026, 1, 9), "配角人设图", 4)
|
||
|
||
# 前期 - 场景图 (1/10-13)
|
||
add(huangxuewen, proj_star, PRE, PLAN, ContentType.SCENE_DESIGN, 0, date(2026, 1, 12), "太空站场景图", 5)
|
||
add(huangxuewen, proj_star, PRE, PLAN, ContentType.SCENE_DESIGN, 0, date(2026, 1, 13), "星球表面场景图", 4)
|
||
|
||
# 制作 - 1/14 起 (~22个工作日到今天)
|
||
# 3个动画师,不是每天都在这个项目上
|
||
# 陈保丹: 14次提交 (2测试 + 12制作)
|
||
star_anim_dates_chen = [
|
||
date(2026, 1, 14), date(2026, 1, 15), date(2026, 1, 16), date(2026, 1, 19),
|
||
date(2026, 1, 20), date(2026, 1, 22), date(2026, 1, 23), date(2026, 1, 26),
|
||
date(2026, 1, 28), date(2026, 1, 30), date(2026, 2, 3), date(2026, 2, 5),
|
||
date(2026, 2, 9), date(2026, 2, 11),
|
||
]
|
||
star_secs_chen = [70, 80, 85, 75, 90, 80, 95, 70, 85, 90, 80, 75, 85, 80]
|
||
for i, (d, s) in enumerate(zip(star_anim_dates_chen, star_secs_chen)):
|
||
wt = TEST if i < 2 else MFG
|
||
add(chenbaodan, proj_star, PROD, wt, ContentType.ANIMATION, s, d,
|
||
f"第{(i//2)+1}集 场景{(i%4)+1}{'(测试)' if wt == TEST else ''}", 3.5)
|
||
|
||
# 谭如平: 12次提交 (1测试 + 11制作)
|
||
star_anim_dates_tan = [
|
||
date(2026, 1, 15), date(2026, 1, 16), date(2026, 1, 19), date(2026, 1, 21),
|
||
date(2026, 1, 23), date(2026, 1, 27), date(2026, 1, 29), date(2026, 2, 2),
|
||
date(2026, 2, 4), date(2026, 2, 6), date(2026, 2, 10), date(2026, 2, 12),
|
||
]
|
||
star_secs_tan = [75, 70, 80, 65, 85, 70, 75, 80, 90, 70, 75, 85]
|
||
for i, (d, s) in enumerate(zip(star_anim_dates_tan, star_secs_tan)):
|
||
wt = TEST if i < 1 else MFG
|
||
add(tanruping, proj_star, PROD, wt, ContentType.ANIMATION, s, d,
|
||
f"第{(i//2)+3}集 镜头{(i%3)+1}{'(测试)' if wt == TEST else ''}", 3)
|
||
|
||
# 郑奕晴: 11次提交 (1测试 + 10制作)
|
||
star_anim_dates_zheng = [
|
||
date(2026, 1, 16), date(2026, 1, 20), date(2026, 1, 22), date(2026, 1, 26),
|
||
date(2026, 1, 28), date(2026, 2, 2), date(2026, 2, 4), date(2026, 2, 6),
|
||
date(2026, 2, 10), date(2026, 2, 12), date(2026, 2, 13),
|
||
]
|
||
star_secs_zheng = [85, 75, 90, 80, 85, 95, 70, 80, 75, 90, 85]
|
||
for i, (d, s) in enumerate(zip(star_anim_dates_zheng, star_secs_zheng)):
|
||
wt = TEST if i < 1 else MFG
|
||
add(zhengyiqing, proj_star, PROD, wt, ContentType.ANIMATION, s, d,
|
||
f"第{(i//2)+5}集 动画{(i%3)+1}{'(测试)' if wt == TEST else ''}", 3.5)
|
||
|
||
# ────────────────────────────────────────────
|
||
# AI 短剧原创 S1 (target=2880s, 创建 1/6)
|
||
# 前期: 1/6 - 1/22
|
||
# 制作: 1/23 - now
|
||
# ────────────────────────────────────────────
|
||
|
||
# 前期 - 策划案 (1/6-7)
|
||
add(huangrongying, proj_orig, PRE, PLAN, ContentType.PLANNING, 0, date(2026, 1, 6), "原创S1 世界观策划案", 4)
|
||
add(huangrongying, proj_orig, PRE, PLAN, ContentType.PLANNING, 0, date(2026, 1, 7), "原创S1 策划案终稿", 3)
|
||
|
||
# 前期 - 剧本 (1/8-14)
|
||
for i, d in enumerate([date(2026, 1, 8), date(2026, 1, 9), date(2026, 1, 12),
|
||
date(2026, 1, 13), date(2026, 1, 14)]):
|
||
add(huangrongying, proj_orig, PRE, PLAN, ContentType.SCRIPT, 0, d,
|
||
f"原创S1 第{i+1}集剧本", 6)
|
||
|
||
# 前期 - 分镜 (1/15-17)
|
||
for i, d in enumerate([date(2026, 1, 15), date(2026, 1, 16), date(2026, 1, 17)]):
|
||
add(daixiaoqian, proj_orig, PRE, PLAN, ContentType.STORYBOARD, 0, d,
|
||
f"原创S1 第{i*2+1}-{i*2+2}集分镜", 5)
|
||
|
||
# 前期 - 人设图 (1/20-21)
|
||
add(huangxuewen, proj_orig, PRE, PLAN, ContentType.CHARACTER_DESIGN, 0, date(2026, 1, 20), "原创S1 主角人设图", 5)
|
||
add(huangxuewen, proj_orig, PRE, PLAN, ContentType.CHARACTER_DESIGN, 0, date(2026, 1, 21), "原创S1 配角人设图", 4)
|
||
|
||
# 前期 - 场景图 (1/22)
|
||
add(huangxuewen, proj_orig, PRE, PLAN, ContentType.SCENE_DESIGN, 0, date(2026, 1, 22), "原创S1 场景图", 5)
|
||
|
||
# 制作 - 1/23 起 (~16个工作日到今天)
|
||
# 魏春丽: 6次, 黄秋霞: 5次, 李静: 4次
|
||
orig_dates_wei = [date(2026, 1, 23), date(2026, 1, 26), date(2026, 1, 29),
|
||
date(2026, 2, 3), date(2026, 2, 6), date(2026, 2, 10)]
|
||
orig_secs_wei = [80, 90, 75, 85, 95, 80]
|
||
for i, (d, s) in enumerate(zip(orig_dates_wei, orig_secs_wei)):
|
||
add(weichunli, proj_orig, PROD, MFG, ContentType.ANIMATION, s, d,
|
||
f"原创S1 第1集 片段{i+1}", 4)
|
||
|
||
orig_dates_huang = [date(2026, 1, 27), date(2026, 1, 30), date(2026, 2, 4),
|
||
date(2026, 2, 9), date(2026, 2, 12)]
|
||
orig_secs_huang = [70, 80, 65, 75, 85]
|
||
for i, (d, s) in enumerate(zip(orig_dates_huang, orig_secs_huang)):
|
||
add(huangqiuxia, proj_orig, PROD, MFG, ContentType.ANIMATION, s, d,
|
||
f"原创S1 第2集 动画{i+1}", 3.5)
|
||
|
||
orig_dates_li = [date(2026, 2, 3), date(2026, 2, 5), date(2026, 2, 10), date(2026, 2, 13)]
|
||
orig_secs_li = [75, 70, 80, 65]
|
||
for i, (d, s) in enumerate(zip(orig_dates_li, orig_secs_li)):
|
||
add(lijing, proj_orig, PROD, MFG, ContentType.ANIMATION, s, d,
|
||
f"原创S1 第3集 片段{i+1}", 3.5)
|
||
|
||
# ────────────────────────────────────────────
|
||
# 原创 S1 风格测试 (target=60s, 创建 1/2)
|
||
# 前期: 1/2-7, 制作(全测试): 1/8-17
|
||
# ────────────────────────────────────────────
|
||
|
||
# 前期 - 策划案 (1/2-3)
|
||
add(huangrongying, proj_orig_test, PRE, PLAN, ContentType.PLANNING, 0, date(2026, 1, 2), "原创风格测试 策划案", 3)
|
||
add(huangrongying, proj_orig_test, PRE, PLAN, ContentType.PLANNING, 0, date(2026, 1, 3), "原创风格测试 策划终稿", 2)
|
||
|
||
# 前期 - 人设图 (1/6-7)
|
||
add(huangxuewen, proj_orig_test, PRE, PLAN, ContentType.CHARACTER_DESIGN, 0, date(2026, 1, 6), "风格测试 人设图初稿", 4)
|
||
add(huangxuewen, proj_orig_test, PRE, PLAN, ContentType.CHARACTER_DESIGN, 0, date(2026, 1, 7), "风格测试 人设图定稿", 3)
|
||
|
||
# 制作(测试) - 戴伟全部 TEST
|
||
test_dates = [date(2026, 1, 8), date(2026, 1, 9), date(2026, 1, 12),
|
||
date(2026, 1, 14), date(2026, 1, 16)]
|
||
test_secs = [12, 14, 10, 16, 18]
|
||
test_descs = ["角色动作测试", "场景氛围测试", "打光方案测试", "运镜方案A", "运镜方案B"]
|
||
for d, s, desc in zip(test_dates, test_secs, test_descs):
|
||
add(daiwei, proj_orig_test, PROD, TEST, ContentType.ANIMATION, s, d,
|
||
f"原创风格测试-{desc}", 2)
|
||
|
||
# ────────────────────────────────────────────
|
||
# 甲方风格测试 (target=60s, 创建 1/27)
|
||
# 前期: 1/27 - now (策划案仍未定稿,甲方反复修改)
|
||
# ────────────────────────────────────────────
|
||
|
||
# 前期 - 策划案 (1/27起,至今未完成)
|
||
add(huangrongying, proj_client_test, PRE, PLAN, ContentType.PLANNING, 0, date(2026, 1, 27), "甲方风格策划案 v1", 4)
|
||
add(huangrongying, proj_client_test, PRE, PLAN, ContentType.PLANNING, 0, date(2026, 1, 30), "甲方风格策划案 v2(反馈修改)", 3)
|
||
add(huangrongying, proj_client_test, PRE, PLAN, ContentType.PLANNING, 0, date(2026, 2, 5), "甲方风格策划案 v3(二次反馈)", 3)
|
||
add(huangrongying, proj_client_test, PRE, PLAN, ContentType.PLANNING, 0, date(2026, 2, 11), "甲方风格策划案 v4(三次反馈)", 3)
|
||
|
||
# 前期 - 人设图 (2/3-5, 边做边等策划案定稿)
|
||
add(huangxuewen, proj_client_test, PRE, PLAN, ContentType.CHARACTER_DESIGN, 0, date(2026, 2, 3), "甲方风格 人设图初稿", 5)
|
||
add(huangxuewen, proj_client_test, PRE, PLAN, ContentType.CHARACTER_DESIGN, 0, date(2026, 2, 5), "甲方风格 人设图修改", 4)
|
||
|
||
# 少量测试动画 (2/10-12, 用于给甲方展示方向)
|
||
add(daiwei, proj_client_test, PROD, TEST, ContentType.ANIMATION, 10, date(2026, 2, 10), "甲方风格测试片段1", 2)
|
||
add(daiwei, proj_client_test, PROD, TEST, ContentType.ANIMATION, 14, date(2026, 2, 12), "甲方风格测试片段2", 2)
|
||
|
||
db.add_all(subs)
|
||
print(f"[3] Created {len(subs)} submissions")
|
||
|
||
# ══════════════════════════════════════════════════════════════
|
||
# 成本数据
|
||
# ══════════════════════════════════════════════════════════════
|
||
|
||
# AI 工具成本
|
||
db.add(AIToolCost(
|
||
tool_name="Midjourney", subscription_period=SubscriptionPeriod.MONTHLY,
|
||
amount=200, allocation_type=CostAllocationType.TEAM,
|
||
recorded_by=qiushaohui.id, record_date=today.replace(day=1),
|
||
))
|
||
db.add(AIToolCost(
|
||
tool_name="Runway", subscription_period=SubscriptionPeriod.MONTHLY,
|
||
amount=600, allocation_type=CostAllocationType.PROJECT,
|
||
project_id=proj_star.id,
|
||
recorded_by=qiushaohui.id, record_date=today.replace(day=1),
|
||
))
|
||
db.add(AIToolCost(
|
||
tool_name="ChatGPT Plus", subscription_period=SubscriptionPeriod.MONTHLY,
|
||
amount=150, allocation_type=CostAllocationType.TEAM,
|
||
recorded_by=qiushaohui.id, record_date=today.replace(day=1),
|
||
))
|
||
print("[4] Created 3 AI tool costs")
|
||
|
||
# 外包成本
|
||
db.add(OutsourceCost(
|
||
project_id=proj_star.id, outsource_type=OutsourceType.ANIMATION,
|
||
episode_start=10, episode_end=13, amount=20000,
|
||
recorded_by=qiushaohui.id, record_date=today - timedelta(days=5),
|
||
))
|
||
print("[5] Created 1 outsource cost")
|
||
|
||
# 固定开支
|
||
db.add(OverheadCost(
|
||
cost_type=OverheadCostType.OFFICE_RENT,
|
||
amount=8000, record_month=today.strftime("%Y-%m"),
|
||
recorded_by=qiushaohui.id, note="办公室月租",
|
||
))
|
||
db.add(OverheadCost(
|
||
cost_type=OverheadCostType.UTILITIES,
|
||
amount=500, record_month=today.strftime("%Y-%m"),
|
||
recorded_by=qiushaohui.id, note="水电费",
|
||
))
|
||
print("[6] Created 2 overhead costs")
|
||
|
||
db.commit()
|
||
|
||
# ── 打印统计摘要 ──
|
||
print(f"\n{'='*55}")
|
||
print("[DONE] Demo data seeded successfully!")
|
||
print(f" Projects: 5 | Milestones: {len(milestones)}")
|
||
print(f" Submissions: {len(subs)}")
|
||
print(f" AI tools: 3 | Outsource: 1 | Overhead: 2")
|
||
print(f"\n 预期展示效果:")
|
||
print(f" · 品牌方 TVC 进度>200% → 蓝红双色进度条")
|
||
print(f" · 星际漫游/TVC/甲方测试有超期里程碑 → 工时损耗")
|
||
print(f" · 原创风格测试全测试 → 高 waste_rate")
|
||
print(f" · 5个项目覆盖4种类型, created_at设为过去日期")
|
||
print(f" · 前期结束后才有制作提交")
|
||
print(f" · owners/制片无提交")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
seed_demo()
|