from pathlib import Path

from openpyxl import Workbook, load_workbook
from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
from openpyxl.utils import get_column_letter


ROOT = Path(__file__).resolve().parent
OUTPUT_DIR = ROOT / "output"
OUTPUT_FILE = OUTPUT_DIR / "智慧食堂产品经理岗位说明书与月度绩效考核_V1.0_20260903.xlsx"


TITLE_FILL = PatternFill("solid", fgColor="E97132")
HEADER_FILL = PatternFill("solid", fgColor="FBE2D5")
SECTION_FILL = PatternFill("solid", fgColor="FFF2CC")
LIGHT_FILL = PatternFill("solid", fgColor="F7F7F7")
WHITE_FILL = PatternFill("solid", fgColor="FFFFFF")
THIN = Side(style="thin", color="D9D9D9")
BORDER = Border(left=THIN, right=THIN, top=THIN, bottom=THIN)


def style_ws(ws, widths):
    ws.freeze_panes = "A2"
    for row in ws.iter_rows():
        for cell in row:
            cell.font = Font(name="微软雅黑", size=12, color="222222")
            cell.alignment = Alignment(vertical="center", wrap_text=True)
            cell.border = BORDER
            if cell.row == 1:
                cell.fill = TITLE_FILL
                cell.font = Font(name="微软雅黑", size=12, bold=True, color="FFFFFF")
                cell.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
            elif cell.row == 2:
                cell.fill = HEADER_FILL
                cell.font = Font(name="微软雅黑", size=12, bold=True, color="222222")
                cell.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
            else:
                cell.fill = WHITE_FILL if cell.row % 2 else LIGHT_FILL
    for idx, width in enumerate(widths, start=1):
        ws.column_dimensions[get_column_letter(idx)].width = width
    for row in range(1, ws.max_row + 1):
        ws.row_dimensions[row].height = 34
    ws.row_dimensions[1].height = 40
    ws.auto_filter.ref = ws.dimensions


def add_title(ws, title, headers):
    ws.append([title] + [""] * (len(headers) - 1))
    ws.merge_cells(start_row=1, start_column=1, end_row=1, end_column=len(headers))
    ws.append(headers)


