@waterwx/dsh-novel-forge 2.1.0-alpha → 2.1.0

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 (253) hide show
  1. package/README.md +368 -457
  2. package/lib/client.js +20495 -22316
  3. package/lib/index.js +4640 -3932
  4. package/lib/types/action-guard.d.ts +61 -0
  5. package/lib/types/ai-scan.d.ts +0 -6
  6. package/lib/types/assets.d.ts +7 -9
  7. package/lib/types/assistant.d.ts +25 -0
  8. package/lib/types/author-assets.d.ts +1 -3
  9. package/lib/types/bookshelf.d.ts +13 -3
  10. package/lib/types/client/api.d.ts +49 -29
  11. package/lib/types/client/chip-prefs.d.ts +36 -0
  12. package/lib/types/client/docx.d.ts +2 -2
  13. package/lib/types/client/llmLive.d.ts +12 -14
  14. package/lib/types/client/locales.d.ts +12 -67
  15. package/lib/types/client/mount.d.ts +0 -2
  16. package/lib/types/client/panel/AdaptModeView.d.ts +1 -1
  17. package/lib/types/client/panel/AiTag.d.ts +1 -0
  18. package/lib/types/client/panel/AssetsTab.d.ts +1 -1
  19. package/lib/types/client/panel/AssistantTab.d.ts +4 -1
  20. package/lib/types/client/panel/AuthorAssetsView.d.ts +1 -1
  21. package/lib/types/client/panel/AuthorHome.d.ts +12 -12
  22. package/lib/types/client/panel/CmdPalette.d.ts +12 -0
  23. package/lib/types/client/panel/CreateBookView.d.ts +1 -1
  24. package/lib/types/client/panel/GlobalAssetLibraryView.d.ts +1 -1
  25. package/lib/types/client/panel/ImportModal.d.ts +1 -1
  26. package/lib/types/client/panel/LiveFeedLog.d.ts +8 -0
  27. package/lib/types/client/panel/ModelManager.d.ts +2 -2
  28. package/lib/types/client/panel/NovelPanel.d.ts +7 -2
  29. package/lib/types/client/panel/PageHeader.d.ts +18 -0
  30. package/lib/types/client/panel/ProgressConsole.d.ts +1 -1
  31. package/lib/types/client/panel/PromptSlotsView.d.ts +11 -0
  32. package/lib/types/client/panel/ReaderView.d.ts +1 -1
  33. package/lib/types/client/panel/RunPanel.d.ts +1 -1
  34. package/lib/types/client/panel/SettingsView.d.ts +13 -10
  35. package/lib/types/client/panel/ShelfView.d.ts +11 -2
  36. package/lib/types/client/panel/SubPage.d.ts +27 -0
  37. package/lib/types/client/panel/TensionView.d.ts +18 -0
  38. package/lib/types/client/panel/TimelineView.d.ts +18 -0
  39. package/lib/types/client/panel/WorldTab.d.ts +1 -1
  40. package/lib/types/client/panel/helpers.d.ts +5 -3
  41. package/lib/types/client/panel/market-radar-state.d.ts +56 -0
  42. package/lib/types/client/panel/outline-markdown.d.ts +112 -0
  43. package/lib/types/client/panel/status-badge.d.ts +13 -0
  44. package/lib/types/client/panel/storage-parse.d.ts +46 -0
  45. package/lib/types/client/panel/toast.d.ts +2 -0
  46. package/lib/types/client/panel/usePersistentState.d.ts +17 -0
  47. package/lib/types/client/panel/views.d.ts +21 -35
  48. package/lib/types/client/run-status.d.ts +21 -0
  49. package/lib/types/client/sidebar-entry.d.ts +0 -2
  50. package/lib/types/digest-parse.d.ts +29 -0
  51. package/lib/types/docx-core.d.ts +16 -0
  52. package/lib/types/docx.d.ts +2 -3
  53. package/lib/types/engine.d.ts +122 -103
  54. package/lib/types/home.d.ts +11 -0
  55. package/lib/types/index.d.ts +21 -13
  56. package/lib/types/llm-live.d.ts +62 -36
  57. package/lib/types/llm-retry.d.ts +38 -0
  58. package/lib/types/market-radar-scan.d.ts +0 -1
  59. package/lib/types/market-radar-sources.d.ts +1 -1
  60. package/lib/types/migrate-output.d.ts +25 -0
  61. package/lib/types/model-capability.d.ts +119 -0
  62. package/lib/types/model-request.d.ts +36 -0
  63. package/lib/types/output-budget.d.ts +86 -0
  64. package/lib/types/plotline-align.d.ts +35 -0
  65. package/lib/types/prompt-slots.d.ts +57 -0
  66. package/lib/types/prompting.d.ts +2 -27
  67. package/lib/types/protocol.d.ts +479 -595
  68. package/lib/types/revision.d.ts +76 -0
  69. package/lib/types/routes.d.ts +9 -3
  70. package/lib/types/run-selection.d.ts +51 -0
  71. package/lib/types/run.d.ts +31 -0
  72. package/lib/types/settings-persist.d.ts +59 -0
  73. package/lib/types/snapshots.d.ts +46 -0
  74. package/lib/types/stage-contract.d.ts +58 -0
  75. package/lib/types/stream-fallback.d.ts +60 -0
  76. package/lib/types/strip-headings.d.ts +33 -0
  77. package/lib/types/tension.d.ts +53 -0
  78. package/lib/types/timeline.d.ts +37 -0
  79. package/package.json +50 -27
  80. package/assets/styles/arcane-thick-3d.webp +0 -0
  81. package/assets/styles/chinese-ink.webp +0 -0
  82. package/assets/styles/clay-stopmotion-3d.webp +0 -0
  83. package/assets/styles/dark-ghibli.webp +0 -0
  84. package/assets/styles/dark-gothic-3d.webp +0 -0
  85. package/assets/styles/film-photo.webp +0 -0
  86. package/assets/styles/guofeng-heavy.webp +0 -0
  87. package/assets/styles/guoman-2d-gufeng.webp +0 -0
  88. package/assets/styles/guoman-3d-tianyuan.webp +0 -0
  89. package/assets/styles/guoman-3d-xuanhuan.webp +0 -0
  90. package/assets/styles/horror-game-3d.webp +0 -0
  91. package/assets/styles/hyperreal-3d.webp +0 -0
  92. package/assets/styles/japan-cel-dark.webp +0 -0
  93. package/assets/styles/korean-webtoon.webp +0 -0
  94. package/assets/styles/low-cyberpunk-3d.webp +0 -0
  95. package/assets/styles/nextgen-cg.webp +0 -0
  96. package/assets/styles/noir-film.webp +0 -0
  97. package/assets/styles/openworld-survival.webp +0 -0
  98. package/assets/styles/paper-cut-3d.webp +0 -0
  99. package/assets/styles/pixar-adult-3d.webp +0 -0
  100. package/assets/styles/pop-marvel-2d.webp +0 -0
  101. package/assets/styles/sandiao-qban.webp +0 -0
  102. package/assets/styles/shinkai-anime.webp +0 -0
  103. package/assets/styles/tactical-stealth.webp +0 -0
  104. package/assets/styles/urban-lightreal-3d.webp +0 -0
  105. package/assets/styles/vaporwave-3d.webp +0 -0
  106. package/assets/styles/vhs90.webp +0 -0
  107. package/lib/types/client/panel/BookshelfBar.d.ts +0 -11
  108. package/lib/types/client/panel/FlowGuide.d.ts +0 -22
  109. package/lib/types/client/panel/MangaRoleLibrary.d.ts +0 -20
  110. package/lib/types/client/panel/MangaWorkspace.d.ts +0 -12
  111. package/lib/types/client/panel/ModelPicker.d.ts +0 -11
  112. package/lib/types/client/panel/ProgressHomeView.d.ts +0 -5
  113. package/lib/types/client/panel/PropLibrary.d.ts +0 -8
  114. package/lib/types/client/panel/SceneLibrary.d.ts +0 -16
  115. package/lib/types/client/panel/StoryboardTab.d.ts +0 -19
  116. package/lib/types/client/panel/StyleCard.d.ts +0 -8
  117. package/lib/types/client/panel/StyleGallery.d.ts +0 -1
  118. package/lib/types/comic-presets.d.ts +0 -12
  119. package/lib/types/manga-genre-rules.d.ts +0 -22
  120. package/lib/types/prompt-utils.d.ts +0 -35
  121. package/lib/types/review-policy.d.ts +0 -97
  122. package/lib/types/shot-language.d.ts +0 -46
  123. package/lib/types/src/ai-scan.d.ts +0 -36
  124. package/lib/types/src/assets.d.ts +0 -37
  125. package/lib/types/src/assistant.d.ts +0 -45
  126. package/lib/types/src/author-assets.d.ts +0 -25
  127. package/lib/types/src/bookshelf.d.ts +0 -42
  128. package/lib/types/src/client/api.d.ts +0 -234
  129. package/lib/types/src/client/docx.d.ts +0 -15
  130. package/lib/types/src/client/index.d.ts +0 -14
  131. package/lib/types/src/client/locales.d.ts +0 -212
  132. package/lib/types/src/client/mount.d.ts +0 -9
  133. package/lib/types/src/client/panel/AdaptModeView.d.ts +0 -5
  134. package/lib/types/src/client/panel/AssetsTab.d.ts +0 -12
  135. package/lib/types/src/client/panel/AssistantTab.d.ts +0 -7
  136. package/lib/types/src/client/panel/AuthorAssetsView.d.ts +0 -4
  137. package/lib/types/src/client/panel/AuthorHome.d.ts +0 -32
  138. package/lib/types/src/client/panel/BookshelfBar.d.ts +0 -11
  139. package/lib/types/src/client/panel/CreateBookView.d.ts +0 -9
  140. package/lib/types/src/client/panel/FlowGuide.d.ts +0 -22
  141. package/lib/types/src/client/panel/GlobalAssetLibraryView.d.ts +0 -4
  142. package/lib/types/src/client/panel/ImportModal.d.ts +0 -7
  143. package/lib/types/src/client/panel/MangaRoleLibrary.d.ts +0 -20
  144. package/lib/types/src/client/panel/MangaWorkspace.d.ts +0 -12
  145. package/lib/types/src/client/panel/ModelManager.d.ts +0 -14
  146. package/lib/types/src/client/panel/NovelPanel.d.ts +0 -13
  147. package/lib/types/src/client/panel/ProgressConsole.d.ts +0 -17
  148. package/lib/types/src/client/panel/ProgressHomeView.d.ts +0 -5
  149. package/lib/types/src/client/panel/PropLibrary.d.ts +0 -8
  150. package/lib/types/src/client/panel/ReaderView.d.ts +0 -8
  151. package/lib/types/src/client/panel/ReasoningSection.d.ts +0 -10
  152. package/lib/types/src/client/panel/RunPanel.d.ts +0 -5
  153. package/lib/types/src/client/panel/SceneLibrary.d.ts +0 -16
  154. package/lib/types/src/client/panel/SettingsView.d.ts +0 -16
  155. package/lib/types/src/client/panel/ShelfView.d.ts +0 -15
  156. package/lib/types/src/client/panel/StoryboardTab.d.ts +0 -19
  157. package/lib/types/src/client/panel/StyleCard.d.ts +0 -8
  158. package/lib/types/src/client/panel/StyleGallery.d.ts +0 -1
  159. package/lib/types/src/client/panel/WorldTab.d.ts +0 -10
  160. package/lib/types/src/client/panel/controller.d.ts +0 -19
  161. package/lib/types/src/client/panel/helpers.d.ts +0 -18
  162. package/lib/types/src/client/panel/views.d.ts +0 -77
  163. package/lib/types/src/client/sidebar-entry.d.ts +0 -13
  164. package/lib/types/src/client/text.d.ts +0 -9
  165. package/lib/types/src/comic-presets.d.ts +0 -12
  166. package/lib/types/src/docx.d.ts +0 -19
  167. package/lib/types/src/engine.d.ts +0 -402
  168. package/lib/types/src/index.d.ts +0 -79
  169. package/lib/types/src/manga-genre-rules.d.ts +0 -22
  170. package/lib/types/src/novel-context.d.ts +0 -80
  171. package/lib/types/src/prompt-utils.d.ts +0 -35
  172. package/lib/types/src/protocol.d.ts +0 -2176
  173. package/lib/types/src/review-policy.d.ts +0 -97
  174. package/lib/types/src/routes.d.ts +0 -29
  175. package/lib/types/src/run.d.ts +0 -32
  176. package/lib/types/src/shot-language.d.ts +0 -46
  177. package/lib/types/src/story-beat-language.d.ts +0 -35
  178. package/lib/types/src/style-library.d.ts +0 -33
  179. package/lib/types/story-beat-language.d.ts +0 -35
  180. package/lib/types/style-library.d.ts +0 -33
  181. package/src/ai-scan.ts +0 -179
  182. package/src/assets.ts +0 -1774
  183. package/src/assistant.ts +0 -915
  184. package/src/author-assets.ts +0 -147
  185. package/src/bookshelf.ts +0 -167
  186. package/src/client/api.ts +0 -716
  187. package/src/client/css-modules.d.ts +0 -8
  188. package/src/client/docx.ts +0 -69
  189. package/src/client/index.ts +0 -34
  190. package/src/client/llmLive.ts +0 -101
  191. package/src/client/locales.ts +0 -418
  192. package/src/client/mount.tsx +0 -97
  193. package/src/client/mount.tsx._new +0 -97
  194. package/src/client/mount.tsx._nf +0 -97
  195. package/src/client/mount.tsx._tmp +0 -97
  196. package/src/client/panel/AdaptModeView.tsx +0 -535
  197. package/src/client/panel/AssetsTab.tsx +0 -458
  198. package/src/client/panel/AssistantTab.tsx +0 -339
  199. package/src/client/panel/AuthorAssetsView.tsx +0 -208
  200. package/src/client/panel/AuthorHome.tsx +0 -235
  201. package/src/client/panel/BookAnalysisView.tsx +0 -60
  202. package/src/client/panel/BookshelfBar.tsx +0 -170
  203. package/src/client/panel/CreateBookView.tsx +0 -371
  204. package/src/client/panel/DirectorView.tsx +0 -200
  205. package/src/client/panel/FlowGuide.tsx +0 -84
  206. package/src/client/panel/GlobalAssetLibraryView.tsx +0 -172
  207. package/src/client/panel/IdeaInspirationView.tsx +0 -71
  208. package/src/client/panel/ImportModal.tsx +0 -303
  209. package/src/client/panel/KnowledgeBaseView.tsx +0 -73
  210. package/src/client/panel/LiveFeedLog.tsx +0 -76
  211. package/src/client/panel/MangaRoleLibrary.tsx +0 -1002
  212. package/src/client/panel/MangaWorkspace.tsx +0 -715
  213. package/src/client/panel/MarketRadarView.tsx +0 -374
  214. package/src/client/panel/ModelManager.tsx +0 -205
  215. package/src/client/panel/NovelPanel.tsx +0 -4721
  216. package/src/client/panel/ProgressConsole.tsx +0 -63
  217. package/src/client/panel/ProgressHomeView.tsx +0 -87
  218. package/src/client/panel/PropLibrary.tsx +0 -175
  219. package/src/client/panel/ReaderView.tsx +0 -306
  220. package/src/client/panel/ReasoningSection.tsx +0 -31
  221. package/src/client/panel/RunPanel.tsx +0 -204
  222. package/src/client/panel/SceneLibrary.tsx +0 -453
  223. package/src/client/panel/SettingsView.tsx +0 -289
  224. package/src/client/panel/ShelfView.tsx +0 -242
  225. package/src/client/panel/StoryboardTab.tsx +0 -472
  226. package/src/client/panel/StyleCard.tsx +0 -90
  227. package/src/client/panel/StyleGallery.tsx +0 -58
  228. package/src/client/panel/WorldTab.tsx +0 -202
  229. package/src/client/panel/controller.ts +0 -45
  230. package/src/client/panel/helpers.ts +0 -67
  231. package/src/client/panel/panel.module.css +0 -4359
  232. package/src/client/panel/views.tsx +0 -314
  233. package/src/client/sidebar-entry.ts +0 -122
  234. package/src/client/text.ts +0 -28
  235. package/src/comic-presets.ts +0 -67
  236. package/src/docx.ts +0 -83
  237. package/src/engine.ts +0 -5636
  238. package/src/global-assets.ts +0 -59
  239. package/src/index.ts +0 -345
  240. package/src/llm-live.ts +0 -68
  241. package/src/manga-genre-rules.ts +0 -87
  242. package/src/market-radar-scan.ts +0 -41
  243. package/src/market-radar-sources.ts +0 -173
  244. package/src/novel-context.ts +0 -287
  245. package/src/prompt-utils.ts +0 -73
  246. package/src/prompting.ts +0 -159
  247. package/src/protocol.ts +0 -2565
  248. package/src/review-policy.ts +0 -161
  249. package/src/routes.ts +0 -3939
  250. package/src/run.ts +0 -338
  251. package/src/shot-language.ts +0 -181
  252. package/src/story-beat-language.ts +0 -130
  253. package/src/style-library.ts +0 -84
