codebee 0.1.47 → 0.1.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/app/core/aiflavor.py +80 -2
- package/app/core/automation.py +55 -2
- package/app/core/flows.py +12 -3
- package/app/core/hooks.py +156 -0
- package/app/core/pipeline.py +135 -8
- package/app/core/planner.py +127 -11
- package/app/core/store.py +67 -1
- package/app/core/usage.py +290 -286
- package/app/core/volumes.py +355 -0
- package/app/core/zentao.py +9 -4
- package/app/main.py +38 -0
- package/app/ui/app.js +737 -69
- package/app/ui/i18n.js +49 -1
- package/app/ui/index.html +81 -7
- package/app/ui/style.css +177 -0
- package/package.json +1 -1
package/app/ui/i18n.js
CHANGED
|
@@ -46,6 +46,16 @@
|
|
|
46
46
|
"推荐任务类型": "Recommended task type",
|
|
47
47
|
"切换类型": "Switch type",
|
|
48
48
|
"这个需求更适合「{0}」流程,能使用对应的规划与质量门禁。是否切换后执行?": "This request fits the {0} workflow, which provides matching planning and quality gates. Switch before running?",
|
|
49
|
+
// 自动化卡片上的偏好标签(短名与胶囊面同步取用)
|
|
50
|
+
"自动": "Auto",
|
|
51
|
+
"快速": "Fast",
|
|
52
|
+
"专家": "Expert",
|
|
53
|
+
"自动推荐": "Auto-recommended",
|
|
54
|
+
"编排模式:": "Orchestration mode: ",
|
|
55
|
+
"思考程度:": "Reasoning effort: ",
|
|
56
|
+
"对话模型:": "Chat model: ",
|
|
57
|
+
"只对「直接执行」类流程生效;留「自动推荐」时按系统路由挑模型。": "Applies only to the Direct execution workflow; leave it on Auto-recommended to let routing pick the model.",
|
|
58
|
+
"选择对话模型前请先选厂商": "Choose a provider before picking a chat model",
|
|
49
59
|
|
|
50
60
|
// —— 引擎/角色 ——
|
|
51
61
|
|
|
@@ -758,6 +768,16 @@
|
|
|
758
768
|
"评审维度(逗号分隔,可自定义)": "Review dimensions (comma-separated; custom OK)",
|
|
759
769
|
"连载模式:章节数(空 = 单稿件一次成文)": "Serial: chapters (blank = single draft)",
|
|
760
770
|
"每章约字数": "Approx. words per chapter",
|
|
771
|
+
// —— 分卷(卷结构:大纲规划 / 写作注入 / 成书分割 / UI 分组)——
|
|
772
|
+
"分卷:每卷章数(空 = 不分卷)": "Volumes: chapters per volume (blank = no volumes)",
|
|
773
|
+
"分卷:指定卷结构(可选,优先于每卷章数)": "Volumes: explicit structure (optional; overrides chapters per volume)",
|
|
774
|
+
"例:20(卷边界按全书章号自动推导)": "e.g. 20 (boundaries derived from book-wide chapter numbers)",
|
|
775
|
+
"例:第一卷 少年初入江湖 20章;第二卷 风云再起 16章": "e.g. Vol 1 The Young Wanderer 20 ch; Vol 2 Storm Rising 16 ch",
|
|
776
|
+
"每卷一行或分号分隔:卷名 + 章数(或第1-20章)。也可以在任务目标里直接这样写,会自动识别": "One per line or separated by semicolons: volume name + chapter count (or ch.1-20). You can also write this in the task goal — it is detected automatically.",
|
|
777
|
+
"分卷:每卷章数(留空 = 不分卷)": "Volumes: chapters per volume (blank = no volumes)",
|
|
778
|
+
"卷": "Vol",
|
|
779
|
+
"未分卷": "No volumes",
|
|
780
|
+
"其他文件": "Other files",
|
|
761
781
|
"实现者": "Implementer",
|
|
762
782
|
"评审组": "Reviewers",
|
|
763
783
|
"管理": "Manage",
|
|
@@ -2411,6 +2431,32 @@
|
|
|
2411
2431
|
"导出与导入前自动备份的旧 zip": "Old zips from exports and pre-import auto-backups",
|
|
2412
2432
|
"只保留每个日志的末尾 1MB": "Keeps only the last 1MB of each log",
|
|
2413
2433
|
"含平台登录态,清理后发布时需重新扫码登录": "Contains platform logins; re-scan the QR code to publish after clearing",
|
|
2434
|
+
|
|
2435
|
+
// —— 概览首页 & KPI 卡 ——
|
|
2436
|
+
"工作台": "Workspace",
|
|
2437
|
+
"概览": "Overview",
|
|
2438
|
+
"用量趋势": "Usage trend",
|
|
2439
|
+
"快捷入口": "Quick actions",
|
|
2440
|
+
"最近运行": "Recent runs",
|
|
2441
|
+
"查看全部": "View all",
|
|
2442
|
+
"执行次数": "Runs",
|
|
2443
|
+
"成功率": "Success rate",
|
|
2444
|
+
"Token 消耗": "Tokens used",
|
|
2445
|
+
"上期": "Previous",
|
|
2446
|
+
"日均 ": "Daily avg ",
|
|
2447
|
+
"成功 ": "OK ",
|
|
2448
|
+
"较上期": "vs prev",
|
|
2449
|
+
"与上一个同长周期相比": "Compared with the previous period of equal length",
|
|
2450
|
+
"近 30 天执行 ": "Last 30 days: ",
|
|
2451
|
+
" · 消耗 ": " · used ",
|
|
2452
|
+
" tokens · 费用 ": " tokens · cost ",
|
|
2453
|
+
" · 当前 ": " · ",
|
|
2454
|
+
" 个任务运行中": " task(s) running now",
|
|
2455
|
+
"暂无用量记录。跑一个任务后这里会出现统计。": "No usage yet. Stats appear here once you run a task.",
|
|
2456
|
+
"描述目标,交给智能体执行": "Describe a goal and let agents run it",
|
|
2457
|
+
"项目资料与沉淀": "Project docs and notes",
|
|
2458
|
+
"装技能扩展能力": "Install skills to extend",
|
|
2459
|
+
"定时与周期执行": "Scheduled and recurring runs",
|
|
2414
2460
|
};
|
|
2415
2461
|
|
|
2416
2462
|
// ---------- 工具 ----------
|
|
@@ -2490,7 +2536,9 @@
|
|
|
2490
2536
|
});
|
|
2491
2537
|
// 编排 pill 短名取自 option 文本,重译后要跟着换语言
|
|
2492
2538
|
if (typeof window.syncCmpSelFace === "function") {
|
|
2493
|
-
|
|
2539
|
+
// au-* 是自动化弹框里的偏好胶囊:弹框未开时这两个 id 不在 DOM 里,
|
|
2540
|
+
// syncCmpSelFace 对缺失元素直接返回,无需额外守卫
|
|
2541
|
+
["f-mode", "f-thinking", "au-mode", "au-thinking"].forEach((id) => window.syncCmpSelFace(id));
|
|
2494
2542
|
}
|
|
2495
2543
|
if (typeof window.cmpDirectBtnSync === "function") {
|
|
2496
2544
|
window.cmpDirectBtnSync(); // 「自动推荐/推荐」等词也要换语言
|
package/app/ui/index.html
CHANGED
|
@@ -114,15 +114,22 @@
|
|
|
114
114
|
<span class="ss-label" data-i18n="搜索">搜索</span>
|
|
115
115
|
<span class="kbd" aria-hidden="true">Ctrl K</span>
|
|
116
116
|
</button>
|
|
117
|
+
<!-- 快捷导航:只放最常用的全局页(data-page 是页面 id 真源)。
|
|
118
|
+
点它们只换主栏内容,左栏任务树原地不动(app.js switchTab 的 main 形态);
|
|
119
|
+
对应入口已从下面设置导航移除,同一页不再两处重复。 -->
|
|
117
120
|
<div class="side-quick">
|
|
118
|
-
<button class="qitem" id="btn-q-
|
|
121
|
+
<button class="qitem" id="btn-q-overview" data-page="overview" title="概览" data-i18n-title="概览">
|
|
122
|
+
<svg class="ico" aria-hidden="true"><use href="#i-gauge"></use></svg>
|
|
123
|
+
<span data-i18n="概览">概览</span>
|
|
124
|
+
</button>
|
|
125
|
+
<button class="qitem" id="btn-q-runs" data-page="runs" title="运行记录" data-i18n-title="运行记录">
|
|
126
|
+
<svg class="ico" aria-hidden="true"><use href="#i-history"></use></svg>
|
|
127
|
+
<span data-i18n="运行记录">运行记录</span>
|
|
128
|
+
</button>
|
|
129
|
+
<button class="qitem" id="btn-q-automation" data-page="automation" title="自动化" data-i18n-title="自动化">
|
|
119
130
|
<svg class="ico" aria-hidden="true"><use href="#i-calendar-days"></use></svg>
|
|
120
131
|
<span data-i18n="自动化">自动化</span>
|
|
121
132
|
</button>
|
|
122
|
-
<button class="qitem" id="btn-q-market" title="插件市场" data-i18n-title="插件市场">
|
|
123
|
-
<svg class="ico" aria-hidden="true"><use href="#i-blocks"></use></svg>
|
|
124
|
-
<span data-i18n="插件市场">插件市场</span>
|
|
125
|
-
</button>
|
|
126
133
|
</div>
|
|
127
134
|
<div class="side-section tasks">
|
|
128
135
|
<div class="side-label-row">
|
|
@@ -174,10 +181,10 @@
|
|
|
174
181
|
<button id="btn-set-back" class="set-back" data-i18n="返回 CodeBee">
|
|
175
182
|
<svg class="ico" aria-hidden="true"><use href="#i-arrow-left"></use></svg>返回 CodeBee
|
|
176
183
|
</button>
|
|
184
|
+
<!-- 概览 / 运行记录 / 自动化已升为左栏快捷导航(见 .side-quick),此处不再重复挂条目 -->
|
|
177
185
|
<div data-i18n="编排" class="set-group">编排</div>
|
|
178
186
|
<button class="set-item active" data-sub="tasks" data-i18n="任务"><svg class="ico" aria-hidden="true"><use href="#i-tasks"></use></svg>任务</button>
|
|
179
|
-
<button class="set-item" data-sub="
|
|
180
|
-
<button class="set-item" data-sub="automation" data-i18n="自动化"><svg class="ico" aria-hidden="true"><use href="#i-calendar-days"></use></svg>自动化</button>
|
|
187
|
+
<button class="set-item" data-sub="hooks" data-i18n="钩子"><svg class="ico" aria-hidden="true"><use href="#i-link"></use></svg>钩子</button>
|
|
181
188
|
<button class="set-item" data-sub="__wxdigest" data-i18n="微信群聊汇报"><svg class="ico" aria-hidden="true"><use href="#i-bee"></use></svg>微信群聊汇报</button>
|
|
182
189
|
<button class="set-item" data-sub="zentao" data-i18n="禅道"><svg class="ico" aria-hidden="true"><use href="#i-search"></use></svg>禅道</button>
|
|
183
190
|
<button class="set-item" data-sub="usage" data-i18n="用量统计"><svg class="ico" aria-hidden="true"><use href="#i-chart"></use></svg>用量统计</button>
|
|
@@ -243,6 +250,53 @@
|
|
|
243
250
|
<main>
|
|
244
251
|
<!-- ================= 设置页(导航在左栏,内容为居中窄栏) ================= -->
|
|
245
252
|
<section id="page-settings" class="page">
|
|
253
|
+
<!-- 概览首页:日期 → 一句话概览 → KPI 卡 → 趋势 + 快捷入口 → 最近运行。
|
|
254
|
+
全页数据来自真实台账(/api/usage)与运行记录(/api/state),无占位假数。 -->
|
|
255
|
+
<div id="sub-overview" class="subpage hidden">
|
|
256
|
+
<div class="ov-head">
|
|
257
|
+
<div class="ov-head-text">
|
|
258
|
+
<div id="ov-date" class="ov-eyebrow"></div>
|
|
259
|
+
<h1 id="ov-title" class="ov-title" data-i18n="概览">概览</h1>
|
|
260
|
+
<p id="ov-sub" class="ov-sub"></p>
|
|
261
|
+
</div>
|
|
262
|
+
<div class="ov-head-act">
|
|
263
|
+
<button class="ghost" onclick="switchTab('runs')">
|
|
264
|
+
<svg class="ico" aria-hidden="true"><use href="#i-history"></use></svg><span data-i18n="运行记录">运行记录</span>
|
|
265
|
+
</button>
|
|
266
|
+
<button class="primary" onclick="exitSettings()">
|
|
267
|
+
<svg class="ico" aria-hidden="true"><use href="#i-plus"></use></svg><span data-i18n="新建任务">新建任务</span>
|
|
268
|
+
</button>
|
|
269
|
+
</div>
|
|
270
|
+
</div>
|
|
271
|
+
<div id="ov-kpis" class="ov-kpis"></div>
|
|
272
|
+
<div class="ov-row">
|
|
273
|
+
<div class="panel ov-trend">
|
|
274
|
+
<div class="panel-head">
|
|
275
|
+
<h2 data-i18n="用量趋势">用量趋势</h2>
|
|
276
|
+
<div class="actions" id="ov-ranges">
|
|
277
|
+
<div class="seg" role="group" aria-label="时间范围" data-i18n-aria="时间范围">
|
|
278
|
+
<button class="seg-btn active" data-days="7" data-i18n="近 7 天" onclick="setOvDays(7)">近 7 天</button>
|
|
279
|
+
<button class="seg-btn" data-days="30" data-i18n="近 30 天" onclick="setOvDays(30)">近 30 天</button>
|
|
280
|
+
</div>
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
<div id="ov-trend-body" class="ov-trend-body"></div>
|
|
284
|
+
</div>
|
|
285
|
+
<div class="panel ov-quick">
|
|
286
|
+
<div class="panel-head"><h2 data-i18n="快捷入口">快捷入口</h2></div>
|
|
287
|
+
<div id="ov-quick-body" class="ov-quick-body"></div>
|
|
288
|
+
</div>
|
|
289
|
+
</div>
|
|
290
|
+
<div class="panel wide ov-recent">
|
|
291
|
+
<div class="panel-head">
|
|
292
|
+
<h2 data-i18n="最近运行">最近运行</h2>
|
|
293
|
+
<div class="actions">
|
|
294
|
+
<button class="ghost small" onclick="switchTab('runs')" data-i18n="查看全部">查看全部</button>
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
<div id="ov-recent-body" class="ov-recent-body"></div>
|
|
298
|
+
</div>
|
|
299
|
+
</div>
|
|
246
300
|
<div id="sub-tasks" class="subpage">
|
|
247
301
|
<div class="panel wide composer">
|
|
248
302
|
<div class="hero-row">
|
|
@@ -382,7 +436,9 @@
|
|
|
382
436
|
<div class="field"><label data-i18n="连载模式:章节数(空 = 单稿件一次成文)">连载模式:章节数(空 = 单稿件一次成文)</label><input id="f-chapters" type="number" min="2" max="20" placeholder="例:8(逐章起草+评审+修订)" data-i18n-ph="例:8(逐章起草+评审+修订)"></div>
|
|
383
437
|
<div class="field"><label data-i18n="每章约字数">每章约字数</label><input id="f-words-per-ch" type="number" min="500" max="8000" step="100" placeholder="例:2500" data-i18n-ph="例:2500"></div>
|
|
384
438
|
<div class="field"><label data-i18n="同章赛马稿件数">同章赛马稿件数</label><input id="f-variants" type="number" min="1" max="3" step="1" placeholder="1 = 关闭(2-3 每章多稿择优,更贵)" data-i18n-ph="1 = 关闭(2-3 每章多稿择优,更贵)"></div>
|
|
439
|
+
<div class="field"><label data-i18n="分卷:每卷章数(空 = 不分卷)">分卷:每卷章数(空 = 不分卷)</label><input id="f-vol-chapters" type="number" min="2" max="200" step="1" placeholder="例:20(卷边界按全书章号自动推导)" data-i18n-ph="例:20(卷边界按全书章号自动推导)"></div>
|
|
385
440
|
</div>
|
|
441
|
+
<div class="field" id="f-vol-spec-field"><label data-i18n="分卷:指定卷结构(可选,优先于每卷章数)">分卷:指定卷结构(可选,优先于每卷章数)</label><input id="f-vol-spec" placeholder="例:第一卷 少年初入江湖 20章;第二卷 风云再起 16章" data-i18n-ph="例:第一卷 少年初入江湖 20章;第二卷 风云再起 16章" data-i18n-title="每卷一行或分号分隔:卷名 + 章数(或第1-20章)。也可以在任务目标里直接这样写,会自动识别" title="每卷一行或分号分隔:卷名 + 章数(或第1-20章)。也可以在任务目标里直接这样写,会自动识别"></div>
|
|
386
442
|
</div>
|
|
387
443
|
|
|
388
444
|
<div id="f-manual-only" class="hidden">
|
|
@@ -595,6 +651,24 @@
|
|
|
595
651
|
</div>
|
|
596
652
|
</div>
|
|
597
653
|
|
|
654
|
+
<!-- 钩子:任务生命周期事件挂本机命令(stdin JSON / stdout 注入) -->
|
|
655
|
+
<div id="sub-hooks" class="subpage hidden">
|
|
656
|
+
<div class="panel wide">
|
|
657
|
+
<div class="panel-head">
|
|
658
|
+
<h2 data-i18n="钩子">钩子</h2>
|
|
659
|
+
<div class="actions">
|
|
660
|
+
<button id="btn-hooks-add" class="primary small" title="加一条钩子" data-i18n-title="加一条钩子"><span data-i18n="新建钩子">新建钩子</span></button>
|
|
661
|
+
</div>
|
|
662
|
+
</div>
|
|
663
|
+
<p class="hint" data-i18n="在任务生命周期的关键点执行本机命令:命令从标准输入收到 JSON(事件与任务上下文),标准输出回 {"inject": "文本"} 即把文本注入提示词(run_end 的输出被忽略,适合回写知识库)。命令按空格分词执行,不支持管道;失败或超时自动跳过,绝不挡主流程。">在任务生命周期的关键点执行本机命令:命令从标准输入收到 JSON(事件与任务上下文),标准输出回 {"inject": "文本"} 即把文本注入提示词(run_end 的输出被忽略,适合回写知识库)。命令按空格分词执行,不支持管道;失败或超时自动跳过,绝不挡主流程。</p>
|
|
664
|
+
<div id="hooks-list" class="cards"></div>
|
|
665
|
+
<div id="hooks-empty" class="empty hidden" data-i18n="还没有钩子——点「新建钩子」在任务开始 / 消息送达 / 运行结束时挂你自己的脚本。">还没有钩子——点「新建钩子」在任务开始 / 消息送达 / 运行结束时挂你自己的脚本。</div>
|
|
666
|
+
<div class="actions" style="margin-top:10px">
|
|
667
|
+
<button id="btn-hooks-save" class="primary small" title="保存全部钩子" data-i18n-title="保存全部钩子"><span data-i18n="保存钩子">保存钩子</span></button>
|
|
668
|
+
</div>
|
|
669
|
+
</div>
|
|
670
|
+
</div>
|
|
671
|
+
|
|
598
672
|
<!-- 禅道:Bug 自动扫描修复 -->
|
|
599
673
|
<div id="sub-zentao" class="subpage hidden">
|
|
600
674
|
<div class="panel wide">
|
package/app/ui/style.css
CHANGED
|
@@ -5708,3 +5708,180 @@ button.request-busy > * { opacity: .18; }
|
|
|
5708
5708
|
padding: 1px 7px; border-radius: 6px; }
|
|
5709
5709
|
.chat-act:hover { background: color-mix(in srgb, var(--text) 8%, transparent);
|
|
5710
5710
|
color: var(--text); }
|
|
5711
|
+
|
|
5712
|
+
/* 屏蔽顶部滑动加载线(用户拍板 2026-09-22):后台/长请求(如禅道内网不可达
|
|
5713
|
+
15-30s)会让线一直滑,观感差;操作反馈由「操作状态」中心承担,不丢信息 */
|
|
5714
|
+
#request-progress { display: none !important; }
|
|
5715
|
+
|
|
5716
|
+
/* 钩子管理卡片(设置 → 钩子,2026-09-22):名称/事件/开关一行,命令整行,
|
|
5717
|
+
* 底部超时+测试。mono 字体命令输入便于读路径 */
|
|
5718
|
+
.hook-card { display: flex; flex-direction: column; gap: 10px; }
|
|
5719
|
+
.hook-card .hook-row { display: flex; align-items: center; gap: 10px; }
|
|
5720
|
+
.hook-card .hook-name { flex: 1 1 auto; min-width: 180px; }
|
|
5721
|
+
.hook-card .hook-event { flex: none; width: 150px; }
|
|
5722
|
+
.hook-card .hook-cmd { width: 100%; box-sizing: border-box; font-family: var(--mono); font-size: 12px; }
|
|
5723
|
+
.hook-card .hook-foot { flex-wrap: wrap; }
|
|
5724
|
+
.hook-card .hook-foot .switch { display: inline-flex; align-items: center; gap: 6px; }
|
|
5725
|
+
.hook-card .hook-foot .switch em { font-style: normal; font-size: 12.5px; color: var(--muted); }
|
|
5726
|
+
.hook-card .hook-foot-lab { font-size: 12.5px; color: var(--muted); }
|
|
5727
|
+
.hook-card .hook-timeout { width: 64px; flex: none; }
|
|
5728
|
+
.hook-card .hook-test-out { flex: 1 1 160px; min-width: 0; overflow: hidden;
|
|
5729
|
+
text-overflow: ellipsis; white-space: nowrap; }
|
|
5730
|
+
.hook-card .switch { display: inline-flex; align-items: center; cursor: pointer; }
|
|
5731
|
+
.hook-card .switch input { appearance: none; width: 34px; height: 19px; border-radius: 999px;
|
|
5732
|
+
background: var(--border, rgba(128,128,128,.4)); position: relative; cursor: pointer;
|
|
5733
|
+
transition: background .15s; margin: 0; }
|
|
5734
|
+
.hook-card .switch input:checked { background: var(--accent); }
|
|
5735
|
+
.hook-card .switch input::after { content: ""; position: absolute; top: 2px; left: 2px;
|
|
5736
|
+
width: 15px; height: 15px; border-radius: 50%; background: #fff; transition: left .15s; }
|
|
5737
|
+
.hook-card .switch input:checked::after { left: 17px; }
|
|
5738
|
+
|
|
5739
|
+
/* ==========================================================================
|
|
5740
|
+
概览首页 + KPI 卡三件套(2026-09-22)
|
|
5741
|
+
配色一律走变量(--accent/--ok/--warn/--bad/--accent2),所以 7 套皮肤
|
|
5742
|
+
与日间/夜间都自动成立,无需为皮肤另写规则。
|
|
5743
|
+
========================================================================== */
|
|
5744
|
+
|
|
5745
|
+
/* ---------- KPI 卡:图标块 / 环比徽章 / 迷你走势 ---------- */
|
|
5746
|
+
/* .kpi 定位上下文:走势图绝对定位钉在右下角 */
|
|
5747
|
+
.kpi { position: relative; }
|
|
5748
|
+
.kpi.has-top { padding-top: 11px; }
|
|
5749
|
+
.kpi-top {
|
|
5750
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
5751
|
+
gap: 8px; margin-bottom: 9px;
|
|
5752
|
+
}
|
|
5753
|
+
/* 图标独立成块(淡彩底 + 本色图标),不再是标签行里的装饰性小图标 */
|
|
5754
|
+
.kpi-ico {
|
|
5755
|
+
width: 26px; height: 26px; flex: none; border-radius: 8px;
|
|
5756
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
5757
|
+
}
|
|
5758
|
+
.kpi-ico .ico { width: 15px; height: 15px; stroke-width: 2; }
|
|
5759
|
+
.kpi-ico.t-accent { color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
|
|
5760
|
+
.kpi-ico.t-ok { color: var(--ok); background: color-mix(in srgb, var(--ok) 14%, transparent); }
|
|
5761
|
+
.kpi-ico.t-warn { color: var(--warn); background: color-mix(in srgb, var(--warn) 14%, transparent); }
|
|
5762
|
+
.kpi-ico.t-bad { color: var(--bad); background: color-mix(in srgb, var(--bad) 14%, transparent); }
|
|
5763
|
+
.kpi-ico.t-calm { color: var(--accent2); background: color-mix(in srgb, var(--accent2) 14%, transparent); }
|
|
5764
|
+
|
|
5765
|
+
.kpi-delta {
|
|
5766
|
+
flex: none; font-size: 11px; font-weight: 600; white-space: nowrap;
|
|
5767
|
+
padding: 2px 8px; border-radius: 999px;
|
|
5768
|
+
}
|
|
5769
|
+
.kpi-delta.good { color: var(--ok); background: color-mix(in srgb, var(--ok) 14%, transparent); }
|
|
5770
|
+
.kpi-delta.bad { color: var(--bad); background: color-mix(in srgb, var(--bad) 14%, transparent); }
|
|
5771
|
+
.kpi-delta.flat { color: var(--muted); background: color-mix(in srgb, var(--muted) 14%, transparent); }
|
|
5772
|
+
|
|
5773
|
+
/* 走势图钉在右下;副行文字给它让位(.kpi-s 本就 nowrap + 省略号) */
|
|
5774
|
+
.kpi.has-spark { padding-bottom: 34px; }
|
|
5775
|
+
.kpi.has-spark .kpi-s { padding-right: 80px; }
|
|
5776
|
+
.kpi-spark { position: absolute; right: 10px; bottom: 8px; width: 72px; height: 24px; }
|
|
5777
|
+
.kspark { display: block; width: 100%; height: 100%; overflow: visible; }
|
|
5778
|
+
.kspark .ks-line { fill: none; stroke-width: 1.6; stroke-linejoin: round; stroke-linecap: round; }
|
|
5779
|
+
.kspark .ks-area { stroke: none; opacity: .16; }
|
|
5780
|
+
.kspark.t-accent .ks-line { stroke: var(--accent); }
|
|
5781
|
+
.kspark.t-accent .ks-area { fill: var(--accent); }
|
|
5782
|
+
.kspark.t-ok .ks-line { stroke: var(--ok); }
|
|
5783
|
+
.kspark.t-ok .ks-area { fill: var(--ok); }
|
|
5784
|
+
.kspark.t-warn .ks-line { stroke: var(--warn); }
|
|
5785
|
+
.kspark.t-warn .ks-area { fill: var(--warn); }
|
|
5786
|
+
.kspark.t-bad .ks-line { stroke: var(--bad); }
|
|
5787
|
+
.kspark.t-bad .ks-area { fill: var(--bad); }
|
|
5788
|
+
.kspark.t-calm .ks-line { stroke: var(--accent2); }
|
|
5789
|
+
.kspark.t-calm .ks-area { fill: var(--accent2); }
|
|
5790
|
+
|
|
5791
|
+
/* ---------- 概览页版式 ---------- */
|
|
5792
|
+
/* #sub-overview 本身就是 .subpage(纵向 flex + 20px 间距),
|
|
5793
|
+
所以下列各块不再自带外边距,避免出现双倍留白 */
|
|
5794
|
+
.ov-head {
|
|
5795
|
+
display: flex; align-items: flex-end; justify-content: space-between;
|
|
5796
|
+
gap: 16px; flex-wrap: wrap;
|
|
5797
|
+
}
|
|
5798
|
+
.ov-eyebrow { color: var(--muted); font-size: 12px; margin-bottom: 6px; }
|
|
5799
|
+
.ov-title { margin: 0; font-size: 26px; font-weight: 700; letter-spacing: -.02em; }
|
|
5800
|
+
.ov-sub { margin: 9px 0 0; color: var(--muted); font-size: 13px; }
|
|
5801
|
+
.ov-head-act { display: flex; gap: 8px; flex: none; }
|
|
5802
|
+
.ov-head-act button { display: inline-flex; align-items: center; gap: 6px; }
|
|
5803
|
+
.ov-head-act .ico { width: 14px; height: 14px; }
|
|
5804
|
+
|
|
5805
|
+
.ov-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
|
|
5806
|
+
.ov-row {
|
|
5807
|
+
display: grid; gap: 12px; align-items: start;
|
|
5808
|
+
grid-template-columns: minmax(0, 1.62fr) minmax(0, 1fr);
|
|
5809
|
+
}
|
|
5810
|
+
|
|
5811
|
+
/* ---------- 快捷入口:图标块 + 主副标题 + 右上箭头 ---------- */
|
|
5812
|
+
.ov-quick-body { display: flex; flex-direction: column; gap: 2px; }
|
|
5813
|
+
.ov-q {
|
|
5814
|
+
display: flex; align-items: center; gap: 10px; width: 100%;
|
|
5815
|
+
text-align: left; background: none; border: none; cursor: pointer;
|
|
5816
|
+
color: var(--text); font-family: inherit; padding: 8px 9px; border-radius: 10px;
|
|
5817
|
+
transition: background-color .15s;
|
|
5818
|
+
}
|
|
5819
|
+
.ov-q:hover { background: var(--panel2); }
|
|
5820
|
+
.ov-q-ico {
|
|
5821
|
+
width: 28px; height: 28px; flex: none; border-radius: 9px;
|
|
5822
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
5823
|
+
color: var(--accent); background: color-mix(in srgb, var(--accent) 13%, transparent);
|
|
5824
|
+
}
|
|
5825
|
+
.ov-q-ico .ico { width: 15px; height: 15px; stroke-width: 2; }
|
|
5826
|
+
.ov-q-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
|
|
5827
|
+
.ov-q-text b { font-size: 13px; font-weight: 600; }
|
|
5828
|
+
.ov-q-text i {
|
|
5829
|
+
font-size: 11.5px; font-style: normal; color: var(--muted);
|
|
5830
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
5831
|
+
}
|
|
5832
|
+
/* ↗ 复用 i-arrow-up 旋转 45°,不再单加一个精灵图标 */
|
|
5833
|
+
.ov-q-go { flex: none; display: inline-flex; color: var(--muted); opacity: .5; transform: rotate(45deg); }
|
|
5834
|
+
.ov-q:hover .ov-q-go { opacity: .9; }
|
|
5835
|
+
/* 四行各自分色:一列同色图标太平 */
|
|
5836
|
+
.ov-q:nth-child(2) .ov-q-ico { color: var(--accent2); background: color-mix(in srgb, var(--accent2) 13%, transparent); }
|
|
5837
|
+
.ov-q:nth-child(3) .ov-q-ico { color: var(--ok); background: color-mix(in srgb, var(--ok) 13%, transparent); }
|
|
5838
|
+
.ov-q:nth-child(4) .ov-q-ico { color: var(--warn); background: color-mix(in srgb, var(--warn) 13%, transparent); }
|
|
5839
|
+
|
|
5840
|
+
/* ---------- 最近运行:发丝线分隔的行 ---------- */
|
|
5841
|
+
.ov-recent-body { display: flex; flex-direction: column; }
|
|
5842
|
+
.ov-recent .panel-head { margin-bottom: 8px; }
|
|
5843
|
+
.ov-run {
|
|
5844
|
+
display: flex; align-items: center; gap: 12px; width: 100%;
|
|
5845
|
+
text-align: left; background: none; border: none; cursor: pointer;
|
|
5846
|
+
color: var(--text); font-family: inherit; padding: 11px 8px;
|
|
5847
|
+
border-top: 1px solid var(--border); transition: background-color .15s;
|
|
5848
|
+
}
|
|
5849
|
+
.ov-run:first-child { border-top: none; }
|
|
5850
|
+
.ov-run:hover { background: var(--panel2); }
|
|
5851
|
+
.ov-run-ico { flex: none; width: 16px; display: inline-flex; align-items: center; justify-content: center; }
|
|
5852
|
+
.ov-run-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
|
|
5853
|
+
.ov-run-main b { font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
5854
|
+
.ov-run-main i {
|
|
5855
|
+
font-size: 11.5px; font-style: normal; color: var(--muted);
|
|
5856
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
5857
|
+
}
|
|
5858
|
+
.ov-run-meta { flex: none; display: flex; align-items: center; gap: 10px; }
|
|
5859
|
+
.ov-run-time { min-width: 54px; text-align: right; color: var(--muted); font-size: 11.5px; white-space: nowrap; }
|
|
5860
|
+
|
|
5861
|
+
/* ---------- 窄屏:KPI 两列 → 一列,趋势与快捷入口改纵向 ---------- */
|
|
5862
|
+
@media (max-width: 1080px) {
|
|
5863
|
+
.ov-kpis { grid-template-columns: repeat(2, 1fr); }
|
|
5864
|
+
.ov-row { grid-template-columns: 1fr; }
|
|
5865
|
+
}
|
|
5866
|
+
@media (max-width: 640px) {
|
|
5867
|
+
.ov-kpis { grid-template-columns: 1fr; }
|
|
5868
|
+
.ov-head { flex-direction: column; align-items: flex-start; }
|
|
5869
|
+
/* 窄屏放不下并排:走势图落到卡片底部通栏,副行不再让位 */
|
|
5870
|
+
.kpi-spark { position: static; width: 100%; margin-top: 8px; }
|
|
5871
|
+
.kpi.has-spark { padding-bottom: 12px; }
|
|
5872
|
+
.kpi.has-spark .kpi-s { padding-right: 0; }
|
|
5873
|
+
}
|
|
5874
|
+
|
|
5875
|
+
|
|
5876
|
+
/* 分卷:章节评审卡按卷分组(.ch-vol 卷头 + 卷内容器)。卷头是一条细分隔线
|
|
5877
|
+
* 加卷名/卷内达标数/章号区间;不分卷时完全不渲染,视觉与分卷前一致。 */
|
|
5878
|
+
.ch-vol { margin: 10px 0 14px; }
|
|
5879
|
+
.ch-vol-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
|
|
5880
|
+
padding: 4px 2px 6px; border-bottom: 1px solid var(--border, rgba(128,128,128,.22)); }
|
|
5881
|
+
.ch-vol-head b { font-size: 13px; letter-spacing: .01em; }
|
|
5882
|
+
.ch-vol > .ch-row { margin: 6px 0 0 10px; }
|
|
5883
|
+
|
|
5884
|
+
/* 分卷:发布页章节清单按卷分组(.pb-vol 卷头 + 其下章节按钮)。 */
|
|
5885
|
+
.pb-vol { margin: 8px 0 12px; }
|
|
5886
|
+
.pb-vol-head { font-size: 12.5px; color: var(--muted); padding: 2px 2px 6px;
|
|
5887
|
+
border-bottom: 1px solid var(--border, rgba(128,128,128,.22)); margin-bottom: 6px; }
|
package/package.json
CHANGED