def build():
    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
    wb = Workbook()
    wb.remove(wb.active)

    ws = wb.create_sheet("岗位说明书")
    headers = ["模块", "内容", "执行要求", "证据/交付物"]
    add_title(ws, "智慧食堂产品经理岗位说明书 V1.0", headers)
    rows = [
        ["岗位名称", "智慧食堂产品经理", "统一负责智慧食堂产品边界、需求偏差、定制周期和标准化回流。", "岗位说明书"],
        ["岗位定位", "售前偏差评估和产品标准化负责人", "不是售前产品讲解岗，也不是演示脚本产出岗；销售材料由销售/市场/解决方案材料体系承担，产品经理负责判断能否响应。", "偏差分析表、周期评估表、评审结论"],
        ["核心目标", "把客户和招投标需求转成清晰的产品边界、偏差结论和研发交付判断", "每个重点售前项目必须回答：标准覆盖多少、配置覆盖多少、定制多少、无法响应多少、定制要多久。", "标准支持率、配置支持率、定制开发率、无法响应率"],
        ["职责1：客户访谈", "完成客户访谈和需求澄清", "问清客户场景、使用角色、现有系统、业务流程、设备环境、数据接口、验收要求、采购约束和时间要求。", "客户访谈纪要、需求确认清单"],
        ["职责2：招投标拆解", "逐条拆解招标文件或客户需求", "按功能、硬件、接口、部署、服务、验收、资质等维度拆解，不用笼统判断代替逐条分析。", "要求响应矩阵、需求拆解表"],
        ["职责3：偏差判断", "判断标准支持、配置支持、接口适配、定制开发、无法响应", "必须标注依据、风险、缺资料项和需评审项；不能把未验证能力写成标准能力。", "偏差分析表、风险清单"],
        ["职责4：定制周期评估", "输出定制化开发周期建议", "按前端、后端、接口、硬件、测试、部署、联调拆分周期，并经研发、测试、交付确认。", "定制周期评估表、评审记录"],
        ["职责5：内部评审", "组织产品、研发、测试、交付、商务共同确认", "重点确认能否响应、是否承接、周期是否可信、成本与交付风险是否可控。", "评审纪要、决策记录"],
        ["职责6：标准化回流", "把高频定制项沉淀为标准产品能力", "将项目需求回流成标准功能、配置项、接口模板、验收清单、FAQ或明确拒绝项。", "标准化改进清单、产品路线图"],
        ["权限边界", "不能单方对外承诺价格、交期、接口、资质、功能和效果", "未经研发、测试、交付、商务确认的内容不能进入对外承诺。", "审批记录、评审结论"],
        ["任职要求", "懂客户场景、懂产品边界、懂研发交付成本、懂招投标偏差判断", "能用证据说话，能拆需求，能做取舍，能推动跨部门评审。", "月度绩效考核表"],
    ]
    for row in rows:
        ws.append(row)
    style_ws(ws, [22, 34, 62, 34])

    ws = wb.create_sheet("工作任务")
    headers = ["周期", "任务编号", "具体工作任务", "完成标准", "证据/输出"]
    add_title(ws, "智慧食堂产品经理每日/每周/每月工作任务", headers)
    rows = [
        ["每日", "D-01", "查看当天新增客户需求、招标文件、售前问题、项目反馈和研发阻塞。", "所有新增事项有状态：待访谈、待拆解、待评审、已结论、阻塞。", "需求池更新记录"],
        ["每日", "D-02", "完成客户访谈或访谈准备。", "访谈必须覆盖场景、流程、角色、系统、接口、设备、验收、时间和采购约束。", "访谈提纲/纪要"],
        ["每日", "D-03", "更新需求拆解和偏差分类。", "每条需求标注标准支持、配置支持、接口适配、定制开发、无法响应或缺资料。", "需求拆解表"],
        ["每日", "D-04", "回复销售、交付、研发的产品边界问题。", "只给边界和判断依据，不输出未经评审的对外交期和承诺。", "问题答复记录"],
        ["每日", "D-05", "跟进定制需求评估。", "推动研发、测试、交付补齐周期、风险和前置条件。", "周期评估进展"],
        ["每日", "D-06", "记录当天结论和待确认项。", "当天形成一句话结论：标准化推进什么、卡在哪里、明天闭什么。", "日报/工作记录"],
        ["每周", "W-01", "组织重点售前项目需求偏差评审。", "本周重点项目完成偏差结论或明确阻塞原因。", "评审纪要"],
        ["每周", "W-02", "输出招投标/客户需求偏差分析表。", "至少覆盖重点项目的逐条需求、响应分类、风险和补证动作。", "偏差分析表"],
        ["每周", "W-03", "汇总本周共性定制需求。", "判断是否转为标准功能、配置项、接口模板、延后或拒绝。", "标准化候选清单"],
        ["每周", "W-04", "与研发确认定制开发周期。", "按前端、后端、接口、硬件、测试、部署、联调拆分并确认。", "周期确认表"],
        ["每周", "W-05", "与交付确认现场条件和验收风险。", "明确部署环境、接口责任、设备条件、客户配合项和验收风险。", "交付风险清单"],
        ["每周", "W-06", "输出售前判断周结论。", "说明哪些项目可标准响应、哪些偏差大、哪些不建议承接。", "周报"],
        ["每月", "M-01", "复盘本月售前/招投标项目偏差情况。", "形成标准支持率、配置支持率、定制开发率、无法响应率。", "月度偏差分析"],
        ["每月", "M-02", "梳理高频定制需求。", "形成下月产品路线图建议或标准化改进清单。", "产品路线图建议"],
        ["每月", "M-03", "复盘定制周期评估准确性。", "对比预估周期与实际周期，说明偏差原因和改进口径。", "周期复盘表"],
        ["每月", "M-04", "输出产品标准化改进清单。", "明确哪些能力下月必须标准化，哪些继续保持项目定制或拒绝。", "标准化改进清单"],
        ["每月", "M-05", "输出月度产品经理绩效自评。", "按100分考核表填写完成情况、证据路径、问题复盘和下月改进。", "绩效自评表"],
    ]
    for row in rows:
        ws.append(row)
    style_ws(ws, [12, 12, 50, 54, 30])

    ws = wb.create_sheet("月度绩效考核")
    headers = ["考核项", "权重", "月度目标", "评分规则", "证据要求"]
    add_title(ws, "智慧食堂产品经理月度绩效考核指标（100分）", headers)
    rows = [
        ["客户访谈质量", 20, "每月至少完成4个有效客户/售前访谈。", "访谈覆盖客户场景、角色、流程、现有系统、接口、设备、验收、时间和采购约束得满分；缺关键字段按项扣分。", "访谈纪要、需求确认清单"],
        ["招投标需求拆解", 20, "重点售前/招投标项目100%形成逐条需求拆解表。", "逐条拆解、分类清晰、有证据路径得满分；笼统判断、漏拆、无依据扣分。", "要求响应矩阵、需求拆解表"],
        ["偏差结论准确性", 20, "每个重点项目输出偏差比例和风险结论。", "必须包含标准支持率、配置支持率、定制开发率、无法响应率；结论能支撑是否承接和报价边界得满分。", "偏差分析表、风险清单"],
        ["定制周期评估", 15, "所有定制项给出研发、测试、联调周期建议。", "按前端、后端、接口、硬件、测试、部署、联调拆分，并经研发/测试/交付确认得满分；产品单方估算不得满分。", "定制周期评估表、跨部门确认记录"],
        ["产品标准化回流", 15, "每月至少沉淀3项标准化改进。", "高频定制项转为标准功能、配置项、接口模板、验收清单、FAQ或拒绝项得分；只记录问题不计为沉淀。", "标准化改进清单、路线图或模板"],
        ["跨部门评审闭环", 10, "重点偏差项目完成产品、研发、测试、交付、商务评审。", "评审有结论、有责任人、有下一步、有风险处理方式得满分；只有口头沟通扣分。", "评审纪要、决策记录"],
        ["合计", 100, "月度满分100分。", "建议90分以上优秀，80-89分合格，70-79分需改进，70分以下不达标。", "月度绩效汇总"],
    ]
    for row in rows:
        ws.append(row)
    style_ws(ws, [24, 10, 42, 66, 34])

    ws = wb.create_sheet("扣分否决规则")
    headers = ["类型", "规则", "处理方式", "说明"]
    add_title(ws, "扣分、否决与偏差率计算规则", headers)
    rows = [
        ["一票否决", "未完成客户访谈就给出定制开发周期。", "当月绩效最高不超过60分。", "没有访谈证据，周期判断不可用于销售或投标。"],
        ["一票否决", "未逐条拆解招标需求就判断可以响应。", "当月绩效最高不超过60分。", "不能用总体印象替代要求响应矩阵。"],
        ["重大扣分", "未经研发、测试、交付确认，直接对外承诺开发周期。", "当月绩效最高不超过70分。", "周期必须是跨部门确认结果。"],
        ["重大扣分", "把定制开发、规划能力或未验证能力写成标准功能。", "当月绩效最高不超过70分。", "会直接造成销售误承诺和交付风险。"],
        ["重大扣分", "隐瞒无法响应项或重大偏差。", "当月绩效最高不超过60分。", "偏差结论必须真实，不以赢单为唯一目标。"],
        ["扣分项", "需求池、偏差表、评审纪要或证据路径缺失。", "按缺失项扣2-5分。", "没有证据的完成不计入绩效。"],
        ["扣分项", "月报只写推进中、沟通中、已完成，没有偏差比例和下月动作。", "月度汇报相关分不得满分。", "产品经理月报必须结论先行。"],
        ["计算口径", "标准支持率 = 标准已支持条目 / 总需求条目。", "用于偏差结论。", "标准已支持必须能回指当前产品能力。"],
        ["计算口径", "配置支持率 = 配置可支持条目 / 总需求条目。", "用于偏差结论。", "配置支持不能包含代码开发。"],
        ["计算口径", "定制开发率 = 需定制开发条目 / 总需求条目。", "用于周期和报价边界。", "定制项必须拆周期和风险。"],
        ["计算口径", "无法响应率 = 暂不支持或无法响应条目 / 总需求条目。", "用于承接建议。", "无法响应项必须在评审中明确。"],
    ]
    for row in rows:
        ws.append(row)
    style_ws(ws, [16, 52, 32, 48])

    wb.save(OUTPUT_FILE)

    # Re-open to validate the generated workbook is readable.
    check = load_workbook(OUTPUT_FILE, data_only=True)
    expected = {"岗位说明书", "工作任务", "月度绩效考核", "扣分否决规则"}
    actual = set(check.sheetnames)
    missing = expected - actual
    if missing:
        raise SystemExit(f"missing sheets: {sorted(missing)}")
    for sheet in expected:
        if check[sheet].max_row < 3:
            raise SystemExit(f"sheet has too few rows: {sheet}")
    print(OUTPUT_FILE)


if __name__ == "__main__":
    build()
