chore: commit pending local changes (2026-09-17 github sync)
This commit is contained in:
parent
beca611f29
commit
6ef74388c1
@ -40,14 +40,18 @@ HT_DELIVERY_CONFIRM = "bid_delivery_confirm"
|
|||||||
HT_FLOW_CONFIRM = "flow_plan_confirm" # 流程裁剪确认(引擎通用类型,pipeline_flow_plans 机制)
|
HT_FLOW_CONFIRM = "flow_plan_confirm" # 流程裁剪确认(引擎通用类型,pipeline_flow_plans 机制)
|
||||||
HT_TEMPLATE_CONFIRM = "tech_template_confirm" # 技术方案模版/骨架确认(纯技术方案流程,2026-09-14 批2)
|
HT_TEMPLATE_CONFIRM = "tech_template_confirm" # 技术方案模版/骨架确认(纯技术方案流程,2026-09-14 批2)
|
||||||
|
|
||||||
BLOCKING_HT_TYPES = (HT_TENDER_FILE, HT_FLOW_CONFIRM, HT_TEMPLATE_CONFIRM)
|
BLOCKING_HT_TYPES = (HT_TENDER_FILE, HT_FLOW_CONFIRM)
|
||||||
# 2026-09-03 起只保留「等招标文件」为全局阻塞:
|
# 2026-09-03 起只保留「等招标文件」为全局阻塞:
|
||||||
# - HT_HUMAN_DOCS(等人类资质文件)降级为章节级依赖——只阻塞商务章(等资料准备),技术/报价章不受影响;
|
# - HT_HUMAN_DOCS(等人类资质文件)降级为章节级依赖——只阻塞商务章(等资料准备),技术/报价章不受影响;
|
||||||
# - HT_QC_ESCALATION(QC 轮次用尽)降级为章节级依赖——只阻塞依赖该产出类型的章节,其余章节照常流转。
|
# - HT_QC_ESCALATION(QC 轮次用尽)降级为章节级依赖——只阻塞依赖该产出类型的章节,其余章节照常流转。
|
||||||
# 2026-09-11 增 HT_FLOW_CONFIRM:裁剪计划待用户确认期间全局阻塞(确认后才按计划派发,
|
# 2026-09-11 增 HT_FLOW_CONFIRM:裁剪计划待用户确认期间全局阻塞(确认后才按计划派发,
|
||||||
# 防「用户在确认、对账器按旧流程抢跑」)。驳回后的暂停由 bid_flow 查 pipeline_flow_plans 状态兜住。
|
# 防「用户在确认、对账器按旧流程抢跑」)。驳回后的暂停由 bid_flow 查 pipeline_flow_plans 状态兜住。
|
||||||
# 2026-09-14 增 HT_TEMPLATE_CONFIRM:技术方案模版骨架待用户确认期间全局阻塞(用户明确要
|
# 2026-09-17 阻塞语义分流:HT_TEMPLATE_CONFIRM 移出全局阻塞——
|
||||||
# 「模版由用户确认后」才开写章节——骨架没确认就编写 = 方向错了全白写)。
|
# - 纯技术方案流程:骨架确认卡的是全流程,但 T3 段本就显式 waiting(确认前不派任何任务),
|
||||||
|
# 全局阻塞是重复保险,移除后行为不变;
|
||||||
|
# - 标准投标流程(模版裁剪链挂入后):裁剪确认只关技术章的事,商务/报价章与其他维度
|
||||||
|
# 照常流转——若全局阻塞,用户晚确认一天模版,整个标书停摆(过度阻塞)。
|
||||||
|
# 技术章的门禁在 C 段按章节卡(tech_tpl_confirmed 才派技术章编写)。
|
||||||
|
|
||||||
# ── QC 契合度审核类型(解析产出逐类审核)──
|
# ── QC 契合度审核类型(解析产出逐类审核)──
|
||||||
QC_TYPE_SCORING = "scoring_items" # 评分项 + 得分规则
|
QC_TYPE_SCORING = "scoring_items" # 评分项 + 得分规则
|
||||||
|
|||||||
@ -142,6 +142,54 @@ def _clean_md_cell(text):
|
|||||||
return t.strip()
|
return t.strip()
|
||||||
|
|
||||||
|
|
||||||
|
# ── 内联 markdown → Word run(2026-09-17 用户报障:**粗体** 原样带星号落 docx)──
|
||||||
|
_MD_BOLD_RE = re.compile(r'\*\*([^*]+)\*\*')
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_inline_code(s):
|
||||||
|
"""去掉行内代码反引号(docx 无等宽语义,保留文字)。"""
|
||||||
|
return re.sub(r'`([^`]*)`', r'\1', s or '')
|
||||||
|
|
||||||
|
|
||||||
|
def _add_runs_with_inline_md(para, text):
|
||||||
|
"""把一段文本按内联 markdown 拆成 runs 写进段落:**粗体**→加粗 run,
|
||||||
|
`code`→去反引号,制表符→空格,其余原样。无标记时等价 add_paragraph(text)。"""
|
||||||
|
t = (text or '').replace('\t', ' ')
|
||||||
|
pos = 0
|
||||||
|
for m in _MD_BOLD_RE.finditer(t):
|
||||||
|
if m.start() > pos:
|
||||||
|
para.add_run(_strip_inline_code(t[pos:m.start()]))
|
||||||
|
r = para.add_run(_strip_inline_code(m.group(1)))
|
||||||
|
r.bold = True
|
||||||
|
pos = m.end()
|
||||||
|
if pos < len(t):
|
||||||
|
para.add_run(_strip_inline_code(t[pos:]))
|
||||||
|
if not t:
|
||||||
|
para.add_run('')
|
||||||
|
|
||||||
|
|
||||||
|
# 项目符号(半角 - * 必须跟空白;全角 •/·/●/◦/- 可不跟空白,用户实测 "•\t**xx**")
|
||||||
|
_MD_BULLET_RE = re.compile(r'^\s*(?:[-*]\s+|(?:[•·●◦]|-)\s*)(?=\S)')
|
||||||
|
# 小节号标题:"1.3 xxx" / "2.1.3 xxx"(点分编号开头)
|
||||||
|
_MD_NUMHEAD_RE = re.compile(r'^\s*(\d+(?:\.\d+)+)[\s、.\.]*(\S.*)$')
|
||||||
|
|
||||||
|
|
||||||
|
def _numhead_heading(line):
|
||||||
|
"""识别小节号标题行,返回 (level, text) 或 None。
|
||||||
|
|
||||||
|
保守判定防误伤正文:编号后标题 ≤40 字且不含句号("1.3 倍冗余……" 这类
|
||||||
|
以小数开头的正文句子不当标题)。level = 点分段数(1.3→2,2.1.3→3),封顶 4。
|
||||||
|
"""
|
||||||
|
m = _MD_NUMHEAD_RE.match(line or '')
|
||||||
|
if not m:
|
||||||
|
return None
|
||||||
|
no, rest = m.group(1), m.group(2).strip()
|
||||||
|
if not rest or len(rest) > 40 or '。' in rest:
|
||||||
|
return None
|
||||||
|
level = min(4, no.count('.') + 1)
|
||||||
|
return level, "%s %s" % (no, rest)
|
||||||
|
|
||||||
|
|
||||||
def _write_docx(path, title, subtitle, chapters):
|
def _write_docx(path, title, subtitle, chapters):
|
||||||
"""用 python-docx 写标书。返回 (ok, page_hint_or_err)。
|
"""用 python-docx 写标书。返回 (ok, page_hint_or_err)。
|
||||||
|
|
||||||
@ -247,14 +295,20 @@ def _write_docx(path, title, subtitle, chapters):
|
|||||||
doc.add_paragraph("[配图缺失(下载失败):%s %s]" % (alt or "", url[:80]))
|
doc.add_paragraph("[配图缺失(下载失败):%s %s]" % (alt or "", url[:80]))
|
||||||
img_fail += 1
|
img_fail += 1
|
||||||
continue
|
continue
|
||||||
|
_nh = _numhead_heading(t)
|
||||||
if t.startswith("### "):
|
if t.startswith("### "):
|
||||||
doc.add_heading(t[4:], level=3)
|
doc.add_heading(_strip_inline_code(t[4:].replace('**', '')), level=3)
|
||||||
elif t.startswith("## "):
|
elif t.startswith("## "):
|
||||||
doc.add_heading(t[3:], level=2)
|
doc.add_heading(_strip_inline_code(t[3:].replace('**', '')), level=2)
|
||||||
elif t.startswith("# "):
|
elif t.startswith("# "):
|
||||||
doc.add_heading(t[2:], level=2)
|
doc.add_heading(_strip_inline_code(t[2:].replace('**', '')), level=2)
|
||||||
elif t.lstrip().startswith(("- ", "* ")):
|
elif _nh is not None:
|
||||||
doc.add_paragraph(t.lstrip()[2:], style="List Bullet")
|
# 小节号标题("1.3 xxx")→ 真 Word 标题层级(目录/导航可用)
|
||||||
|
doc.add_heading(_strip_inline_code(_nh[1].replace('**', '')), level=_nh[0])
|
||||||
|
elif _MD_BULLET_RE.match(t) and not t.lstrip().startswith('**'):
|
||||||
|
# 项目符号行(- * • · ● ◦ -,可跟制表符)→ List Bullet + 内联粗体
|
||||||
|
_bp = doc.add_paragraph(style="List Bullet")
|
||||||
|
_add_runs_with_inline_md(_bp, _MD_BULLET_RE.sub('', t))
|
||||||
elif _is_table_sep(t):
|
elif _is_table_sep(t):
|
||||||
continue # 游离分隔行(无表头)跳过
|
continue # 游离分隔行(无表头)跳过
|
||||||
elif t.strip().startswith('|') and t.strip().endswith('|'):
|
elif t.strip().startswith('|') and t.strip().endswith('|'):
|
||||||
@ -269,7 +323,9 @@ def _write_docx(path, title, subtitle, chapters):
|
|||||||
except Exception:
|
except Exception:
|
||||||
doc.add_paragraph(t)
|
doc.add_paragraph(t)
|
||||||
else:
|
else:
|
||||||
doc.add_paragraph(t)
|
# 普通段落/编号行:**粗体** 拆 run 加粗,`code` 去反引号,\t→空格
|
||||||
|
_pp = doc.add_paragraph()
|
||||||
|
_add_runs_with_inline_md(_pp, t)
|
||||||
doc.add_page_break()
|
doc.add_page_break()
|
||||||
doc.save(path)
|
doc.save(path)
|
||||||
if img_ok or img_fail or tbl_ok:
|
if img_ok or img_fail or tbl_ok:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user