@@ -1,31 +0,0 @@
1
- /**
2
- * 推理强度(思考强度)独立容器:写作类/分析类两个 reasoningEffort 下拉。
3
- */
4
- import { Brain } from 'lucide-react'
5
- import type { NovelConfig } from '../../protocol.ts'
6
- import { tt } from './helpers.ts'
7
- import css from './panel.module.css'
8
-
9
- const REASONING_OPTIONS = ['off', 'low', 'high', 'max'] as const
10
- const REASONING_LABEL: Record<string, string> = {
11
- off: tt('settings.reasoning.off'),
12
- low: tt('settings.reasoning.low'),
13
- high: tt('settings.reasoning.high'),
14
- max: tt('settings.reasoning.max'),
15
- }
16
-
17
- export interface ReasoningSectionProps {
18
- reasoningEffort: NovelConfig['reasoningEffort']
19
- analysisReasoning: NovelConfig['analysisReasoning']
20
- onChange: (patch: { reasoningEffort?: NovelConfig['reasoningEffort']; analysisReasoning?: NovelConfig['analysisReasoning'] }) => void
21
- }
22
-
23
- export function ReasoningSection({ reasoningEffort, analysisReasoning, onChange }: ReasoningSectionProps): JSX.Element {
24
- return (
25
- <div className={css.card + ' ' + css.settingsCard} style={{ gap: 'var(--nf-space-24)' }}>
26
- <span className={css.cardTitle}><Brain size={18} style={{ verticalAlign: -3 }} /> {tt('settings.reasoningSection')}</span>
27
- <div className={css.field}><label className={css.fieldLabel}>{tt('settings.reasoningEffort')}</label><select className={css.input} value={reasoningEffort ?? 'off'} onChange={e => onChange({ reasoningEffort: e.target.value as NovelConfig['reasoningEffort'] })}>{REASONING_OPTIONS.map(v => <option key={v} value={v}>{REASONING_LABEL[v]}</option>)}</select><span className={css.meta}>{tt('settings.reasoningHint')}</span></div>
28
- <div className={css.field}><label className={css.fieldLabel}>{tt('settings.analysisReasoning')}</label><select className={css.input} value={analysisReasoning ?? 'low'} onChange={e => onChange({ analysisReasoning: e.target.value as NovelConfig['analysisReasoning'] })}>{REASONING_OPTIONS.map(v => <option key={v} value={v}>{REASONING_LABEL[v]}</option>)}</select><span className={css.meta}>{tt('settings.analysisReasoningHint')}</span></div>
29
- </div>
30
- )
31
- }
@@ -1,204 +0,0 @@
1
- /**
2
- * 生产单面板:区间批量生产(计划补足 → 逐章生成 → 被拒分级处理 → 断点续跑)。
3
- * 与「AI进度」悬浮窗不同:这是标准流水线设备,一键下单、实时进度、日志可查。
4
- */
5
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
6
- import type { NovelApi } from '../api.ts'
7
- import type { RunState } from '../../protocol.ts'
8
- import css from './panel.module.css'
9
-
10
- export function RunPanel({ api, totalChapters }: { api: NovelApi; totalChapters: number }) {
11
- const [run, setRun] = useState<RunState | null>(null)
12
- const [startNo, setStartNo] = useState<number>(1)
13
- const [endNo, setEndNo] = useState<number>(0)
14
- const [count, setCount] = useState<number>(30)
15
- const [mode, setMode] = useState<'count' | 'range'>('count')
16
- const [busy, setBusy] = useState(false)
17
- const [err, setErr] = useState('')
18
- const logRef = useRef<HTMLDivElement>(null)
19
-
20
- // 默认起点:最后一章 + 1;count 模式终点 = 起点 + count - 1
21
- useEffect(() => {
22
- setStartNo(totalChapters + 1)
23
- setEndNo(totalChapters + 30)
24
- }, [totalChapters])
25
-
26
- const poll = useCallback(async () => {
27
- try {
28
- const s = await api.runStatus()
29
- setRun(s)
30
- } catch { /* 静默 */ }
31
- }, [api])
32
-
33
- // 运行期间每 5 秒轮询一次状态。
34
- useEffect(() => {
35
- void poll()
36
- const timer = window.setInterval(() => { void poll() }, 5000)
37
- return () => window.clearInterval(timer)
38
- }, [poll])
39
-
40
- // 日志自动滚底。
41
- useEffect(() => {
42
- logRef.current?.scrollTo({ top: logRef.current.scrollHeight })
43
- }, [run?.log.length])
44
-
45
- const effectiveEnd = mode === 'count' ? startNo + count - 1 : endNo
46
-
47
- const handleStart = async (): Promise<void> => {
48
- setBusy(true)
49
- setErr('')
50
- try {
51
- const req = mode === 'count'
52
- ? { startNo, count }
53
- : { startNo, endNo }
54
- const s = await api.runStart(req)
55
- setRun(s)
56
- } catch (e) {
57
- setErr((e as Error).message)
58
- } finally {
59
- setBusy(false)
60
- }
61
- }
62
-
63
- const handleControl = async (action: 'pause' | 'resume' | 'stop'): Promise<void> => {
64
- setBusy(true)
65
- setErr('')
66
- try {
67
- const s = await api.runControl(action)
68
- if (s !== null) setRun(s)
69
- } catch (e) {
70
- setErr((e as Error).message)
71
- } finally {
72
- setBusy(false)
73
- }
74
- }
75
-
76
- const statusLabel = useMemo(() => {
77
- if (run === null) return '未启动'
78
- return {
79
- running: '🏭 生产中',
80
- paused: '⏸ 已暂停',
81
- done: '✅ 已完成',
82
- stopped: '⏹ 已停止',
83
- error: '❌ 异常',
84
- }[run.status] ?? run.status
85
- }, [run])
86
-
87
- const ratio = run !== null && run.endNo > run.startNo
88
- ? Math.min(Math.max((run.currentNo - run.startNo) / (run.endNo - run.startNo), 0), 1)
89
- : 0
90
-
91
- return (
92
- <div className={css.card} style={{ flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', gap: 'var(--nf-space-10)' }}>
93
- <div className={css.row} style={{ justifyContent: 'space-between', flexWrap: 'wrap' }}>
94
- <span className={css.cardTitle}>🏭 生产单(标准流水线:计划 → 生成 → 审稿 → 分级处理)</span>
95
- <span className={`${css.badge} ${run?.status === 'running' ? css.badgeWritten : run?.status === 'done' ? css.badgeDone : css.badgePending}`}>{statusLabel}</span>
96
- </div>
97
-
98
- <div className={css.meta}>
99
- 一键下生产单:自动补计划 → 逐章生成(完整质量门:生成→摘要+事实→审稿→作者复盘)→ 被拒章分级处理(无 high 豁免 / 有 high 按意见修订+验证 / 两轮不过转待人工)。中断后可从断点继续。
100
- </div>
101
-
102
- {/* 下单区 */}
103
- <div className={css.row} style={{ flexWrap: 'wrap', gap: 'var(--nf-space-8)', alignItems: 'flex-end' }}>
104
- <div style={{ display: 'flex', gap: 'var(--nf-space-4)', alignItems: 'center' }}>
105
- <button
106
- type="button"
107
- className={`${css.button} ${css.buttonSmall} ${mode === 'count' ? css.buttonPrimary : ''}`}
108
- onClick={() => { setMode('count') }}
109
- title="从当前末章 +1 起,新增 N 章"
110
- >
111
- 新增 N 章
112
- </button>
113
- <button
114
- type="button"
115
- className={`${css.button} ${css.buttonSmall} ${mode === 'range' ? css.buttonPrimary : ''}`}
116
- onClick={() => { setMode('range') }}
117
- title="指定起止章号区间"
118
- >
119
- 指定区间
120
- </button>
121
- </div>
122
- {mode === 'count' ? (
123
- <>
124
- <div className={css.field} style={{ flex: 'none', minWidth: 90 }}>
125
- <label className={css.fieldLabel}>起始章</label>
126
- <input className={css.input} type="number" min={1} value={startNo} onChange={e => { setStartNo(Math.max(1, Number(e.target.value) || 1)) }} />
127
- </div>
128
- <div className={css.field} style={{ flex: 'none', minWidth: 90 }}>
129
- <label className={css.fieldLabel}>新增章数</label>
130
- <input className={css.input} type="number" min={1} max={200} value={count} onChange={e => { setCount(Math.max(1, Math.min(200, Number(e.target.value) || 1))) }} />
131
- </div>
132
- </>
133
- ) : (
134
- <>
135
- <div className={css.field} style={{ flex: 'none', minWidth: 90 }}>
136
- <label className={css.fieldLabel}>起始章</label>
137
- <input className={css.input} type="number" min={1} value={startNo} onChange={e => { setStartNo(Math.max(1, Number(e.target.value) || 1)) }} />
138
- </div>
139
- <div className={css.field} style={{ flex: 'none', minWidth: 90 }}>
140
- <label className={css.fieldLabel}>结束章</label>
141
- <input className={css.input} type="number" min={1} value={endNo} onChange={e => { setEndNo(Math.max(1, Number(e.target.value) || 1)) }} />
142
- </div>
143
- </>
144
- )}
145
- <button type="button" className={`${css.button} ${css.buttonPrimary}`} disabled={busy || (run?.status === 'running')} onClick={() => { void handleStart() }} title="启动生产单">
146
- {run?.status === 'running' ? '生产中…' : run?.status === 'paused' ? '▶ 继续' : '▶ 下单生产'}
147
- </button>
148
- {run !== null && run.status !== 'done' && (
149
- <>
150
- <button type="button" className={`${css.button} ${css.buttonSmall}`} disabled={busy || run.status !== 'running'} onClick={() => { void handleControl('pause') }}>
151
- ⏸ 暂停
152
- </button>
153
- <button type="button" className={`${css.button} ${css.buttonSmall}`} disabled={busy || run.status === 'stopped'} onClick={() => { void handleControl('stop') }}>
154
- ⏹ 停止
155
- </button>
156
- </>
157
- )}
158
- {run !== null && run.status === 'paused' && (
159
- <button type="button" className={`${css.button} ${css.buttonSmall} ${css.buttonPrimary}`} disabled={busy} onClick={() => { void handleControl('resume') }}>
160
- ▶ 继续
161
- </button>
162
- )}
163
- </div>
164
-
165
- {err !== '' && <div style={{ color: 'var(--nf-error)', fontSize: 'var(--nf-fs-12)' }}>{err}</div>}
166
-
167
- {/* 进度区 */}
168
- {run !== null && (
169
- <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--nf-space-6)' }}>
170
- <div className={css.row} style={{ flexWrap: 'wrap', gap: 'var(--nf-space-8)' }}>
171
- <span className={css.meta}>范围:第 {run.startNo} - {run.endNo} 章 · 当前:第 {run.currentNo} 章</span>
172
- <span className={css.meta}>新生成 {run.stats?.generated ?? 0} · 修订通过 {run.stats?.revised ?? 0} · 豁免 {run.stats?.exempted ?? 0} · 重生成 {run.stats?.regenerated ?? 0} · 失败 {run.stats?.error ?? 0}</span>
173
- </div>
174
- <div className={css.bigProgressBar}>
175
- <div className={css.bigProgressBarFill} style={{ width: `${Math.round(ratio * 100)}%` }} />
176
- </div>
177
- {run.pendingManual.length > 0 && (
178
- <div className={css.meta} style={{ color: 'var(--nf-warn)' }}>
179
- ⚠️ 待人工:第 {run.pendingManual.join('、')} 章(两轮修订仍不过,保留草稿,可在章节列表处理)
180
- </div>
181
- )}
182
- {run.status === 'done' && <div className={css.meta} style={{ color: 'var(--nf-success)' }}>✅ 生产单完成:{run.startNo}-{run.endNo} 章处理完毕,待人工 {run.pendingManual.length} 章。</div>}
183
- {run.error !== undefined && <div className={css.meta} style={{ color: 'var(--nf-error)' }}>异常:{run.error}</div>}
184
- </div>
185
- )}
186
-
187
- {/* 日志区 */}
188
- <div className={css.meta} style={{ fontWeight: 600 }}>运行日志({run?.log.length ?? 0})</div>
189
- <div
190
- ref={logRef}
191
- style={{ flex: 1, minHeight: 120, overflowY: 'auto', border: '1px solid var(--nf-border)', borderRadius: 'var(--nf-radius-10)', background: 'var(--nf-bg-inset)', padding: 'var(--nf-space-8)', display: 'flex', flexDirection: 'column', gap: 'var(--nf-space-2)', fontSize: 'var(--nf-fs-12)' }}
192
- >
193
- {run === null || run.log.length === 0 ? (
194
- <span className={css.meta}>尚无日志——下单后这里会实时显示每章进度。</span>
195
- ) : run.log.map((l, i) => (
196
- <div key={i} style={{ display: 'flex', gap: 'var(--nf-space-6)', opacity: 0.85 }}>
197
- <span style={{ color: 'var(--nf-text-3)', flex: 'none' }}>{new Date(l.at).toLocaleTimeString('zh-CN', { hour12: false })}</span>
198
- <span>{l.text}</span>
199
- </div>
200
- ))}
201
- </div>
202
- </div>
203
- )
204
- }