Files
wecom-fullstack 0a6525edab
ci/woodpecker/push/main Pipeline was successful
feat(strategy): P0 战略基座 — strategy_charter + GET/PUT /api/cma/charter + P组入口
- 表 strategy_charter(一账套一行,entity_id 唯一):mission/vision/vision_year/vision_measurable/values_text/value_items(JSON) 全 NOT NULL
- 迁移脚本 backend/scripts/migrate_strategy_charter_20261021.py:--check/--apply/--down(回滚先 mysqldump,有数据需 --force),零 INSERT
- API:GET 无行 → filled=false 空态(禁示例数据);PUT 字段白名单 + 账套隔离三道 + vision_year 4位年份 + value_items [{name,meaning}] 结构校验
- 前端:P 组「战略章程」入口 + MyDialog 编辑(ceo/finance 可写,其余只读);战略地图页顶部只读章程条
- 用例 43 条 + auth-surface 58 条 = 101 passed;vite build rc=0
2026-10-21 18:54:09 +08:00

65 lines
3.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""战略基座 — 战略章程(使命 / 愿景 / 价值观)
任务:`project-20261021-cma-strategy-charter-p0-fullstack`(P0 战略基座)
依据:《2026-10-21 CMA 知识库 M0 与系统实现差距报告》§四 P0 —— 知识卡
`CMA-P1-B-009 愿景、使命与价值观`:使命=为何存在;愿景=要成为什么
(**带年份与可验证状态**);价值观=不可交易的底线,是决策冲突时的裁决依据。
单一事实源:每个账套(entity_id)**一条**章程行,唯一键 uq_strategy_charter_entity。
本模块只做「表结构 + 契约常量」;读写端点见 app/api/charter.py。
字段语义(派单表:语义不可减,类型可调整):
mission 使命 TEXT NOT NULL
vision 愿景 TEXT NOT NULL
vision_year 愿景达成年份 VARCHAR(20) NOT NULL(**不可空**;4 位年份)
vision_measurable 可验证状态 TEXT NOT NULL(**不可空**;用可核对的规模/业务口径描述)
values_text 价值观总述 TEXT NOT NULL
value_items 价值观条目 JSON NOT NULL `[{name, meaning}]`
—— 每条须能作"决策冲突时的裁决依据"
隔离:`entity_id NOT NULL` + 唯一键以 entity_id 打头(多租户隔离 + 索引可用性)。
禁止示例数据:本模块与迁移脚本**零 INSERT**;GET 无行返回 `filled=false` 空态。
"""
from sqlalchemy import Column, Integer, String, Text, JSON, DateTime, UniqueConstraint, func
from app.database import Base
# 愿景年度格式:4 位年份(不臆造业务上限;允许字符串以兼容前端输入)
VISION_YEAR_RE = r"^\d{4}$"
# 长文本上限(与列宽一致,避免 MySQL 截断静默丢字)
MISSION_MAX_LEN = 1000
VISION_MAX_LEN = 1000
VISION_MEASURABLE_MAX_LEN = 1000
VALUES_TEXT_MAX_LEN = 2000
VALUE_ITEM_NAME_MAX_LEN = 50
VALUE_ITEM_MEANING_MAX_LEN = 300
VALUE_ITEMS_MAX = 20
class StrategyCharter(Base):
"""战略章程 — 使命/愿景(年度+可验证状态)/价值观(每账套一行)"""
__tablename__ = "strategy_charter"
id = Column(Integer, primary_key=True)
entity_id = Column(Integer, nullable=False, comment="企业ID(账套,多租户隔离;唯一键已建索引)")
mission = Column(Text, nullable=False, comment="使命:我们为何存在(做什么、为谁做)")
vision = Column(Text, nullable=False, comment="愿景:要成为什么")
vision_year = Column(String(20), nullable=False, comment="愿景达成年份 YYYY(不可空)")
vision_measurable = Column(
Text, nullable=False,
comment="可验证状态:用可核对的规模/业务口径描述(不可空)",
)
values_text = Column(Text, nullable=False, comment="价值观总述(不可交易的底线)")
value_items = Column(
JSON, nullable=False,
comment="价值观条目数组 [{name, meaning}],每条可作决策冲突时的裁决依据",
)
updated_by = Column(Integer, nullable=True, comment="最后修改人 user.id")
updated_by_name = Column(String(50), nullable=True, comment="最后修改人姓名(快照)")
created_at = Column(DateTime, server_default=func.now())
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
__table_args__ = (
UniqueConstraint("entity_id", name="uq_strategy_charter_entity"),
)