package com.kaidi.oa.seed;
import com.kaidi.oa.common.Money;
import com.kaidi.oa.domain.MeetingActionItem;
import com.kaidi.oa.domain.MeetingMinute;
import com.kaidi.oa.domain.SupervisionProject;
import com.kaidi.oa.domain.SvIndepClaim;
import com.kaidi.oa.repository.MeetingActionItemRepository;
import com.kaidi.oa.repository.MeetingMinuteRepository;
import com.kaidi.oa.repository.SupervisionProjectRepository;
import com.kaidi.oa.repository.SvIndepClaimRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import java.time.Instant;
import java.util.List;
/**
* 工程监理部 · 缺口补完演示数据播种器。
*
*
补完两个 PARTIAL→MET 缺口:
*
* - 缺口 5(索赔独立状态机):播种 SvIndepClaim 多阶段演示数据,
* 覆盖 INTENT/INCIDENT/ASSESSMENT/OPINION/CLOSED/REJECTED 各阶段,
* 包含关键线路影响分析字段。
* - 缺口 7(监理例会纪要按项目过滤+待办任务结构化):
* 播种 MeetingMinute(含 supervisionProjectId)及配套 MeetingActionItem
* (含 assignee+dueDate,关联责任人)。
*
*
* @Order(210) 在 DataSeeder(@Order 1) 之后运行;幂等(SvIndepClaim.count>0 则跳过)。
*/
@Order(210)
@DemoSeed
public class SvSupervisionMinuteSeeder implements CommandLineRunner {
private final SvIndepClaimRepository claimRepo;
private final SupervisionProjectRepository projectRepo;
private final MeetingMinuteRepository minuteRepo;
private final MeetingActionItemRepository actionItemRepo;
public SvSupervisionMinuteSeeder(SvIndepClaimRepository claimRepo,
SupervisionProjectRepository projectRepo,
MeetingMinuteRepository minuteRepo,
MeetingActionItemRepository actionItemRepo) {
this.claimRepo = claimRepo;
this.projectRepo = projectRepo;
this.minuteRepo = minuteRepo;
this.actionItemRepo = actionItemRepo;
}
@Override
public void run(String... args) throws Exception {
seedIndepClaims();
seedSupervisionMinutes();
}
// ========================================================================
// 1. 索赔独立状态机演示数据
// ========================================================================
private void seedIndepClaims() {
if (claimRepo.count() > 0) return;
// 获取第一个监理项目做关联(如无则不关联)
List projects = projectRepo.findAll();
Long projectId1 = projects.isEmpty() ? null : projects.get(0).getId();
String projectCode1 = projects.isEmpty() ? "JL-2026-001" : projects.get(0).getCode();
Long projectId2 = projects.size() > 1 ? projects.get(1).getId() : projectId1;
String projectCode2 = projects.size() > 1 ? projects.get(1).getCode() : projectCode1;
Instant now = Instant.now();
// 索赔1:已完成四阶段,状态 CLOSED(赶工费用索赔,关键线路影响=5天,核定3天)
SvIndepClaim c1 = new SvIndepClaim();
c1.setSupervisionProjectId(projectId1);
c1.setSupervisionProjectCode(projectCode1);
c1.setClaimCode("SYC-1");
c1.setContractor("湖南城建建设有限公司");
c1.setIntentDate("2026-03-10");
c1.setIntentSummary("因设计变更导致基础换填工程量增加,施工方提出工期延误及费用增加索赔");
c1.setIncidentStartDate("2026-02-15");
c1.setIncidentEndDate("2026-03-08");
c1.setIncidentDetail("2月15日建设单位下达设计变更通知单,要求将原持力层由3米加深至5米,导致土方开挖量增加约1800m³,工期顺延。施工方已按新标准施工,3月8日完成隐蔽验收。");
c1.setEvidenceRef("变更通知单BG-2026-003,隐蔽验收记录HB-0308");
c1.setDurationImpactDays(8);
c1.setCriticalPathImpactDays(5);
c1.setCriticalPathImpact("该延误位于关键路径(基础→主体结构),关键线路延误5天,其余3天属非关键工序可平行赶工");
c1.setClaimAmount(Money.of(125000.00));
c1.setCostImpactDetail("增加土方开挖1800m³×35元/m³=63000元,换填级配碎石580m³×107元/m³=62060元,合计125060元,舍尾为125000元");
c1.setReviewer("张建国");
c1.setReviewConclusion("部分支持");
c1.setApprovedDurationDays(3);
c1.setApprovedAmount(Money.of(98000.00));
c1.setReviewOpinion("经复核,设计变更工程量属实,但部分换填单价偏高。核定费用补偿98000元,工期补偿3天(关键线路)。");
c1.setReviewDate("2026-03-20");
c1.setClaimStatus("CLOSED");
c1.setCreatedAt(now);
c1.setUpdatedAt(now);
claimRepo.save(c1);
// 索赔2:处于 ASSESSMENT 阶段(甲方原因停工索赔)
SvIndepClaim c2 = new SvIndepClaim();
c2.setSupervisionProjectId(projectId1);
c2.setSupervisionProjectCode(projectCode1);
c2.setClaimCode("SYC-2");
c2.setContractor("湖南城建建设有限公司");
c2.setIntentDate("2026-04-18");
c2.setIntentSummary("因建设单位资金周转问题导致工程暂停施工16天,施工方提出窝工费用及固定设施费索赔");
c2.setIncidentStartDate("2026-04-01");
c2.setIncidentEndDate("2026-04-17");
c2.setIncidentDetail("建设单位4月1日口头通知暂停施工,4月17日恢复。停工期间共有工人42人待命,塔吊2台、混凝土泵1台未能正常作业,产生窝工损失及机械停滞费用。");
c2.setEvidenceRef("停工令(口头转书面)BT-2026-001,考勤记录2026-04-01至04-17");
c2.setDurationImpactDays(16);
c2.setCriticalPathImpactDays(16);
c2.setCriticalPathImpact("停工期间为主体结构关键施工阶段,全部16天均影响关键线路,计划竣工日期相应顺延16天");
c2.setClaimAmount(Money.of(287500.00));
c2.setCostImpactDetail("工人窝工42人×16天×60元/工日=40320元,塔吊停滞2台×16天×2200元/台天=70400元,泵车停滞1台×16天×3500元/天=56000元,现场管理费=120780元,合计287500元");
c2.setClaimStatus("ASSESSMENT");
c2.setCreatedAt(now);
c2.setUpdatedAt(now);
claimRepo.save(c2);
// 索赔3:处于 INCIDENT 阶段(不可抗力索赔)
SvIndepClaim c3 = new SvIndepClaim();
c3.setSupervisionProjectId(projectId2);
c3.setSupervisionProjectCode(projectCode2);
c3.setClaimCode("SYC-3");
c3.setContractor("中建八局第二建设有限公司");
c3.setIntentDate("2026-05-05");
c3.setIntentSummary("因持续暴雨(超50年一遇)导致施工区域积水,基坑边坡出现局部滑塌,申请工期顺延及处置费用");
c3.setIncidentStartDate("2026-04-28");
c3.setIncidentEndDate("2026-05-03");
c3.setIncidentDetail("4月28日至5月3日连续6天强降雨,日均降水量超过80mm,累计降水量512mm,超过50年一遇设计标准。基坑东侧边坡出现约15m范围局部滑塌,需紧急处置后方可继续施工。");
c3.setEvidenceRef("气象局降雨记录证明,现场影像资料IMG-2026-0428至0503,应急处置方案EP-2026-001");
c3.setClaimStatus("INCIDENT");
c3.setCreatedAt(now);
c3.setUpdatedAt(now);
claimRepo.save(c3);
// 索赔4:处于 INTENT 阶段(材料涨价索赔)
SvIndepClaim c4 = new SvIndepClaim();
c4.setSupervisionProjectId(projectId2);
c4.setSupervisionProjectCode(projectCode2);
c4.setClaimCode("SYC-4");
c4.setContractor("中建八局第二建设有限公司");
c4.setIntentDate("2026-05-28");
c4.setIntentSummary("螺纹钢价格较签合同时上涨约18%,申请材料差价补偿");
c4.setClaimStatus("INTENT");
c4.setCreatedAt(now);
c4.setUpdatedAt(now);
claimRepo.save(c4);
// 索赔5:已驳回(无有效证据)
SvIndepClaim c5 = new SvIndepClaim();
c5.setSupervisionProjectId(projectId1);
c5.setSupervisionProjectCode(projectCode1);
c5.setClaimCode("SYC-5");
c5.setContractor("湖南城建建设有限公司");
c5.setIntentDate("2026-01-15");
c5.setIntentSummary("施工方申请因图纸延迟发放导致的窝工损失补偿");
c5.setIncidentStartDate("2026-01-08");
c5.setIncidentEndDate("2026-01-14");
c5.setIncidentDetail("施工方称图纸未及时到位导致7天停工,但经查实:图纸已于1月7日发放,停工系施工方自身组织问题。");
c5.setEvidenceRef("图纸签收记录20260107");
c5.setClaimStatus("REJECTED");
c5.setCreatedAt(now);
c5.setUpdatedAt(now);
claimRepo.save(c5);
}
// ========================================================================
// 2. 监理例会纪要(含 supervisionProjectId + 结构化待办任务)
// ========================================================================
private void seedSupervisionMinutes() {
// 只有纪要数<=2时才补种(DataSeeder可能已种1条)
if (minuteRepo.count() > 5) return;
List projects = projectRepo.findAll();
Long projectId1 = projects.isEmpty() ? null : projects.get(0).getId();
Long projectId2 = projects.size() > 1 ? projects.get(1).getId() : projectId1;
Instant now = Instant.now();
// 纪要1:靖州县污水处理厂第8次监理例会,有3条待办
MeetingMinute m1 = new MeetingMinute();
m1.setSupervisionProjectId(projectId1);
m1.setTitle("靖州县污水处理厂工程第8次监理例会纪要");
m1.setContent("会议时间:2026-04-07 09:00\n会议地点:项目部会议室\n\n" +
"【质量情况】本周完成生化池底板混凝土浇筑,坍落度、温度控制合格。" +
"但北侧剪力墙模板拼缝偏差超标(实测3-5mm,规范≤2mm),需整改。\n\n" +
"【进度情况】本周形象进度完成计划的95%,主体结构进度正常。\n\n" +
"【安全情况】发现1处高处作业未佩戴安全带,已现场整改。\n\n" +
"【计量支付】第5期进度款已提交监理审核,监理将于7日内出具支付证书。");
m1.setStatus("已发布");
m1.setDecisions("北侧剪力墙模板拼缝超标,施工方3天内完成整改并提交整改报告;\n" +
"高处作业安全带配戴问题,安全员每日专项巡查并记录;\n" +
"第5期进度款审核,监理4月10日前出具支付证书");
m1.setCreatedAt(now);
MeetingMinute savedM1 = minuteRepo.save(m1);
// 为纪要1生成3条待办任务(结构化,含assignee+dueDate)
actionItem(savedM1.getId(), savedM1.getTitle(),
"北侧剪力墙模板拼缝超标,完成整改并提交整改报告",
"李明(施工方质量负责人)", "2026-04-10", now);
actionItem(savedM1.getId(), savedM1.getTitle(),
"高处作业安全带配戴情况每日专项巡查记录",
"王安全(安全监理)", "2026-04-14", now);
actionItem(savedM1.getId(), savedM1.getTitle(),
"第5期进度款审核,出具支付证书",
"张建国(总监)", "2026-04-10", now);
// 纪要2:岳阳市排水管网第3次专题会议(安全专题)
MeetingMinute m2 = new MeetingMinute();
m2.setSupervisionProjectId(projectId2);
m2.setTitle("岳阳市排水管网改造工程雨季施工安全专题会议纪要");
m2.setContent("会议时间:2026-05-12 14:30\n会议地点:施工现场临时会议室\n\n" +
"【会议背景】气象部门预报5月下旬将迎来持续强降雨,为确保雨季施工安全,专门召开安全专题会。\n\n" +
"【主要风险】①基坑周边地表水渗流;②临时排水沟排水能力不足;③脚手架基础积水沉降风险。\n\n" +
"【应对措施】施工方需在5月20日前完成基坑周边截水沟加宽施工,增设3台潜水泵24小时备用," +
"对全部脚手架基础进行加固处理,并建立每日雨前雨后巡查机制。");
m2.setStatus("已发布");
m2.setDecisions("基坑周边截水沟加宽施工,5月20日前完工;\n" +
"增设潜水泵3台24小时备用,5月18日前就位;\n" +
"全部脚手架基础加固处理,5月22日前完成并复验");
m2.setCreatedAt(now);
MeetingMinute savedM2 = minuteRepo.save(m2);
// 为纪要2生成3条待办任务
actionItem(savedM2.getId(), savedM2.getTitle(),
"基坑周边截水沟加宽施工完工",
"赵强(施工方项目经理)", "2026-05-20", now);
actionItem(savedM2.getId(), savedM2.getTitle(),
"增设潜水泵3台就位并调试",
"赵强(施工方项目经理)", "2026-05-18", now);
actionItem(savedM2.getId(), savedM2.getTitle(),
"脚手架基础加固完成后监理复验",
"刘华(专业监理)", "2026-05-23", now);
// 纪要3:草稿状态(尚未发布)
MeetingMinute m3 = new MeetingMinute();
m3.setSupervisionProjectId(projectId1);
m3.setTitle("靖州县污水处理厂工程第9次监理例会纪要(草稿)");
m3.setContent("会议时间:2026-04-14 09:00\n会议地点:项目部会议室\n\n【待补充...】");
m3.setStatus("草稿");
m3.setCreatedAt(now);
minuteRepo.save(m3);
}
private void actionItem(Long minuteId, String minuteTitle, String content,
String assignee, String dueDate, Instant now) {
MeetingActionItem item = new MeetingActionItem();
item.setMinuteId(minuteId);
item.setMinuteTitle(minuteTitle);
item.setContent(content);
item.setAssignee(assignee);
item.setDueDate(dueDate);
item.setStatus("待办");
item.setCreatedAt(now);
item.setUpdatedAt(now);
actionItemRepo.save(item);
}
}