sillyspec 3.20.1 → 3.20.3

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.
Files changed (209) hide show
  1. package/.claude/skills/sillyspec-archive/SKILL.md +1 -5
  2. package/.claude/skills/sillyspec-auto/SKILL.md +2 -8
  3. package/.claude/skills/sillyspec-brainstorm/SKILL.md +1 -28
  4. package/.claude/skills/sillyspec-commit/SKILL.md +3 -4
  5. package/.claude/skills/sillyspec-continue/SKILL.md +4 -5
  6. package/.claude/skills/sillyspec-doctor/SKILL.md +3 -12
  7. package/.claude/skills/sillyspec-execute/SKILL.md +2 -15
  8. package/.claude/skills/sillyspec-explore/SKILL.md +1 -14
  9. package/.claude/skills/sillyspec-plan/SKILL.md +36 -5
  10. package/.claude/skills/sillyspec-propose/SKILL.md +0 -4
  11. package/.claude/skills/sillyspec-quick/SKILL.md +1 -5
  12. package/.claude/skills/sillyspec-resume/SKILL.md +66 -23
  13. package/.claude/skills/sillyspec-scan/SKILL.md +1 -5
  14. package/.claude/skills/sillyspec-state/SKILL.md +8 -8
  15. package/.claude/skills/sillyspec-status/SKILL.md +1 -5
  16. package/.claude/skills/sillyspec-verify/SKILL.md +1 -5
  17. package/.claude/skills/sillyspec-workspace/SKILL.md +3 -11
  18. package/.sillyspec/changes/archive/2026-04-08-derive-state/design.md +97 -0
  19. package/.sillyspec/changes/archive/2026-04-08-derive-state/plan.md +51 -0
  20. package/.sillyspec/changes/archive/2026-04-08-derive-state/proposal.md +29 -0
  21. package/.sillyspec/changes/archive/2026-04-08-derive-state/requirements.md +34 -0
  22. package/.sillyspec/changes/archive/2026-04-08-derive-state/tasks.md +13 -0
  23. package/.sillyspec/changes/archive/2026-04-08-derive-state/verify-result.md +43 -0
  24. package/.sillyspec/changes/auto-mode/design.md +50 -0
  25. package/.sillyspec/changes/auto-mode/proposal.md +19 -0
  26. package/.sillyspec/changes/auto-mode/requirements.md +21 -0
  27. package/.sillyspec/changes/auto-mode/tasks.md +7 -0
  28. package/.sillyspec/changes/brainstorm-archive/2026-04-05-dashboard-design.md +206 -0
  29. package/.sillyspec/changes/brainstorm-archive/2026-04-05-unified-docs-design.md +199 -0
  30. package/.sillyspec/changes/dashboard/design.md +219 -0
  31. package/.sillyspec/changes/dashboard/design.md.braindraft +206 -0
  32. package/.sillyspec/changes/run-command-design/design.md +1230 -0
  33. package/.sillyspec/changes/unified-docs-design/design.md +199 -0
  34. package/.sillyspec/docs/sillyspec/scan/.gitkeep +0 -0
  35. package/.sillyspec/knowledge/INDEX.md +8 -0
  36. package/.sillyspec/knowledge/uncategorized.md +3 -0
  37. package/.sillyspec/plans/2026-04-05-dashboard.md +737 -0
  38. package/.sillyspec/projects/sillyspec.yaml +3 -0
  39. package/README.md +11 -13
  40. package/SKILL.md +40 -44
  41. package/dist/steps/brainstorm/01-load-context.md +30 -0
  42. package/dist/steps/brainstorm/02-reuse-check.md +6 -0
  43. package/dist/steps/brainstorm/03-prototype-analysis.md +11 -0
  44. package/dist/steps/brainstorm/04-module-split.md +23 -0
  45. package/dist/steps/brainstorm/05-dialog-explore.md +8 -0
  46. package/dist/steps/brainstorm/06-propose-approaches.md +3 -0
  47. package/dist/steps/brainstorm/07-present-design.md +3 -0
  48. package/dist/steps/brainstorm/08-write-design.md +21 -0
  49. package/dist/steps/brainstorm/09-self-review.md +15 -0
  50. package/dist/steps/brainstorm/10-user-confirm.md +3 -0
  51. package/dist/steps/brainstorm/11-output-spec.md +7 -0
  52. package/dist/steps/brainstorm/manifest.yaml +26 -0
  53. package/dist/steps/execute/01-load-context.md +41 -0
  54. package/dist/steps/execute/02-scan-conventions.md +47 -0
  55. package/dist/steps/execute/03-skill-mcp.md +19 -0
  56. package/dist/steps/execute/04-assign-task.md +22 -0
  57. package/dist/steps/execute/04b-prompt-template.md +54 -0
  58. package/dist/steps/execute/05-write-test.md +7 -0
  59. package/dist/steps/execute/06-write-code.md +8 -0
  60. package/dist/steps/execute/07-run-test.md +26 -0
  61. package/dist/steps/execute/08-fix-issues.md +28 -0
  62. package/dist/steps/execute/09-next-task.md +33 -0
  63. package/dist/steps/execute/manifest.yaml +28 -0
  64. package/dist/steps/plan/01-load-context.md +22 -0
  65. package/dist/steps/plan/02-anchor-confirm.md +1 -0
  66. package/dist/steps/plan/03-expand-tasks.md +33 -0
  67. package/dist/steps/plan/04-mark-order.md +15 -0
  68. package/dist/steps/plan/05-e2e-planning.md +17 -0
  69. package/dist/steps/plan/06-self-check.md +16 -0
  70. package/dist/steps/plan/07-save.md +1 -0
  71. package/dist/steps/plan/manifest.yaml +18 -0
  72. package/dist/steps/scan/01-env-detect.md +51 -0
  73. package/dist/steps/scan/02-tech-stack.md +16 -0
  74. package/dist/steps/scan/03-conventions.md +16 -0
  75. package/dist/steps/scan/04-structure.md +19 -0
  76. package/dist/steps/scan/05-quality.md +18 -0
  77. package/dist/steps/scan/06-complete.md +49 -0
  78. package/dist/steps/scan/manifest.yaml +16 -0
  79. package/dist/steps/verify/01-load-specs.md +28 -0
  80. package/dist/steps/verify/02-check-tasks.md +1 -0
  81. package/dist/steps/verify/03-check-design.md +6 -0
  82. package/dist/steps/verify/04-run-tests.md +7 -0
  83. package/dist/steps/verify/05-e2e-tests.md +27 -0
  84. package/dist/steps/verify/05b-e2e-fix.md +33 -0
  85. package/dist/steps/verify/06-code-quality.md +25 -0
  86. package/dist/steps/verify/07-lint-check.md +27 -0
  87. package/dist/steps/verify/08-output-report.md +14 -0
  88. package/dist/steps/verify/manifest.yaml +22 -0
  89. package/package.json +2 -8
  90. package/packages/dashboard/dist/assets/{index-Bq_Z2hne.js → index-D1EVTLmc.js} +1264 -1264
  91. package/packages/dashboard/dist/assets/index-DGe8CqeP.css +1 -0
  92. package/packages/dashboard/dist/index.html +2 -2
  93. package/packages/dashboard/package-lock.json +6 -6
  94. package/packages/dashboard/server/executor.js +1 -1
  95. package/packages/dashboard/server/index.js +18 -98
  96. package/packages/dashboard/server/parser.js +71 -139
  97. package/packages/dashboard/server/watcher.js +6 -14
  98. package/packages/dashboard/src/App.vue +185 -418
  99. package/packages/dashboard/src/components/ActionBar.vue +1 -10
  100. package/packages/dashboard/src/components/CommandPalette.vue +1 -5
  101. package/packages/dashboard/src/components/DocPreview.vue +8 -105
  102. package/packages/dashboard/src/components/DocTree.vue +19 -75
  103. package/packages/dashboard/src/components/PipelineStage.vue +2 -22
  104. package/packages/dashboard/src/components/PipelineView.vue +5 -32
  105. package/packages/dashboard/src/components/ProjectOverview.vue +139 -113
  106. package/packages/dashboard/src/components/StageBadge.vue +3 -17
  107. package/packages/dashboard/src/components/StepCard.vue +2 -7
  108. package/packages/dashboard/src/composables/useDashboard.js +0 -28
  109. package/src/derive.js +147 -0
  110. package/src/index.js +40 -685
  111. package/src/init.js +63 -119
  112. package/src/migrate.js +7 -7
  113. package/src/progress.js +248 -1474
  114. package/src/run.js +302 -2920
  115. package/src/setup.js +64 -2
  116. package/src/stages/archive.js +17 -123
  117. package/src/stages/brainstorm.js +48 -454
  118. package/src/stages/doctor.js +46 -99
  119. package/src/stages/execute.js +59 -420
  120. package/src/stages/index.js +18 -12
  121. package/src/stages/plan.js +189 -492
  122. package/src/stages/propose.js +11 -70
  123. package/src/stages/quick.js +13 -52
  124. package/src/stages/scan.js +68 -468
  125. package/src/stages/status.js +1 -1
  126. package/src/stages/verify.js +16 -203
  127. package/src/step.js +543 -0
  128. package/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
  129. package/.husky/pre-push +0 -13
  130. package/.npmrc-tmp +0 -1
  131. package/CLAUDE.md +0 -18
  132. package/docs/brainstorm-plan-contract.md +0 -64
  133. package/docs/plan-execute-contract.md +0 -123
  134. package/docs/platform-scan-protocol.md +0 -298
  135. package/docs/revision-mode.md +0 -115
  136. package/docs/sillyspec/file-lifecycle/known-implementation-gaps.md +0 -99
  137. package/docs/sillyspec/file-lifecycle/platform-workflows-sync.md +0 -218
  138. package/docs/sillyspec/file-lifecycle/stage-artifacts.md +0 -167
  139. package/docs/sillyspec/file-lifecycle/storage-and-state.md +0 -148
  140. package/docs/sillyspec/file-lifecycle/worktree-and-guard.md +0 -193
  141. package/docs/sillyspec/file-lifecycle.md +0 -125
  142. package/docs/workflow-contract-regression.md +0 -106
  143. package/docs/worktree-isolation.md +0 -252
  144. package/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
  145. package/packages/dashboard/dist/prototype-dashboard.html +0 -836
  146. package/packages/dashboard/dist/prototype-overview.html +0 -256
  147. package/packages/dashboard/public/prototype-dashboard.html +0 -836
  148. package/packages/dashboard/public/prototype-overview.html +0 -256
  149. package/packages/dashboard/src/components/HResizeHandle.vue +0 -48
  150. package/packages/dashboard/src/components/ProjectCard.vue +0 -187
  151. package/packages/dashboard/src/components/VResizeHandle.vue +0 -61
  152. package/packages/dashboard/src/composables/useLayout.js +0 -131
  153. package/src/brainstorm-postcheck.js +0 -158
  154. package/src/change-list.js +0 -52
  155. package/src/change-risk-profile.js +0 -352
  156. package/src/classify-change.js +0 -73
  157. package/src/constants.js +0 -70
  158. package/src/contract-matrix.js +0 -278
  159. package/src/db.js +0 -201
  160. package/src/endpoint-extractor.js +0 -315
  161. package/src/hooks/claude-pre-tool-use.cjs +0 -125
  162. package/src/hooks/worktree-guard.js +0 -761
  163. package/src/knowledge-match.js +0 -130
  164. package/src/modules.js +0 -482
  165. package/src/scan-postcheck.js +0 -380
  166. package/src/stage-contract.js +0 -700
  167. package/src/stages/brainstorm-auto.js +0 -229
  168. package/src/stages/explore.js +0 -34
  169. package/src/stages/knowledge.js +0 -498
  170. package/src/stages/plan-postcheck.js +0 -513
  171. package/src/sync.js +0 -497
  172. package/src/task-review.js +0 -346
  173. package/src/workflow.js +0 -785
  174. package/src/worktree-apply.js +0 -549
  175. package/src/worktree.js +0 -932
  176. package/templates/workflows/archive-impact.yaml +0 -79
  177. package/templates/workflows/scan-docs.yaml +0 -132
  178. package/test/brainstorm-plan-contract.test.mjs +0 -273
  179. package/test/check-syntax.mjs +0 -26
  180. package/test/cli-top-level-aliases.test.mjs +0 -174
  181. package/test/contract-artifacts.test.mjs +0 -323
  182. package/test/decision-supersede.test.mjs +0 -277
  183. package/test/knowledge-match.test.mjs +0 -231
  184. package/test/plan-execute-contract.test.mjs +0 -330
  185. package/test/plan-optimization.test.mjs +0 -572
  186. package/test/platform-artifacts.test.mjs +0 -190
  187. package/test/platform-failure-samples.test.mjs +0 -199
  188. package/test/platform-recovery-chain.test.mjs +0 -179
  189. package/test/platform-recovery.test.mjs +0 -167
  190. package/test/platform-scan-p0.test.mjs +0 -175
  191. package/test/revision-v1.test.mjs +0 -1145
  192. package/test/run-sanitize-project-name.test.mjs +0 -51
  193. package/test/run-scan-postcheck-fail.test.mjs +0 -64
  194. package/test/run-scan-project-parse.test.mjs +0 -77
  195. package/test/run-tests.mjs +0 -48
  196. package/test/scan-docs-yaml-placeholders.test.mjs +0 -84
  197. package/test/scan-knowledge.test.mjs +0 -175
  198. package/test/scan-paths.test.mjs +0 -68
  199. package/test/scan-postcheck-project-priority.test.mjs +0 -85
  200. package/test/scan-postcheck.test.mjs +0 -183
  201. package/test/scan-workflow-anyfailed-block.test.mjs +0 -52
  202. package/test/spec-dir.test.mjs +0 -206
  203. package/test/stage-contract-failed-post-check.test.mjs +0 -102
  204. package/test/stage-contract.test.mjs +0 -299
  205. package/test/stage-definitions.test.mjs +0 -39
  206. package/test/wait-gates.test.mjs +0 -501
  207. package/test/workflow-spec-base.test.mjs +0 -142
  208. package/test/worktree-guard.test.mjs +0 -136
  209. package/test/worktree-native-overlay.test.mjs +0 -188
