feat: expand module workflows, dynamic config, notifications and console API

This commit is contained in:
wangyunlong committed 2026-09-04 09:49:37 +08:00
1 parent 8df5266abb
commit b124d757b0
309 files changed
+89357 -6231

No files matched your search

+344 -10
View File
@@ -7,7 +7,7 @@
<meta name="theme-color" content="#f5f7fb">
<title>GYXX Flow · 工作流控制台</title>
<meta name="description" content="按业务模块查看、配置和运行 GYXX Flow 工作流。">
<link rel="stylesheet" href="/assets/app.css?v=workflow-lineage-20260803a">
<link rel="stylesheet" href="/assets/app.css?v=scheduler-control-v1-20260831">
</head>
<body>
<a class="skip-link" href="#main-content">跳到主要内容</a>
@@ -26,9 +26,12 @@
</div>
<div class="topbar__actions">
<div class="service-pill" id="service-pill" data-tone="neutral" role="status" aria-live="polite" title="正在读取调度服务状态">
<span class="service-pill__dot" aria-hidden="true"></span>
<span id="service-pill-label">正在连接</span>
<div class="scheduler-control">
<div class="service-pill" id="service-pill" data-tone="neutral" role="status" aria-live="polite" title="正在读取调度服务状态">
<span class="service-pill__dot" aria-hidden="true"></span>
<span id="service-pill-label">正在连接</span>
</div>
<button class="button button--secondary scheduler-start-button" id="scheduler-start-button" type="button" hidden>启动调度器</button>
</div>
<span class="timezone-chip" id="timezone-chip">Asia/Shanghai</span>
<span class="refresh-time" id="refresh-time">尚未刷新</span>
@@ -52,6 +55,29 @@
<span class="module-nav__count" id="all-module-count">…</span>
</button>
</nav>
<div class="sidebar-config sidebar-analysis">
<span class="sidebar-config__label">运行分析</span>
<button class="module-nav__item sidebar-config__item" id="daily-summary-nav-button" type="button" data-view="daily-summary" aria-controls="daily-summary-view">
<span class="module-nav__glyph sidebar-config__glyph" aria-hidden="true">报</span>
<span class="module-nav__copy"><strong>每日运行汇总</strong><small>逐工作流异常分析</small></span>
<span class="module-nav__count" id="daily-summary-abnormal-count">…</span>
</button>
</div>
<div class="sidebar-config">
<span class="sidebar-config__label">配置中心</span>
<button class="module-nav__item sidebar-config__item" id="notification-nav-button" type="button" data-view="notifications" aria-controls="notification-view">
<span class="module-nav__glyph sidebar-config__glyph" aria-hidden="true">
<svg viewBox="0 0 20 20" focusable="false"><path d="M4.5 8.2a5.5 5.5 0 0 1 11 0v2.7l1.2 2.2H3.3l1.2-2.2V8.2Z"/><path d="M8 15.1a2.1 2.1 0 0 0 4 0"/></svg>
</span>
<span class="module-nav__copy"><strong>通知路由</strong><small>收件人与应用绑定</small></span>
<span class="module-nav__count" id="notification-route-count">…</span>
</button>
<button class="module-nav__item sidebar-config__item" id="dynamic-config-nav-button" type="button" data-view="dynamic-configs" aria-controls="dynamic-config-view">
<span class="module-nav__glyph sidebar-config__glyph dynamic-config-nav__glyph" aria-hidden="true">配</span>
<span class="module-nav__copy"><strong>款式平台配置</strong><small>ERP、平台商品 ID 与目标表</small></span>
<span class="module-nav__count" id="dynamic-config-nav-count">…</span>
</button>
</div>
<div class="sidebar__footer">
<span class="sidebar__status-dot" id="sidebar-status-dot" aria-hidden="true"></span>
<div>
@@ -62,6 +88,7 @@
</aside>
<main class="main" id="main-content" tabindex="-1">
<div id="workflow-view">
<section class="hero" aria-labelledby="page-title">
<div class="hero__copy">
<span class="eyebrow">WORKFLOW OPERATIONS</span>
@@ -93,6 +120,44 @@
</article>
</section>
<section class="schedule-distribution" id="schedule-distribution" aria-labelledby="schedule-distribution-title" aria-busy="true">
<header class="schedule-distribution__header">
<div>
<span class="eyebrow">SCHEDULE DISTRIBUTION</span>
<h2 id="schedule-distribution-title">工作流时间分布</h2>
<p>折线高度表示同一时间的工作流数量;选择节点查看任务,运行中的节点会持续闪烁。</p>
</div>
<div class="schedule-distribution__summary" aria-live="polite">
<strong id="schedule-node-count">…</strong>
<span id="schedule-node-detail">正在读取时间节点</span>
</div>
</header>
<div class="schedule-day-filter" id="schedule-day-filter" role="group" aria-label="按星期查看自动计划">
<button type="button" data-schedule-day="all" aria-pressed="true">全部周期</button>
<button type="button" data-schedule-day="Monday" aria-pressed="false">周一</button>
<button type="button" data-schedule-day="Tuesday" aria-pressed="false">周二</button>
<button type="button" data-schedule-day="Wednesday" aria-pressed="false">周三</button>
<button type="button" data-schedule-day="Thursday" aria-pressed="false">周四</button>
<button type="button" data-schedule-day="Friday" aria-pressed="false">周五</button>
<button type="button" data-schedule-day="Saturday" aria-pressed="false">周六</button>
<button type="button" data-schedule-day="Sunday" aria-pressed="false">周日</button>
</div>
<div class="schedule-distribution__body" id="schedule-distribution-body">
<div class="schedule-distribution__loading" aria-hidden="true">
<span class="skeleton skeleton--line skeleton--wide"></span>
<span class="skeleton skeleton--block"></span>
</div>
</div>
<footer class="schedule-distribution__legend">
<span><i data-accent="violet"></i>内容营销</span>
<span><i data-accent="blue"></i>商品经营</span>
<span><i data-accent="amber"></i>店铺运营</span>
<span><i data-accent="green"></i>供应链</span>
<span class="schedule-legend-live"><i></i>正在执行</span>
<small>选择星期时,显示每天运行的任务与该日周计划。</small>
</footer>
</section>
<section class="control-bar" aria-label="筛选工作流">
<label class="search-field" for="workflow-search">
<span aria-hidden="true">⌕</span>
@@ -126,6 +191,11 @@
<span aria-hidden="true"></span>
只看异常
</label>
<button class="hidden-workflows-toggle" id="hidden-workflows-toggle" type="button" aria-pressed="false" title="查看和恢复已隐藏的工作流(仅当前浏览器)">
<span class="hidden-workflows-toggle__icon" aria-hidden="true"><svg viewBox="0 0 20 20"><path d="M2.5 10s2.6-4.2 7.5-4.2 7.5 4.2 7.5 4.2-2.6 4.2-7.5 4.2S2.5 10 2.5 10Z"/><circle cx="10" cy="10" r="2.1"/><path d="m3.3 3.3 13.4 13.4"/></svg></span>
<span id="hidden-workflows-toggle-label">隐藏管理</span>
<span class="hidden-workflows-toggle__count" id="hidden-workflows-count">0</span>
</button>
</div>
</section>
@@ -144,6 +214,184 @@
</div>
</section>
</div>
</div>
<section class="daily-summary-page" id="daily-summary-view" aria-labelledby="daily-summary-title" aria-busy="true" hidden>
<header class="daily-summary-page__header">
<div>
<span class="eyebrow">DAILY OPERATIONS REVIEW</span>
<h1 id="daily-summary-title">昨天的工作流运行汇总</h1>
<p id="daily-summary-period">正在确定昨天的执行日期,并生成逐工作流执行说明。</p>
</div>
<div class="daily-summary-page__actions">
<label for="daily-summary-date"><span>执行日期</span><input id="daily-summary-date" type="date"></label>
<button class="button button--secondary" id="daily-summary-refresh-button" type="button">重新生成汇总</button>
</div>
</header>
<div class="daily-summary-analysis-note" id="daily-summary-analysis-note" role="status" aria-live="polite">正在生成昨天的运行汇总…</div>
<section class="daily-summary-metrics" aria-label="每日运行统计">
<article data-tone="neutral"><span>纳入汇总</span><strong id="daily-summary-total">…</strong></article>
<article data-tone="success"><span>正常执行</span><strong id="daily-summary-normal">…</strong></article>
<article data-tone="info"><span>重试恢复</span><strong id="daily-summary-recovered">…</strong></article>
<article data-tone="danger"><span>执行异常</span><strong id="daily-summary-abnormal">…</strong></article>
<article data-tone="warning"><span>未执行</span><strong id="daily-summary-missed">…</strong></article>
</section>
<section class="daily-summary-overview" aria-labelledby="daily-summary-overview-title">
<span class="daily-summary-overview__mark" aria-hidden="true">析</span>
<div><h2 id="daily-summary-overview-title">汇总结论</h2><p id="daily-summary-overview-copy">等待分析结果</p></div>
</section>
<div class="daily-summary-list" id="daily-summary-list">
<div class="daily-summary-loading" aria-hidden="true"><span class="skeleton skeleton--line skeleton--wide"></span><span class="skeleton skeleton--block"></span><span class="skeleton skeleton--block"></span></div>
</div>
</section>
<section class="notification-page" id="notification-view" aria-labelledby="notification-page-title" aria-busy="true" hidden>
<header class="notification-page__header">
<div class="notification-page__heading">
<div class="notification-page__mark" aria-hidden="true">
<svg viewBox="0 0 24 24" focusable="false"><path d="M5 10a7 7 0 0 1 14 0v3.5l1.5 2.8h-17L5 13.5V10Z"/><path d="M9.2 19a3 3 0 0 0 5.6 0"/></svg>
</div>
<div>
<h1 id="notification-page-title">通知路由与收件人</h1>
<p>决定哪些工作流通过分析端 Hermes 机器人通知,以及每一份产出发送给谁。</p>
</div>
</div>
<div class="notification-page__actions">
<span class="notification-unsaved" id="notification-unsaved" role="status" hidden>有未保存修改</span>
<button class="button button--secondary" id="notification-reload-button" type="button">重新载入</button>
<button class="button button--primary" id="notification-save-button" type="button" disabled>保存全部配置</button>
</div>
</header>
<div class="notification-feedback" id="notification-feedback" role="status" aria-live="polite" hidden></div>
<section class="notification-app" aria-labelledby="notification-app-title">
<div class="notification-app__identity">
<span class="notification-app__icon" aria-hidden="true">
<svg viewBox="0 0 24 24" focusable="false"><path d="M7 6.5h10a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2Z"/><path d="M9 6.5V5a3 3 0 0 1 6 0v1.5M9 12h6M12 9v6"/></svg>
</span>
<div>
<h2 id="notification-app-title">发送应用作用域</h2>
<p>OpenID 只在对应飞书应用内有效;切换应用后,未绑定人员需要先通过手机号解析。</p>
</div>
</div>
<label class="notification-app__selector" for="notification-app-profile">
<span>分析端应用</span>
<select id="notification-app-profile" aria-describedby="notification-app-hint"></select>
<small id="notification-app-hint">应用密钥仅保留在服务端运行时,不会传到浏览器。</small>
</label>
</section>
<div class="notification-workspace">
<section class="notification-panel notification-routes-panel" aria-labelledby="notification-routes-title">
<header class="notification-panel__header">
<div>
<h2 id="notification-routes-title">工作流通知路由</h2>
<p>这里只显示后端已接入通知能力的工作流。</p>
</div>
<span class="notification-panel__count" id="notification-routes-count">读取中</span>
</header>
<div class="notification-route-list" id="notification-route-list">
<div class="notification-loading" aria-hidden="true"><span class="skeleton skeleton--line skeleton--wide"></span><span class="skeleton skeleton--block"></span><span class="skeleton skeleton--block"></span></div>
</div>
</section>
<section class="notification-panel notification-people-panel" aria-labelledby="notification-people-title">
<header class="notification-panel__header">
<div>
<h2 id="notification-people-title">收件人目录</h2>
<p id="notification-people-subtitle">姓名、手机号与应用内 OpenID 绑定。</p>
</div>
<button class="button button--secondary notification-add-person" id="notification-add-person-button" type="button">
<svg aria-hidden="true" viewBox="0 0 16 16"><path d="M8 3v10M3 8h10"/></svg>
添加联系人
</button>
</header>
<form class="notification-person-form" id="notification-person-form" novalidate hidden>
<div class="notification-person-form__header">
<div><h3 id="notification-person-form-title">添加联系人</h3><p>修改先保存在当前页面,点击“保存全部配置”后生效。</p></div>
<button class="icon-button" id="notification-person-form-close" type="button" aria-label="关闭联系人编辑">×</button>
</div>
<input id="notification-person-id" type="hidden">
<div class="notification-person-form__grid">
<label class="field"><span>姓名</span><input id="notification-person-name" type="text" maxlength="64" autocomplete="off" required></label>
<label class="field"><span>手机号</span><input id="notification-person-mobile" type="tel" inputmode="tel" maxlength="24" autocomplete="tel" placeholder="用于当前应用解析 OpenID"></label>
<label class="field notification-person-form__openid"><span>当前应用 OpenID</span><input id="notification-person-open-id" type="text" maxlength="96" autocomplete="off" placeholder="ou_…"><small id="notification-person-binding-hint">可直接填写,或通过手机号向当前应用查询。</small></label>
</div>
<p class="form-error" id="notification-person-form-error" role="alert" hidden></p>
<div class="notification-person-form__actions">
<button class="button button--ghost notification-person-delete" id="notification-person-delete-button" type="button" hidden>删除联系人</button>
<button class="button button--secondary" id="notification-person-resolve-button" type="button">通过手机号绑定</button>
<button class="button button--primary" type="submit">保存到当前页面</button>
</div>
<div class="notification-delete-confirm" id="notification-delete-confirm" role="alert" hidden>
<p><strong>删除这位联系人?</strong><span>相关路由中的选择也会一并移除,保存全部配置后生效。</span></p>
<div><button class="button button--ghost" id="notification-delete-cancel" type="button">取消</button><button class="button button--danger" id="notification-delete-confirm-button" type="button">确认删除</button></div>
</div>
</form>
<label class="notification-people-search" for="notification-people-search">
<svg aria-hidden="true" viewBox="0 0 20 20"><circle cx="8.5" cy="8.5" r="5.5"/><path d="m13 13 4 4"/></svg>
<input id="notification-people-search" type="search" placeholder="搜索姓名、手机号或 OpenID" autocomplete="off">
</label>
<div class="notification-people-list" id="notification-people-list" aria-live="polite">
<div class="notification-loading" aria-hidden="true"><span class="skeleton skeleton--line skeleton--wide"></span><span class="skeleton skeleton--line"></span><span class="skeleton skeleton--line skeleton--wide"></span></div>
</div>
</section>
</div>
</section>
<section class="dynamic-config-page" id="dynamic-config-view" aria-labelledby="dynamic-config-title" aria-busy="true" hidden>
<header class="dynamic-config-header">
<div class="dynamic-config-header__copy">
<span class="eyebrow">STYLE CONFIGURATION WORKSPACE</span>
<h1 id="dynamic-config-title">款式配置中心</h1>
<p>一款一条配置,集中维护 ERP、飞书业务目标和各平台商品身份。</p>
</div>
<div class="dynamic-config-header__actions">
<div class="dynamic-config-source-note"><span class="config-source-dot" aria-hidden="true"></span><span><small>配置来源</small><strong>云端 PostgreSQL</strong></span></div>
<button class="button button--secondary" id="dynamic-config-reload-button" type="button">重新载入</button>
<button class="button button--primary" id="dynamic-config-add-button" type="button"><span aria-hidden="true">+</span>新增款式</button>
</div>
</header>
<section class="dynamic-config-source-bar" aria-label="款式配置读取范围">
<div class="dynamic-config-source-bar__lead"><span class="config-source-icon" aria-hidden="true">↗</span><div><strong>统一配置,按款式生效</strong><p>新启动的工作流会读取这里的最新版本。</p></div></div>
<div class="dynamic-config-source-bar__items"><span><b>01</b>ERP 款式编码</span><span><b>02</b>业务目标地址</span><span><b>03</b>平台商品身份</span></div>
</section>
<section class="dynamic-config-summary" aria-label="配置统计">
<article data-tone="brand"><div><span>款式</span><small>一款一条公共配置</small></div><strong id="dynamic-config-total">…</strong></article>
<article data-tone="success"><div><span>启用款式</span><small>会进入工作流解析</small></div><strong id="dynamic-config-enabled">…</strong></article>
<article data-tone="platform"><div><span>平台映射</span><small>商品身份子配置</small></div><strong id="dynamic-config-platform-count">…</strong></article>
<article data-tone="neutral"><div><span>当前结果</span><small>符合当前筛选</small></div><strong id="dynamic-config-matched">…</strong></article>
</section>
<section class="dynamic-config-ledger" aria-labelledby="dynamic-config-ledger-title">
<header class="dynamic-config-toolbar">
<div class="dynamic-config-toolbar__title"><div class="section-kicker"><span aria-hidden="true">目录</span><small>CONFIGURED STYLES</small></div><h2 id="dynamic-config-ledger-title">款式目录</h2><p>先看款式身份与状态,需要调整时再进入通用编辑页。</p></div>
<div class="dynamic-config-filters">
<label class="dynamic-config-search" for="dynamic-config-search"><span class="sr-only">搜索配置</span><span aria-hidden="true">⌕</span><input id="dynamic-config-search" type="search" placeholder="搜索款式、品牌、商品 ID 或 ERP 编码" autocomplete="off"></label>
<label class="sr-only" for="dynamic-config-platform">筛选平台</label>
<select id="dynamic-config-platform"><option value="">全部平台</option></select>
<label class="sr-only" for="dynamic-config-status">筛选状态</label>
<select id="dynamic-config-status"><option value="">全部状态</option><option value="true">仅启用</option><option value="false">仅停用</option></select>
</div>
</header>
<div class="dynamic-config-feedback" id="dynamic-config-feedback" role="status" aria-live="polite" hidden></div>
<div class="dynamic-config-table-wrap">
<div class="dynamic-config-table" role="list" aria-label="款式配置列表">
<div class="dynamic-config-table-head" aria-hidden="true"><span>款式身份</span><span>平台商品</span><span>ERP / 业务目标</span><span>状态</span><span>操作</span></div>
<div id="dynamic-config-table-body"><div class="dynamic-config-loading">正在读取云端配置…</div></div>
</div>
</div>
</section>
</section>
</main>
</div>
@@ -197,6 +445,7 @@
<footer class="drawer__footer">
<button class="button button--secondary" id="drawer-configure-button" type="button">配置定时</button>
<button class="button button--stop" id="drawer-stop-button" type="button" hidden>停止执行</button>
<button class="button button--force" id="drawer-force-run-button" type="button">强制重跑</button>
<button class="button button--primary" id="drawer-run-button" type="button">立即运行</button>
</footer>
</aside>
@@ -211,17 +460,41 @@
</header>
<form id="run-form" novalidate>
<div class="modal__body">
<label class="field">
<label class="field" id="run-period-field">
<span id="run-period-label">业务日期</span>
<input id="run-business-date" name="business_date" type="date" required>
<small id="run-date-hint">本次数据处理所对应的业务日期。</small>
</label>
<label class="field" id="run-store-field" hidden>
<span>上传店铺</span>
<select id="run-store" name="store">
<option value="flagship">光影行星旗舰店</option>
<option value="luggage">光影行星鑫华达专卖店:龙虾仔</option>
</select>
<small>先扫描飞书并按所选店铺规则筛选;存在未上传附件时才登录该店铺账号。</small>
</label>
<label class="field" id="run-tmall-topic-field" hidden>
<span id="run-tmall-topic-label">天猫话题关键词</span>
<input id="run-tmall-topic-keyword" name="tmall_topic_keyword" type="text" maxlength="120" autocomplete="off" placeholder="例如:秋上新">
<small id="run-tmall-topic-hint">输入完整话题或关键词;系统会在搜索结果中按包含关系选中。</small>
</label>
<label class="field" id="run-tmall-baibu-field" hidden>
<span>导入范围</span>
<select id="run-tmall-baibu-mode" name="tmall_baibu_import_mode">
<option value="without_hyperlinks">导入去掉超链的</option>
<option value="all">导入全部</option>
</select>
<small id="run-tmall-baibu-hint">默认跳过带超链入口,只导入普通入口。</small>
</label>
<fieldset class="field">
<legend>执行方式</legend>
<div class="segmented-control">
<label><input type="radio" name="execute" value="true"><span><strong>真实执行</strong><small>允许产生实际业务影响</small></span></label>
<label><input type="radio" name="execute" value="false" checked><span><strong>安全预演</strong><small>检查流程但不执行外部效果</small></span></label>
<label><input type="radio" name="execute" value="true"><span><strong id="run-execute-title">真实执行</strong><small id="run-execute-description">允许产生实际业务影响</small></span></label>
<label><input type="radio" name="execute" value="false" checked><span><strong id="run-preview-title">安全预演</strong><small id="run-preview-description">检查流程但不执行外部效果</small></span></label>
</div>
</fieldset>
@@ -233,12 +506,17 @@
<div class="run-warning" id="run-warning">
<span aria-hidden="true">!</span>
<p><strong>这是一次真实执行</strong>任务可能进行采集、写库或发送通知等外部操作。</p>
<p><strong id="run-warning-title">这是一次真实执行</strong><span id="run-warning-description">任务可能进行采集、写库或发送通知等外部操作。</span></p>
</div>
<label class="confirm-check" id="run-force-row" hidden>
<input id="run-force" name="force_refresh" type="checkbox">
<span id="run-force-label">强制重跑:忽略幂等跳过与已有结果,重新采集并正式执行</span>
</label>
<label class="confirm-check" id="run-confirm-row">
<input id="run-confirmed" name="confirmed" type="checkbox">
<span>我已确认业务日期和执行影响,并继续运行</span>
<span id="run-confirm-label">我已确认业务日期和执行影响,并继续运行</span>
</label>
<p class="form-error" id="run-form-error" role="alert" hidden></p>
</div>
@@ -278,6 +556,62 @@
</section>
</div>
<div class="overlay overlay--center" id="dynamic-config-overlay" hidden>
<div class="overlay__backdrop" data-close="dynamic-config" aria-hidden="true"></div>
<section class="modal dynamic-config-modal" id="dynamic-config-modal" role="dialog" aria-modal="true" aria-labelledby="dynamic-config-form-title" aria-hidden="true">
<header class="modal__header dynamic-config-modal__header">
<div class="dynamic-config-modal__heading"><div class="dynamic-config-modal__eyebrow"><span class="config-modal-mark" aria-hidden="true">款</span><span class="eyebrow">STYLE CONFIGURATION</span></div><h2 id="dynamic-config-form-title">新增款式</h2><p id="dynamic-config-form-subtitle">一次维护款式公共配置与全部平台商品身份。</p></div>
<div class="dynamic-config-modal__header-actions"><span class="dynamic-config-revision" id="dynamic-config-editor-revision">新配置</span><button class="icon-button" id="dynamic-config-form-close" type="button" aria-label="关闭配置编辑">×</button></div>
</header>
<form id="dynamic-config-form" novalidate>
<input id="dynamic-config-id" type="hidden"><input id="dynamic-config-revision" type="hidden">
<div class="dynamic-config-editor-shell">
<aside class="dynamic-config-form-rail" aria-label="编辑页导航">
<div class="dynamic-config-form-identity"><span class="dynamic-config-editor-avatar" id="dynamic-config-editor-avatar">款</span><div><small>当前款式</small><strong id="dynamic-config-editor-style">新款式</strong><span class="dynamic-config-form-identity__status" id="dynamic-config-editor-status">准备创建</span><span class="dynamic-config-form-identity__summary" id="dynamic-config-editor-summary">新配置 · 1 个平台 · 1 个目标</span></div></div>
<nav class="dynamic-config-form-nav" aria-label="配置分区">
<button type="button" data-config-section-nav="identity" class="is-active"><span>01</span><strong>基础信息</strong><small>款式与 ERP 编码</small></button>
<button type="button" data-config-section-nav="destinations"><span>02</span><strong>业务目标</strong><small>可扩展飞书表格地址</small></button>
<button type="button" data-config-section-nav="platforms"><span>03</span><strong>平台映射</strong><small>商品 ID 与画像表</small></button>
</nav>
<div class="dynamic-config-form-rail__tip"><span aria-hidden="true">✦</span><div><strong>为下一条逻辑留位置</strong><p>新分析逻辑只需新增一条业务目标,使用稳定的逻辑标识读取对应地址。</p></div></div>
</aside>
<div class="modal__body dynamic-config-form-body">
<p class="form-error" id="dynamic-config-form-error" role="alert" hidden></p>
<section class="dynamic-config-form-section" id="dynamic-config-identity-section" data-config-section="identity" aria-labelledby="dynamic-config-identity-title">
<header><span>01</span><div><h3 id="dynamic-config-identity-title">款式基本信息</h3><p>ERP 编码和款式身份只维护一次,所有平台共享。</p></div></header>
<div class="dynamic-config-form-grid">
<label class="field"><span>款式名称 <i>必填</i></span><input id="config-style-name" maxlength="120" placeholder="例如:云栖" required></label>
<label class="field"><span>品牌</span><input id="config-brand" maxlength="120" placeholder="例如:光影行星"></label>
<label class="field field--full"><span>ERP 款式编码 <small>多个编码用逗号或换行分隔</small></span><textarea id="config-erp-codes" rows="2" placeholder="例如:10521, 10522"></textarea></label>
<label class="field dynamic-config-enabled-field"><span><strong>参与工作流</strong><small>停用后保留记录,但整款不再被工作流解析。</small></span><input id="config-enabled" type="checkbox" checked><i aria-hidden="true"></i></label>
<label class="field field--full"><span>备注</span><input id="config-note" maxlength="500" placeholder="记录这款的业务说明、特殊规则或负责人"></label>
<input id="config-style-content" type="hidden">
</div>
</section>
<section class="dynamic-config-form-section dynamic-config-destinations-section" id="dynamic-config-destinations-section" data-config-section="destinations" aria-labelledby="dynamic-config-destinations-title">
<header><span>02</span><div><h3 id="dynamic-config-destinations-title">业务目标</h3><p>每条目标由“逻辑标识 + 目标名称 + 飞书地址”组成,后续新增分析逻辑不用改页面结构。</p></div><button class="button button--secondary" id="dynamic-config-add-destination" type="button"><span aria-hidden="true">+</span>新增目标</button></header>
<div class="dynamic-config-destination-callout"><span aria-hidden="true">↳</span><p><strong>怎么扩展?</strong>例如新增“款式质量分析”:添加一条目标,逻辑标识填 <code>style_quality_analysis</code>,再粘贴新的飞书表格地址。</p></div>
<div class="dynamic-config-destination-editor" id="dynamic-config-destination-editor"></div>
</section>
<section class="dynamic-config-form-section dynamic-config-platform-section" id="dynamic-config-platforms-section" data-config-section="platforms" aria-labelledby="dynamic-config-platforms-title">
<header><span>03</span><div><h3 id="dynamic-config-platforms-title">平台商品身份</h3><p>一个平台一行:填写商品 ID;需要画像采集时再填本平台人群画像表。</p></div><button class="button button--secondary" id="dynamic-config-add-platform" type="button"><span aria-hidden="true">+</span>添加平台</button></header>
<div class="dynamic-config-platform-editor" id="dynamic-config-platform-editor"></div>
<datalist id="config-platform-options"><option value="天猫"><option value="京东旗舰店"><option value="京东自营"><option value="抖音"><option value="拼多多"><option value="拼多多光影行星GYXX箱包专卖店"><option value="拼多多光影行星箱包官方旗舰店"><option value="拼多多光影行星官方旗舰店"></datalist>
</section>
</div>
</div>
<footer class="modal__footer dynamic-config-modal__footer">
<button class="button button--danger" id="dynamic-config-delete-button" type="button" hidden>删除款式</button>
<span class="dynamic-config-modal__save-hint">保存后,新启动的工作流会读取这条配置。</span>
<button class="button button--ghost" id="dynamic-config-cancel-button" type="button">取消</button>
<button class="button button--primary" id="dynamic-config-save-button" type="submit">保存款式</button>
</footer>
</form>
</section>
</div>
<div class="overlay overlay--center overlay--auth" id="token-overlay" hidden>
<div class="overlay__backdrop"></div>
<section class="modal token-modal" id="token-modal" role="dialog" aria-modal="true" aria-labelledby="token-modal-title" aria-hidden="true">
@@ -298,6 +632,6 @@
<div class="toast-region" id="toast-region" aria-live="polite" aria-atomic="false"></div>
<script src="/assets/app.js?v=monthly-range-20260806a" defer></script>
<script src="/assets/app.js?v=scheduler-control-v1-20260831" defer></script>
</body>
</html>