scrum-skills 0.3.3 → 0.3.5
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/.agents/skills/diagram-design/SKILL.md +11 -1
- package/.agents/skills/diagram-design/UPSTREAM.json +13 -1
- package/.agents/skills/diagram-design/references/primitives-core.md +4 -0
- package/README.md +2 -2
- package/assets/board/200.html +1 -1
- package/assets/board/404.html +1 -1
- package/assets/board/_nuxt/BKrRful0.js +3 -0
- package/assets/board/_nuxt/{DjzLR9Bl.js → BXL77dAA.js} +1 -1
- package/assets/board/_nuxt/{BkcaOYQ_.js → DKRYKLGF.js} +61 -50
- package/assets/board/_nuxt/D_ct-Stz.js +1 -1
- package/assets/board/_nuxt/builds/latest.json +1 -1
- package/assets/board/_nuxt/builds/meta/205ddf7c-da58-4213-ac80-82930a216157.json +1 -0
- package/assets/board/_nuxt/diagrams.BWgRXpo3.css +1 -0
- package/assets/board/_nuxt/{entry.BCuHiFgF.css → entry.DplN301E.css} +1 -1
- package/assets/board/_nuxt/last-change.Byf5fhdY.css +1 -0
- package/assets/board/burndown/index.html +1 -1
- package/assets/board/diagrams/index.html +1 -1
- package/assets/board/epics/index.html +1 -1
- package/assets/board/gantt/index.html +1 -1
- package/assets/board/index.html +1 -1
- package/assets/board/last-change/index.html +1 -1
- package/assets/board/milestones/index.html +1 -1
- package/assets/board/tests/index.html +1 -1
- package/bin/scrum-skills.mjs +0 -0
- package/docs/ai-assistant-guide.md +2 -1
- package/package.json +11 -12
- package/tools/ai.mjs +46 -2
- package/assets/board/_nuxt/CReA4TEB.js +0 -3
- package/assets/board/_nuxt/builds/meta/2218461a-f45b-41d6-ae44-b0d2332a9511.json +0 -1
- package/assets/board/_nuxt/diagrams.D1ybqBem.css +0 -1
- package/assets/board/_nuxt/last-change.C05Vc3BF.css +0 -1
|
@@ -160,6 +160,7 @@ These mark "AI slop" schematics of any type:
|
|
|
160
160
|
| Identical boxes for every node | Erases hierarchy |
|
|
161
161
|
| Legend floating inside the diagram area | Collides with nodes |
|
|
162
162
|
| Arrow labels with no masking rect | Bleeds through the line |
|
|
163
|
+
| 标签压在自己的连线上(垫白底也算) | 白底把线切掉一截:标签整块挪到线外,离开线时根本不需要白底 |
|
|
163
164
|
| Vertical `writing-mode` text on arrows | Unreadable |
|
|
164
165
|
| 3 equal-width summary cards as default | Generic grid — vary widths |
|
|
165
166
|
| Shadow on any element | Shadows are out. Borders are in. |
|
|
@@ -231,6 +232,15 @@ Non-negotiable, and §9 checks each one. Full text and edge cases: [primitives-c
|
|
|
231
232
|
|
|
232
233
|
---
|
|
233
234
|
|
|
235
|
+
|
|
236
|
+
### 本项目出图约定:标签整块离开连线
|
|
237
|
+
|
|
238
|
+
读者的反馈很一致:连线上的文字背后那块白底会把线切掉一截,顺着线读到一半就断了。本项目出图时,下面三条优先于 §6 的出厂写法:
|
|
239
|
+
|
|
240
|
+
1. **标签整块坐在线外。** 横线的标签压在线**上方**,标签底边与线留 6~10px;竖线的标签立在线**右侧**,左边缘与线留 6~10px。宁可把标签挪到线段上的空白处,也不许为了「居中好看」让它横跨线条。
|
|
241
|
+
2. **标签离开线条时,不垫白底。** 文字背后没有线穿过,mask rect 只会多出一块脏斑;只有「标签必须跨过别的连线」(两条走线交汇、标签只能落在交叉点上)时才补 `fill="{paper}"` 的底,且底只包住文字(四周各留 2px),与任何线条保持 ≥6px。**绝不许底压在自己的目标连线上。**
|
|
242
|
+
3. **区域 / 分组标题不跨框线。** 虚线框(服务治理区、数据层区、外部系统区这类)的标题要么放在框外上方空白处,要么在框内顶部预留 20~24px 的 header 带、标题落在带里;禁止用白底 rect 盖住虚线边框,那会让边框在标题处凭空断一截。
|
|
243
|
+
|
|
234
244
|
## 7. Layout & Spacing
|
|
235
245
|
|
|
236
246
|
Structural geometry sits on a 4px grid: node origins, widths, heights, gaps, and padding divide by 4. Type sizes follow the role ramp in [output-spec.md](references/output-spec.md), not the grid. Allowed values, the off-grid exceptions, and page layout: [`references/layout-budget.md`](references/layout-budget.md).
|
|
@@ -296,7 +306,7 @@ Run before producing any diagram.
|
|
|
296
306
|
- [ ] **§6 rule 4:** a distinct attach point per connector on a shared edge, 12px or more apart, none hiding another?
|
|
297
307
|
- [ ] **§6 rule 5:** no transit behind a non-endpoint box, except the unavoidable case (dashed, label at the visible end)?
|
|
298
308
|
- [ ] **§6 rule 6:** no label mask overlapping a node drawn after it? (From a repository checkout, run `(仓库级脚本未随包分发:越界与动画契约以 node tools/diagram-lint.mjs 为准)
|
|
299
|
-
- [ ]
|
|
309
|
+
- [ ] 标签整块坐在线外(横线在上方、竖线在右侧,间距 6~10px)?离开线时没垫多余白底?区域标题没跨在虚线框上?
|
|
300
310
|
- [ ] Legend is a horizontal bottom strip, not floating?
|
|
301
311
|
- [ ] No vertical `writing-mode` text?
|
|
302
312
|
- [ ] `viewBox` expanded for the legend strip (~60px)?
|
|
@@ -72,5 +72,17 @@
|
|
|
72
72
|
"SKILL.md"
|
|
73
73
|
]
|
|
74
74
|
},
|
|
75
|
-
"upstreamSelfCheckSha": "见上游仓库(本仓库不分发 python 脚本)"
|
|
75
|
+
"upstreamSelfCheckSha": "见上游仓库(本仓库不分发 python 脚本)",
|
|
76
|
+
"labelRules": {
|
|
77
|
+
"source": "scripts/sync-diagram-skill.mjs(LABEL_RULES_*)",
|
|
78
|
+
"injected": [
|
|
79
|
+
"SKILL.md",
|
|
80
|
+
"references/primitives-core.md"
|
|
81
|
+
],
|
|
82
|
+
"rules": [
|
|
83
|
+
"标签整块离开连线",
|
|
84
|
+
"标签离线不垫白底",
|
|
85
|
+
"区域标题不跨虚线框"
|
|
86
|
+
]
|
|
87
|
+
}
|
|
76
88
|
}
|
|
@@ -98,6 +98,10 @@ These six rules are **non-negotiable**. Run the pre-output checklist (SKILL.md
|
|
|
98
98
|
font-family="{sublabel}" text-anchor="middle">tech:port</text>
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
+
|
|
102
|
+
> **本项目口径(覆盖本节示例):** 标签整块坐在线外——横线在上方、竖线在右侧,间距 6~10px;
|
|
103
|
+
> 标签离开线条时**不垫白底 mask**,白底只在确有线从文字背后穿过时才用,且四周与任何线条保持 ≥6px。
|
|
104
|
+
> 区域 / 分组标题放在框外或框内顶部预留的 header 带里,**禁止用白底 rect 盖住虚线框**。
|
|
101
105
|
## Arrow labels — always mask, always with margin
|
|
102
106
|
|
|
103
107
|
Every arrow label needs an opaque rect behind it. Without one it bleeds through the line. **And the label must sit with a visible gap above the connector — never on top of it.**
|
package/README.md
CHANGED
|
@@ -122,7 +122,7 @@ npx scrum-skills serve # → http://localhost:4173
|
|
|
122
122
|
| 字段 | 说明 |
|
|
123
123
|
|---|---|
|
|
124
124
|
| 服务商 | DeepSeek / OpenAI / Moonshot / 硅基流动 / 本地 Ollama / 自定义,选中后自动带出接口地址与模型名 |
|
|
125
|
-
| 接口地址 · API Key · 模型名 | OpenAI 兼容端点即可;Ollama 可以留空 Key |
|
|
125
|
+
| 接口地址 · API Key · 模型名 | OpenAI 兼容端点即可;Ollama 可以留空 Key。填好 Key 后「模型名」右侧的「拉取列表」可点,直接从接口拉回模型 id 选一个(本地地址免 Key) |
|
|
126
126
|
| 系统提示词 · 温度 | 系统提示词默认留空:内置说明只讲「能碰哪些数据 / 两个工具 / 四条回答纪律」,不写人设也不提厂商;温度默认 0.3(改数据这类活不需要发挥) |
|
|
127
127
|
| 工具调用轮数上限 | 默认 30:模型连着调工具时跑到上限会强制收口一轮 |
|
|
128
128
|
| 上下文上限 · 超长自动压缩 | 默认 256000 token;超了先把老对话压掉,系统提示词与当前提问永远保留 |
|
|
@@ -192,7 +192,7 @@ AGILE_DIR=/别的项目 pnpm dev # 看别的项目的数据
|
|
|
192
192
|
|
|
193
193
|
pnpm build # 构建看板静态产物 → assets/board
|
|
194
194
|
pnpm validate # 只校验数据
|
|
195
|
-
pnpm test # 回归测试(校验器 / 测试资产与覆盖计算 / 看板皮肤与配色 / 布局回归 / 卡片操作 / 项目目录 / 最后更新页与历史版本 / 交付说明写入策略 / 提交信息与自动提交 / AI 服务与面板,
|
|
195
|
+
pnpm test # 回归测试(校验器 / 测试资产与覆盖计算 / 看板皮肤与配色 / 布局回归 / 卡片操作 / 项目目录 / 最后更新页与历史版本 / 交付说明写入策略 / 提交信息与自动提交 / AI 服务与面板,293 个用例)
|
|
196
196
|
pnpm serve # 起看板(读目标目录的 agile/,同时提供 /api/ai)
|
|
197
197
|
```
|
|
198
198
|
|
package/assets/board/200.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/
|
|
1
|
+
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/DKRYKLGF.js"}}</script><link rel="stylesheet" href="/_nuxt/entry.DplN301E.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DKRYKLGF.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DK3Fl9T5.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CFCM18fF.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BxuBMtk_.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DxBwVNyP.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BygIGL69.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/SywdkA98.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BW3xJdEx.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/SrNUvNwO.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CI0scS-N.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D_ct-Stz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/P6qlvBHA.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CdPGFZyy.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Bubk0xn-.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DJM7u8P3.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DUgGsde6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BrWE0up6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BE6t7Q2m.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DqUSsCJ2.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/q_8bxRMt.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DFQDFspC.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/C9MgRdhu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BQgzP7ur.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CgQ30j_6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DzmVW5-D.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B0C2jsdk.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CYGiZn-X.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/C3SpAhCW.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Cdf_T8Xa.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DV4ti-Pq.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CXG7GZes.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Dki9VkAL.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DLr85ebo.js"><script type="module" src="/_nuxt/DKRYKLGF.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/I-sGtDIB.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/BuBzMkFZ.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/BAQQngAq.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DHihWhf5.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.Y9imKiDC.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/1XlYaCp9.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.DufSBGVC.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/BtzUbHO_.js"><link rel="icon" type="image/svg+xml" href="/favicon.svg"><link rel="apple-touch-icon" href="/favicon.svg"></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"205ddf7c-da58-4213-ac80-82930a216157",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1794050656472,false]</script></body></html>
|
package/assets/board/404.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/
|
|
1
|
+
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/DKRYKLGF.js"}}</script><link rel="stylesheet" href="/_nuxt/entry.DplN301E.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DKRYKLGF.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DK3Fl9T5.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CFCM18fF.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BxuBMtk_.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DxBwVNyP.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BygIGL69.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/SywdkA98.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BW3xJdEx.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/SrNUvNwO.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CI0scS-N.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D_ct-Stz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/P6qlvBHA.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CdPGFZyy.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Bubk0xn-.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DJM7u8P3.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DUgGsde6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BrWE0up6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BE6t7Q2m.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DqUSsCJ2.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/q_8bxRMt.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DFQDFspC.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/C9MgRdhu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BQgzP7ur.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CgQ30j_6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DzmVW5-D.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B0C2jsdk.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CYGiZn-X.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/C3SpAhCW.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Cdf_T8Xa.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DV4ti-Pq.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CXG7GZes.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Dki9VkAL.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DLr85ebo.js"><script type="module" src="/_nuxt/DKRYKLGF.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/I-sGtDIB.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/BuBzMkFZ.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/BAQQngAq.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DHihWhf5.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.Y9imKiDC.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/1XlYaCp9.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.DufSBGVC.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/BtzUbHO_.js"><link rel="icon" type="image/svg+xml" href="/favicon.svg"><link rel="apple-touch-icon" href="/favicon.svg"></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"205ddf7c-da58-4213-ac80-82930a216157",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1794050656472,false]</script></body></html>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{t as e}from"./DJM7u8P3.js";import{t}from"./CI0scS-N.js";import{I as n,i as r,s as i}from"#entry";import{At as a,B as ee,I as te,K as o,N as ne,S as re,U as s,Xt as c,Yt as ie,at as ae,b as l,d as u,f as d,i as f,lt as oe,m as p,p as m,qt as h,s as se,u as g,v as ce,xt as _,y as v}from"./BxuBMtk_.js";import{c as y}from"./BygIGL69.js";var le={added:`新增`,updated:`状态变更`,removed:`移除`},ue=`更新交付记录`,b=`变更`,x=e=>typeof e==`string`?e.replace(/\s+/g,` `).trim():``;function de(e){let t=Array.isArray(e?.changes)?e.changes:[],n=x(e?.title)||ue,r=t.some(e=>e?.action===`added`)?`feat`:`chore`,i=[];for(let e of t){let t=x(e?.id);if(!t)continue;let n=x(e.title)||x(e.note),r=le[e.action]||x(e.action)||b;e.action===`updated`&&(x(e.from)||x(e.to))&&(r+=` ${x(e.from)||`—`} → ${x(e.to)||`—`}`),i.push(`- ${t}${n?` ${n}`:``}(${r})`)}return i.length?`${r}: ${n}\n\n${i.join(`
|
|
2
|
+
`)}`:`${r}: ${n}`}var S=/(?:^|(?<=[\s。;;::,,))]))(?:\d{1,2}[.)、]|[((]\d{1,2}[))]|[①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳]|[-*•·])\s+/gm,C=/(?<=[。;;])/,w=e=>typeof e==`string`?e.replace(/[\r\n]+/g,` `).replace(/\s{2,}/g,` `).trim():``,T=e=>e.match(S)?.length??0,E=20,D=e=>e.replace(/[;;,,]+$/,``).trim(),O=e=>e.length>1?e.map(D).filter(Boolean):e;function k(e){if(T(e)<2)return[];let t=e.split(S).map(w).filter(Boolean);return t.length>1&&t[0].length<=E&&/[::]$/.test(t[0])&&t.splice(0,2,`${t[0]}${t[1]}`),O(t)}function fe(e){if(Array.isArray(e))return O(e.map(w).filter(Boolean));let t=w(e);if(!t)return[];let n=String(e).split(/\r?\n/).map(w).filter(Boolean);if(n.length>1)return O(n.flatMap(e=>{let t=k(e);return t.length?t:[e]}).filter(Boolean));let r=k(t);if(r.length>1)return r;let i=O(t.split(C).map(w).filter(Boolean));return i.length>1?i:[t]}var pe={class:`rule-top`},me={class:`rule-ic`},he={class:`rule-state`},ge={class:`mono`},_e={key:0},ve={class:`rule-cases`},ye={class:`case-when`},be={class:`case-then`},xe={key:1,class:`lc-hist-bar`},Se={class:`hist-badge`},Ce={class:`hist-readonly mono`},we=[`title`,`disabled`,`onClick`],Te={key:2,class:`card lc-empty`},Ee={class:`em-ic`},De={key:3,class:`lc`},Oe={class:`lc-hero`},ke={class:`hero-body`},Ae={class:`hero-kicker`},je={class:`k-date mono`},Me={key:0,class:`k-time mono`},Ne={key:1,class:`k-today`},Pe=[`title`],Fe={class:`hero-title`},Ie={key:0,class:`hero-points`},Le={key:1,class:`hero-sum`},Re={class:`hero-meta`},ze={class:`hero-aside`},Be={class:`ring-in`},Ve={class:`lc-nav`,"aria-label":`分区导航`},He=[`href`,`onClick`],Ue={class:`lc-nav-lb`},We={class:`lc-nav-ct`},Ge={id:`lc-scenarios`,class:`lc-sc-sec`},Ke={class:`s-hd solo`},qe={class:`s-ic tone-mint`},Je={class:`s-count`},Ye={key:0,class:`dim sec-empty`},Xe={key:1,class:`lc-sc-grid`},Ze={class:`sc-hd`},Qe={class:`sc-id mono`},$e={class:`sc-title`},et={key:0,class:`sc-body`},tt={class:`lc-sc-steps`},nt={class:`sc-acc`},rt={class:`sc-acc-h`},it={class:`sc-acc-t`},at={key:0,class:`sc-foot`},ot={key:0},st={key:1,class:`sc-ids`},ct={key:0,id:`lc-access`,class:`card sec lc-access`},lt={class:`s-hd`},ut={class:`s-ic tone-sky`},dt={class:`s-count`},ft={class:`sec-bd acc-grid`},pt={key:0,class:`acc-col`},mt={class:`u-head`},ht=[`href`],gt={class:`u-label`},_t=[`onClick`],vt={class:`u-url mono`},yt={key:0,class:`u-note`},bt={key:1,class:`acc-col`},xt={class:`a-head`},St={key:0,class:`a-role`},Ct={class:`a-user mono`},wt=[`onClick`],Tt={class:`a-line`},Et={key:0,class:`a-pass mono`},Dt={key:1,class:`a-none dim`},Ot={key:0,class:`a-note`},kt={key:1,id:`lc-prep`,class:`card sec lc-prep`},At={class:`s-hd`},jt={class:`s-ic tone-amber`},Mt={class:`s-count`},Nt={class:`steps`},Pt={class:`step-bd`},Ft={class:`step-text`},It={key:0,class:`cmd-row`},Lt={class:`cmd mono`},Rt=[`onClick`],zt={key:1,class:`step-note`},Bt={id:`lc-changes`,class:`card sec`},Vt={class:`s-hd`},Ht={class:`s-ic`},Ut={class:`s-count`},Wt={key:0,class:`sec-empty dim`},Gt={key:1,class:`tbl-wrap`},Kt={class:`tbl lc-tbl`},qt={class:`ent`},Jt={class:`ent-top`},Yt={key:0,class:`ent-title`},Xt={key:0,class:`flow mono`},Zt={class:`fl`},Qt={class:`fl`},$t={class:`cell-note`},en={class:`chips`},tn=[`title`],nn={key:0,class:`dim`},rn={class:`two`},an={id:`lc-extras`,class:`card sec`},on={class:`s-hd`},sn={class:`s-ic`},cn={class:`s-count`},ln={class:`sec-bd lc-extras`},un={key:0,class:`dim`},dn={class:`x-body`},fn={class:`x-title`},pn={key:0,class:`x-detail`},mn={key:1,class:`chips x-files`},hn=[`title`],gn={id:`lc-checks`,class:`card sec`},_n={class:`s-hd`},vn={class:`s-ic tone-mint`},yn={class:`s-count`},bn={class:`sec-bd lc-checks`},xn={key:0,class:`dim`},Sn={class:`v-body`},Cn={class:`v-what`},wn={key:0,class:`v-detail`},Tn={class:`two`},En={id:`lc-notes`,class:`card sec`},Dn={class:`s-hd`},On={class:`s-ic`},kn={class:`s-count`},An={class:`sec-bd`},jn={key:0,class:`dim`},Mn={key:1,class:`lc-notes`},Nn={key:0,id:`lc-open`,class:`card sec sec-warn`},Pn={class:`s-hd`},Fn={class:`s-ic`},In={class:`s-count`},Ln={class:`sec-bd`},Rn={class:`lc-notes warn`},zn={class:`lc-hist`,role:`dialog`,"aria-modal":`true`,"aria-labelledby":`lc-hist-title`},Bn={class:`lc-hist-hd`},Vn={class:`lc-hist-hd-txt`},Hn={class:`lc-hist-sub`},Un={key:0,class:`lc-hist-err`},Wn={key:1,class:`lc-hist-hint dim`},Gn={key:2,class:`lc-hist-list`},Kn=[`disabled`,`onClick`],qn={class:`hist-item-main`},Jn={class:`mono`},Yn={class:`mono hist-item-hash`},Xn={key:0,class:`lc-hist-hint dim`},Zn={class:`lc-hist-ft`},Qn={class:`lc-hist lc-commit`,role:`dialog`,"aria-modal":`true`,"aria-labelledby":`lc-commit-title`},$n={class:`lc-hist-hd`},er=[`disabled`],tr={key:0,class:`cm-done`},nr={class:`cm-done-ic`},rr={class:`cm-done-bd`},ir={class:`cm-done-t`},ar={class:`mono`},or={class:`cm-done-s`},sr={class:`cm-done-n`},cr={key:1,class:`cm-body`},lr={class:`cm-msg mono`},ur={class:`micro`},dr={key:0,class:`cm-hint dim`},fr={key:1,class:`cm-hint warn`},pr={key:2,class:`cm-hint warn`},mr={key:3,class:`cm-hint dim`},hr={key:4,class:`cm-files`},gr=[`title`],_r={key:2,class:`lc-hist-err`},vr={class:`lc-hist-ft`},yr={class:`dim`},br={class:`cm-acts`},xr=[`disabled`],Sr=[`disabled`],A=r(re({__name:`last-change`,setup(r){let{lastChange:re,lastChangeGit:le,refresh:ue}=i(),b=_(null),x=g(()=>b.value?.doc?.lastChange??re.value),S=g(()=>le.value),C=_([]),w=_(!1),T=_(!1),E=_(``),D=_(!1),O=g(()=>b.value?[b.value]:[]);async function k(){if(!T.value){T.value=!0,E.value=``;try{let e=await n(`/api/agile/last-change/history`);C.value=e.entries??[]}catch(e){E.value=e?.data?.error||e?.message||`读不到 git 历史`}finally{T.value=!1}}}async function A(){w.value=!0,C.value.length||await k()}async function Cr(e){if(!D.value){D.value=!0,E.value=``;try{b.value=await n(`/api/agile/last-change/revision`,{query:{hash:e.hash}}),w.value=!1,window.scrollTo({top:0,behavior:`smooth`})}catch(e){E.value=e?.data?.error||e?.message||`取不到这个版本`}finally{D.value=!1}}}function wr(){b.value=null,window.scrollTo({top:0,behavior:`smooth`})}let Tr=_(null);ae(b,async()=>{await ne(),Tr.value?.querySelector(`.hist-tab.on`)?.scrollIntoView({inline:`nearest`,block:`nearest`})});function Er(e){e.key===`Escape`&&(J.value?$():w.value&&=!1)}ee(()=>window.addEventListener(`keydown`,Er)),te(()=>window.removeEventListener(`keydown`,Er));let Dr={committed:{text:`已提交`,tone:`ok`},dirty:{text:`未提交改动`,tone:`warn`},untracked:{text:`未纳入版本库`,tone:`warn`},"no-git":{text:`非 git 仓库`,tone:`neutral`},missing:{text:`尚未生成`,tone:`neutral`}},j=g(()=>Dr[S.value?.state??`missing`]??Dr.missing),Or=[{key:`committed`,when:`已提交`,then:`下次写入整份覆盖;上一版留在 git 历史里,点「查看历史」随时翻回来`},{key:`pending`,when:`未提交`,then:`下次写入合并:新交付接在旧记录后面,不冲掉还没入库的内容`}],kr=g(()=>{let e=S.value?.state;return e===`committed`?`committed`:e===`dirty`||e===`untracked`||e===`no-git`?`pending`:``}),M=g(()=>fe(x.value?.summary)),Ar=g(()=>(x.value?.mergedFrom?.length??0)+1),jr=g(()=>(x.value?.mergedFrom??[]).map(e=>`${e.at??``} ${e.title??``}`.trim()).filter(Boolean).join(`
|
|
3
|
+
`)),Mr={added:`新增`,updated:`状态变更`,removed:`移除`},Nr={story:`故事`,task:`任务`},Pr={pass:`通过`,fail:`失败`,partial:`部分`,skipped:`未跑`},Fr={pass:`i-lucide-check`,fail:`i-lucide-x`,partial:`i-lucide-minus`,skipped:`i-lucide-minus`},N=g(()=>x.value?.changes??[]),P=g(()=>de(x.value??{})),F=g(()=>x.value?.extras??[]),I=g(()=>x.value?.verification??[]),L=g(()=>x.value?.scenarios??[]),R=g(()=>x.value?.preparation??[]),z=g(()=>x.value?.notes??[]),B=g(()=>x.value?.open??[]),V=g(()=>x.value?.access?.urls??[]),H=g(()=>x.value?.access?.accounts??[]),U=g(()=>I.value.filter(e=>e.result===`pass`).length),Ir=g(()=>I.value.length>0&&U.value===I.value.length),Lr=g(()=>I.value.length?Math.round(U.value/I.value.length*100):0),Rr=g(()=>[...new Set([...N.value.flatMap(e=>e.files??[]),...F.value.flatMap(e=>e.files??[])])]),zr=e=>e.kind===`story`?e.id:e.id.replace(/-T\d+$/,``),Br=g(()=>[{id:`lc-scenarios`,label:`测试场景`,icon:`i-lucide-flask-conical`,count:`${L.value.length}`,tone:`teal`},...V.value.length||H.value.length?[{id:`lc-access`,label:`调试入口与账号`,icon:`i-lucide-key-round`,count:`${V.value.length+H.value.length}`,tone:`sky`}]:[],...R.value.length?[{id:`lc-prep`,label:`测试前准备`,icon:`i-lucide-terminal-square`,count:`${R.value.length}`,tone:`amber`}]:[],{id:`lc-changes`,label:`变更清单`,icon:`i-lucide-git-commit-horizontal`,count:`${N.value.length}`,tone:`violet`},{id:`lc-extras`,label:`额外做的事`,icon:`i-lucide-sparkles`,count:`${F.value.length}`,tone:`peach`},{id:`lc-checks`,label:`验证结果`,icon:`i-lucide-badge-check`,count:`${U.value}/${I.value.length}`,tone:`mint`},{id:`lc-notes`,label:`说明`,icon:`i-lucide-message-square-more`,count:`${z.value.length}`,tone:`slate`},...B.value.length?[{id:`lc-open`,label:`还没做的`,icon:`i-lucide-list-todo`,count:`${B.value.length}`,tone:`rose`}]:[]]);function Vr(e){let t=document.getElementById(e);t&&(t.scrollIntoView({behavior:`smooth`,block:`start`}),history.replaceState(null,``,`#${e}`))}let W=new Date,Hr=`${W.getFullYear()}-${String(W.getMonth()+1).padStart(2,`0`)}-${String(W.getDate()).padStart(2,`0`)}`,G=g(()=>(x.value?.at??``).slice(0,10)),Ur=g(()=>{let e=(x.value?.at??``).slice(10).replace(/^[T ]/,``);return/^\d{2}:\d{2}/.test(e)?e:``}),Wr=g(()=>!!G.value&&G.value===Hr),K=_(``);async function q(e,t){try{await navigator.clipboard.writeText(e),K.value=t,setTimeout(()=>{K.value===t&&(K.value=``)},1600)}catch{K.value=``}}let J=_(!1),Y=_(!1),X=_(``),Z=_(null),Q=_(null),Gr=g(()=>!!Z.value?.isRepo&&!Z.value?.blocked&&(Z.value?.files.length??0)>0&&!Y.value);async function Kr(){if(!Y.value){J.value=!0,X.value=``,Q.value=null,Z.value=null;try{Z.value=await n(`/api/agile/git/status`)}catch(e){X.value=e?.data?.error||e?.message||`读不到 git 状态`}}}function $(){Y.value||(J.value=!1,X.value=``,Q.value=null,Z.value=null)}async function qr(){if(Gr.value){Y.value=!0,X.value=``;try{let{token:e}=await n(`/api/projects`);Q.value=await n(`/api/agile/git/commit`,{method:`POST`,headers:{"x-project-token":e},body:{message:P.value}}),await ue()}catch(e){X.value=e?.data?.error||e?.message||`提交失败`}finally{Y.value=!1}}}return(n,r)=>{let i=e,ee=t;return s(),p(f,null,[a(b)?(s(),p(`div`,xe,[u(`span`,Se,[l(i,{name:`i-lucide-history`,class:`hist-badge-ic`}),r[8]||=v(`历史版本`,-1)]),u(`span`,Ce,[v(`只读 · `+c(a(b).short),1),a(b).date?(s(),p(f,{key:0},[v(` · `+c(a(b).date),1)],64)):m(``,!0)]),u(`div`,{ref_key:`tabsRef`,ref:Tr,class:`lc-hist-tabs`},[u(`button`,{class:`hist-tab`,onClick:wr},`最新`),(s(!0),p(f,null,o(a(O),e=>(s(),p(`button`,{key:e.hash,class:h([`hist-tab`,{on:a(b)?.hash===e.hash}]),title:`${e.date} ${e.subject??``}`,disabled:a(D),onClick:t=>Cr(e)},[v(c(e.short),1),u(`i`,null,c(e.date.slice(5,16)),1)],10,we))),128))],512),u(`button`,{class:`rule-btn`,onClick:A},[l(i,{name:`i-lucide-list`,class:`rule-btn-ic`}),r[9]||=v(`选择历史…`,-1)])])):(s(),p(`div`,{key:0,class:h([`lc-rule`,`is-${a(j).tone}`])},[u(`div`,pe,[u(`span`,me,[l(i,{name:`i-lucide-git-branch`,class:`rule-svg`})]),r[6]||=u(`b`,{class:`rule-title`},`写入规则`,-1),r[7]||=u(`span`,{class:`rule-file mono`},`agile/last-change.json`,-1),u(`span`,he,[u(`i`,{class:h([`rule-dot`,`tone-${a(j).tone}`])},null,2),v(` 当前 `+c(a(j).text),1),a(S)?.state===`committed`&&a(S).hash?(s(),p(f,{key:0},[r[4]||=v(` · `,-1),u(`span`,ge,c(a(S).hash),1)],64)):m(``,!0)]),u(`button`,{class:`rule-btn`,onClick:A},[l(i,{name:`i-lucide-history`,class:`rule-btn-ic`}),r[5]||=v(`查看历史 `,-1),a(C).length?(s(),p(`i`,_e,c(a(C).length),1)):m(``,!0)])]),u(`ul`,ve,[(s(),p(f,null,o(Or,e=>u(`li`,{key:e.key,class:h([`rule-case`,{on:a(kr)===e.key}])},[u(`span`,ye,c(e.when),1),l(i,{name:`i-lucide-arrow-right`,class:`case-arrow`}),u(`span`,be,c(e.then),1)],2)),64))])],2)),a(x)?(s(),p(`div`,De,[u(`header`,Oe,[u(`div`,ke,[u(`p`,Ae,[r[11]||=u(`span`,{class:`k-dot`},null,-1),r[12]||=v(`最近一次交付 `,-1),r[13]||=u(`span`,{class:`k-sep`},null,-1),u(`span`,je,c(a(G)),1),a(Ur)?(s(),p(`span`,Me,c(a(Ur)),1)):m(``,!0),a(Wr)?(s(),p(`span`,Ne,`今天`)):m(``,!0),a(x).merged?(s(),p(`span`,{key:2,class:`k-merged`,title:a(jr)},`合并记录 · `+c(a(Ar))+` 次交付`,9,Pe)):m(``,!0)]),u(`h2`,Fe,c(a(x).title),1),a(M).length>1?(s(),p(`ol`,Ie,[(s(!0),p(f,null,o(a(M),(e,t)=>(s(),p(`li`,{key:t},c(e),1))),128))])):a(M).length?(s(),p(`p`,Le,c(a(M)[0]),1)):m(``,!0),u(`div`,Re,[u(`span`,null,[u(`b`,null,c(a(N).length),1),r[14]||=v(` 处变更`,-1)]),r[19]||=u(`i`,{class:`meta-sep`},null,-1),u(`span`,null,[u(`b`,null,c(a(Rr).length),1),r[15]||=v(` 个文件`,-1)]),r[20]||=u(`i`,{class:`meta-sep`},null,-1),u(`span`,null,[u(`b`,null,c(a(L).length),1),r[16]||=v(` 条测试场景`,-1)]),a(F).length?(s(),p(f,{key:0},[r[18]||=u(`i`,{class:`meta-sep`},null,-1),u(`span`,null,[u(`b`,null,c(a(F).length),1),r[17]||=v(` 项额外工作`,-1)])],64)):m(``,!0)])]),u(`div`,ze,[u(`div`,{class:h([`ring`,{warn:a(I).length&&!a(Ir)}]),style:ie({"--pct":a(Lr)})},[u(`div`,Be,[u(`b`,null,[v(c(a(U)),1),u(`small`,null,`/`+c(a(I).length||0),1)]),u(`span`,null,c(a(I).length?a(Ir)?`验证全通过`:`有未通过项`:`无验证记录`),1)])],6)])]),u(`nav`,Ve,[(s(!0),p(f,null,o(a(Br),e=>(s(),p(`a`,{key:e.id,class:h([`lc-nav-link`,`tone-${e.tone}`]),href:`#${e.id}`,onClick:y(t=>Vr(e.id),[`prevent`])},[l(i,{name:e.icon,class:`lc-nav-ic`},null,8,[`name`]),u(`span`,Ue,c(e.label),1),u(`b`,We,c(e.count),1)],10,He))),128))]),u(`section`,Ge,[u(`div`,Ke,[u(`span`,qe,[l(i,{name:`i-lucide-flask-conical`,class:`s-svg`})]),r[21]||=u(`h2`,{class:`s-title`},`测试场景`,-1),u(`span`,Je,c(a(L).length),1),r[22]||=u(`span`,{class:`s-hint`},`一条一段:照着步骤走,末尾那句就是验收标准`,-1)]),a(L).length?(s(),p(`div`,Xe,[(s(!0),p(f,null,o(a(L),(e,t)=>(s(),p(`article`,{key:e.id??t,class:`sc lc-sc`},[u(`header`,Ze,[u(`span`,Qe,c(e.id??`TC-${t+1}`),1),u(`h3`,$e,c(e.title),1)]),e.steps?.length?(s(),p(`div`,et,[r[23]||=u(`p`,{class:`micro`},`测试步骤`,-1),u(`ol`,tt,[(s(!0),p(f,null,o(e.steps,(e,t)=>(s(),p(`li`,{key:t},c(e),1))),128))])])):m(``,!0),u(`div`,nt,[u(`p`,rt,[l(i,{name:`i-lucide-badge-check`,class:`sc-acc-ic`}),r[24]||=v(`验收标准`,-1)]),u(`p`,it,c(e.expect),1),e.acceptance||e.storyIds?.length?(s(),p(`div`,at,[e.acceptance?(s(),p(`span`,ot,`对应验收:`+c(e.acceptance),1)):m(``,!0),e.storyIds?.length?(s(),p(`span`,st,[(s(!0),p(f,null,o(e.storyIds,e=>(s(),d(ee,{key:e,to:`/story/${e}`,class:`ent-id mono`},{default:oe(()=>[v(c(e),1)]),_:2},1032,[`to`]))),128))])):m(``,!0)])):m(``,!0)])]))),128))])):(s(),p(`p`,Ye,`这次没有单独列测试场景。`))]),a(V).length||a(H).length?(s(),p(`section`,ct,[u(`div`,lt,[u(`span`,ut,[l(i,{name:`i-lucide-key-round`,class:`s-svg`})]),r[25]||=u(`h2`,{class:`s-title`},`调试入口与账号`,-1),u(`span`,dt,c(a(V).length+a(H).length),1),r[26]||=u(`span`,{class:`s-hint`},`照着这一栏就能自己跑起来点一遍`,-1)]),u(`div`,ft,[a(V).length?(s(),p(`div`,pt,[r[27]||=u(`p`,{class:`micro`},`访问地址`,-1),(s(!0),p(f,null,o(a(V),(e,t)=>(s(),p(`div`,{key:t,class:`u-item`},[u(`div`,mt,[u(`a`,{href:e.url,target:`_blank`,rel:`noreferrer`,class:`u-link`},[u(`span`,gt,c(e.label??`入口`),1),l(i,{name:`i-lucide-arrow-up-right`,class:`u-go`})],8,ht),u(`button`,{class:h([`cpy`,{ok:a(K)===`url-${t}`}]),onClick:n=>q(e.url,`url-${t}`)},[l(i,{name:a(K)===`url-${t}`?`i-lucide-check`:`i-lucide-copy`,class:`cpy-ic`},null,8,[`name`]),v(` `+c(a(K)===`url-${t}`?`已复制`:`复制`),1)],10,_t)]),u(`p`,vt,c(e.url),1),e.note?(s(),p(`p`,yt,c(e.note),1)):m(``,!0)]))),128))])):m(``,!0),a(H).length?(s(),p(`div`,bt,[r[29]||=u(`p`,{class:`micro`},`账号密码`,-1),(s(!0),p(f,null,o(a(H),(e,t)=>(s(),p(`div`,{key:t,class:`a-item`},[u(`div`,xt,[e.role?(s(),p(`span`,St,c(e.role),1)):m(``,!0),u(`span`,Ct,c(e.username),1),u(`button`,{class:h([`cpy`,{ok:a(K)===`acc-${t}`}]),onClick:n=>q(e.password?`账号:${e.username}\n密码:${e.password}`:e.username,`acc-${t}`)},[l(i,{name:a(K)===`acc-${t}`?`i-lucide-check`:`i-lucide-copy`,class:`cpy-ic`},null,8,[`name`]),v(` `+c(a(K)===`acc-${t}`?`已复制`:`复制`),1)],10,wt)]),u(`div`,Tt,[r[28]||=u(`span`,{class:`a-key`},`密码`,-1),e.password?(s(),p(`span`,Et,c(e.password),1)):(s(),p(`span`,Dt,`无密码 / 走单点登录`))]),e.note?(s(),p(`p`,Ot,c(e.note),1)):m(``,!0)]))),128))])):m(``,!0)])])):m(``,!0),a(R).length?(s(),p(`section`,kt,[u(`div`,At,[u(`span`,jt,[l(i,{name:`i-lucide-terminal-square`,class:`s-svg`})]),r[30]||=u(`h2`,{class:`s-title`},`测试前准备`,-1),u(`span`,Mt,c(a(R).length),1),r[31]||=u(`span`,{class:`s-hint`},`按顺序做完这些再开始点,命令可直接复制`,-1)]),u(`ol`,Nt,[(s(!0),p(f,null,o(a(R),(e,t)=>(s(),p(`li`,{key:t},[u(`div`,Pt,[u(`p`,Ft,c(e.step),1),e.command?(s(),p(`div`,It,[u(`code`,Lt,c(e.command),1),u(`button`,{class:h([`cpy`,{ok:a(K)===`cmd-${t}`}]),onClick:n=>q(e.command??``,`cmd-${t}`)},[l(i,{name:a(K)===`cmd-${t}`?`i-lucide-check`:`i-lucide-copy`,class:`cpy-ic`},null,8,[`name`]),v(` `+c(a(K)===`cmd-${t}`?`已复制`:`复制`),1)],10,Rt)])):m(``,!0),e.note?(s(),p(`p`,zt,c(e.note),1)):m(``,!0)])]))),128))])])):m(``,!0),u(`section`,Bt,[u(`div`,Vt,[u(`span`,Ht,[l(i,{name:`i-lucide-git-commit-horizontal`,class:`s-svg`})]),r[33]||=u(`h2`,{class:`s-title`},`变更清单`,-1),u(`span`,Ut,c(a(N).length),1),r[34]||=u(`span`,{class:`s-hint`},`故事与任务各自是新增还是状态变更、动过哪些文件`,-1),a(N).length?(s(),p(`button`,{key:0,class:h([`rule-btn s-copy`,{ok:a(K)===`commit`}]),title:`按 Conventional Commits 生成:首行是标题,正文每条变更带编号与名称`,onClick:r[0]||=e=>q(a(P),`commit`)},[l(i,{name:a(K)===`commit`?`i-lucide-check`:`i-lucide-clipboard-copy`,class:`rule-btn-ic`},null,8,[`name`]),v(` `+c(a(K)===`commit`?`已复制`:`复制变更信息`),1)],2)):m(``,!0),!a(b)&&a(N).length?(s(),p(`button`,{key:1,class:`rule-btn s-commit`,title:`把这次交付整份提交进本地仓库:git add -A + git commit,不 push`,onClick:Kr},[l(i,{name:`i-lucide-git-commit-vertical`,class:`rule-btn-ic`}),r[32]||=v(`自动提交 `,-1)])):m(``,!0)]),a(N).length?(s(),p(`div`,Gt,[u(`table`,Kt,[r[36]||=u(`colgroup`,null,[u(`col`,{class:`c-ent`}),u(`col`,{class:`c-act`}),u(`col`),u(`col`,{class:`c-file`})],-1),r[37]||=u(`thead`,null,[u(`tr`,null,[u(`th`,null,`条目`),u(`th`,null,`变更`),u(`th`,null,`变更内容`),u(`th`,null,`涉及文件`)])],-1),u(`tbody`,null,[(s(!0),p(f,null,o(a(N),(e,t)=>(s(),p(`tr`,{key:`${e.kind}-${e.id}-${t}`},[u(`td`,null,[u(`div`,qt,[u(`div`,Jt,[u(`span`,{class:h([`kind`,`kind-${e.kind}`])},c(Nr[e.kind]??e.kind),3),l(ee,{to:`/story/${zr(e)}`,class:`ent-id mono`},{default:oe(()=>[v(c(e.id),1)]),_:2},1032,[`to`])]),e.title?(s(),p(`p`,Yt,c(e.title),1)):m(``,!0)])]),u(`td`,null,[u(`span`,{class:h([`act`,`act-${e.action}`])},c(Mr[e.action]??e.action),3),e.from||e.to?(s(),p(`p`,Xt,[u(`span`,Zt,c(e.from??`—`),1),r[35]||=u(`i`,null,`→`,-1),u(`span`,Qt,c(e.to??`—`),1)])):m(``,!0)]),u(`td`,$t,c(e.note??`—`),1),u(`td`,null,[u(`div`,en,[(s(!0),p(f,null,o(e.files,e=>(s(),p(`span`,{key:e,class:`fchip mono`,title:e},c(e),9,tn))),128)),e.files?.length?m(``,!0):(s(),p(`span`,nn,`—`))])])]))),128))])])])):(s(),p(`p`,Wt,`这次没有涉及任何故事或任务。`))]),u(`div`,rn,[u(`section`,an,[u(`div`,on,[u(`span`,sn,[l(i,{name:`i-lucide-sparkles`,class:`s-svg`})]),r[38]||=u(`h2`,{class:`s-title`},`额外做的事`,-1),u(`span`,cn,c(a(F).length),1)]),u(`div`,ln,[a(F).length?m(``,!0):(s(),p(`p`,un,`没有计划外的改动。`)),(s(!0),p(f,null,o(a(F),(e,t)=>(s(),p(`article`,{key:t,class:`x-item`},[r[39]||=u(`span`,{class:`x-mark`},null,-1),u(`div`,dn,[u(`p`,fn,c(e.title),1),e.detail?(s(),p(`p`,pn,c(e.detail),1)):m(``,!0),e.files?.length?(s(),p(`div`,mn,[(s(!0),p(f,null,o(e.files,e=>(s(),p(`span`,{key:e,class:`fchip mono`,title:e},c(e),9,hn))),128))])):m(``,!0)])]))),128))])]),u(`section`,gn,[u(`div`,_n,[u(`span`,vn,[l(i,{name:`i-lucide-badge-check`,class:`s-svg`})]),r[40]||=u(`h2`,{class:`s-title`},`验证结果`,-1),u(`span`,yn,c(a(U))+`/`+c(a(I).length),1)]),u(`div`,bn,[a(I).length?m(``,!0):(s(),p(`p`,xn,`这次没有留下验证记录。`)),(s(!0),p(f,null,o(a(I),(e,t)=>(s(),p(`div`,{key:t,class:`v-item`},[u(`span`,{class:h([`v-ic`,`v-${e.result}`])},[l(i,{name:Fr[e.result]??`i-lucide-circle`,class:`v-svg`},null,8,[`name`])],2),u(`div`,Sn,[u(`p`,Cn,c(e.what),1),e.detail?(s(),p(`p`,wn,c(e.detail),1)):m(``,!0)]),u(`span`,{class:h([`v-res`,`v-${e.result}`])},c(Pr[e.result]??e.result),3)]))),128))])])]),u(`div`,Tn,[u(`section`,En,[u(`div`,Dn,[u(`span`,On,[l(i,{name:`i-lucide-message-square-more`,class:`s-svg`})]),r[41]||=u(`h2`,{class:`s-title`},`说明`,-1),u(`span`,kn,c(a(z).length),1)]),u(`div`,An,[a(z).length?(s(),p(`ul`,Mn,[(s(!0),p(f,null,o(a(z),(e,t)=>(s(),p(`li`,{key:t},c(e),1))),128))])):(s(),p(`p`,jn,`没有额外说明。`))])]),a(B).length?(s(),p(`section`,Nn,[u(`div`,Pn,[u(`span`,Fn,[l(i,{name:`i-lucide-list-todo`,class:`s-svg`})]),r[42]||=u(`h2`,{class:`s-title`},`还没做的`,-1),u(`span`,In,c(a(B).length),1)]),u(`div`,Ln,[u(`ul`,Rn,[(s(!0),p(f,null,o(a(B),(e,t)=>(s(),p(`li`,{key:t},c(e),1))),128))])])])):m(``,!0)])])):(s(),p(`div`,Te,[u(`span`,Ee,[l(i,{name:`i-lucide-clipboard-list`,class:`em-svg`})]),r[10]||=ce(`<h2 class="em-title" data-v-0de58a93>还没有交付记录</h2><p class="em-sub" data-v-0de58a93> 每完成一项功能,AI 都要把「改了哪些故事与任务、额外做了什么、验了什么、怎么测」 写进下面这个文件,这一页就会自动排出来。 </p><p class="em-path mono" data-v-0de58a93>agile/last-change.json</p><p class="em-note" data-v-0de58a93> 每次只保留最近一次(覆盖写,不追加)· 格式见 <span class="mono" data-v-0de58a93>.agents/skills/scrum-planning/references/schema.md</span> 第 4 节 </p>`,4)])),(s(),d(se,{to:`body`},[a(w)?(s(),p(`div`,{key:0,class:`lc-hist-mask`,onClick:r[3]||=y(e=>w.value=!1,[`self`])},[u(`div`,zn,[u(`header`,Bn,[u(`div`,Vn,[r[46]||=u(`h3`,{id:`lc-hist-title`,class:`lc-hist-title`},`历史版本`,-1),u(`p`,Hn,[r[43]||=v(` 从 git 里读 `,-1),r[44]||=u(`span`,{class:`mono`},`agile/last-change.json`,-1),r[45]||=v(` 的提交记录 `,-1),a(C).length?(s(),p(f,{key:0},[v(`· 共 `+c(a(C).length)+` 版`,1)],64)):m(``,!0)])]),u(`button`,{class:`lc-hist-x`,"aria-label":`关闭`,onClick:r[1]||=e=>w.value=!1},[l(i,{name:`i-lucide-x`,class:`lc-hist-x-ic`})])]),a(E)?(s(),p(`p`,Un,c(a(E)),1)):a(T)?(s(),p(`div`,Wn,`正在读 git 历史…`)):(s(),p(`div`,Gn,[(s(!0),p(f,null,o(a(C),(e,t)=>(s(),p(`button`,{key:e.hash,class:h([`hist-item`,{on:a(b)?.hash===e.hash}]),disabled:a(D),onClick:t=>Cr(e)},[u(`span`,{class:h([`hist-item-dot`,{live:t===0}])},null,2),u(`span`,qn,[u(`b`,null,c(e.subject||`(没有提交说明)`),1),u(`i`,Jn,c(e.date),1)]),u(`span`,Yn,c(e.short),1)],10,Kn))),128)),a(C).length?m(``,!0):(s(),p(`p`,Xn,` 这个文件还没有提交记录 —— 先 commit 一次,历史里才会出现版本。 `))])),u(`footer`,Zn,[r[47]||=u(`span`,{class:`dim`},`选一个版本即可在页面上只读查看,不会改动文件。`,-1),u(`button`,{class:`hist-close`,onClick:r[2]||=e=>w.value=!1},`关闭`)])])])):m(``,!0)])),(s(),d(se,{to:`body`},[a(J)?(s(),p(`div`,{key:0,class:`lc-hist-mask`,onClick:y($,[`self`])},[u(`div`,Qn,[u(`header`,$n,[r[48]||=u(`div`,{class:`lc-hist-hd-txt`},[u(`h3`,{id:`lc-commit-title`,class:`lc-hist-title`},`提交这次交付`),u(`p`,{class:`lc-hist-sub`},[v(` 将执行 `),u(`span`,{class:`mono`},`git add -A`),v(` + `),u(`span`,{class:`mono`},`git commit`),v(`,只提交到本地,不 push `)])],-1),u(`button`,{class:`lc-hist-x`,"aria-label":`关闭`,disabled:a(Y),onClick:$},[l(i,{name:`i-lucide-x`,class:`lc-hist-x-ic`})],8,er)]),a(Q)?(s(),p(`div`,tr,[u(`span`,nr,[l(i,{name:`i-lucide-check`,class:`cm-done-svg`})]),u(`div`,rr,[u(`p`,ir,[r[49]||=v(`已提交 `,-1),u(`span`,ar,c(a(Q).hash),1)]),u(`p`,or,c(a(Q).subject),1),u(`p`,sr,c(a(Q).files)+` 个文件 · 分支 `+c(a(Q).branch??`分离头指针`),1)])])):(s(),p(`div`,cr,[r[51]||=u(`p`,{class:`micro`},`提交信息`,-1),u(`pre`,lr,c(a(P)),1),u(`p`,ur,[r[50]||=v(` 将提交的文件`,-1),a(Z)?(s(),p(f,{key:0},[v(` · `+c(a(Z).files.length),1)],64)):m(``,!0)]),!a(Z)&&!a(X)?(s(),p(`p`,dr,`正在读 git 状态…`)):a(Z)&&!a(Z).isRepo?(s(),p(`p`,fr,`这个目录不是 git 仓库,没法自动提交。`)):a(Z)?.blocked?(s(),p(`p`,pr,c(a(Z).blocked),1)):a(Z)?.files.length?(s(),p(`ul`,hr,[(s(!0),p(f,null,o(a(Z).files,e=>(s(),p(`li`,{key:e.path,class:`cm-file`},[u(`span`,{class:h([`cm-code`,e.code===`??`?`cm-new`:`cm-mod`])},c(e.code),3),u(`span`,{class:`mono cm-path`,title:e.path},c(e.path),9,gr)]))),128))])):(s(),p(`p`,mr,`没有未提交的改动,不需要提交。`))])),a(X)?(s(),p(`p`,_r,c(a(X)),1)):m(``,!0),u(`footer`,vr,[u(`span`,yr,c(a(Z)?.branch?`当前分支 ${a(Z).branch}`:`提交后工作区应当是干净的`),1),u(`span`,br,[u(`button`,{class:`hist-close`,disabled:a(Y),onClick:$},c(a(Q)?`关闭`:`取消`),9,xr),a(Q)?m(``,!0):(s(),p(`button`,{key:0,class:`cm-go`,disabled:!a(Gr),onClick:qr},c(a(Y)?`提交中…`:`确认提交`),9,Sr))])])])])):m(``,!0)]))],64)}}}),[[`__scopeId`,`data-v-0de58a93`]]);export{A as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./DJM7u8P3.js";import{t}from"./CI0scS-N.js";import{c as n,d as r,f as i,h as a,i as o,l as ee,m as s,p as te,s as c,t as l,u}from"#entry";import{At as d,B as f,I as p,K as m,N as ne,S as h,U as g,Xt as _,Yt as v,at as y,b,d as x,f as re,gt as ie,i as S,lt as ae,m as C,p as w,qt as T,u as E,ut as oe,v as se,xt as D,y as O,yt as ce}from"./BxuBMtk_.js";import{a as le,c as k,o as ue,s as de}from"./BygIGL69.js";var fe={class:`diagrams-page`},pe={key:0,class:`callout soft`},me={key:1,class:`dg-layout`},he={class:`dg-list`},ge={class:`dg-head`},_e={class:`dg-total mono`},ve={class:`dg-filter`},ye={class:`dg-tree`},be=[`aria-expanded`,`onClick`],xe={class:`dg-group-lb`},Se={class:`dg-group-n mono`},Ce={class:`dg-items`},we=[`onClick`,`onKeydown`],Te={class:`dg-name`},Ee={class:`mono`},De={key:0,class:`tag tag-warning`},Oe={key:0,class:`foot dim`},ke={class:`dg-main`},Ae={class:`dg-main-hd`},je={class:`dg-h2`},Me={class:`tag tag-neutral`},Ne={key:0,class:`tag tag-warning`,title:`图的更新时间早于故事最后一次测试通过`},Pe={class:`dim tip mono`},Fe=[`href`],Ie=
|
|
1
|
+
import{t as e}from"./DJM7u8P3.js";import{t}from"./CI0scS-N.js";import{c as n,d as r,f as i,h as a,i as o,l as ee,m as s,p as te,s as c,t as l,u}from"#entry";import{At as d,B as f,I as p,K as m,N as ne,S as h,U as g,Xt as _,Yt as v,at as y,b,d as x,f as re,gt as ie,i as S,lt as ae,m as C,p as w,qt as T,u as E,ut as oe,v as se,xt as D,y as O,yt as ce}from"./BxuBMtk_.js";import{a as le,c as k,o as ue,s as de}from"./BygIGL69.js";var fe={class:`diagrams-page`},pe={key:0,class:`callout soft`},me={key:1,class:`dg-layout`},he={class:`dg-list`},ge={class:`dg-head`},_e={class:`dg-total mono`},ve={class:`dg-filter`},ye={class:`dg-tree`},be=[`aria-expanded`,`onClick`],xe={class:`dg-group-lb`},Se={class:`dg-group-n mono`},Ce={class:`dg-items`},we=[`onClick`,`onKeydown`],Te={class:`dg-name`},Ee={class:`mono`},De={key:0,class:`tag tag-warning`},Oe={key:0,class:`foot dim`},ke={class:`dg-main`},Ae={class:`dg-main-hd`},je={class:`dg-h2`},Me={class:`tag tag-neutral`},Ne={key:0,class:`tag tag-warning`,title:`图的更新时间早于故事最后一次测试通过`},Pe={class:`dim tip mono`},Fe=[`href`],Ie={class:`dg-meta`},Le={key:0},Re={key:1,class:`dim`},ze={class:`dg-tags`},Be={key:1,class:`dim`},Ve=[`href`],He={key:3,class:`dim`},Ue=[`disabled`],We={class:`mono dim dg-path`},Ge=[`src`,`alt`],Ke={key:1,class:`dg-canvas-hint dim`},qe={class:`dg-zoom`},Je={class:`dg-zval mono`},Ye=[`src`,`title`],A=o(h({__name:`diagrams`,setup(o){let h=l(),{diagrams:A,staleDiagrams:Xe,storyById:Ze,md:Qe,DIAGRAM_KINDS:$e,DIAGRAM_KIND_LABEL:j,DIAGRAM_KIND_ICON:et,DIAGRAM_KIND_DOT:tt}=c(),M=D(``),N=D(!1),P=D(``),F=()=>{let e=h.value?.query?.focus;typeof e==`string`&&e&&(P.value=e)};F(),y(()=>h.value?.query?.focus,F),y(()=>h.value?.path,F);let I=E(()=>u(A.value,{keyword:M.value,onlyStale:N.value,stale:Xe.value})),L=ce({}),nt=e=>{L[e]=!L[e]},rt=E(()=>{let e=new Map;for(let t of I.value){let n=e.get(t.kind);n?n.push(t):e.set(t.kind,[t])}return $e.filter(t=>e.has(t)).map(t=>({key:t,label:j[t],color:tt[t],items:e.get(t)??[]}))}),R=E(()=>I.value.find(e=>e.id===P.value)??I.value[0]??null);y(I,e=>{e.length&&(e.some(e=>e.id===P.value)||(P.value=e[0].id))},{immediate:!0});let it=e=>Xe.value.has(e),at=e=>`/api/agile/diagram?id=${encodeURIComponent(e)}`,z=e=>`/api/agile/diagram?id=${encodeURIComponent(e)}&format=svg`,ot=e=>{let t=/^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?)$/.exec(e??``);return t?`${t[1]} / ${t[2]}`:`3 / 2`},st=e=>e.map(e=>Ze.value.get(e)).filter(Boolean),B=D(null),V=D({w:0,h:0}),H=D({scale:1,x:0,y:0}),U=D(1),W=D(``),G=D(!1),K=D(!1),ct=E(()=>s(H.value.scale)),q=E(()=>!!R.value?.svg&&!G.value),J=new Map,Y=null,X=()=>{let e=B.value;if(!e||!V.value.w||!V.value.h)return;let t=r(V.value,{width:e.clientWidth,height:e.clientHeight});H.value=t,U.value=t.scale},lt=async e=>{if(!e?.svg){W.value=``,G.value=!0;return}W.value=``;let t=J.get(e.id);if(t)W.value=t.url,V.value={w:t.w,h:t.h},G.value=!1,await ne(),X();else try{let t=await fetch(z(e.id)).then(e=>{if(!e.ok)throw Error(String(e.status));return e.text()}),n=/viewBox="([-\d.\s,]+)"/i.exec(t)?.[1]?.trim().split(/[\s,]+/).map(Number),r=n&&n[2]||1200,i=n&&n[3]||800,a=URL.createObjectURL(new Blob([t],{type:`image/svg+xml;charset=utf-8`}));J.set(e.id,{url:a,w:r,h:i}),W.value=a,V.value={w:r,h:i},G.value=!1,await ne(),X()}catch{W.value=``,G.value=!0}},ut=e=>{if(!q.value||!V.value.w)return;let t=B.value?.getBoundingClientRect();if(!t)return;let r=n(H.value.scale*Math.exp(-e.deltaY*.0015),U.value);r!==H.value.scale&&(H.value=a(H.value,r,{x:e.clientX-t.left,y:e.clientY-t.top}))},dt=e=>{let t=B.value;if(!t)return;let r=n(H.value.scale*e,U.value);H.value=a(H.value,r,{x:t.clientWidth/2,y:t.clientHeight/2})},ft=e=>{q.value&&(e.target?.closest?.(`.dg-zoom`)||(K.value=!0,Y={x:e.clientX,y:e.clientY,vx:H.value.x,vy:H.value.y},e.currentTarget.setPointerCapture?.(e.pointerId)))},pt=e=>{Y&&(H.value={...H.value,x:Y.vx+(e.clientX-Y.x),y:Y.vy+(e.clientY-Y.y)})},Z=e=>{if(Y){Y=null,K.value=!1;try{e.currentTarget.releasePointerCapture?.(e.pointerId)}catch{}}};y(()=>R.value?.id,()=>lt(R.value)),f(()=>lt(R.value));let Q,mt=()=>{!Q&&B.value&&typeof ResizeObserver<`u`&&(Q=new ResizeObserver(()=>{Math.abs(H.value.scale-U.value)<.001&&X()}),Q.observe(B.value))};f(mt),y(B,()=>mt()),p(()=>{Q?.disconnect(),Q=void 0;for(let e of J.values())URL.revokeObjectURL(e.url);J.clear()});let $=D(``),ht=async e=>{if(!$.value){$.value=e.id;try{let t=await fetch(z(e.id)).then(e=>{if(!e.ok)throw Error(`取不到 SVG(${e.status})`);return e.text()}),n=i(t),r=n?.[2]||1200,a=n?.[3]||800,o=ee(r,a),s=Math.round(r*o),c=Math.round(a*o),l=URL.createObjectURL(new Blob([te(t,s,c)],{type:`image/svg+xml;charset=utf-8`})),u=new Image;await new Promise((e,t)=>{u.onload=()=>e(),u.onerror=()=>t(Error(`SVG 无法加载`)),u.src=l});let d=document.createElement(`canvas`);d.width=s,d.height=c;let f=d.getContext(`2d`);if(!f)throw Error(`拿不到 canvas 上下文`);f.fillStyle=`#ffffff`,f.fillRect(0,0,s,c),f.drawImage(u,0,0,s,c),URL.revokeObjectURL(l);let p=await new Promise(e=>d.toBlob(e,`image/png`));if(!p)throw Error(`PNG 编码失败`);let m=document.createElement(`a`);m.href=URL.createObjectURL(p),m.download=`${e.id}-${e.title||`diagram`}.png`,m.click(),setTimeout(()=>URL.revokeObjectURL(m.href),1e3)}catch(e){alert(`导出 PNG 失败:${e.message}。可以先「下载 SVG」。`)}finally{$.value=``}}};return(n,r)=>{let i=e,a=t;return g(),C(`div`,fe,[d(A).length?(g(),C(`div`,me,[x(`aside`,he,[x(`div`,ge,[r[7]||=x(`h2`,{class:`dg-title`},`图例`,-1),x(`span`,_e,_(d(I).length),1),b(a,{to:`/tests`,class:`dim tip dg-head-link`},{default:ae(()=>[...r[6]||=[O(`看测试用例 →`,-1)]]),_:1})]),x(`div`,ve,[oe(x(`input`,{"onUpdate:modelValue":r[0]||=e=>ie(M)?M.value=e:null,class:`input`,placeholder:`搜标题 / 摘要 / 故事`,"aria-label":`搜索图例`},null,512),[[le,d(M)]]),x(`button`,{class:T([`chip`,{on:d(N)}]),onClick:r[1]||=e=>N.value=!d(N)},[b(i,{name:`i-lucide-clock-alert`,class:`size-3`}),r[8]||=O(`可能过期 `,-1)],2)]),x(`nav`,ye,[(g(!0),C(S,null,m(d(rt),e=>(g(),C(`section`,{key:e.key,class:`dg-group`},[x(`button`,{type:`button`,class:`dg-group-hd`,"aria-expanded":!d(L)[e.key],onClick:t=>nt(e.key)},[x(`i`,{class:`dot`,style:v({background:e.color})},null,4),x(`span`,xe,_(e.label),1),x(`span`,Se,_(e.items.length),1),b(i,{name:`i-lucide-chevron-down`,class:T([`dg-chev`,{fold:d(L)[e.key]}])},null,8,[`class`])],8,be),oe(x(`ul`,Ce,[(g(!0),C(S,null,m(e.items,e=>(g(),C(`li`,{key:e.id,class:T([`dg-item`,{on:d(R)?.id===e.id}]),onClick:t=>P.value=e.id,onKeydown:[de(k(t=>P.value=e.id,[`prevent`]),[`enter`]),de(k(t=>P.value=e.id,[`prevent`]),[`space`])],tabindex:`0`},[b(i,{name:d(et)[e.kind],class:`dg-ic`},null,8,[`name`]),x(`span`,Te,[x(`b`,null,_(e.title),1),x(`small`,Ee,_(e.id)+` · `+_(d(j)[e.kind]),1)]),it(e.id)?(g(),C(`span`,De,`旧`)):w(``,!0)],42,we))),128))],512),[[ue,!d(L)[e.key]]])]))),128))]),d(I).length?w(``,!0):(g(),C(`p`,Oe,`当前筛选下没有图例。`))]),x(`section`,ke,[d(R)?(g(),C(S,{key:0},[x(`div`,Ae,[x(`h2`,je,_(d(R).title),1),x(`span`,Me,_(d(j)[d(R).kind]),1),it(d(R).id)?(g(),C(`span`,Ne,` 可能过期 `)):w(``,!0),x(`span`,Pe,_(d(R).id)+` · 更新 `+_(d(Qe)(d(R).updatedAt)),1),x(`a`,{class:`btn btn-sm dg-open`,href:at(d(R).id),target:`_blank`,rel:`noopener`},[b(i,{name:`i-lucide-external-link`,class:`size-3.5`}),r[9]||=O(`新标签打开 `,-1)],8,Fe)]),x(`div`,Ie,[d(R).summary?(g(),C(`p`,Le,_(d(R).summary),1)):(g(),C(`p`,Re,`没有写摘要——图本身能看懂的话可以不加。`)),x(`div`,ze,[st(d(R).storyIds).length?(g(),C(S,{key:0},[r[10]||=x(`span`,{class:`dim`},`关联故事`,-1),(g(!0),C(S,null,m(st(d(R).storyIds),e=>(g(),re(a,{key:e.id,to:`/story/${e.id}`,class:`tag tag-primary mono`},{default:ae(()=>[O(_(e.id),1)]),_:2},1032,[`to`]))),128))],64)):(g(),C(`span`,Be,`未关联故事`)),r[11]||=x(`span`,{class:`sep`},null,-1),d(R).svg?(g(),C(`a`,{key:2,class:`dl`,href:z(d(R).id),download:``},`下载 SVG`,8,Ve)):(g(),C(`span`,He,`无 SVG 导出`)),d(R).svg?(g(),C(`button`,{key:4,class:`dl`,disabled:!!d($),onClick:r[2]||=e=>ht(d(R))},_(d($)===d(R).id?`导出中…`:`下载 PNG`),9,Ue)):w(``,!0),x(`span`,We,_(d(R).file),1)])]),x(`div`,{ref_key:`frameEl`,ref:B,class:T([`dg-frame`,{dragging:d(K),"has-canvas":d(q)}]),style:v({"--dg-ratio":ot(d(R).aspect)}),onWheel:k(ut,[`prevent`]),onPointerdown:ft,onPointermove:pt,onPointerup:Z,onPointercancel:Z,onPointerleave:Z,onDblclick:X},[d(q)?(g(),C(S,{key:0},[d(W)?(g(),C(`img`,{key:0,class:`dg-canvas-img`,src:d(W),alt:d(R).title,draggable:`false`,style:v({left:`${d(H).x}px`,top:`${d(H).y}px`,width:`${d(V).w*d(H).scale}px`,height:`${d(V).h*d(H).scale}px`})},null,12,Ge)):(g(),C(`p`,Ke,`正在载入 SVG…`)),x(`div`,qe,[x(`button`,{type:`button`,class:`dg-zbtn`,title:`适应窗口(双击画布也行)`,onClick:k(X,[`prevent`])},`适应`),x(`button`,{type:`button`,class:`dg-zbtn`,title:`缩小`,onClick:r[3]||=k(e=>dt(1/1.25),[`prevent`])},`−`),x(`span`,Je,_(d(ct))+`%`,1),x(`button`,{type:`button`,class:`dg-zbtn`,title:`放大`,onClick:r[4]||=k(e=>dt(1.25),[`prevent`])},`+`)]),r[12]||=x(`span`,{class:`dg-hint mono`},`滚轮缩放 · 拖拽平移 · 双击复位`,-1)],64)):(g(),C(`iframe`,{key:1,src:at(d(R).id),title:d(R).title,sandbox:`allow-scripts`,loading:`lazy`,referrerpolicy:`no-referrer`},null,8,Ye))],38)],64)):w(``,!0)])])):(g(),C(`div`,pe,[b(i,{name:`i-lucide-network`,class:`size-4`}),r[5]||=se(`<div data-v-2415570b><b data-v-2415570b>还没有图例</b><p style="margin-top:3px;" data-v-2415570b> 实现故事时遇到模块边界 / 鉴权 / 支付 / 数据模型这类改动,用内置的 <code class="mono" data-v-2415570b>diagram-design</code> skill 出图, 再用 <code class="mono" data-v-2415570b>node tools/diagram.mjs add <file> --title "登录时序" --kind sequence --story S-001</code> 登记;索引写在 <code class="mono" data-v-2415570b>agile/diagrams.json</code>,产物在 <code class="mono" data-v-2415570b>agile/diagrams/</code>。 </p></div>`,1)]))])}}}),[[`__scopeId`,`data-v-2415570b`]]);export{A as default};
|