Files
gyxx-flow/src/gyxx_flow/web/index.html
T

638 lines
45 KiB
HTML
Raw 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.
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light">
<meta name="theme-color" content="#f5f7fb">
<title>GYXX Flow · 工作流控制台</title>
<meta name="description" content="按业务模块查看、配置和运行 GYXX Flow 工作流。">
<link rel="stylesheet" href="/assets/app.css?v=scheduler-control-v1-20260831">
</head>
<body>
<a class="skip-link" href="#main-content">跳到主要内容</a>
<div class="app-shell" id="app-shell">
<header class="topbar">
<div class="topbar__brand">
<button class="icon-button mobile-menu-button" id="mobile-menu-button" type="button" aria-label="打开模块导航" aria-controls="sidebar" aria-expanded="false">
☰
</button>
<span class="brand-mark" aria-hidden="true">G</span>
<span class="brand-copy">
<strong>GYXX Flow</strong>
<small>工作流控制台</small>
</span>
</div>
<div class="topbar__actions">
<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>
<button class="icon-button" id="refresh-button" type="button" aria-label="刷新工作流数据" title="刷新">
↻
</button>
<button class="token-button" id="token-button" type="button" title="管理访问令牌">令牌</button>
</div>
</header>
<div class="sidebar-scrim" id="sidebar-scrim" hidden></div>
<aside class="sidebar" id="sidebar" aria-label="业务模块导航">
<div class="sidebar__intro">
<span class="eyebrow">业务模块</span>
<p>选择模块,快速聚焦对应工作流。</p>
</div>
<nav class="module-nav" id="module-nav" aria-label="工作流模块">
<button class="module-nav__item is-active" type="button" data-module="all" aria-current="page">
<span class="module-nav__glyph module-nav__glyph--all" aria-hidden="true">全</span>
<span class="module-nav__copy"><strong>全部工作流</strong><small>读取中</small></span>
<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>
<strong id="sidebar-status-title">控制台待连接</strong>
<small id="sidebar-status-detail">等待服务器响应</small>
</div>
</div>
</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>
<h1 id="page-title">让每条工作流,都清晰可控</h1>
<p>集中查看自动计划、手动启动任务,并快速定位最近一次执行结果与错误。</p>
</div>
<div class="hero__meta">
<span>数据生成时间</span>
<strong id="generated-at">等待数据</strong>
</div>
</section>
<section class="summary-grid" aria-label="工作流概览">
<article class="summary-card summary-card--total">
<span class="summary-card__icon" aria-hidden="true">流</span>
<div><span>全部工作流</span><strong id="summary-total">…</strong><small>统一目录</small></div>
</article>
<article class="summary-card summary-card--enabled">
<span class="summary-card__icon" aria-hidden="true">启</span>
<div><span>自动运行</span><strong id="summary-enabled">…</strong><small id="summary-scheduled-detail">定时计划</small></div>
</article>
<article class="summary-card summary-card--running">
<span class="summary-card__icon" aria-hidden="true">行</span>
<div><span>当前运行中</span><strong id="summary-running">…</strong><small>实时任务</small></div>
</article>
<article class="summary-card summary-card--failed">
<span class="summary-card__icon" aria-hidden="true">异</span>
<div><span>最近失败</span><strong id="summary-failed">…</strong><small id="summary-unavailable-detail">含不可用项</small></div>
</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>
<input id="workflow-search" type="search" placeholder="搜索名称、ID 或来源任务" autocomplete="off">
<kbd aria-hidden="true">/</kbd>
</label>
<div class="control-bar__filters">
<div class="select-field" data-custom-select>
<label class="sr-only" for="trigger-filter">触发方式</label>
<select id="trigger-filter" aria-label="触发方式">
<option value="all" data-description="显示所有触发类型">全部触发方式</option>
<option value="scheduled" data-description="由常驻调度服务按计划启动">定时工作流</option>
<option value="manual" data-description="仅可从控制台手动启动">仅手动</option>
<option value="unavailable" data-description="当前没有可用执行入口">不可执行</option>
</select>
</div>
<div class="select-field" data-custom-select>
<label class="sr-only" for="status-filter">执行状态</label>
<select id="status-filter" aria-label="执行状态">
<option value="all" data-description="显示全部运行结果">全部执行状态</option>
<option value="running" data-description="正在执行或同步结果">运行中</option>
<option value="failed" data-description="最近一次执行失败">最近失败</option>
<option value="success" data-description="最近一次执行成功">最近成功</option>
<option value="cancelled" data-description="最近一次执行由操作员停止">最近取消</option>
<option value="idle" data-description="还没有执行记录">暂无记录</option>
<option value="paused" data-description="自动计划已经暂停">已暂停</option>
</select>
</div>
<label class="filter-switch">
<input id="error-only-filter" type="checkbox">
<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>
<div class="filter-context" id="filter-context" hidden>
<span id="filter-context-label" role="status" aria-live="polite"></span>
<button type="button" id="clear-filters-button">清除筛选</button>
</div>
<div class="dashboard" id="workflow-dashboard" aria-busy="true">
<section class="module-section skeleton-section" aria-hidden="true">
<div class="skeleton skeleton--heading"></div>
<div class="workflow-grid">
<div class="workflow-card skeleton-card"><span class="skeleton skeleton--line skeleton--wide"></span><span class="skeleton skeleton--line"></span><span class="skeleton skeleton--block"></span></div>
<div class="workflow-card skeleton-card"><span class="skeleton skeleton--line skeleton--wide"></span><span class="skeleton skeleton--line"></span><span class="skeleton skeleton--block"></span></div>
<div class="workflow-card skeleton-card"><span class="skeleton skeleton--line skeleton--wide"></span><span class="skeleton skeleton--line"></span><span class="skeleton skeleton--block"></span></div>
</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>
<div class="overlay" id="drawer-overlay" hidden>
<div class="overlay__backdrop" data-close="drawer" aria-hidden="true"></div>
<aside class="drawer" id="workflow-drawer" role="dialog" aria-modal="true" aria-labelledby="drawer-title" aria-hidden="true">
<header class="drawer__header">
<div class="drawer__identity">
<span class="module-glyph" id="drawer-module-glyph" aria-hidden="true">流</span>
<div class="drawer__title-copy">
<span class="eyebrow" id="drawer-module-name">工作流详情</span>
<div class="drawer__title-row" id="drawer-title-row">
<h2 id="drawer-title">…</h2>
<button class="drawer__rename-button" id="drawer-rename-button" type="button" aria-label="修改工作流显示名称" aria-controls="drawer-name-form" aria-expanded="false">
<svg aria-hidden="true" viewBox="0 0 16 16"><path d="M10.8 2.3a1.4 1.4 0 0 1 2 2L6 11.1l-2.8.7.7-2.8 6.9-6.7Z"/><path d="m9.7 3.4 2.9 2.9"/></svg>
<span>修改名称</span>
</button>
</div>
<form class="drawer-name-editor" id="drawer-name-form" aria-label="修改工作流显示名称" hidden>
<div class="drawer-name-editor__row">
<label class="sr-only" for="drawer-name-input">工作流显示名称</label>
<input id="drawer-name-input" name="display_name" type="text" maxlength="64" autocomplete="off" aria-describedby="drawer-name-hint drawer-name-error" required>
<button class="button button--primary drawer-name-editor__save" id="drawer-name-save" type="submit">保存</button>
<button class="button button--ghost drawer-name-editor__cancel" id="drawer-name-cancel" type="button">取消</button>
</div>
<div class="drawer-name-editor__meta">
<span id="drawer-name-hint">只改变控制台显示,不影响执行、定时计划和历史记录。</span>
<button id="drawer-name-reset" type="button" hidden>恢复默认名称</button>
<span id="drawer-name-count" aria-live="polite">0 / 64</span>
</div>
<p class="drawer-name-editor__error" id="drawer-name-error" role="alert" hidden></p>
</form>
<code id="drawer-workflow-id">…</code>
</div>
</div>
<button class="icon-button" id="drawer-close-button" type="button" aria-label="关闭详情">×</button>
</header>
<div class="drawer__status-row" id="drawer-status-row"></div>
<div class="drawer-tabs" role="tablist" aria-label="工作流详情分类">
<button type="button" role="tab" id="tab-overview" aria-controls="panel-overview" aria-selected="true" data-tab="overview">概览</button>
<button type="button" role="tab" id="tab-steps" aria-controls="panel-steps" aria-selected="false" data-tab="steps" tabindex="-1">执行流程</button>
<button type="button" role="tab" id="tab-history" aria-controls="panel-history" aria-selected="false" data-tab="history" tabindex="-1">运行历史</button>
<button type="button" role="tab" id="tab-schedule" aria-controls="panel-schedule" aria-selected="false" data-tab="schedule" tabindex="-1">定时配置</button>
</div>
<div class="drawer__body">
<section class="drawer-panel" id="panel-overview" role="tabpanel" aria-labelledby="tab-overview" data-panel="overview"></section>
<section class="drawer-panel" id="panel-steps" role="tabpanel" aria-labelledby="tab-steps" data-panel="steps" hidden></section>
<section class="drawer-panel" id="panel-history" role="tabpanel" aria-labelledby="tab-history" data-panel="history" hidden></section>
<section class="drawer-panel" id="panel-schedule" role="tabpanel" aria-labelledby="tab-schedule" data-panel="schedule" hidden></section>
</div>
<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>
</div>
<div class="overlay overlay--center" id="run-overlay" hidden>
<div class="overlay__backdrop" data-close="run" aria-hidden="true"></div>
<section class="modal run-modal" id="run-modal" role="dialog" aria-modal="true" aria-labelledby="run-modal-title" aria-hidden="true">
<header class="modal__header">
<div><span class="eyebrow">MANUAL RUN</span><h2 id="run-modal-title">运行工作流</h2><code id="run-workflow-id">…</code></div>
<button class="icon-button" id="run-close-button" type="button" aria-label="关闭运行确认">×</button>
</header>
<form id="run-form" novalidate>
<div class="modal__body">
<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 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>
<label class="switch-row">
<span><strong>影子模式</strong><small>保留执行证据并标记为 shadow</small></span>
<input id="run-shadow" name="shadow" type="checkbox">
<span class="switch-control" aria-hidden="true"></span>
</label>
<div class="run-warning" id="run-warning">
<span aria-hidden="true">!</span>
<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 id="run-confirm-label">我已确认业务日期和执行影响,并继续运行</span>
</label>
<p class="form-error" id="run-form-error" role="alert" hidden></p>
</div>
<footer class="modal__footer">
<button class="button button--ghost" type="button" id="run-cancel-button">取消</button>
<button class="button button--danger" type="submit" id="run-submit-button" disabled>确认并运行</button>
</footer>
</form>
</section>
</div>
<div class="overlay overlay--center" id="stop-overlay" hidden>
<div class="overlay__backdrop" data-close="stop" aria-hidden="true"></div>
<section class="modal stop-modal" id="stop-modal" role="alertdialog" aria-modal="true" aria-labelledby="stop-modal-title" aria-describedby="stop-modal-description" aria-hidden="true" tabindex="-1">
<header class="modal__header">
<div><span class="eyebrow">STOP RUN</span><h2 id="stop-modal-title">停止工作流</h2><code id="stop-workflow-id">…</code></div>
<button class="icon-button" id="stop-close-button" type="button" aria-label="关闭停止确认">×</button>
</header>
<form id="stop-form">
<div class="modal__body">
<div class="stop-warning">
<span aria-hidden="true">!</span>
<div><strong>确认停止当前执行?</strong><p id="stop-modal-description">系统会终止工作流及其仍在运行的子进程;已经完成的步骤和已产生的外部影响不会回滚。</p></div>
</div>
<dl class="stop-run-facts">
<div><dt>工作流</dt><dd id="stop-workflow-name">…</dd></div>
<div><dt>业务日期</dt><dd id="stop-business-date">…</dd></div>
<div><dt>操作编号</dt><dd><code id="stop-operation-id">…</code></dd></div>
</dl>
<p class="form-error" id="stop-form-error" role="alert" aria-live="assertive" hidden></p>
</div>
<footer class="modal__footer">
<button class="button button--ghost" type="button" id="stop-cancel-button">继续执行</button>
<button class="button button--danger" type="submit" id="stop-submit-button">确认停止</button>
</footer>
</form>
</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">
<div class="token-modal__mark" aria-hidden="true">G</div>
<span class="eyebrow">SECURE CONSOLE</span>
<h2 id="token-modal-title">连接工作流控制台</h2>
<p>请输入控制台访问令牌。令牌仅保存在当前浏览器会话中,关闭页面后自动清除。</p>
<form id="token-form">
<label class="field">
<span>访问令牌</span>
<input id="token-input" type="password" autocomplete="current-password" placeholder="粘贴 Bearer Token" required>
</label>
<p class="form-error" id="token-form-error" role="alert" hidden></p>
<button class="button button--primary button--full" type="submit" id="token-submit-button">验证并进入</button>
</form>
</section>
</div>
<div class="toast-region" id="toast-region" aria-live="polite" aria-atomic="false"></div>
<script src="/assets/app.js?v=scheduler-control-v1-20260831" defer></script>
</body>
</html>