@@ -1,256 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="zh-CN">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Dashboard 概览区域原型</title>
7
- <style>
8
- * {
9
- margin: 0;
10
- padding: 0;
11
- box-sizing: border-box;
12
- }
13
- body {
14
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
15
- background: #F5F5F7;
16
- height: 100vh;
17
- display: flex;
18
- flex-direction: column;
19
- }
20
- /* 概览区域 - 40% */
21
- .overview-section {
22
- height: 40%;
23
- background: #FFFFFF;
24
- border-bottom: 2px solid #2A3040;
25
- padding: 16px 24px;
26
- display: flex;
27
- flex-direction: column;
28
- }
29
- .section-header {
30
- display: flex;
31
- justify-content: space-between;
32
- align-items: center;
33
- margin-bottom: 16px;
34
- }
35
- .section-title {
36
- font-size: 18px;
37
- font-weight: 600;
38
- color: #1A1A1A;
39
- }
40
- .section-actions {
41
- display: flex;
42
- gap: 8px;
43
- }
44
- .btn {
45
- padding: 6px 12px;
46
- border-radius: 6px;
47
- border: none;
48
- cursor: pointer;
49
- font-size: 13px;
50
- font-weight: 500;
51
- }
52
- .btn-primary {
53
- background: #D97706;
54
- color: white;
55
- }
56
- .btn-secondary {
57
- background: #E5E7EB;
58
- color: #374151;
59
- }
60
- /* 水平滚动卡片容器 */
61
- .cards-container {
62
- flex: 1;
63
- display: flex;
64
- gap: 16px;
65
- overflow-x: auto;
66
- overflow-y: hidden;
67
- padding-bottom: 8px;
68
- }
69
- .cards-container::-webkit-scrollbar {
70
- height: 8px;
71
- }
72
- .cards-container::-webkit-scrollbar-track {
73
- background: #F3F4F6;
74
- border-radius: 4px;
75
- }
76
- .cards-container::-webkit-scrollbar-thumb {
77
- background: #D1D5DB;
78
- border-radius: 4px;
79
- }
80
- /* 项目卡片 */
81
- .project-card {
82
- width: 280px;
83
- height: 120px;
84
- background: white;
85
- border: 2px solid #E5E7EB;
86
- border-radius: 12px;
87
- padding: 16px;
88
- display: flex;
89
- flex-direction: column;
90
- justify-content: space-between;
91
- cursor: pointer;
92
- transition: all 0.2s;
93
- flex-shrink: 0;
94
- }
95
- .project-card:hover {
96
- border-color: #D97706;
97
- box-shadow: 0 4px 12px rgba(217, 119, 6, 0.15);
98
- }
99
- .project-card.selected {
100
- border-color: #D97706;
101
- box-shadow: 0 0 0 3px rgba(217, 119, 6, 0.2);
102
- }
103
- .card-header {
104
- display: flex;
105
- justify-content: space-between;
106
- align-items: flex-start;
107
- }
108
- .project-name {
109
- font-size: 16px;
110
- font-weight: 600;
111
- color: #1A1A1A;
112
- }
113
- .last-active {
114
- font-size: 11px;
115
- color: #9CA3AF;
116
- }
117
- .stage-badge {
118
- display: inline-block;
119
- padding: 4px 10px;
120
- border-radius: 12px;
121
- font-size: 12px;
122
- font-weight: 500;
123
- }
124
- .stage-badge.in-progress {
125
- background: #DBEAFE;
126
- color: #1D4ED8;
127
- }
128
- .stage-badge.completed {
129
- background: #D1FAE5;
130
- color: #047857;
131
- }
132
- .stage-badge.pending {
133
- background: #F3F4F6;
134
- color: #6B7280;
135
- }
136
- .progress-section {
137
- display: flex;
138
- align-items: center;
139
- gap: 8px;
140
- }
141
- .progress-bar {
142
- flex: 1;
143
- height: 6px;
144
- background: #E5E7EB;
145
- border-radius: 3px;
146
- overflow: hidden;
147
- }
148
- .progress-fill {
149
- height: 100%;
150
- border-radius: 3px;
151
- transition: width 0.3s;
152
- }
153
- .progress-fill.in-progress { background: #3B82F6; }
154
- .progress-fill.completed { background: #10B981; }
155
- .progress-fill.pending { background: #9CA3AF; }
156
- .progress-text {
157
- font-size: 12px;
158
- font-weight: 600;
159
- color: #374151;
160
- }
161
- /* 详情区域 - 60% */
162
- .detail-section {
163
- flex: 1;
164
- background: #FAFAFA;
165
- padding: 24px;
166
- display: flex;
167
- align-items: center;
168
- justify-content: center;
169
- color: #9CA3AF;
170
- font-size: 14px;
171
- }
172
- </style>
173
- </head>
174
- <body>
175
- <!-- 概览区域 -->
176
- <div class="overview-section">
177
- <div class="section-header">
178
- <h1 class="section-title">项目概览</h1>
179
- <div class="section-actions">
180
- <button class="btn btn-secondary">刷新</button>
181
- <button class="btn btn-primary">添加项目</button>
182
- </div>
183
- </div>
184
- <div class="cards-container">
185
- <!-- 项目卡片 1 - 进行中 -->
186
- <div class="project-card selected">
187
- <div class="card-header">
188
- <span class="project-name">sillyspec</span>
189
- <span class="last-active">2分钟前</span>
190
- </div>
191
- <div>
192
- <span class="stage-badge in-progress">需求探索</span>
193
- </div>
194
- <div class="progress-section">
195
- <div class="progress-bar">
196
- <div class="progress-fill in-progress" style="width: 40%"></div>
197
- </div>
198
- <span class="progress-text">40%</span>
199
- </div>
200
- </div>
201
- <!-- 项目卡片 2 - 进行中 -->
202
- <div class="project-card">
203
- <div class="card-header">
204
- <span class="project-name">my-blog</span>
205
- <span class="last-active">15分钟前</span>
206
- </div>
207
- <div>
208
- <span class="stage-badge in-progress">实现计划</span>
209
- </div>
210
- <div class="progress-section">
211
- <div class="progress-bar">
212
- <div class="progress-fill in-progress" style="width: 75%"></div>
213
- </div>
214
- <span class="progress-text">75%</span>
215
- </div>
216
- </div>
217
- <!-- 项目卡片 3 - 已完成 -->
218
- <div class="project-card">
219
- <div class="card-header">
220
- <span class="project-name">user-service</span>
221
- <span class="last-active">1小时前</span>
222
- </div>
223
- <div>
224
- <span class="stage-badge completed">验证确认</span>
225
- </div>
226
- <div class="progress-section">
227
- <div class="progress-bar">
228
- <div class="progress-fill completed" style="width: 100%"></div>
229
- </div>
230
- <span class="progress-text">100%</span>
231
- </div>
232
- </div>
233
- <!-- 项目卡片 4 - 未开始 -->
234
- <div class="project-card">
235
- <div class="card-header">
236
- <span class="project-name">payment-api</span>
237
- <span class="last-active">昨天</span>
238
- </div>
239
- <div>
240
- <span class="stage-badge pending">未开始</span>
241
- </div>
242
- <div class="progress-section">
243
- <div class="progress-bar">
244
- <div class="progress-fill pending" style="width: 0%"></div>
245
- </div>
246
- <span class="progress-text">0%</span>
247
- </div>
248
- </div>
249
- </div>
250
- </div>
251
- <!-- 详情区域 -->
252
- <div class="detail-section">
253
- 点击上方卡片查看项目详情
254
- </div>
255
- </body>
256
- </html>
@@ -1,48 +0,0 @@
1
- <template>
2
- <div
3
- class="h-resize-handle"
4
- :class="{ 'dragging': isDragging }"
5
- @mousedown="handleMouseDown"
6
- ></div>
7
- </template>
8
-
9
- <script setup>
10
- const props = defineProps({
11
- isDragging: { type: Boolean, default: false },
12
- colIndex: { type: Number, required: true }
13
- })
14
-
15
- const emit = defineEmits(['drag-start', 'drag-end', 'resize'])
16
-
17
- function handleMouseDown(e) {
18
- e.preventDefault()
19
- emit('drag-start', { type: 'horizontal', colIndex: props.colIndex, startX: e.clientX })
20
-
21
- const onMove = (ev) => {
22
- emit('resize', { deltaX: ev.clientX - e.clientX })
23
- }
24
-
25
- const onUp = () => {
26
- emit('drag-end')
27
- window.removeEventListener('mousemove', onMove)
28
- window.removeEventListener('mouseup', onUp)
29
- }
30
-
31
- window.addEventListener('mousemove', onMove)
32
- window.addEventListener('mouseup', onUp)
33
- }
34
- </script>
35
-
36
- <style scoped>
37
- .h-resize-handle {
38
- width: 4px;
39
- background: #E5E7EB;
40
- cursor: col-resize;
41
- transition: background 0.2s;
42
- }
43
-
44
- .h-resize-handle:hover,
45
- .h-resize-handle.dragging {
46
- background: #D97706;
47
- }
48
- </style>
@@ -1,187 +0,0 @@
1
- <template>
2
- <div
3
- class="project-card"
4
- :class="{ selected: isSelected }"
5
- @click="$emit('select', project)"
6
- >
7
- <!-- 卡片头部 -->
8
- <div class="card-header">
9
- <span class="project-name">{{ project.name }}</span>
10
- <span class="last-active">{{ formatTime(project.lastActive) }}</span>
11
- </div>
12
-
13
- <!-- 阶段标签 -->
14
- <div>
15
- <span class="stage-badge" :class="stageClass">{{ stageLabel }}</span>
16
- </div>
17
-
18
- <!-- 进度条 -->
19
- <div class="progress-section">
20
- <div class="progress-bar">
21
- <div class="progress-fill" :class="stageClass" :style="{ width: progressPercent + '%' }"></div>
22
- </div>
23
- <span class="progress-text">{{ progressPercent }}%</span>
24
- </div>
25
- </div>
26
- </template>
27
-
28
- <script setup>
29
- import { computed } from 'vue'
30
-
31
- const props = defineProps({
32
- project: { type: Object, required: true },
33
- isSelected: { type: Boolean, default: false }
34
- })
35
-
36
- defineEmits(['select'])
37
-
38
- const stageLabel = computed(() => {
39
- const stage = props.project?.state?.currentStage
40
- if (!stage) return '未开始'
41
- const stageNames = {
42
- brainstorm: '需求探索',
43
- plan: '实现计划',
44
- execute: '波次执行',
45
- verify: '验证确认'
46
- }
47
- return stageNames[stage] || stage
48
- })
49
-
50
- const stageClass = computed(() => {
51
- const stage = props.project?.state?.currentStage
52
- if (!stage) return 'pending'
53
- const progress = props.project?.state?.progress?.stages?.[stage]
54
- if (progress?.status === 'completed') return 'completed'
55
- if (progress?.status === 'in-progress') return 'in-progress'
56
- return 'pending'
57
- })
58
-
59
- const progressPercent = computed(() => {
60
- const stage = props.project?.state?.currentStage
61
- if (!stage) return 0
62
- const progress = props.project?.state?.progress?.stages?.[stage]
63
- if (!progress) return 0
64
- if (progress.completedSteps !== undefined && progress.steps !== undefined) {
65
- return Math.round((progress.completedSteps / progress.steps) * 100)
66
- }
67
- if (progress.status === 'completed') return 100
68
- if (progress.status === 'in-progress') return 50
69
- return 0
70
- })
71
-
72
- function formatTime(iso) {
73
- if (!iso) return '昨天'
74
- const d = new Date(iso)
75
- const now = new Date()
76
- const diffMs = now - d
77
- if (diffMs < 60000) return '刚刚'
78
- if (diffMs < 3600000) return `${Math.floor(diffMs / 60000)}分钟前`
79
- if (diffMs < 86400000) return `${Math.floor(diffMs / 3600000)}小时前`
80
- return '昨天'
81
- }
82
- </script>
83
-
84
- <style scoped>
85
- .project-card {
86
- width: 280px;
87
- height: 120px;
88
- background: white;
89
- border: 2px solid #E5E7EB;
90
- border-radius: 12px;
91
- padding: 16px;
92
- display: flex;
93
- flex-direction: column;
94
- justify-content: space-between;
95
- cursor: pointer;
96
- transition: all 0.2s;
97
- flex-shrink: 0;
98
- }
99
-
100
- .project-card:hover {
101
- border-color: #D97706;
102
- box-shadow: 0 4px 12px rgba(217, 119, 6, 0.15);
103
- }
104
-
105
- .project-card.selected {
106
- border-color: #D97706;
107
- box-shadow: 0 0 0 3px rgba(217, 119, 6, 0.2);
108
- }
109
-
110
- .card-header {
111
- display: flex;
112
- justify-content: space-between;
113
- align-items: flex-start;
114
- }
115
-
116
- .project-name {
117
- font-size: 16px;
118
- font-weight: 600;
119
- color: #1A1A1A;
120
- }
121
-
122
- .last-active {
123
- font-size: 11px;
124
- color: #9CA3AF;
125
- }
126
-
127
- .stage-badge {
128
- display: inline-block;
129
- padding: 4px 10px;
130
- border-radius: 12px;
131
- font-size: 12px;
132
- font-weight: 500;
133
- }
134
-
135
- .stage-badge.in-progress {
136
- background: #DBEAFE;
137
- color: #1D4ED8;
138
- }
139
-
140
- .stage-badge.completed {
141
- background: #D1FAE5;
142
- color: #047857;
143
- }
144
-
145
- .stage-badge.pending {
146
- background: #F3F4F6;
147
- color: #6B7280;
148
- }
149
-
150
- .progress-section {
151
- display: flex;
152
- align-items: center;
153
- gap: 8px;
154
- }
155
-
156
- .progress-bar {
157
- flex: 1;
158
- height: 6px;
159
- background: #E5E7EB;
160
- border-radius: 3px;
161
- overflow: hidden;
162
- }
163
-
164
- .progress-fill {
165
- height: 100%;
166
- border-radius: 3px;
167
- transition: width 0.3s;
168
- }
169
-
170
- .progress-fill.in-progress {
171
- background: #3B82F6;
172
- }
173
-
174
- .progress-fill.completed {
175
- background: #10B981;
176
- }
177
-
178
- .progress-fill.pending {
179
- background: #9CA3AF;
180
- }
181
-
182
- .progress-text {
183
- font-size: 12px;
184
- font-weight: 600;
185
- color: #374151;
186
- }
187
- </style>
@@ -1,61 +0,0 @@
1
- <template>
2
- <div
3
- class="v-resize-handle"
4
- :class="{ 'dragging': isDragging }"
5
- @mousedown="handleMouseDown"
6
- >
7
- <div class="drag-indicator"></div>
8
- </div>
9
- </template>
10
-
11
- <script setup>
12
- const props = defineProps({
13
- isDragging: { type: Boolean, default: false }
14
- })
15
-
16
- const emit = defineEmits(['drag-start', 'drag-end', 'resize'])
17
-
18
- function handleMouseDown(e) {
19
- emit('drag-start', { type: 'vertical', startY: e.clientY })
20
-
21
- const onMove = (ev) => {
22
- emit('resize', { deltaY: ev.clientY - e.clientY })
23
- }
24
-
25
- const onUp = () => {
26
- emit('drag-end')
27
- window.removeEventListener('mousemove', onMove)
28
- window.removeEventListener('mouseup', onUp)
29
- }
30
-
31
- window.addEventListener('mousemove', onMove)
32
- window.addEventListener('mouseup', onUp)
33
- }
34
- </script>
35
-
36
- <style scoped>
37
- .v-resize-handle {
38
- height: 6px;
39
- background: #2A3040;
40
- cursor: row-resize;
41
- position: relative;
42
- transition: background 0.2s;
43
- }
44
-
45
- .v-resize-handle:hover,
46
- .v-resize-handle.dragging {
47
- background: #D97706;
48
- }
49
-
50
- .drag-indicator {
51
- position: absolute;
52
- top: 50%;
53
- left: 50%;
54
- transform: translate(-50%, -50%);
55
- width: 40px;
56
- height: 4px;
57
- background: rgba(255, 255, 255, 0.3);
58
- border-radius: 2px;
59
- pointer-events: none;
60
- }
61
- </style>
@@ -1,131 +0,0 @@
1
- /**
2
- * 布局管理 Composable
3
- * 管理双层布局的概览/详情比例和三栏宽度
4
- */
5
- import { reactive, ref, onMounted } from 'vue'
6
-
7
- const STORAGE_KEY = 'dashboard-layout-v2'
8
-
9
- // 默认值
10
- const DEFAULT_OVERVIEW_HEIGHT = 30 // 概览区域百分比
11
- const DEFAULT_COLUMN_WIDTHS = [33.33, 33.33, 33.33] // 三栏宽度百分比
12
-
13
- // 最小值限制
14
- const MIN_OVERVIEW_HEIGHT = 15
15
- const MAX_OVERVIEW_HEIGHT = 75
16
- const MIN_COLUMN_WIDTH = 10
17
-
18
- /**
19
- * 布局管理 Hook
20
- */
21
- export function useLayout() {
22
- // 布局状态
23
- const layout = reactive({
24
- overviewHeight: DEFAULT_OVERVIEW_HEIGHT,
25
- columnWidths: [...DEFAULT_COLUMN_WIDTHS]
26
- })
27
-
28
- // 拖动状态
29
- const isDragging = ref(false)
30
- const dragType = ref(null) // 'vertical' | 'horizontal'
31
-
32
- /**
33
- * 加载保存的布局
34
- */
35
- function loadLayout() {
36
- try {
37
- const saved = localStorage.getItem(STORAGE_KEY)
38
- if (saved) {
39
- const parsed = JSON.parse(saved)
40
- if (parsed.overviewHeight !== undefined) {
41
- layout.overviewHeight = Math.max(MIN_OVERVIEW_HEIGHT, Math.min(MAX_OVERVIEW_HEIGHT, parsed.overviewHeight))
42
- }
43
- if (Array.isArray(parsed.columnWidths) && parsed.columnWidths.length === 3) {
44
- layout.columnWidths = parsed.columnWidths
45
- }
46
- }
47
- } catch (e) {
48
- console.error('Failed to load layout:', e)
49
- // 使用默认值
50
- resetLayout()
51
- }
52
- }
53
-
54
- /**
55
- * 保存布局到 localStorage
56
- */
57
- function saveLayout() {
58
- try {
59
- localStorage.setItem(STORAGE_KEY, JSON.stringify({
60
- overviewHeight: layout.overviewHeight,
61
- columnWidths: layout.columnWidths
62
- }))
63
- } catch (e) {
64
- console.error('Failed to save layout:', e)
65
- }
66
- }
67
-
68
- /**
69
- * 重置布局为默认值
70
- */
71
- function resetLayout() {
72
- layout.overviewHeight = DEFAULT_OVERVIEW_HEIGHT
73
- layout.columnWidths = [...DEFAULT_COLUMN_WIDTHS]
74
- saveLayout()
75
- }
76
-
77
- /**
78
- * 设置概览区域高度(百分比)
79
- */
80
- function setOverviewHeight(percent) {
81
- layout.overviewHeight = Math.max(MIN_OVERVIEW_HEIGHT, Math.min(MAX_OVERVIEW_HEIGHT, percent))
82
- saveLayout()
83
- }
84
-
85
- /**
86
- * 设置列宽度(索引,百分比)
87
- */
88
- function setColumnWidth(index, percent) {
89
- if (index >= 0 && index < 3) {
90
- layout.columnWidths[index] = Math.max(MIN_COLUMN_WIDTH, percent)
91
- saveLayout()
92
- }
93
- }
94
-
95
- /**
96
- * 开始拖动
97
- */
98
- function startDrag(type) {
99
- isDragging.value = true
100
- dragType.value = type
101
- document.body.classList.add('resizing')
102
- }
103
-
104
- /**
105
- * 结束拖动
106
- */
107
- function endDrag() {
108
- isDragging.value = false
109
- dragType.value = null
110
- document.body.classList.remove('resizing')
111
- saveLayout()
112
- }
113
-
114
- // 组件挂载时加载布局
115
- onMounted(() => {
116
- loadLayout()
117
- })
118
-
119
- return {
120
- layout,
121
- isDragging,
122
- dragType,
123
- loadLayout,
124
- saveLayout,
125
- resetLayout,
126
- setOverviewHeight,
127
- setColumnWidth,
128
- startDrag,
129
- endDrag
130
- }
131
- }