@robot-admin/naive-ui-components 0.3.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 (352) hide show
  1. package/README.md +257 -0
  2. package/dist/C_ActionBar-DWN-woTc.css.map +1 -0
  3. package/dist/C_ActionBar.cjs +5 -0
  4. package/dist/C_ActionBar.d.cts +2 -0
  5. package/dist/C_ActionBar.d.ts +2 -0
  6. package/dist/C_ActionBar.js +4 -0
  7. package/dist/C_ActionBar2.js +196 -0
  8. package/dist/C_ActionBar2.js.map +1 -0
  9. package/dist/C_AntV-AFKyK6hH.css.map +1 -0
  10. package/dist/C_AntV.cjs +8 -0
  11. package/dist/C_AntV.d.cts +2 -0
  12. package/dist/C_AntV.d.ts +2 -0
  13. package/dist/C_AntV.js +4 -0
  14. package/dist/C_AntV2.js +3150 -0
  15. package/dist/C_AntV2.js.map +1 -0
  16. package/dist/C_Barcode-P_EFj8dC.css.map +1 -0
  17. package/dist/C_Barcode.cjs +4 -0
  18. package/dist/C_Barcode.d.cts +2 -0
  19. package/dist/C_Barcode.d.ts +2 -0
  20. package/dist/C_Barcode.js +3 -0
  21. package/dist/C_Barcode2.js +68 -0
  22. package/dist/C_Barcode2.js.map +1 -0
  23. package/dist/C_Captcha-C-ef41xw.css.map +1 -0
  24. package/dist/C_Captcha.cjs +4 -0
  25. package/dist/C_Captcha.d.cts +2 -0
  26. package/dist/C_Captcha.d.ts +2 -0
  27. package/dist/C_Captcha.js +3 -0
  28. package/dist/C_Captcha2.js +155 -0
  29. package/dist/C_Captcha2.js.map +1 -0
  30. package/dist/C_Cascade-D9kNsjsV.css.map +1 -0
  31. package/dist/C_Cascade.cjs +4 -0
  32. package/dist/C_Cascade.d.cts +2 -0
  33. package/dist/C_Cascade.d.ts +2 -0
  34. package/dist/C_Cascade.js +3 -0
  35. package/dist/C_Cascade2.js +103 -0
  36. package/dist/C_Cascade2.js.map +1 -0
  37. package/dist/C_City-BCQ4ipiK.css.map +1 -0
  38. package/dist/C_City.cjs +4 -0
  39. package/dist/C_City.d.cts +2 -0
  40. package/dist/C_City.d.ts +2 -0
  41. package/dist/C_City.js +3 -0
  42. package/dist/C_City2.js +841 -0
  43. package/dist/C_City2.js.map +1 -0
  44. package/dist/C_Code-C9kvvEmO.css.map +1 -0
  45. package/dist/C_Code.cjs +5 -0
  46. package/dist/C_Code.d.cts +2 -0
  47. package/dist/C_Code.d.ts +2 -0
  48. package/dist/C_Code.js +4 -0
  49. package/dist/C_Code2.js +346 -0
  50. package/dist/C_Code2.js.map +1 -0
  51. package/dist/C_CollapsePanel-BUJHuYcU.css.map +1 -0
  52. package/dist/C_CollapsePanel.cjs +6 -0
  53. package/dist/C_CollapsePanel.d.cts +2 -0
  54. package/dist/C_CollapsePanel.d.ts +2 -0
  55. package/dist/C_CollapsePanel.js +4 -0
  56. package/dist/C_CollapsePanel2.js +319 -0
  57. package/dist/C_CollapsePanel2.js.map +1 -0
  58. package/dist/C_Cron-yx2Ob4Jl.css.map +1 -0
  59. package/dist/C_Cron.cjs +15 -0
  60. package/dist/C_Cron.d.cts +2 -0
  61. package/dist/C_Cron.d.ts +2 -0
  62. package/dist/C_Cron.js +4 -0
  63. package/dist/C_Cron2.js +1209 -0
  64. package/dist/C_Cron2.js.map +1 -0
  65. package/dist/C_Date.cjs +4 -0
  66. package/dist/C_Date.d.cts +2 -0
  67. package/dist/C_Date.d.ts +2 -0
  68. package/dist/C_Date.js +3 -0
  69. package/dist/C_Date2.js +219 -0
  70. package/dist/C_Date2.js.map +1 -0
  71. package/dist/C_Draggable-C483syRC.css.map +1 -0
  72. package/dist/C_Draggable.cjs +5 -0
  73. package/dist/C_Draggable.d.cts +2 -0
  74. package/dist/C_Draggable.d.ts +2 -0
  75. package/dist/C_Draggable.js +3 -0
  76. package/dist/C_Draggable2.js +295 -0
  77. package/dist/C_Draggable2.js.map +1 -0
  78. package/dist/C_Editor-Bp0SyIEw.css.map +1 -0
  79. package/dist/C_Editor.cjs +4 -0
  80. package/dist/C_Editor.d.cts +2 -0
  81. package/dist/C_Editor.d.ts +2 -0
  82. package/dist/C_Editor.js +3 -0
  83. package/dist/C_Editor2.js +160 -0
  84. package/dist/C_Editor2.js.map +1 -0
  85. package/dist/C_FilePreview-CPqvhoCy.css.map +1 -0
  86. package/dist/C_FilePreview.cjs +6 -0
  87. package/dist/C_FilePreview.d.cts +2 -0
  88. package/dist/C_FilePreview.d.ts +2 -0
  89. package/dist/C_FilePreview.js +3 -0
  90. package/dist/C_FilePreview2.js +1031 -0
  91. package/dist/C_FilePreview2.js.map +1 -0
  92. package/dist/C_Form-Jx7PY3sT.css.map +1 -0
  93. package/dist/C_Form.cjs +15 -0
  94. package/dist/C_Form.d.cts +2 -0
  95. package/dist/C_Form.d.ts +2 -0
  96. package/dist/C_Form.js +4 -0
  97. package/dist/C_Form2.js +2510 -0
  98. package/dist/C_Form2.js.map +1 -0
  99. package/dist/C_FormSearch-DvRgxlRn.css.map +1 -0
  100. package/dist/C_FormSearch.cjs +6 -0
  101. package/dist/C_FormSearch.d.cts +2 -0
  102. package/dist/C_FormSearch.d.ts +2 -0
  103. package/dist/C_FormSearch.js +3 -0
  104. package/dist/C_FormSearch2.js +356 -0
  105. package/dist/C_FormSearch2.js.map +1 -0
  106. package/dist/C_FormulaEditor-DtGkt4T_.css.map +1 -0
  107. package/dist/C_FormulaEditor.cjs +13 -0
  108. package/dist/C_FormulaEditor.d.cts +2 -0
  109. package/dist/C_FormulaEditor.d.ts +2 -0
  110. package/dist/C_FormulaEditor.js +4 -0
  111. package/dist/C_FormulaEditor2.js +1433 -0
  112. package/dist/C_FormulaEditor2.js.map +1 -0
  113. package/dist/C_FullCalendar-BF7H0YIx.css.map +1 -0
  114. package/dist/C_FullCalendar.cjs +9 -0
  115. package/dist/C_FullCalendar.d.cts +2 -0
  116. package/dist/C_FullCalendar.d.ts +2 -0
  117. package/dist/C_FullCalendar.js +3 -0
  118. package/dist/C_FullCalendar2.js +377 -0
  119. package/dist/C_FullCalendar2.js.map +1 -0
  120. package/dist/C_Guide.cjs +4 -0
  121. package/dist/C_Guide.d.cts +2 -0
  122. package/dist/C_Guide.d.ts +2 -0
  123. package/dist/C_Guide.js +3 -0
  124. package/dist/C_Guide2.js +58 -0
  125. package/dist/C_Guide2.js.map +1 -0
  126. package/dist/C_Icon.cjs +4 -0
  127. package/dist/C_Icon.d.cts +2 -0
  128. package/dist/C_Icon.d.ts +2 -0
  129. package/dist/C_Icon.js +3 -0
  130. package/dist/C_Icon2.js +286 -0
  131. package/dist/C_Icon2.js.map +1 -0
  132. package/dist/C_ImageCropper-BVJfUufl.css.map +1 -0
  133. package/dist/C_ImageCropper.cjs +6 -0
  134. package/dist/C_ImageCropper.d.cts +2 -0
  135. package/dist/C_ImageCropper.d.ts +2 -0
  136. package/dist/C_ImageCropper.js +4 -0
  137. package/dist/C_ImageCropper2.js +723 -0
  138. package/dist/C_ImageCropper2.js.map +1 -0
  139. package/dist/C_Language.cjs +4 -0
  140. package/dist/C_Language.d.cts +2 -0
  141. package/dist/C_Language.d.ts +2 -0
  142. package/dist/C_Language.js +3 -0
  143. package/dist/C_Language2.js +72 -0
  144. package/dist/C_Language2.js.map +1 -0
  145. package/dist/C_Map-DpzeuWdX.css.map +1 -0
  146. package/dist/C_Map.cjs +7 -0
  147. package/dist/C_Map.d.cts +2 -0
  148. package/dist/C_Map.d.ts +2 -0
  149. package/dist/C_Map.js +3 -0
  150. package/dist/C_Map2.js +199 -0
  151. package/dist/C_Map2.js.map +1 -0
  152. package/dist/C_Markdown-BEjxknqd.css.map +1 -0
  153. package/dist/C_Markdown.cjs +4 -0
  154. package/dist/C_Markdown.d.cts +2 -0
  155. package/dist/C_Markdown.d.ts +2 -0
  156. package/dist/C_Markdown.js +3 -0
  157. package/dist/C_Markdown2.js +186 -0
  158. package/dist/C_Markdown2.js.map +1 -0
  159. package/dist/C_NotificationCenter-0l3TY2Gn.css.map +1 -0
  160. package/dist/C_NotificationCenter.cjs +20 -0
  161. package/dist/C_NotificationCenter.d.cts +2 -0
  162. package/dist/C_NotificationCenter.d.ts +2 -0
  163. package/dist/C_NotificationCenter.js +4 -0
  164. package/dist/C_NotificationCenter2.js +1383 -0
  165. package/dist/C_NotificationCenter2.js.map +1 -0
  166. package/dist/C_Progress.cjs +4 -0
  167. package/dist/C_Progress.d.cts +2 -0
  168. package/dist/C_Progress.d.ts +2 -0
  169. package/dist/C_Progress.js +3 -0
  170. package/dist/C_Progress2.js +103 -0
  171. package/dist/C_Progress2.js.map +1 -0
  172. package/dist/C_QRCode-DbdiAIPg.css.map +1 -0
  173. package/dist/C_QRCode.cjs +5 -0
  174. package/dist/C_QRCode.d.cts +2 -0
  175. package/dist/C_QRCode.d.ts +2 -0
  176. package/dist/C_QRCode.js +3 -0
  177. package/dist/C_QRCode2.js +218 -0
  178. package/dist/C_QRCode2.js.map +1 -0
  179. package/dist/C_Signature-zhHCbra9.css.map +1 -0
  180. package/dist/C_Signature.cjs +8 -0
  181. package/dist/C_Signature.d.cts +2 -0
  182. package/dist/C_Signature.d.ts +2 -0
  183. package/dist/C_Signature.js +4 -0
  184. package/dist/C_Signature2.js +618 -0
  185. package/dist/C_Signature2.js.map +1 -0
  186. package/dist/C_SplitPane-C6sBsfKY.css.map +1 -0
  187. package/dist/C_SplitPane.cjs +6 -0
  188. package/dist/C_SplitPane.d.cts +2 -0
  189. package/dist/C_SplitPane.d.ts +2 -0
  190. package/dist/C_SplitPane.js +4 -0
  191. package/dist/C_SplitPane2.js +356 -0
  192. package/dist/C_SplitPane2.js.map +1 -0
  193. package/dist/C_Steps-CODHN5Hs.css.map +1 -0
  194. package/dist/C_Steps.cjs +4 -0
  195. package/dist/C_Steps.d.cts +2 -0
  196. package/dist/C_Steps.d.ts +2 -0
  197. package/dist/C_Steps.js +3 -0
  198. package/dist/C_Steps2.js +82 -0
  199. package/dist/C_Steps2.js.map +1 -0
  200. package/dist/C_Table-DSNsntmT.css.map +1 -0
  201. package/dist/C_Table.cjs +19 -0
  202. package/dist/C_Table.d.cts +2 -0
  203. package/dist/C_Table.d.ts +2 -0
  204. package/dist/C_Table.js +5 -0
  205. package/dist/C_Table2.js +3009 -0
  206. package/dist/C_Table2.js.map +1 -0
  207. package/dist/C_Theme.cjs +4 -0
  208. package/dist/C_Theme.d.cts +2 -0
  209. package/dist/C_Theme.d.ts +2 -0
  210. package/dist/C_Theme.js +3 -0
  211. package/dist/C_Theme2.js +60 -0
  212. package/dist/C_Theme2.js.map +1 -0
  213. package/dist/C_Time-BvZLYraL.css.map +1 -0
  214. package/dist/C_Time.cjs +5 -0
  215. package/dist/C_Time.d.cts +2 -0
  216. package/dist/C_Time.d.ts +2 -0
  217. package/dist/C_Time.js +3 -0
  218. package/dist/C_Time2.js +199 -0
  219. package/dist/C_Time2.js.map +1 -0
  220. package/dist/C_Tree-0GDv--jX.css.map +1 -0
  221. package/dist/C_Tree.cjs +7 -0
  222. package/dist/C_Tree.d.cts +2 -0
  223. package/dist/C_Tree.d.ts +2 -0
  224. package/dist/C_Tree.js +4 -0
  225. package/dist/C_Tree2.js +441 -0
  226. package/dist/C_Tree2.js.map +1 -0
  227. package/dist/C_Upload-BXd3YYLx.css.map +1 -0
  228. package/dist/C_Upload.cjs +12 -0
  229. package/dist/C_Upload.d.cts +2 -0
  230. package/dist/C_Upload.d.ts +2 -0
  231. package/dist/C_Upload.js +4 -0
  232. package/dist/C_Upload2.js +1388 -0
  233. package/dist/C_Upload2.js.map +1 -0
  234. package/dist/C_VideoPlayer-DYG3RL0Q.css.map +1 -0
  235. package/dist/C_VideoPlayer.cjs +23 -0
  236. package/dist/C_VideoPlayer.d.cts +2 -0
  237. package/dist/C_VideoPlayer.d.ts +2 -0
  238. package/dist/C_VideoPlayer.js +3 -0
  239. package/dist/C_VideoPlayer2.js +1932 -0
  240. package/dist/C_VideoPlayer2.js.map +1 -0
  241. package/dist/C_VtableGantt-fhItIiHE.css.map +1 -0
  242. package/dist/C_VtableGantt.cjs +6 -0
  243. package/dist/C_VtableGantt.d.cts +2 -0
  244. package/dist/C_VtableGantt.d.ts +2 -0
  245. package/dist/C_VtableGantt.js +4 -0
  246. package/dist/C_VtableGantt2.js +873 -0
  247. package/dist/C_VtableGantt2.js.map +1 -0
  248. package/dist/C_WaterFall-8sQDFXKg.css.map +1 -0
  249. package/dist/C_WaterFall.cjs +13 -0
  250. package/dist/C_WaterFall.d.cts +2 -0
  251. package/dist/C_WaterFall.d.ts +2 -0
  252. package/dist/C_WaterFall.js +3 -0
  253. package/dist/C_WaterFall2.js +365 -0
  254. package/dist/C_WaterFall2.js.map +1 -0
  255. package/dist/C_WorkFlow-J-dyIuh9.css.map +1 -0
  256. package/dist/C_WorkFlow.cjs +8 -0
  257. package/dist/C_WorkFlow.d.cts +2 -0
  258. package/dist/C_WorkFlow.d.ts +2 -0
  259. package/dist/C_WorkFlow.js +4 -0
  260. package/dist/C_WorkFlow2.js +1984 -0
  261. package/dist/C_WorkFlow2.js.map +1 -0
  262. package/dist/chunk.js +22 -0
  263. package/dist/city.js +4817 -0
  264. package/dist/city.js.map +1 -0
  265. package/dist/constants.d.ts +273 -0
  266. package/dist/constants.d.ts.map +1 -0
  267. package/dist/constants2.d.ts +178 -0
  268. package/dist/constants2.d.ts.map +1 -0
  269. package/dist/constants3.d.ts +475 -0
  270. package/dist/constants3.d.ts.map +1 -0
  271. package/dist/constants4.d.ts +430 -0
  272. package/dist/constants4.d.ts.map +1 -0
  273. package/dist/constants5.d.ts +4283 -0
  274. package/dist/constants5.d.ts.map +1 -0
  275. package/dist/data.d.ts +67 -0
  276. package/dist/data.d.ts.map +1 -0
  277. package/dist/export-helper.js +9 -0
  278. package/dist/index.cjs +409 -0
  279. package/dist/index.d.cts +96 -0
  280. package/dist/index.d.cts.map +1 -0
  281. package/dist/index.d.ts +103 -0
  282. package/dist/index.d.ts.map +1 -0
  283. package/dist/index.js +230 -0
  284. package/dist/index.js.map +1 -0
  285. package/dist/index.vue.d.ts +80 -0
  286. package/dist/index.vue.d.ts.map +1 -0
  287. package/dist/index10.vue.d.ts +72 -0
  288. package/dist/index10.vue.d.ts.map +1 -0
  289. package/dist/index11.vue.d.ts +26 -0
  290. package/dist/index11.vue.d.ts.map +1 -0
  291. package/dist/index12.vue.d.ts +81 -0
  292. package/dist/index12.vue.d.ts.map +1 -0
  293. package/dist/index13.vue.d.ts +55 -0
  294. package/dist/index13.vue.d.ts.map +1 -0
  295. package/dist/index14.vue.d.ts +33 -0
  296. package/dist/index14.vue.d.ts.map +1 -0
  297. package/dist/index15.vue.d.ts +18 -0
  298. package/dist/index15.vue.d.ts.map +1 -0
  299. package/dist/index16.vue.d.ts +662 -0
  300. package/dist/index16.vue.d.ts.map +1 -0
  301. package/dist/index2.vue.d.ts +38 -0
  302. package/dist/index2.vue.d.ts.map +1 -0
  303. package/dist/index3.vue.d.ts +45 -0
  304. package/dist/index3.vue.d.ts.map +1 -0
  305. package/dist/index4.vue.d.ts +31 -0
  306. package/dist/index4.vue.d.ts.map +1 -0
  307. package/dist/index5.vue.d.ts +35 -0
  308. package/dist/index5.vue.d.ts.map +1 -0
  309. package/dist/index6.vue.d.ts +48 -0
  310. package/dist/index6.vue.d.ts.map +1 -0
  311. package/dist/index7.vue.d.ts +56 -0
  312. package/dist/index7.vue.d.ts.map +1 -0
  313. package/dist/index8.vue.d.ts +41 -0
  314. package/dist/index8.vue.d.ts.map +1 -0
  315. package/dist/index9.vue.d.ts +30 -0
  316. package/dist/index9.vue.d.ts.map +1 -0
  317. package/dist/storage.js +31 -0
  318. package/dist/storage.js.map +1 -0
  319. package/dist/style.css +7725 -0
  320. package/dist/useCalendarEvents.d.ts +148 -0
  321. package/dist/useCalendarEvents.d.ts.map +1 -0
  322. package/dist/useCollapsePanel.d.ts +132 -0
  323. package/dist/useCollapsePanel.d.ts.map +1 -0
  324. package/dist/useCropperCore.d.ts +102 -0
  325. package/dist/useCropperCore.d.ts.map +1 -0
  326. package/dist/useDraggableLayout.d.ts +194 -0
  327. package/dist/useDraggableLayout.d.ts.map +1 -0
  328. package/dist/useDynamicFormState.d.ts +4248 -0
  329. package/dist/useDynamicFormState.d.ts.map +1 -0
  330. package/dist/useEdgeInteraction.d.ts +7614 -0
  331. package/dist/useEdgeInteraction.d.ts.map +1 -0
  332. package/dist/useFullscreen.d.ts +166 -0
  333. package/dist/useFullscreen.d.ts.map +1 -0
  334. package/dist/useInfiniteScroll.d.ts +169 -0
  335. package/dist/useInfiniteScroll.d.ts.map +1 -0
  336. package/dist/useModalEdit.d.ts +960 -0
  337. package/dist/useModalEdit.d.ts.map +1 -0
  338. package/dist/useQRCode.d.ts +87 -0
  339. package/dist/useQRCode.d.ts.map +1 -0
  340. package/dist/useSearchState.d.ts +180 -0
  341. package/dist/useSearchState.d.ts.map +1 -0
  342. package/dist/useSignatureHistory.d.ts +189 -0
  343. package/dist/useSignatureHistory.d.ts.map +1 -0
  344. package/dist/useSplitResize.d.ts +158 -0
  345. package/dist/useSplitResize.d.ts.map +1 -0
  346. package/dist/useTimeSelection.d.ts +105 -0
  347. package/dist/useTimeSelection.d.ts.map +1 -0
  348. package/dist/useTreeOperations.d.ts +183 -0
  349. package/dist/useTreeOperations.d.ts.map +1 -0
  350. package/dist/useWorkflowValidation.d.ts +1052 -0
  351. package/dist/useWorkflowValidation.d.ts.map +1 -0
  352. package/package.json +342 -0
@@ -0,0 +1,1984 @@
1
+ import { t as C_Icon_default } from "./C_Icon2.js";
2
+ import { t as export_helper_default } from "./export-helper.js";
3
+ import { Fragment, Teleport, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, isRef, markRaw, nextTick, normalizeClass, normalizeStyle, onMounted, openBlock, provide, ref, renderList, toDisplayString, unref, vShow, watch, withCtx, withDirectives } from "vue";
4
+ import { NAvatar, NButton, NCard, NDrawer, NDrawerContent, NInput, NModal, NRadio, NRadioGroup, NSelect, NSpace, NTag, NTree, useMessage } from "naive-ui";
5
+ import { VueFlow } from "@vue-flow/core";
6
+
7
+ //#region src/components/C_WorkFlow/data.ts
8
+ const NODE_TYPE_OPTIONS = [
9
+ {
10
+ type: "approval",
11
+ label: "审批人",
12
+ icon: "mdi:account-check",
13
+ iconClass: "approval-icon"
14
+ },
15
+ {
16
+ type: "copy",
17
+ label: "抄送人",
18
+ icon: "mdi:email-outline",
19
+ iconClass: "copy-icon"
20
+ },
21
+ {
22
+ type: "condition",
23
+ label: "条件分支",
24
+ icon: "mdi:source-branch",
25
+ iconClass: "condition-icon"
26
+ }
27
+ ];
28
+ const APPROVAL_MODES = [
29
+ {
30
+ value: "any",
31
+ label: "或签",
32
+ desc: "任意一人同意即可通过"
33
+ },
34
+ {
35
+ value: "all",
36
+ label: "会签",
37
+ desc: "所有人都同意才能通过"
38
+ },
39
+ {
40
+ value: "sequence",
41
+ label: "顺序审批",
42
+ desc: "按选择顺序依次审批"
43
+ }
44
+ ];
45
+ const FIELD_OPTIONS = [
46
+ {
47
+ label: "申请金额",
48
+ value: "amount"
49
+ },
50
+ {
51
+ label: "申请人部门",
52
+ value: "department"
53
+ },
54
+ {
55
+ label: "申请类型",
56
+ value: "type"
57
+ },
58
+ {
59
+ label: "紧急程度",
60
+ value: "priority"
61
+ }
62
+ ];
63
+ const OPERATOR_OPTIONS = [
64
+ {
65
+ label: "等于",
66
+ value: "equals"
67
+ },
68
+ {
69
+ label: "大于",
70
+ value: "greater_than"
71
+ },
72
+ {
73
+ label: "小于",
74
+ value: "less_than"
75
+ },
76
+ {
77
+ label: "包含",
78
+ value: "contains"
79
+ },
80
+ {
81
+ label: "不等于",
82
+ value: "not_equals"
83
+ }
84
+ ];
85
+ const NODE_TITLES = {
86
+ start: "发起人",
87
+ approval: "审批人",
88
+ copy: "抄送人",
89
+ condition: "条件分支"
90
+ };
91
+ const CONFIG_TITLES = {
92
+ approval: "审批人设置",
93
+ copy: "抄送人设置",
94
+ condition: "条件分支设置"
95
+ };
96
+ const FIELD_DISPLAY_NAMES = {
97
+ approvers: "审批人",
98
+ conditions: "条件配置",
99
+ connection: "节点连接",
100
+ copyUsers: "抄送人"
101
+ };
102
+ const ERROR_TYPE_TEXTS = {
103
+ required: "必填",
104
+ incomplete: "不完整",
105
+ warning: "警告",
106
+ error: "错误"
107
+ };
108
+ /** 节点之间的 Y 轴间距(px) */
109
+ const NODE_Y_GAP = 180;
110
+ const INITIAL_NODE = {
111
+ id: "start-1",
112
+ type: "start",
113
+ position: {
114
+ x: 150,
115
+ y: 100
116
+ },
117
+ data: {
118
+ title: "发起人",
119
+ status: "active",
120
+ initiators: []
121
+ }
122
+ };
123
+ const getDefaultAvatar = (name) => `https://ui-avatars.com/api/?name=${encodeURIComponent(name)}&background=random`;
124
+ const generateConditionId = () => `condition-${Date.now()}`;
125
+ const generateEdgeId = (sourceId, targetId) => `edge-${sourceId}-${targetId}`;
126
+ const createDefaultCondition = () => ({
127
+ id: generateConditionId(),
128
+ name: "",
129
+ field: "",
130
+ operator: "equals",
131
+ value: ""
132
+ });
133
+
134
+ //#endregion
135
+ //#region src/components/C_WorkFlow/NodeConfigModal.vue?vue&type=script&setup=true&lang.ts
136
+ const _hoisted_1$5 = {
137
+ key: 0,
138
+ class: "max-h-60vh overflow-y-auto"
139
+ };
140
+ const _hoisted_2$5 = { class: "config-section" };
141
+ const _hoisted_3$5 = {
142
+ class: "flex items-center gap-2 mb-4 text-base font-semibold",
143
+ style: { color: "var(--n-text-color-1)" }
144
+ };
145
+ const _hoisted_4$5 = {
146
+ class: "border rounded-lg p-3 mb-4 max-h-50 overflow-y-auto",
147
+ style: {
148
+ borderColor: "var(--n-border-color)",
149
+ background: "var(--n-color-embedded)"
150
+ }
151
+ };
152
+ const _hoisted_5$5 = {
153
+ key: 0,
154
+ class: "rounded-lg p-4 mb-4 border",
155
+ style: {
156
+ borderColor: "var(--n-border-color)",
157
+ background: "var(--n-color-embedded)"
158
+ }
159
+ };
160
+ const _hoisted_6$5 = {
161
+ class: "mb-2 text-sm font-medium",
162
+ style: { color: "var(--n-text-color-1)" }
163
+ };
164
+ const _hoisted_7$4 = { class: "flex flex-wrap gap-3" };
165
+ const _hoisted_8$4 = { class: "flex items-center gap-2" };
166
+ const _hoisted_9$3 = { class: "font-medium text-sm" };
167
+ const _hoisted_10$2 = {
168
+ class: "text-xs px-1.5 py-0.5 rounded",
169
+ style: {
170
+ color: "var(--n-text-color-3)",
171
+ background: "var(--n-color-embedded)"
172
+ }
173
+ };
174
+ const _hoisted_11$2 = {
175
+ key: 0,
176
+ class: "mt-4"
177
+ };
178
+ const _hoisted_12$2 = { class: "flex flex-col gap-1" };
179
+ const _hoisted_13$2 = { class: "text-sm" };
180
+ const _hoisted_14$2 = {
181
+ class: "text-xs",
182
+ style: { color: "var(--n-text-color-3)" }
183
+ };
184
+ const _hoisted_15$2 = { class: "max-h-60vh overflow-y-auto" };
185
+ const _hoisted_16$2 = { class: "config-section" };
186
+ const _hoisted_17$1 = {
187
+ class: "flex items-center gap-2 mb-4 text-base font-semibold",
188
+ style: { color: "var(--n-text-color-1)" }
189
+ };
190
+ const _hoisted_18$1 = { class: "space-y-3" };
191
+ const _hoisted_19$1 = { class: "flex items-center gap-3 flex-nowrap min-h-10 p-2" };
192
+ var NodeConfigModal_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
193
+ __name: "NodeConfigModal",
194
+ props: {
195
+ show: {
196
+ type: Boolean,
197
+ default: false
198
+ },
199
+ currentNode: { default: null },
200
+ users: { default: () => [] },
201
+ departments: { default: () => [] }
202
+ },
203
+ emits: [
204
+ "update:show",
205
+ "save",
206
+ "cancel"
207
+ ],
208
+ setup(__props, { emit: __emit }) {
209
+ const props = __props;
210
+ const emit = __emit;
211
+ const message = useMessage();
212
+ const searchKeyword = ref("");
213
+ const selectedUsers = ref([]);
214
+ const selectedCopyUsers = ref([]);
215
+ const approvalMode = ref("any");
216
+ const configLoading = ref(false);
217
+ const conditions = ref([]);
218
+ const visible = computed({
219
+ get: () => props.show,
220
+ set: (value) => emit("update:show", value)
221
+ });
222
+ const configTitle = computed(() => {
223
+ if (props.currentNode?.type === "start") return "发起人设置";
224
+ return CONFIG_TITLES[props.currentNode?.type] || "节点设置";
225
+ });
226
+ const departmentUserTree = computed(() => {
227
+ const tree = [];
228
+ const deptMap = /* @__PURE__ */ new Map();
229
+ props.departments?.forEach((dept) => {
230
+ if (!deptMap.has(dept.id)) deptMap.set(dept.id, {
231
+ key: `dept-${dept.id}`,
232
+ label: `${dept.name} ${dept.manager ? `(负责人: ${dept.manager})` : ""}`,
233
+ children: [],
234
+ isLeaf: false,
235
+ disabled: true
236
+ });
237
+ });
238
+ (props.users?.filter((user) => !searchKeyword.value || user.name.includes(searchKeyword.value) || user.department.includes(searchKeyword.value)) || []).forEach((user) => {
239
+ const dept = props.departments?.find((d) => d.name === user.department);
240
+ if (dept && deptMap.has(dept.id)) deptMap.get(dept.id).children.push({
241
+ key: user.id,
242
+ label: `${user.name}${user.role ? `(${user.role})` : ""}`,
243
+ isLeaf: true,
244
+ user
245
+ });
246
+ });
247
+ deptMap.forEach((dept) => {
248
+ if (dept.children.length > 0) tree.push(dept);
249
+ });
250
+ return tree;
251
+ });
252
+ const selectedApprovers = computed(() => props.users?.filter((u) => selectedUsers.value.includes(u.id)) || []);
253
+ const selectedCopyUserList = computed(() => props.users?.filter((u) => selectedCopyUsers.value.includes(u.id)) || []);
254
+ const selectedInitiators = computed(() => props.users?.filter((u) => selectedUsers.value.includes(u.id)) || []);
255
+ const handleUserSelect = (keys) => {
256
+ selectedUsers.value = keys.filter((key) => !key.startsWith("dept-"));
257
+ };
258
+ const handleCopyUserSelect = (keys) => {
259
+ selectedCopyUsers.value = keys.filter((key) => !key.startsWith("dept-"));
260
+ };
261
+ const removeApprover = (userId) => {
262
+ selectedUsers.value = selectedUsers.value.filter((id) => id !== userId);
263
+ };
264
+ const removeCopyUser = (userId) => {
265
+ selectedCopyUsers.value = selectedCopyUsers.value.filter((id) => id !== userId);
266
+ };
267
+ const removeInitiator = (userId) => {
268
+ selectedUsers.value = selectedUsers.value.filter((id) => id !== userId);
269
+ };
270
+ const addCondition = () => conditions.value.push(createDefaultCondition());
271
+ const removeCondition = (index) => conditions.value.splice(index, 1);
272
+ const configureStartNode = (node) => {
273
+ const { initiators } = node.data;
274
+ selectedUsers.value = initiators ? initiators.map((u) => u.id) : [];
275
+ };
276
+ const configureApprovalNode = (node) => {
277
+ selectedUsers.value = (node.data.approvers || []).map((u) => u.id);
278
+ approvalMode.value = node.data.approvalMode || "any";
279
+ };
280
+ const configureCopyNode = (node) => {
281
+ selectedCopyUsers.value = (node.data.copyUsers || []).map((u) => u.id);
282
+ };
283
+ const configureConditionNode = (node) => {
284
+ conditions.value = node.data.conditions || [];
285
+ };
286
+ const saveStartNodeConfig = async () => {
287
+ if (selectedUsers.value.length === 0) {
288
+ message.error("请选择发起人");
289
+ return false;
290
+ }
291
+ const selectedUserObjs = selectedInitiators.value;
292
+ emit("save", { initiators: selectedUserObjs });
293
+ message.success(`已设置 ${selectedUserObjs.length} 个发起人`);
294
+ return true;
295
+ };
296
+ const saveApprovalNodeConfig = async () => {
297
+ if (selectedUsers.value.length === 0) {
298
+ message.error("请至少选择一个审批人");
299
+ return false;
300
+ }
301
+ const selectedUserObjs = selectedApprovers.value;
302
+ emit("save", {
303
+ approvers: selectedUserObjs,
304
+ approvalMode: approvalMode.value
305
+ });
306
+ message.success(`已设置 ${selectedUserObjs.length} 个审批人`);
307
+ return true;
308
+ };
309
+ const saveCopyNodeConfig = async () => {
310
+ const selectedUserObjs = selectedCopyUserList.value;
311
+ emit("save", { copyUsers: selectedUserObjs });
312
+ message.success(`已设置 ${selectedUserObjs.length} 个抄送人`);
313
+ return true;
314
+ };
315
+ const saveConditionNodeConfig = async () => {
316
+ if (conditions.value.length === 0) {
317
+ message.error("请至少添加一个条件分支");
318
+ return false;
319
+ }
320
+ const validConditions = conditions.value.filter((c) => c.name && c.field && c.operator && c.value);
321
+ if (validConditions.length === 0) {
322
+ message.error("请完善条件配置");
323
+ return false;
324
+ }
325
+ emit("save", { conditions: validConditions });
326
+ message.success(`已设置 ${validConditions.length} 个条件分支`);
327
+ return true;
328
+ };
329
+ const saveNodeConfig = async () => {
330
+ if (!props.currentNode) return false;
331
+ configLoading.value = true;
332
+ try {
333
+ const saver = {
334
+ start: saveStartNodeConfig,
335
+ approval: saveApprovalNodeConfig,
336
+ copy: saveCopyNodeConfig,
337
+ condition: saveConditionNodeConfig
338
+ }[props.currentNode.type];
339
+ return saver ? await saver() : false;
340
+ } catch (error) {
341
+ message.error("保存配置失败");
342
+ console.error("Save node config error:", error);
343
+ return false;
344
+ } finally {
345
+ configLoading.value = false;
346
+ }
347
+ };
348
+ const handleCancel = () => {
349
+ emit("cancel");
350
+ };
351
+ watch(() => props.currentNode, (newNode) => {
352
+ if (newNode) {
353
+ searchKeyword.value = "";
354
+ const configurator = {
355
+ start: configureStartNode,
356
+ approval: configureApprovalNode,
357
+ copy: configureCopyNode,
358
+ condition: configureConditionNode
359
+ }[newNode.type];
360
+ if (configurator) configurator(newNode);
361
+ }
362
+ }, { immediate: true });
363
+ const isUserSelectNode = computed(() => [
364
+ "start",
365
+ "approval",
366
+ "copy"
367
+ ].includes(props.currentNode?.type || ""));
368
+ const userSelectConfig = computed(() => {
369
+ const type = props.currentNode?.type;
370
+ if (type === "start") return {
371
+ icon: "mdi:account-star",
372
+ title: "选择发起人",
373
+ checkedKeys: selectedUsers.value,
374
+ onSelect: handleUserSelect,
375
+ selectedUsers: selectedInitiators.value,
376
+ selectedLabel: "已选择发起人",
377
+ tagType: "primary",
378
+ onRemove: removeInitiator
379
+ };
380
+ else if (type === "approval") return {
381
+ icon: "mdi:account-check",
382
+ title: "选择审批人",
383
+ checkedKeys: selectedUsers.value,
384
+ onSelect: handleUserSelect,
385
+ selectedUsers: selectedApprovers.value,
386
+ selectedLabel: "已选择审批人",
387
+ tagType: "info",
388
+ onRemove: removeApprover
389
+ };
390
+ else if (type === "copy") return {
391
+ icon: "mdi:email-outline",
392
+ title: "选择抄送人",
393
+ checkedKeys: selectedCopyUsers.value,
394
+ onSelect: handleCopyUserSelect,
395
+ selectedUsers: selectedCopyUserList.value,
396
+ selectedLabel: "已选择抄送人",
397
+ tagType: "success",
398
+ onRemove: removeCopyUser
399
+ };
400
+ return {
401
+ icon: "",
402
+ title: "",
403
+ checkedKeys: [],
404
+ onSelect: (_keys) => {},
405
+ selectedUsers: [],
406
+ selectedLabel: "",
407
+ tagType: "default",
408
+ onRemove: (_id) => {}
409
+ };
410
+ });
411
+ return (_ctx, _cache) => {
412
+ return openBlock(), createBlock(unref(NModal), {
413
+ show: visible.value,
414
+ "onUpdate:show": _cache[2] || (_cache[2] = ($event) => visible.value = $event),
415
+ style: { "width": "900px" },
416
+ "mask-closable": false,
417
+ preset: "dialog",
418
+ title: configTitle.value,
419
+ "positive-text": "确定",
420
+ "negative-text": "取消",
421
+ loading: configLoading.value,
422
+ onPositiveClick: saveNodeConfig,
423
+ onNegativeClick: handleCancel
424
+ }, {
425
+ default: withCtx(() => [createCommentVNode(" 公共选择面板 "), isUserSelectNode.value ? (openBlock(), createElementBlock("div", _hoisted_1$5, [
426
+ createElementVNode("div", _hoisted_2$5, [
427
+ createElementVNode("h4", _hoisted_3$5, [userSelectConfig.value.icon ? (openBlock(), createBlock(unref(C_Icon_default), {
428
+ key: 0,
429
+ name: userSelectConfig.value.icon,
430
+ size: 16
431
+ }, null, 8, ["name"])) : createCommentVNode("v-if", true), createTextVNode(" " + toDisplayString(userSelectConfig.value.title), 1)]),
432
+ createVNode(unref(NInput), {
433
+ value: searchKeyword.value,
434
+ "onUpdate:value": _cache[0] || (_cache[0] = ($event) => searchKeyword.value = $event),
435
+ placeholder: "搜索用户姓名或部门",
436
+ clearable: "",
437
+ class: "mb-4"
438
+ }, {
439
+ prefix: withCtx(() => [createVNode(unref(C_Icon_default), {
440
+ name: "mdi:magnify",
441
+ size: 16
442
+ })]),
443
+ _: 1
444
+ }, 8, ["value"]),
445
+ createElementVNode("div", _hoisted_4$5, [createVNode(unref(NTree), {
446
+ data: departmentUserTree.value,
447
+ "checked-keys": userSelectConfig.value.checkedKeys,
448
+ selectable: false,
449
+ checkable: "",
450
+ cascade: "",
451
+ "virtual-scroll": true,
452
+ style: { "max-height": "300px" },
453
+ "onUpdate:checkedKeys": userSelectConfig.value.onSelect
454
+ }, null, 8, [
455
+ "data",
456
+ "checked-keys",
457
+ "onUpdate:checkedKeys"
458
+ ])]),
459
+ userSelectConfig.value.selectedUsers.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_5$5, [createElementVNode("h5", _hoisted_6$5, toDisplayString(userSelectConfig.value.selectedLabel) + " (" + toDisplayString(userSelectConfig.value.selectedUsers.length) + ") ", 1), createElementVNode("div", _hoisted_7$4, [(openBlock(true), createElementBlock(Fragment, null, renderList(userSelectConfig.value.selectedUsers, (user) => {
460
+ return openBlock(), createBlock(unref(NTag), {
461
+ key: user.id,
462
+ closable: "",
463
+ type: userSelectConfig.value.tagType,
464
+ onClose: ($event) => userSelectConfig.value.onRemove(user.id)
465
+ }, {
466
+ default: withCtx(() => [createElementVNode("div", _hoisted_8$4, [
467
+ createVNode(unref(NAvatar), {
468
+ src: user.avatar,
469
+ "fallback-src": unref(getDefaultAvatar)(user.name),
470
+ size: "small"
471
+ }, null, 8, ["src", "fallback-src"]),
472
+ createElementVNode("span", _hoisted_9$3, toDisplayString(user.name), 1),
473
+ createElementVNode("span", _hoisted_10$2, toDisplayString(user.department), 1)
474
+ ])]),
475
+ _: 2
476
+ }, 1032, ["type", "onClose"]);
477
+ }), 128))])])) : createCommentVNode("v-if", true)
478
+ ]),
479
+ createCommentVNode(" 审批节点时附带审批模式 "),
480
+ props.currentNode?.type === "approval" ? (openBlock(), createElementBlock("div", _hoisted_11$2, [_cache[3] || (_cache[3] = createElementVNode("h5", {
481
+ class: "mb-3 text-sm font-medium",
482
+ style: { color: "var(--n-text-color-1)" }
483
+ }, " 审批模式 ", -1)), createVNode(unref(NRadioGroup), {
484
+ value: approvalMode.value,
485
+ "onUpdate:value": _cache[1] || (_cache[1] = ($event) => approvalMode.value = $event)
486
+ }, {
487
+ default: withCtx(() => [createVNode(unref(NSpace), { vertical: "" }, {
488
+ default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(APPROVAL_MODES), (mode) => {
489
+ return openBlock(), createBlock(unref(NRadio), {
490
+ key: mode.value,
491
+ value: mode.value
492
+ }, {
493
+ default: withCtx(() => [createElementVNode("div", _hoisted_12$2, [createElementVNode("strong", _hoisted_13$2, toDisplayString(mode.label), 1), createElementVNode("span", _hoisted_14$2, toDisplayString(mode.desc), 1)])]),
494
+ _: 2
495
+ }, 1032, ["value"]);
496
+ }), 128))]),
497
+ _: 1
498
+ })]),
499
+ _: 1
500
+ }, 8, ["value"])])) : createCommentVNode("v-if", true)
501
+ ])) : props.currentNode?.type === "condition" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createCommentVNode(" 条件节点配置 "), createElementVNode("div", _hoisted_15$2, [createElementVNode("div", _hoisted_16$2, [createElementVNode("h4", _hoisted_17$1, [createVNode(unref(C_Icon_default), {
502
+ name: "mdi:source-branch",
503
+ size: 16
504
+ }), _cache[4] || (_cache[4] = createTextVNode(" 条件分支设置 ", -1))]), createElementVNode("div", _hoisted_18$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(conditions.value, (condition, index) => {
505
+ return openBlock(), createElementBlock("div", {
506
+ key: condition.id,
507
+ class: "condition-item"
508
+ }, [createVNode(unref(NCard), {
509
+ size: "small",
510
+ class: "border border-gray-200 hover:border-gray-300 transition-colors"
511
+ }, {
512
+ default: withCtx(() => [createElementVNode("div", _hoisted_19$1, [
513
+ createVNode(unref(NInput), {
514
+ value: condition.name,
515
+ "onUpdate:value": ($event) => condition.name = $event,
516
+ placeholder: "分支名称",
517
+ style: { "width": "150px" },
518
+ class: "flex-shrink-0"
519
+ }, null, 8, ["value", "onUpdate:value"]),
520
+ createVNode(unref(NSelect), {
521
+ value: condition.field,
522
+ "onUpdate:value": ($event) => condition.field = $event,
523
+ placeholder: "选择字段",
524
+ options: unref(FIELD_OPTIONS),
525
+ style: { "width": "120px" },
526
+ class: "flex-shrink-0"
527
+ }, null, 8, [
528
+ "value",
529
+ "onUpdate:value",
530
+ "options"
531
+ ]),
532
+ createVNode(unref(NSelect), {
533
+ value: condition.operator,
534
+ "onUpdate:value": ($event) => condition.operator = $event,
535
+ placeholder: "操作符",
536
+ options: unref(OPERATOR_OPTIONS),
537
+ style: { "width": "100px" },
538
+ class: "flex-shrink-0"
539
+ }, null, 8, [
540
+ "value",
541
+ "onUpdate:value",
542
+ "options"
543
+ ]),
544
+ createVNode(unref(NInput), {
545
+ value: condition.value,
546
+ "onUpdate:value": ($event) => condition.value = $event,
547
+ placeholder: "值",
548
+ style: { "width": "120px" },
549
+ class: "flex-shrink-0"
550
+ }, null, 8, ["value", "onUpdate:value"]),
551
+ createVNode(unref(NButton), {
552
+ quaternary: "",
553
+ type: "error",
554
+ onClick: ($event) => removeCondition(index),
555
+ class: "flex-shrink-0 ml-auto"
556
+ }, {
557
+ icon: withCtx(() => [createVNode(unref(C_Icon_default), {
558
+ name: "mdi:delete",
559
+ size: 16
560
+ })]),
561
+ _: 2
562
+ }, 1032, ["onClick"])
563
+ ])]),
564
+ _: 2
565
+ }, 1024)]);
566
+ }), 128)), createVNode(unref(NButton), {
567
+ dashed: "",
568
+ block: "",
569
+ onClick: addCondition,
570
+ class: "w-full"
571
+ }, {
572
+ icon: withCtx(() => [createVNode(unref(C_Icon_default), {
573
+ name: "mdi:plus",
574
+ size: 16
575
+ })]),
576
+ default: withCtx(() => [_cache[5] || (_cache[5] = createTextVNode(" 添加条件 ", -1))]),
577
+ _: 1,
578
+ __: [5]
579
+ })])])])], 2112)) : createCommentVNode("v-if", true)]),
580
+ _: 1
581
+ }, 8, [
582
+ "show",
583
+ "title",
584
+ "loading"
585
+ ]);
586
+ };
587
+ }
588
+ });
589
+
590
+ //#endregion
591
+ //#region src/components/C_WorkFlow/NodeConfigModal.vue
592
+ var NodeConfigModal_default = NodeConfigModal_vue_vue_type_script_setup_true_lang_default;
593
+
594
+ //#endregion
595
+ //#region src/components/C_WorkFlow/nodes/StartNode.vue?vue&type=script&setup=true&lang.ts
596
+ const _hoisted_1$4 = { class: "start-node" };
597
+ const _hoisted_2$4 = { class: "node-content" };
598
+ const _hoisted_3$4 = { class: "node-info" };
599
+ const _hoisted_4$4 = { class: "node-text" };
600
+ const _hoisted_5$4 = {
601
+ key: 0,
602
+ class: "initiator-name"
603
+ };
604
+ const _hoisted_6$4 = {
605
+ key: 1,
606
+ class: "placeholder-text"
607
+ };
608
+ var StartNode_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
609
+ __name: "StartNode",
610
+ props: {
611
+ id: {},
612
+ data: {}
613
+ },
614
+ setup(__props) {
615
+ const props = __props;
616
+ const showAddMenuFn = inject("showAddMenu");
617
+ const initiatorNames = computed(() => {
618
+ const { initiators } = props.data;
619
+ if (!initiators || !Array.isArray(initiators) || initiators.length === 0) return "";
620
+ return initiators.map((user) => user?.name || "未知用户").join("、");
621
+ });
622
+ const showAddMenu = (event) => {
623
+ event.stopPropagation();
624
+ const rect = event.currentTarget.getBoundingClientRect();
625
+ if (showAddMenuFn) showAddMenuFn({
626
+ x: rect.left + rect.width / 2,
627
+ y: rect.bottom + 10
628
+ }, props.id);
629
+ };
630
+ return (_ctx, _cache) => {
631
+ return openBlock(), createElementBlock("div", _hoisted_1$4, [
632
+ createCommentVNode(" 主要内容区域 "),
633
+ createElementVNode("div", _hoisted_2$4, [_cache[0] || (_cache[0] = createElementVNode("div", { class: "node-icon" }, "🚀", -1)), createElementVNode("div", _hoisted_3$4, [createElementVNode("div", _hoisted_4$4, toDisplayString(_ctx.data.title), 1), initiatorNames.value ? (openBlock(), createElementBlock("div", _hoisted_5$4, toDisplayString(initiatorNames.value), 1)) : (openBlock(), createElementBlock("div", _hoisted_6$4, "点击设置发起人"))])]),
634
+ createCommentVNode(" 添加节点按钮 "),
635
+ createElementVNode("div", {
636
+ class: "add-node-btn",
637
+ onClick: showAddMenu,
638
+ title: "添加下一个节点"
639
+ }, [createVNode(unref(C_Icon_default), {
640
+ name: "mdi:plus",
641
+ size: 16
642
+ })])
643
+ ]);
644
+ };
645
+ }
646
+ });
647
+
648
+ //#endregion
649
+ //#region src/components/C_WorkFlow/nodes/StartNode.vue
650
+ var StartNode_default = /* @__PURE__ */ export_helper_default(StartNode_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-8dfd664b"]]);
651
+
652
+ //#endregion
653
+ //#region src/components/C_WorkFlow/nodes/ApprovalNode.vue?vue&type=script&setup=true&lang.ts
654
+ const _hoisted_1$3 = { class: "approval-node" };
655
+ const _hoisted_2$3 = { class: "node-header" };
656
+ const _hoisted_3$3 = { class: "node-icon" };
657
+ const _hoisted_4$3 = { class: "node-title" };
658
+ const _hoisted_5$3 = {
659
+ key: 0,
660
+ class: "node-badge"
661
+ };
662
+ const _hoisted_6$3 = {
663
+ key: 1,
664
+ class: "approval-mode-badge"
665
+ };
666
+ const _hoisted_7$3 = { class: "node-content" };
667
+ const _hoisted_8$3 = {
668
+ key: 0,
669
+ class: "approvers-list"
670
+ };
671
+ const _hoisted_9$2 = { class: "approver-info" };
672
+ const _hoisted_10$1 = { class: "approver-avatar" };
673
+ const _hoisted_11$1 = { class: "approver-details" };
674
+ const _hoisted_12$1 = { class: "approver-name" };
675
+ const _hoisted_13$1 = { class: "approver-dept" };
676
+ const _hoisted_14$1 = { class: "approver-role" };
677
+ const _hoisted_15$1 = {
678
+ key: 0,
679
+ class: "more-count"
680
+ };
681
+ const _hoisted_16$1 = {
682
+ key: 1,
683
+ class: "placeholder"
684
+ };
685
+ var ApprovalNode_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
686
+ __name: "ApprovalNode",
687
+ props: {
688
+ id: {},
689
+ data: {}
690
+ },
691
+ setup(__props) {
692
+ const props = __props;
693
+ const showAddMenuFn = inject("showAddMenu");
694
+ const deleteNodeFn = inject("deleteNode");
695
+ const approvers = computed(() => props.data.approvers ?? []);
696
+ const approverCount = computed(() => approvers.value.length);
697
+ const displayApprovers = computed(() => approvers.value.slice(0, 3));
698
+ const moreCount = computed(() => Math.max(0, approverCount.value - 3));
699
+ const getApprovalModeText = (mode) => {
700
+ return {
701
+ any: "或签",
702
+ all: "会签",
703
+ sequence: "顺序"
704
+ }[mode] || "";
705
+ };
706
+ const getDefaultAvatar = (name) => {
707
+ return `https://ui-avatars.com/api/?name=${encodeURIComponent(name)}&background=random`;
708
+ };
709
+ const handleNodeClick = () => {};
710
+ const showAddMenu = (event) => {
711
+ event.stopPropagation();
712
+ const rect = event.currentTarget.getBoundingClientRect();
713
+ if (showAddMenuFn) showAddMenuFn({
714
+ x: rect.left + rect.width / 2,
715
+ y: rect.bottom + 10
716
+ }, props.id);
717
+ };
718
+ const handleDelete = (event) => {
719
+ event.stopPropagation();
720
+ if (deleteNodeFn) deleteNodeFn(props.id);
721
+ };
722
+ return (_ctx, _cache) => {
723
+ return openBlock(), createElementBlock("div", _hoisted_1$3, [
724
+ createElementVNode("div", { class: normalizeClass(["status-indicator", _ctx.data.status]) }, null, 2),
725
+ createCommentVNode(" 删除按钮 "),
726
+ createElementVNode("div", {
727
+ class: "delete-btn",
728
+ onClick: handleDelete,
729
+ title: "删除节点"
730
+ }, [createVNode(unref(C_Icon_default), {
731
+ name: "mdi:close",
732
+ size: 12
733
+ })]),
734
+ createElementVNode("div", {
735
+ class: "node-card",
736
+ onClick: handleNodeClick
737
+ }, [createElementVNode("div", _hoisted_2$3, [
738
+ createElementVNode("div", _hoisted_3$3, [createVNode(unref(C_Icon_default), {
739
+ name: "mdi:account",
740
+ size: 12,
741
+ color: "white"
742
+ })]),
743
+ createElementVNode("span", _hoisted_4$3, toDisplayString(_ctx.data.title), 1),
744
+ approverCount.value > 0 ? (openBlock(), createElementBlock("div", _hoisted_5$3, toDisplayString(approverCount.value), 1)) : createCommentVNode("v-if", true),
745
+ _ctx.data.approvalMode ? (openBlock(), createElementBlock("div", _hoisted_6$3, toDisplayString(getApprovalModeText(_ctx.data.approvalMode)), 1)) : createCommentVNode("v-if", true)
746
+ ]), createElementVNode("div", _hoisted_7$3, [approverCount.value > 0 ? (openBlock(), createElementBlock("div", _hoisted_8$3, [(openBlock(true), createElementBlock(Fragment, null, renderList(displayApprovers.value, (approver) => {
747
+ return openBlock(), createElementBlock("div", {
748
+ key: approver.id,
749
+ class: "approver-tag"
750
+ }, [createElementVNode("div", _hoisted_9$2, [createElementVNode("div", _hoisted_10$1, [createVNode(unref(NAvatar), {
751
+ src: approver.avatar,
752
+ "fallback-src": getDefaultAvatar(approver.name),
753
+ size: "small"
754
+ }, null, 8, ["src", "fallback-src"])]), createElementVNode("div", _hoisted_11$1, [
755
+ createElementVNode("span", _hoisted_12$1, toDisplayString(approver.name), 1),
756
+ createElementVNode("span", _hoisted_13$1, toDisplayString(approver.department), 1),
757
+ createElementVNode("span", _hoisted_14$1, toDisplayString(approver.role), 1)
758
+ ])])]);
759
+ }), 128)), moreCount.value > 0 ? (openBlock(), createElementBlock("div", _hoisted_15$1, "+" + toDisplayString(moreCount.value), 1)) : createCommentVNode("v-if", true)])) : (openBlock(), createElementBlock("div", _hoisted_16$1, [createVNode(unref(C_Icon_default), {
760
+ name: "mdi:account-plus",
761
+ size: 24,
762
+ color: "#9ca3af"
763
+ }), _cache[0] || (_cache[0] = createElementVNode("span", null, "请设置审批人", -1))]))])]),
764
+ createElementVNode("div", {
765
+ class: "add-node-btn",
766
+ onClick: showAddMenu,
767
+ title: "添加下一个节点"
768
+ }, [createVNode(unref(C_Icon_default), {
769
+ name: "mdi:plus",
770
+ size: 16
771
+ })])
772
+ ]);
773
+ };
774
+ }
775
+ });
776
+
777
+ //#endregion
778
+ //#region src/components/C_WorkFlow/nodes/ApprovalNode.vue
779
+ var ApprovalNode_default = /* @__PURE__ */ export_helper_default(ApprovalNode_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-f7fd7107"]]);
780
+
781
+ //#endregion
782
+ //#region src/components/C_WorkFlow/nodes/CopyNode.vue?vue&type=script&setup=true&lang.ts
783
+ const _hoisted_1$2 = { class: "copy-node" };
784
+ const _hoisted_2$2 = { class: "node-header" };
785
+ const _hoisted_3$2 = { class: "node-title" };
786
+ const _hoisted_4$2 = {
787
+ key: 0,
788
+ class: "node-badge"
789
+ };
790
+ const _hoisted_5$2 = { class: "node-content" };
791
+ const _hoisted_6$2 = {
792
+ key: 0,
793
+ class: "copy-users-list"
794
+ };
795
+ const _hoisted_7$2 = {
796
+ key: 0,
797
+ class: "more-count"
798
+ };
799
+ const _hoisted_8$2 = {
800
+ key: 1,
801
+ class: "placeholder"
802
+ };
803
+ var CopyNode_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
804
+ __name: "CopyNode",
805
+ props: {
806
+ id: {},
807
+ data: {}
808
+ },
809
+ setup(__props) {
810
+ const props = __props;
811
+ const showAddMenuFn = inject("showAddMenu");
812
+ const deleteNodeFn = inject("deleteNode");
813
+ const copyUsers = computed(() => props.data.copyUsers ?? []);
814
+ const copyCount = computed(() => copyUsers.value.length);
815
+ const displayCopyUsers = computed(() => copyUsers.value.slice(0, 3));
816
+ const moreCount = computed(() => Math.max(0, copyCount.value - 3));
817
+ const handleNodeClick = () => {};
818
+ const showAddMenu = (event) => {
819
+ event.stopPropagation();
820
+ const rect = event.currentTarget.getBoundingClientRect();
821
+ if (showAddMenuFn) showAddMenuFn({
822
+ x: rect.left + rect.width / 2,
823
+ y: rect.bottom + 10
824
+ }, props.id);
825
+ };
826
+ const handleDelete = (event) => {
827
+ event.stopPropagation();
828
+ if (deleteNodeFn) deleteNodeFn(props.id);
829
+ };
830
+ return (_ctx, _cache) => {
831
+ return openBlock(), createElementBlock("div", _hoisted_1$2, [
832
+ createElementVNode("div", { class: normalizeClass(["status-indicator", _ctx.data.status]) }, null, 2),
833
+ createCommentVNode(" 删除按钮 "),
834
+ createElementVNode("div", {
835
+ class: "delete-btn",
836
+ onClick: handleDelete,
837
+ title: "删除节点"
838
+ }, [createVNode(unref(C_Icon_default), {
839
+ name: "mdi:close",
840
+ size: 12
841
+ })]),
842
+ createElementVNode("div", {
843
+ class: "node-card",
844
+ onClick: handleNodeClick
845
+ }, [createElementVNode("div", _hoisted_2$2, [
846
+ _cache[0] || (_cache[0] = createElementVNode("div", { class: "node-icon" }, "📋", -1)),
847
+ createElementVNode("span", _hoisted_3$2, toDisplayString(_ctx.data.title), 1),
848
+ copyCount.value > 0 ? (openBlock(), createElementBlock("div", _hoisted_4$2, toDisplayString(copyCount.value), 1)) : createCommentVNode("v-if", true)
849
+ ]), createElementVNode("div", _hoisted_5$2, [copyCount.value > 0 ? (openBlock(), createElementBlock("div", _hoisted_6$2, [(openBlock(true), createElementBlock(Fragment, null, renderList(displayCopyUsers.value, (user) => {
850
+ return openBlock(), createElementBlock("div", {
851
+ key: user.id,
852
+ class: "copy-user-tag"
853
+ }, toDisplayString(user.name), 1);
854
+ }), 128)), moreCount.value > 0 ? (openBlock(), createElementBlock("div", _hoisted_7$2, "+" + toDisplayString(moreCount.value), 1)) : createCommentVNode("v-if", true)])) : (openBlock(), createElementBlock("div", _hoisted_8$2, "请设置抄送人"))])]),
855
+ createElementVNode("div", {
856
+ class: "add-node-btn",
857
+ onClick: showAddMenu,
858
+ title: "添加下一个节点"
859
+ }, [createVNode(unref(C_Icon_default), {
860
+ name: "mdi:plus",
861
+ size: 16
862
+ })])
863
+ ]);
864
+ };
865
+ }
866
+ });
867
+
868
+ //#endregion
869
+ //#region src/components/C_WorkFlow/nodes/CopyNode.vue
870
+ var CopyNode_default = /* @__PURE__ */ export_helper_default(CopyNode_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-6ae0b500"]]);
871
+
872
+ //#endregion
873
+ //#region src/components/C_WorkFlow/nodes/ConditionNode.vue?vue&type=script&setup=true&lang.ts
874
+ const _hoisted_1$1 = { class: "condition-node" };
875
+ const _hoisted_2$1 = { class: "node-card" };
876
+ const _hoisted_3$1 = { class: "node-header" };
877
+ const _hoisted_4$1 = { class: "node-title" };
878
+ const _hoisted_5$1 = {
879
+ key: 0,
880
+ class: "node-badge"
881
+ };
882
+ const _hoisted_6$1 = { class: "node-content" };
883
+ const _hoisted_7$1 = {
884
+ key: 0,
885
+ class: "conditions-list"
886
+ };
887
+ const _hoisted_8$1 = {
888
+ key: 0,
889
+ class: "more-count"
890
+ };
891
+ const _hoisted_9$1 = {
892
+ key: 1,
893
+ class: "placeholder"
894
+ };
895
+ var ConditionNode_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
896
+ __name: "ConditionNode",
897
+ props: {
898
+ id: {},
899
+ data: {}
900
+ },
901
+ setup(__props) {
902
+ const props = __props;
903
+ const showAddMenuFn = inject("showAddMenu");
904
+ const deleteNodeFn = inject("deleteNode");
905
+ const conditions = computed(() => props.data.conditions ?? []);
906
+ const conditionCount = computed(() => conditions.value.length);
907
+ const displayConditions = computed(() => conditions.value.slice(0, 2));
908
+ const moreCount = computed(() => Math.max(0, conditionCount.value - 2));
909
+ const showAddMenu = (event) => {
910
+ event.stopPropagation();
911
+ const rect = event.currentTarget.getBoundingClientRect();
912
+ if (showAddMenuFn) showAddMenuFn({
913
+ x: rect.left + rect.width / 2,
914
+ y: rect.bottom + 10
915
+ }, props.id);
916
+ };
917
+ const handleDelete = (event) => {
918
+ event.stopPropagation();
919
+ if (deleteNodeFn) deleteNodeFn(props.id);
920
+ };
921
+ return (_ctx, _cache) => {
922
+ return openBlock(), createElementBlock("div", _hoisted_1$1, [
923
+ createElementVNode("div", { class: normalizeClass(["status-indicator", _ctx.data.status]) }, null, 2),
924
+ createCommentVNode(" 删除按钮 "),
925
+ createElementVNode("div", {
926
+ class: "delete-btn",
927
+ onClick: handleDelete,
928
+ title: "删除节点"
929
+ }, [createVNode(unref(C_Icon_default), {
930
+ name: "mdi:close",
931
+ size: 12
932
+ })]),
933
+ createElementVNode("div", _hoisted_2$1, [createElementVNode("div", _hoisted_3$1, [
934
+ _cache[0] || (_cache[0] = createElementVNode("div", { class: "node-icon" }, "🔀", -1)),
935
+ createElementVNode("span", _hoisted_4$1, toDisplayString(_ctx.data.title), 1),
936
+ conditionCount.value > 0 ? (openBlock(), createElementBlock("div", _hoisted_5$1, toDisplayString(conditionCount.value), 1)) : createCommentVNode("v-if", true)
937
+ ]), createElementVNode("div", _hoisted_6$1, [conditionCount.value > 0 ? (openBlock(), createElementBlock("div", _hoisted_7$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(displayConditions.value, (condition) => {
938
+ return openBlock(), createElementBlock("div", {
939
+ key: condition.id,
940
+ class: "condition-tag"
941
+ }, [_cache[1] || (_cache[1] = createElementVNode("span", { class: "condition-icon" }, "→", -1)), createElementVNode("span", null, toDisplayString(condition.name || "条件" + (displayConditions.value.indexOf(condition) + 1)), 1)]);
942
+ }), 128)), moreCount.value > 0 ? (openBlock(), createElementBlock("div", _hoisted_8$1, "+" + toDisplayString(moreCount.value), 1)) : createCommentVNode("v-if", true)])) : (openBlock(), createElementBlock("div", _hoisted_9$1, "请设置分支条件"))])]),
943
+ createElementVNode("div", {
944
+ class: "add-node-btn",
945
+ onClick: showAddMenu,
946
+ title: "添加下一个节点"
947
+ }, [createVNode(unref(C_Icon_default), {
948
+ name: "mdi:plus",
949
+ size: 16
950
+ })])
951
+ ]);
952
+ };
953
+ }
954
+ });
955
+
956
+ //#endregion
957
+ //#region src/components/C_WorkFlow/nodes/ConditionNode.vue
958
+ var ConditionNode_default = /* @__PURE__ */ export_helper_default(ConditionNode_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-60e87967"]]);
959
+
960
+ //#endregion
961
+ //#region src/components/C_WorkFlow/composables/useWorkflowNodes.ts
962
+ /**
963
+ * 工作流节点管理 Composable
964
+ * 封装节点 CRUD、provide/inject、边重连、画布操作等逻辑
965
+ */
966
+ /** 节点组件映射(模块级常量,仅初始化一次) */
967
+ const NODE_COMPONENT_MAP = {
968
+ start: markRaw(StartNode_default),
969
+ approval: markRaw(ApprovalNode_default),
970
+ copy: markRaw(CopyNode_default),
971
+ condition: markRaw(ConditionNode_default)
972
+ };
973
+ /** 工作流节点管理 —— 封装节点 CRUD、provide/inject、边重连、画布操作等逻辑 */
974
+ function useWorkflowNodes(props, emit, vueFlowRef) {
975
+ const message = useMessage();
976
+ const nodes = ref([{ ...INITIAL_NODE }]);
977
+ const edges = ref([]);
978
+ const showAddMenu = ref(false);
979
+ const menuPosition = ref({
980
+ x: 0,
981
+ y: 0
982
+ });
983
+ const showNodeConfig = ref(false);
984
+ const currentNode = ref(null);
985
+ const currentAddNodeId = ref(null);
986
+ const nodeTypes = computed(() => NODE_COMPONENT_MAP);
987
+ const workflowStats = computed(() => {
988
+ const stats = {
989
+ totalNodes: nodes.value.length,
990
+ approvalNodes: 0,
991
+ copyNodes: 0,
992
+ conditionNodes: 0
993
+ };
994
+ nodes.value.forEach((n) => {
995
+ if (n.type === "approval") stats.approvalNodes++;
996
+ else if (n.type === "copy") stats.copyNodes++;
997
+ else if (n.type === "condition") stats.conditionNodes++;
998
+ });
999
+ return stats;
1000
+ });
1001
+ /** 获取当前工作流完整数据 */
1002
+ const getCurrentWorkflowData = () => ({
1003
+ nodes: nodes.value,
1004
+ edges: edges.value,
1005
+ config: {
1006
+ version: "1.0",
1007
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
1008
+ }
1009
+ });
1010
+ /** 触发数据变更事件 */
1011
+ const emitChange = () => {
1012
+ const data = getCurrentWorkflowData();
1013
+ emit("update:modelValue", data);
1014
+ emit("change", data);
1015
+ };
1016
+ /** 延迟适应画布视图 */
1017
+ const deferFitView = (padding = 60, duration = 400) => {
1018
+ nextTick(() => {
1019
+ setTimeout(() => {
1020
+ vueFlowRef.value?.fitView?.({
1021
+ padding,
1022
+ duration
1023
+ });
1024
+ }, 100);
1025
+ });
1026
+ };
1027
+ const handleShowAddMenu = (position, nodeId) => {
1028
+ menuPosition.value = {
1029
+ x: typeof position.x === "number" ? position.x : 0,
1030
+ y: typeof position.y === "number" ? position.y : 0
1031
+ };
1032
+ currentAddNodeId.value = nodeId || null;
1033
+ showAddMenu.value = true;
1034
+ };
1035
+ const closeAddMenu = () => {
1036
+ showAddMenu.value = false;
1037
+ };
1038
+ const deleteNode = (nodeId) => {
1039
+ if (nodeId === "start-1") {
1040
+ message.warning("不能删除开始节点");
1041
+ return;
1042
+ }
1043
+ const nodeIndex = nodes.value.findIndex((n) => n.id === nodeId);
1044
+ if (nodeIndex === -1) return;
1045
+ const incomingEdges = edges.value.filter((e) => e.target === nodeId);
1046
+ const outgoingEdges = edges.value.filter((e) => e.source === nodeId);
1047
+ nodes.value.splice(nodeIndex, 1);
1048
+ edges.value = edges.value.filter((e) => e.source !== nodeId && e.target !== nodeId);
1049
+ incomingEdges.forEach((inEdge) => {
1050
+ outgoingEdges.forEach((outEdge) => {
1051
+ edges.value.push({
1052
+ id: generateEdgeId(inEdge.source, outEdge.target),
1053
+ source: inEdge.source,
1054
+ target: outEdge.target,
1055
+ animated: true,
1056
+ type: "default"
1057
+ });
1058
+ });
1059
+ });
1060
+ nodes.value.forEach((node, i) => {
1061
+ if (i >= nodeIndex) node.position.y -= NODE_Y_GAP;
1062
+ });
1063
+ emitChange();
1064
+ message.success("节点已删除");
1065
+ deferFitView();
1066
+ };
1067
+ provide("showAddMenu", handleShowAddMenu);
1068
+ provide("deleteNode", deleteNode);
1069
+ const getTargetNodeInfo = () => {
1070
+ let targetNodeIndex = nodes.value.length - 1;
1071
+ let targetNode = nodes.value[targetNodeIndex];
1072
+ if (currentAddNodeId.value) {
1073
+ const foundIndex = nodes.value.findIndex((n) => n.id === currentAddNodeId.value);
1074
+ if (foundIndex !== -1) {
1075
+ targetNodeIndex = foundIndex;
1076
+ targetNode = nodes.value[targetNodeIndex];
1077
+ }
1078
+ }
1079
+ return {
1080
+ targetNodeIndex,
1081
+ targetNode
1082
+ };
1083
+ };
1084
+ const createNewNode = (type, targetNode) => ({
1085
+ id: `${type}-${Date.now()}`,
1086
+ type,
1087
+ position: {
1088
+ x: targetNode?.position.x || 150,
1089
+ y: (targetNode?.position.y || 130) + NODE_Y_GAP
1090
+ },
1091
+ data: {
1092
+ title: NODE_TITLES[type],
1093
+ status: "pending",
1094
+ ...type === "approval" && {
1095
+ approvers: [],
1096
+ approvalMode: "any"
1097
+ },
1098
+ ...type === "copy" && { copyUsers: [] },
1099
+ ...type === "condition" && { conditions: [] }
1100
+ }
1101
+ });
1102
+ /** 将新节点插入到 targetNode 之后,重连所有边 */
1103
+ const reconnectEdges = (targetNode, newNode) => {
1104
+ const outgoing = edges.value.filter((e) => e.source === targetNode.id);
1105
+ edges.value = edges.value.filter((e) => e.source !== targetNode.id);
1106
+ edges.value.push({
1107
+ id: generateEdgeId(targetNode.id, newNode.id),
1108
+ source: targetNode.id,
1109
+ target: newNode.id,
1110
+ animated: true,
1111
+ type: "default"
1112
+ });
1113
+ outgoing.forEach((edge) => {
1114
+ edges.value.push({
1115
+ id: generateEdgeId(newNode.id, edge.target),
1116
+ source: newNode.id,
1117
+ target: edge.target,
1118
+ animated: true,
1119
+ type: "default"
1120
+ });
1121
+ });
1122
+ };
1123
+ const addNode = (type) => {
1124
+ try {
1125
+ const { targetNodeIndex, targetNode } = getTargetNodeInfo();
1126
+ const newNode = createNewNode(type, targetNode);
1127
+ nodes.value.splice(targetNodeIndex + 1, 0, newNode);
1128
+ for (let i = targetNodeIndex + 2; i < nodes.value.length; i++) nodes.value[i].position.y += NODE_Y_GAP;
1129
+ if (targetNode) reconnectEdges(targetNode, newNode);
1130
+ showAddMenu.value = false;
1131
+ currentAddNodeId.value = null;
1132
+ emitChange();
1133
+ deferFitView();
1134
+ } catch (error) {
1135
+ console.error("Error adding node:", error);
1136
+ message.error("添加节点失败,请重试");
1137
+ }
1138
+ };
1139
+ const onNodeClick = (event) => {
1140
+ const { node } = event;
1141
+ currentNode.value = node;
1142
+ showNodeConfig.value = true;
1143
+ emit("node-click", node);
1144
+ };
1145
+ const handleConfigSave = (configData) => {
1146
+ if (!currentNode.value) return;
1147
+ const nodeIndex = nodes.value.findIndex((n) => n.id === currentNode.value.id);
1148
+ if (nodeIndex !== -1) {
1149
+ const updatedNode = {
1150
+ ...nodes.value[nodeIndex],
1151
+ data: {
1152
+ ...nodes.value[nodeIndex].data,
1153
+ ...configData
1154
+ }
1155
+ };
1156
+ nodes.value.splice(nodeIndex, 1, updatedNode);
1157
+ currentNode.value = updatedNode;
1158
+ }
1159
+ emitChange();
1160
+ showNodeConfig.value = false;
1161
+ message.success("节点配置已保存");
1162
+ };
1163
+ const fitView = () => {
1164
+ if (!vueFlowRef.value?.fitView) {
1165
+ message.warning("画布未准备就绪,请稍后重试");
1166
+ return;
1167
+ }
1168
+ nextTick(() => {
1169
+ vueFlowRef.value.fitView({
1170
+ padding: 50,
1171
+ includeHiddenNodes: false,
1172
+ minZoom: .5,
1173
+ maxZoom: 1.5,
1174
+ duration: 800
1175
+ });
1176
+ });
1177
+ message.success("已适应窗口大小");
1178
+ };
1179
+ /** 重置节点和边(不涉及验证状态) */
1180
+ const resetNodes = () => {
1181
+ nodes.value = [{ ...INITIAL_NODE }];
1182
+ edges.value = [];
1183
+ emitChange();
1184
+ deferFitView(80, 600);
1185
+ message.success("画布已清空");
1186
+ };
1187
+ watch(() => props.modelValue, (newValue) => {
1188
+ if (newValue && newValue !== getCurrentWorkflowData()) {
1189
+ nodes.value = newValue.nodes || [];
1190
+ edges.value = newValue.edges || [];
1191
+ }
1192
+ }, { deep: true });
1193
+ onMounted(() => {
1194
+ nextTick(() => {
1195
+ setTimeout(() => {
1196
+ vueFlowRef.value?.fitView?.({
1197
+ padding: 80,
1198
+ includeHiddenNodes: false,
1199
+ minZoom: .8,
1200
+ maxZoom: 1.2,
1201
+ duration: 600
1202
+ });
1203
+ }, 300);
1204
+ });
1205
+ });
1206
+ return {
1207
+ nodes,
1208
+ edges,
1209
+ showAddMenu,
1210
+ menuPosition,
1211
+ showNodeConfig,
1212
+ currentNode,
1213
+ nodeTypes,
1214
+ workflowStats,
1215
+ addNode,
1216
+ onNodeClick,
1217
+ closeAddMenu,
1218
+ handleConfigSave,
1219
+ resetNodes,
1220
+ getCurrentWorkflowData,
1221
+ fitView,
1222
+ deleteNode
1223
+ };
1224
+ }
1225
+
1226
+ //#endregion
1227
+ //#region src/components/C_WorkFlow/composables/useWorkflowValidation.ts
1228
+ /**
1229
+ * 工作流验证 Composable
1230
+ * 封装流程校验逻辑、错误展示和节点定位
1231
+ */
1232
+ /** 工作流验证 —— 封装流程校验逻辑、错误展示和节点定位 */
1233
+ function useWorkflowValidation(nodes, edges, vueFlowRef, options) {
1234
+ const message = useMessage();
1235
+ const validationErrors = ref([]);
1236
+ const showValidationErrors = ref(false);
1237
+ /** 执行工作流验证,返回错误列表(纯逻辑,不操作 UI) */
1238
+ const validateWorkflow = () => {
1239
+ const errors = [];
1240
+ nodes.value.forEach((node) => {
1241
+ if (node.type === "approval") {
1242
+ if ((node.data.approvers || []).length === 0) errors.push({
1243
+ nodeId: node.id,
1244
+ nodeName: node.data.title,
1245
+ field: "approvers",
1246
+ message: "审批节点必须设置至少一个审批人,否则流程无法正常运行",
1247
+ type: "required"
1248
+ });
1249
+ }
1250
+ if (node.type === "condition") {
1251
+ const conditions = node.data.conditions || [];
1252
+ if (conditions.length === 0) errors.push({
1253
+ nodeId: node.id,
1254
+ nodeName: node.data.title,
1255
+ field: "conditions",
1256
+ message: "条件分支节点必须配置至少一个分支条件,否则无法进行条件判断",
1257
+ type: "required"
1258
+ });
1259
+ else {
1260
+ const incomplete = conditions.filter((c) => !c.name || !c.field || !c.operator || !c.value);
1261
+ if (incomplete.length > 0) errors.push({
1262
+ nodeId: node.id,
1263
+ nodeName: node.data.title,
1264
+ field: "conditions",
1265
+ message: `有 ${incomplete.length} 个条件分支配置不完整,请完善所有必填字段`,
1266
+ type: "incomplete"
1267
+ });
1268
+ }
1269
+ }
1270
+ });
1271
+ const connectedNodes = /* @__PURE__ */ new Set();
1272
+ edges.value.forEach((edge) => {
1273
+ connectedNodes.add(edge.source);
1274
+ connectedNodes.add(edge.target);
1275
+ });
1276
+ nodes.value.forEach((node) => {
1277
+ if (node.type !== "start" && !connectedNodes.has(node.id)) errors.push({
1278
+ nodeId: node.id,
1279
+ nodeName: node.data.title,
1280
+ field: "connection",
1281
+ message: "此节点未与其他节点连接,可能导致流程中断",
1282
+ type: "warning"
1283
+ });
1284
+ });
1285
+ return errors;
1286
+ };
1287
+ /** 执行验证并更新 UI 状态(消息提示 + 抽屉) */
1288
+ const validateCurrentWorkflow = () => {
1289
+ const errors = validateWorkflow();
1290
+ validationErrors.value = errors;
1291
+ if (errors.length === 0) {
1292
+ message.success("工作流验证通过!所有节点配置正确");
1293
+ showValidationErrors.value = false;
1294
+ } else {
1295
+ message.error(`发现 ${errors.length} 个问题,请查看详细错误`);
1296
+ showValidationErrors.value = true;
1297
+ options?.onValidateError?.(errors);
1298
+ }
1299
+ };
1300
+ /** 定位到错误节点并打开配置弹窗 */
1301
+ const jumpToErrorNode = (nodeId) => {
1302
+ const node = nodes.value.find((n) => n.id === nodeId);
1303
+ if (!node || !vueFlowRef.value) return;
1304
+ vueFlowRef.value.setCenter(node.position.x, node.position.y, {
1305
+ zoom: 1.2,
1306
+ duration: 800
1307
+ });
1308
+ setTimeout(() => {
1309
+ options?.onShowNodeConfig?.(node);
1310
+ showValidationErrors.value = false;
1311
+ }, 900);
1312
+ message.info(`已定位到节点:${node.data.title}`);
1313
+ };
1314
+ const getFieldDisplayName = (field) => FIELD_DISPLAY_NAMES[field] || field;
1315
+ const getErrorTypeText = (type) => ERROR_TYPE_TEXTS[type] || type;
1316
+ /** 重置验证状态 */
1317
+ const resetValidation = () => {
1318
+ validationErrors.value = [];
1319
+ showValidationErrors.value = false;
1320
+ };
1321
+ return {
1322
+ validationErrors,
1323
+ showValidationErrors,
1324
+ validateWorkflow,
1325
+ validateCurrentWorkflow,
1326
+ jumpToErrorNode,
1327
+ getFieldDisplayName,
1328
+ getErrorTypeText,
1329
+ resetValidation
1330
+ };
1331
+ }
1332
+
1333
+ //#endregion
1334
+ //#region src/components/C_WorkFlow/composables/useWorkflowPreview.ts
1335
+ /**
1336
+ * 工作流预览 Composable
1337
+ * 封装流程预览逻辑、节点排序和步骤展示
1338
+ */
1339
+ const NODE_TYPE_META = {
1340
+ start: {
1341
+ label: "发起人",
1342
+ icon: "mdi:play-circle",
1343
+ colorClass: "start"
1344
+ },
1345
+ approval: {
1346
+ label: "审批节点",
1347
+ icon: "mdi:account-check",
1348
+ colorClass: "approval"
1349
+ },
1350
+ copy: {
1351
+ label: "抄送节点",
1352
+ icon: "mdi:email-outline",
1353
+ colorClass: "copy"
1354
+ },
1355
+ condition: {
1356
+ label: "条件分支",
1357
+ icon: "mdi:source-branch",
1358
+ colorClass: "condition"
1359
+ }
1360
+ };
1361
+ const APPROVAL_MODE_LABELS = {
1362
+ any: "或签(任一审批人通过即可)",
1363
+ all: "会签(所有审批人必须通过)",
1364
+ sequence: "顺序审批(按顺序依次审批)"
1365
+ };
1366
+ const OPERATOR_LABELS = {
1367
+ equals: "等于",
1368
+ not_equals: "不等于",
1369
+ greater_than: "大于",
1370
+ less_than: "小于",
1371
+ contains: "包含"
1372
+ };
1373
+ /** 工作流预览 —— 封装流程预览逻辑、节点排序和步骤展示 */
1374
+ function useWorkflowPreview(nodes, edges) {
1375
+ const showPreview = ref(false);
1376
+ const previewSteps = ref([]);
1377
+ const previewStats = ref({
1378
+ totalNodes: 0,
1379
+ approvalNodes: 0,
1380
+ copyNodes: 0,
1381
+ conditionNodes: 0,
1382
+ totalEdges: 0
1383
+ });
1384
+ /** 提取开始节点详情 */
1385
+ const extractStartDetails = (data) => {
1386
+ const initiators = data.initiators || [];
1387
+ return initiators.length > 0 ? [{
1388
+ type: "users",
1389
+ label: "发起人",
1390
+ users: initiators
1391
+ }] : [{
1392
+ type: "text",
1393
+ label: "发起人",
1394
+ value: "所有人"
1395
+ }];
1396
+ };
1397
+ /** 提取审批节点详情 */
1398
+ const extractApprovalDetails = (data) => {
1399
+ const mode = data.approvalMode || "any";
1400
+ const approvers = data.approvers || [];
1401
+ const items = [{
1402
+ type: "mode",
1403
+ label: "审批方式",
1404
+ value: APPROVAL_MODE_LABELS[mode] || mode,
1405
+ modeKey: mode
1406
+ }];
1407
+ if (approvers.length > 0) items.push({
1408
+ type: "users",
1409
+ label: "审批人",
1410
+ users: approvers
1411
+ });
1412
+ else items.push({
1413
+ type: "warning",
1414
+ label: "审批人",
1415
+ value: "未设置"
1416
+ });
1417
+ return items;
1418
+ };
1419
+ /** 提取抄送节点详情 */
1420
+ const extractCopyDetails = (data) => {
1421
+ const copyUsers = data.copyUsers || [];
1422
+ return copyUsers.length > 0 ? [{
1423
+ type: "users",
1424
+ label: "抄送人",
1425
+ users: copyUsers
1426
+ }] : [{
1427
+ type: "text",
1428
+ label: "抄送人",
1429
+ value: "未设置"
1430
+ }];
1431
+ };
1432
+ /** 提取条件节点详情 */
1433
+ const extractConditionDetails = (data) => {
1434
+ const conditions = data.conditions || [];
1435
+ if (conditions.length === 0) return [{
1436
+ type: "warning",
1437
+ label: "条件分支",
1438
+ value: "未配置"
1439
+ }];
1440
+ return conditions.map((cond, i) => {
1441
+ const op = OPERATOR_LABELS[cond.operator] || cond.operator;
1442
+ return {
1443
+ type: "text",
1444
+ label: `分支 ${i + 1}`,
1445
+ value: `${cond.name || "未命名"} — ${cond.field || "?"} ${op} ${cond.value || "?"}`
1446
+ };
1447
+ });
1448
+ };
1449
+ /** 节点详情提取策略 */
1450
+ const detailExtractors = {
1451
+ start: extractStartDetails,
1452
+ approval: extractApprovalDetails,
1453
+ copy: extractCopyDetails,
1454
+ condition: extractConditionDetails
1455
+ };
1456
+ /** 从节点数据中提取可读的配置详情 */
1457
+ const extractNodeDetails = (node) => {
1458
+ const extractor = detailExtractors[node.type || "start"];
1459
+ return extractor ? extractor(node.data) : [];
1460
+ };
1461
+ /** 基于 BFS 对流程节点进行拓扑排序 */
1462
+ const sortNodesByFlow = () => {
1463
+ const nodeMap = /* @__PURE__ */ new Map();
1464
+ nodes.value.forEach((n) => nodeMap.set(n.id, n));
1465
+ const adjacency = /* @__PURE__ */ new Map();
1466
+ const inDegree = /* @__PURE__ */ new Map();
1467
+ nodes.value.forEach((n) => {
1468
+ adjacency.set(n.id, []);
1469
+ inDegree.set(n.id, 0);
1470
+ });
1471
+ edges.value.forEach((e) => {
1472
+ adjacency.get(e.source)?.push(e.target);
1473
+ inDegree.set(e.target, (inDegree.get(e.target) || 0) + 1);
1474
+ });
1475
+ const queue = [];
1476
+ inDegree.forEach((deg, id) => {
1477
+ if (deg === 0) queue.push(id);
1478
+ });
1479
+ const sorted = [];
1480
+ const visited = /* @__PURE__ */ new Set();
1481
+ while (queue.length > 0) {
1482
+ const id = queue.shift();
1483
+ if (visited.has(id)) continue;
1484
+ visited.add(id);
1485
+ const node = nodeMap.get(id);
1486
+ if (node) sorted.push(node);
1487
+ const neighbors = adjacency.get(id) || [];
1488
+ for (const next of neighbors) {
1489
+ const newDeg = (inDegree.get(next) || 1) - 1;
1490
+ inDegree.set(next, newDeg);
1491
+ if (newDeg <= 0 && !visited.has(next)) queue.push(next);
1492
+ }
1493
+ }
1494
+ nodes.value.forEach((n) => {
1495
+ if (!visited.has(n.id)) sorted.push(n);
1496
+ });
1497
+ return sorted;
1498
+ };
1499
+ /** 构建预览步骤列表 */
1500
+ const buildFlowSteps = () => {
1501
+ return sortNodesByFlow().map((node, index) => {
1502
+ const meta = NODE_TYPE_META[node.type || "start"] || NODE_TYPE_META.start;
1503
+ return {
1504
+ order: index + 1,
1505
+ node,
1506
+ nodeTypeLabel: meta.label,
1507
+ icon: meta.icon,
1508
+ colorClass: meta.colorClass,
1509
+ details: extractNodeDetails(node)
1510
+ };
1511
+ });
1512
+ };
1513
+ const computeStats = () => {
1514
+ const stats = {
1515
+ totalNodes: nodes.value.length,
1516
+ approvalNodes: 0,
1517
+ copyNodes: 0,
1518
+ conditionNodes: 0,
1519
+ totalEdges: edges.value.length
1520
+ };
1521
+ nodes.value.forEach((n) => {
1522
+ if (n.type === "approval") stats.approvalNodes++;
1523
+ else if (n.type === "copy") stats.copyNodes++;
1524
+ else if (n.type === "condition") stats.conditionNodes++;
1525
+ });
1526
+ return stats;
1527
+ };
1528
+ /** 打开预览面板 */
1529
+ const openPreview = () => {
1530
+ previewSteps.value = buildFlowSteps();
1531
+ previewStats.value = computeStats();
1532
+ showPreview.value = true;
1533
+ };
1534
+ /** 关闭预览面板 */
1535
+ const closePreview = () => {
1536
+ showPreview.value = false;
1537
+ };
1538
+ return {
1539
+ showPreview,
1540
+ previewSteps,
1541
+ previewStats,
1542
+ openPreview,
1543
+ closePreview
1544
+ };
1545
+ }
1546
+
1547
+ //#endregion
1548
+ //#region src/components/C_WorkFlow/index.vue?vue&type=script&setup=true&lang.ts
1549
+ const _hoisted_1 = { class: "approval-workflow-container" };
1550
+ const _hoisted_2 = { class: "floating-toolbar" };
1551
+ const _hoisted_3 = { class: "add-menu-content" };
1552
+ const _hoisted_4 = ["onClick"];
1553
+ const _hoisted_5 = { class: "menu-text" };
1554
+ const _hoisted_6 = {
1555
+ key: 0,
1556
+ class: "validation-success"
1557
+ };
1558
+ const _hoisted_7 = { class: "success-icon" };
1559
+ const _hoisted_8 = {
1560
+ key: 1,
1561
+ class: "validation-errors"
1562
+ };
1563
+ const _hoisted_9 = { class: "error-summary" };
1564
+ const _hoisted_10 = { class: "error-icon" };
1565
+ const _hoisted_11 = { class: "error-list" };
1566
+ const _hoisted_12 = { class: "error-header" };
1567
+ const _hoisted_13 = { class: "error-number" };
1568
+ const _hoisted_14 = { class: "error-info" };
1569
+ const _hoisted_15 = { class: "error-node" };
1570
+ const _hoisted_16 = { class: "error-field" };
1571
+ const _hoisted_17 = { class: "error-message" };
1572
+ const _hoisted_18 = { class: "error-actions" };
1573
+ const _hoisted_19 = { class: "validation-footer" };
1574
+ const _hoisted_20 = { class: "preview-stats" };
1575
+ const _hoisted_21 = { class: "stat-item" };
1576
+ const _hoisted_22 = { class: "stat-value" };
1577
+ const _hoisted_23 = { class: "stat-item approval" };
1578
+ const _hoisted_24 = { class: "stat-value" };
1579
+ const _hoisted_25 = { class: "stat-item copy" };
1580
+ const _hoisted_26 = { class: "stat-value" };
1581
+ const _hoisted_27 = { class: "stat-item condition" };
1582
+ const _hoisted_28 = { class: "stat-value" };
1583
+ const _hoisted_29 = { class: "stat-item edge" };
1584
+ const _hoisted_30 = { class: "stat-value" };
1585
+ const _hoisted_31 = { class: "preview-timeline" };
1586
+ const _hoisted_32 = { class: "step-connector" };
1587
+ const _hoisted_33 = { class: "step-dot" };
1588
+ const _hoisted_34 = {
1589
+ key: 0,
1590
+ class: "step-line"
1591
+ };
1592
+ const _hoisted_35 = { class: "step-content" };
1593
+ const _hoisted_36 = { class: "step-header" };
1594
+ const _hoisted_37 = { class: "step-order" };
1595
+ const _hoisted_38 = { class: "step-type-badge" };
1596
+ const _hoisted_39 = { class: "step-title" };
1597
+ const _hoisted_40 = {
1598
+ key: 0,
1599
+ class: "step-details"
1600
+ };
1601
+ const _hoisted_41 = { class: "detail-label" };
1602
+ const _hoisted_42 = { class: "warning-text" };
1603
+ const _hoisted_43 = {
1604
+ key: 0,
1605
+ class: "preview-empty"
1606
+ };
1607
+ const _hoisted_44 = { class: "preview-footer" };
1608
+ var index_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
1609
+ name: "C_WorkFlow",
1610
+ __name: "index",
1611
+ props: {
1612
+ users: { default: () => [] },
1613
+ roles: { default: () => [] },
1614
+ departments: { default: () => [] },
1615
+ modelValue: {},
1616
+ readonly: {
1617
+ type: Boolean,
1618
+ default: false
1619
+ },
1620
+ theme: { default: "light" }
1621
+ },
1622
+ emits: [
1623
+ "update:modelValue",
1624
+ "change",
1625
+ "node-click",
1626
+ "edge-click",
1627
+ "save",
1628
+ "validate-error"
1629
+ ],
1630
+ setup(__props, { expose: __expose, emit: __emit }) {
1631
+ const props = __props;
1632
+ const emit = __emit;
1633
+ const message = useMessage();
1634
+ const vueFlowRef = ref();
1635
+ const { nodes, edges, showAddMenu, menuPosition, showNodeConfig, currentNode, nodeTypes, workflowStats, addNode, onNodeClick, closeAddMenu, handleConfigSave, resetNodes, getCurrentWorkflowData, fitView, deleteNode } = useWorkflowNodes(props, emit, vueFlowRef);
1636
+ const { validationErrors, showValidationErrors, validateWorkflow, validateCurrentWorkflow, jumpToErrorNode, getFieldDisplayName, getErrorTypeText, resetValidation } = useWorkflowValidation(nodes, edges, vueFlowRef, {
1637
+ onShowNodeConfig: (node) => {
1638
+ currentNode.value = node;
1639
+ showNodeConfig.value = true;
1640
+ },
1641
+ onValidateError: (errors) => emit("validate-error", errors)
1642
+ });
1643
+ const { showPreview, previewSteps, previewStats, openPreview, closePreview } = useWorkflowPreview(nodes, edges);
1644
+ const saveWorkflow = () => {
1645
+ const errors = validateWorkflow();
1646
+ if (errors.length > 0) {
1647
+ message.error(`工作流验证失败: ${errors[0].message}`);
1648
+ showValidationErrors.value = true;
1649
+ return;
1650
+ }
1651
+ emit("save", getCurrentWorkflowData());
1652
+ message.success("工作流保存成功");
1653
+ };
1654
+ const previewWorkflow = () => {
1655
+ openPreview();
1656
+ };
1657
+ const confirmAndSave = () => {
1658
+ closePreview();
1659
+ saveWorkflow();
1660
+ };
1661
+ const clearWorkflow = () => {
1662
+ resetNodes();
1663
+ resetValidation();
1664
+ };
1665
+ __expose({
1666
+ validateWorkflow,
1667
+ getCurrentWorkflowData,
1668
+ saveWorkflow,
1669
+ previewWorkflow,
1670
+ deleteNode,
1671
+ stats: workflowStats
1672
+ });
1673
+ return (_ctx, _cache) => {
1674
+ return openBlock(), createElementBlock("div", _hoisted_1, [
1675
+ createCommentVNode(" 浮动工具栏 "),
1676
+ createElementVNode("div", _hoisted_2, [
1677
+ createVNode(unref(NButton), {
1678
+ size: "small",
1679
+ type: "primary",
1680
+ onClick: saveWorkflow
1681
+ }, {
1682
+ icon: withCtx(() => [createVNode(unref(C_Icon_default), {
1683
+ name: "mdi:content-save",
1684
+ size: 16
1685
+ })]),
1686
+ default: withCtx(() => [_cache[7] || (_cache[7] = createTextVNode(" 保存 ", -1))]),
1687
+ _: 1,
1688
+ __: [7]
1689
+ }),
1690
+ createVNode(unref(NButton), {
1691
+ size: "small",
1692
+ onClick: previewWorkflow
1693
+ }, {
1694
+ icon: withCtx(() => [createVNode(unref(C_Icon_default), {
1695
+ name: "mdi:eye",
1696
+ size: 16
1697
+ })]),
1698
+ default: withCtx(() => [_cache[8] || (_cache[8] = createTextVNode(" 预览 ", -1))]),
1699
+ _: 1,
1700
+ __: [8]
1701
+ }),
1702
+ createVNode(unref(NButton), {
1703
+ size: "small",
1704
+ onClick: unref(validateCurrentWorkflow),
1705
+ title: "检查工作流配置是否正确"
1706
+ }, {
1707
+ icon: withCtx(() => [createVNode(unref(C_Icon_default), {
1708
+ name: "mdi:check-circle",
1709
+ size: 16
1710
+ })]),
1711
+ default: withCtx(() => [_cache[9] || (_cache[9] = createTextVNode(" 验证流程 ", -1))]),
1712
+ _: 1,
1713
+ __: [9]
1714
+ }, 8, ["onClick"]),
1715
+ _cache[10] || (_cache[10] = createElementVNode("div", { class: "toolbar-divider" }, null, -1)),
1716
+ createVNode(unref(NButton), {
1717
+ size: "small",
1718
+ onClick: unref(fitView),
1719
+ title: "适应窗口"
1720
+ }, {
1721
+ icon: withCtx(() => [createVNode(unref(C_Icon_default), {
1722
+ name: "mdi:fit-to-screen",
1723
+ size: 16
1724
+ })]),
1725
+ _: 1
1726
+ }, 8, ["onClick"]),
1727
+ createVNode(unref(NButton), {
1728
+ size: "small",
1729
+ type: "error",
1730
+ onClick: clearWorkflow,
1731
+ title: "清空画布"
1732
+ }, {
1733
+ icon: withCtx(() => [createVNode(unref(C_Icon_default), {
1734
+ name: "mdi:delete-sweep",
1735
+ size: 16
1736
+ })]),
1737
+ _: 1
1738
+ })
1739
+ ]),
1740
+ createCommentVNode(" Vue Flow 画布 "),
1741
+ createVNode(unref(VueFlow), {
1742
+ ref_key: "vueFlowRef",
1743
+ ref: vueFlowRef,
1744
+ nodes: unref(nodes),
1745
+ "onUpdate:nodes": _cache[0] || (_cache[0] = ($event) => isRef(nodes) ? nodes.value = $event : null),
1746
+ edges: unref(edges),
1747
+ "onUpdate:edges": _cache[1] || (_cache[1] = ($event) => isRef(edges) ? edges.value = $event : null),
1748
+ "node-types": unref(nodeTypes),
1749
+ class: "workflow-canvas",
1750
+ "default-viewport": {
1751
+ zoom: 1,
1752
+ x: 0,
1753
+ y: 0
1754
+ },
1755
+ "min-zoom": .5,
1756
+ "max-zoom": 2,
1757
+ "fit-view-on-init": true,
1758
+ "nodes-draggable": true,
1759
+ "elements-selectable": true,
1760
+ onNodeClick: unref(onNodeClick),
1761
+ onPaneClick: unref(closeAddMenu)
1762
+ }, null, 8, [
1763
+ "nodes",
1764
+ "edges",
1765
+ "node-types",
1766
+ "onNodeClick",
1767
+ "onPaneClick"
1768
+ ]),
1769
+ createCommentVNode(" 节点添加菜单 "),
1770
+ (openBlock(), createBlock(Teleport, { to: "body" }, [withDirectives(createElementVNode("div", {
1771
+ class: "add-node-menu",
1772
+ style: normalizeStyle({
1773
+ left: unref(menuPosition).x + "px",
1774
+ top: unref(menuPosition).y + "px"
1775
+ })
1776
+ }, [createElementVNode("div", _hoisted_3, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(NODE_TYPE_OPTIONS), (nodeType) => {
1777
+ return openBlock(), createElementBlock("div", {
1778
+ key: nodeType.type,
1779
+ class: "add-menu-item",
1780
+ onClick: ($event) => unref(addNode)(nodeType.type)
1781
+ }, [createElementVNode("div", { class: normalizeClass(["menu-icon", nodeType.iconClass]) }, [createVNode(unref(C_Icon_default), {
1782
+ name: nodeType.icon,
1783
+ size: 16
1784
+ }, null, 8, ["name"])], 2), createElementVNode("span", _hoisted_5, toDisplayString(nodeType.label), 1)], 8, _hoisted_4);
1785
+ }), 128))])], 4), [[vShow, unref(showAddMenu)]])])),
1786
+ createCommentVNode(" 节点配置弹窗 - 拆分到独立组件 "),
1787
+ createVNode(NodeConfigModal_default, {
1788
+ show: unref(showNodeConfig),
1789
+ "onUpdate:show": _cache[2] || (_cache[2] = ($event) => isRef(showNodeConfig) ? showNodeConfig.value = $event : null),
1790
+ "current-node": unref(currentNode),
1791
+ users: _ctx.users,
1792
+ departments: _ctx.departments,
1793
+ onSave: unref(handleConfigSave),
1794
+ onCancel: _cache[3] || (_cache[3] = ($event) => showNodeConfig.value = false)
1795
+ }, null, 8, [
1796
+ "show",
1797
+ "current-node",
1798
+ "users",
1799
+ "departments",
1800
+ "onSave"
1801
+ ]),
1802
+ createCommentVNode(" 验证错误日志抽屉 "),
1803
+ createVNode(unref(NDrawer), {
1804
+ show: unref(showValidationErrors),
1805
+ "onUpdate:show": _cache[5] || (_cache[5] = ($event) => isRef(showValidationErrors) ? showValidationErrors.value = $event : null),
1806
+ width: 450,
1807
+ placement: "right"
1808
+ }, {
1809
+ default: withCtx(() => [createVNode(unref(NDrawerContent), {
1810
+ title: "流程验证结果",
1811
+ closable: ""
1812
+ }, {
1813
+ footer: withCtx(() => [createElementVNode("div", _hoisted_19, [createVNode(unref(NButton), { onClick: _cache[4] || (_cache[4] = ($event) => showValidationErrors.value = false) }, {
1814
+ default: withCtx(() => _cache[16] || (_cache[16] = [createTextVNode("关闭", -1)])),
1815
+ _: 1,
1816
+ __: [16]
1817
+ }), createVNode(unref(NButton), {
1818
+ type: "primary",
1819
+ onClick: unref(validateCurrentWorkflow)
1820
+ }, {
1821
+ icon: withCtx(() => [createVNode(unref(C_Icon_default), {
1822
+ name: "mdi:refresh",
1823
+ size: 16
1824
+ })]),
1825
+ default: withCtx(() => [_cache[17] || (_cache[17] = createTextVNode(" 重新验证 ", -1))]),
1826
+ _: 1,
1827
+ __: [17]
1828
+ }, 8, ["onClick"])])]),
1829
+ default: withCtx(() => [unref(validationErrors).length === 0 ? (openBlock(), createElementBlock("div", _hoisted_6, [
1830
+ createElementVNode("div", _hoisted_7, [createVNode(unref(C_Icon_default), {
1831
+ name: "mdi:check-circle",
1832
+ size: 32,
1833
+ color: "#52c41a"
1834
+ })]),
1835
+ _cache[11] || (_cache[11] = createElementVNode("h3", null, "验证通过", -1)),
1836
+ _cache[12] || (_cache[12] = createElementVNode("p", null, "工作流配置正确,所有节点都已正确设置!", -1))
1837
+ ])) : (openBlock(), createElementBlock("div", _hoisted_8, [
1838
+ createElementVNode("div", _hoisted_9, [
1839
+ createElementVNode("div", _hoisted_10, [createVNode(unref(C_Icon_default), {
1840
+ name: "mdi:alert-circle",
1841
+ size: 24,
1842
+ color: "#ff4d4f"
1843
+ })]),
1844
+ createElementVNode("h3", null, "发现 " + toDisplayString(unref(validationErrors).length) + " 个问题", 1),
1845
+ _cache[13] || (_cache[13] = createElementVNode("p", null, "请修复以下问题后重新验证:", -1))
1846
+ ]),
1847
+ createElementVNode("div", _hoisted_11, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(validationErrors), (error, index) => {
1848
+ return openBlock(), createElementBlock("div", {
1849
+ key: error.nodeId,
1850
+ class: "error-item"
1851
+ }, [
1852
+ createElementVNode("div", _hoisted_12, [
1853
+ createElementVNode("span", _hoisted_13, toDisplayString(index + 1), 1),
1854
+ createElementVNode("div", _hoisted_14, [createElementVNode("strong", _hoisted_15, toDisplayString(error.nodeName), 1), createElementVNode("span", _hoisted_16, toDisplayString(unref(getFieldDisplayName)(error.field)), 1)]),
1855
+ createElementVNode("div", { class: normalizeClass(["error-type", error.type]) }, toDisplayString(unref(getErrorTypeText)(error.type)), 3)
1856
+ ]),
1857
+ createElementVNode("div", _hoisted_17, toDisplayString(error.message), 1),
1858
+ createElementVNode("div", _hoisted_18, [createVNode(unref(NButton), {
1859
+ size: "small",
1860
+ type: "primary",
1861
+ onClick: ($event) => unref(jumpToErrorNode)(error.nodeId)
1862
+ }, {
1863
+ icon: withCtx(() => [createVNode(unref(C_Icon_default), {
1864
+ name: "mdi:target",
1865
+ size: 16
1866
+ })]),
1867
+ default: withCtx(() => [_cache[14] || (_cache[14] = createTextVNode(" 定位节点 ", -1))]),
1868
+ _: 2,
1869
+ __: [14]
1870
+ }, 1032, ["onClick"])])
1871
+ ]);
1872
+ }), 128))]),
1873
+ _cache[15] || (_cache[15] = createElementVNode("div", { class: "validation-tips" }, [createElementVNode("h4", null, "💡 常见问题解决方案:"), createElementVNode("ul", null, [
1874
+ createElementVNode("li", null, [createElementVNode("strong", null, "审批人未设置:"), createTextVNode("点击审批节点,在弹窗中选择审批人员 ")]),
1875
+ createElementVNode("li", null, [createElementVNode("strong", null, "条件分支未配置:"), createTextVNode("点击条件节点,添加至少一个条件分支 ")]),
1876
+ createElementVNode("li", null, [createElementVNode("strong", null, "节点连接断开:"), createTextVNode(" 检查节点之间的连线是否正确 ")])
1877
+ ])], -1))
1878
+ ]))]),
1879
+ _: 1
1880
+ })]),
1881
+ _: 1
1882
+ }, 8, ["show"]),
1883
+ createCommentVNode(" 流程预览抽屉 "),
1884
+ createVNode(unref(NDrawer), {
1885
+ show: unref(showPreview),
1886
+ "onUpdate:show": _cache[6] || (_cache[6] = ($event) => isRef(showPreview) ? showPreview.value = $event : null),
1887
+ width: 520,
1888
+ placement: "right"
1889
+ }, {
1890
+ default: withCtx(() => [createVNode(unref(NDrawerContent), {
1891
+ title: "流程预览",
1892
+ closable: ""
1893
+ }, {
1894
+ footer: withCtx(() => [createElementVNode("div", _hoisted_44, [createVNode(unref(NButton), { onClick: unref(closePreview) }, {
1895
+ default: withCtx(() => _cache[24] || (_cache[24] = [createTextVNode("关闭", -1)])),
1896
+ _: 1,
1897
+ __: [24]
1898
+ }, 8, ["onClick"]), createVNode(unref(NButton), {
1899
+ type: "primary",
1900
+ onClick: confirmAndSave
1901
+ }, {
1902
+ icon: withCtx(() => [createVNode(unref(C_Icon_default), {
1903
+ name: "mdi:content-save",
1904
+ size: 16
1905
+ })]),
1906
+ default: withCtx(() => [_cache[25] || (_cache[25] = createTextVNode(" 确认并保存 ", -1))]),
1907
+ _: 1,
1908
+ __: [25]
1909
+ })])]),
1910
+ default: withCtx(() => [
1911
+ createElementVNode("div", _hoisted_20, [
1912
+ createElementVNode("div", _hoisted_21, [createElementVNode("span", _hoisted_22, toDisplayString(unref(previewStats).totalNodes), 1), _cache[18] || (_cache[18] = createElementVNode("span", { class: "stat-label" }, "总节点", -1))]),
1913
+ createElementVNode("div", _hoisted_23, [createElementVNode("span", _hoisted_24, toDisplayString(unref(previewStats).approvalNodes), 1), _cache[19] || (_cache[19] = createElementVNode("span", { class: "stat-label" }, "审批", -1))]),
1914
+ createElementVNode("div", _hoisted_25, [createElementVNode("span", _hoisted_26, toDisplayString(unref(previewStats).copyNodes), 1), _cache[20] || (_cache[20] = createElementVNode("span", { class: "stat-label" }, "抄送", -1))]),
1915
+ createElementVNode("div", _hoisted_27, [createElementVNode("span", _hoisted_28, toDisplayString(unref(previewStats).conditionNodes), 1), _cache[21] || (_cache[21] = createElementVNode("span", { class: "stat-label" }, "条件", -1))]),
1916
+ createElementVNode("div", _hoisted_29, [createElementVNode("span", _hoisted_30, toDisplayString(unref(previewStats).totalEdges), 1), _cache[22] || (_cache[22] = createElementVNode("span", { class: "stat-label" }, "连线", -1))])
1917
+ ]),
1918
+ createElementVNode("div", _hoisted_31, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(previewSteps), (step, index) => {
1919
+ return openBlock(), createElementBlock("div", {
1920
+ key: step.node.id,
1921
+ class: normalizeClass(["preview-step", step.colorClass])
1922
+ }, [
1923
+ createCommentVNode(" 时间线连接线 "),
1924
+ createElementVNode("div", _hoisted_32, [createElementVNode("div", _hoisted_33, [createVNode(unref(C_Icon_default), {
1925
+ name: step.icon,
1926
+ size: 16
1927
+ }, null, 8, ["name"])]), index < unref(previewSteps).length - 1 ? (openBlock(), createElementBlock("div", _hoisted_34)) : createCommentVNode("v-if", true)]),
1928
+ createCommentVNode(" 步骤内容 "),
1929
+ createElementVNode("div", _hoisted_35, [
1930
+ createElementVNode("div", _hoisted_36, [createElementVNode("span", _hoisted_37, "步骤 " + toDisplayString(step.order), 1), createElementVNode("span", _hoisted_38, toDisplayString(step.nodeTypeLabel), 1)]),
1931
+ createElementVNode("div", _hoisted_39, toDisplayString(step.node.data.title), 1),
1932
+ step.details.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_40, [(openBlock(true), createElementBlock(Fragment, null, renderList(step.details, (detail, dIdx) => {
1933
+ return openBlock(), createElementBlock("div", {
1934
+ key: dIdx,
1935
+ class: normalizeClass(["step-detail-item", { "is-warning": detail.type === "warning" }])
1936
+ }, [
1937
+ createElementVNode("span", _hoisted_41, toDisplayString(detail.label) + ":", 1),
1938
+ createCommentVNode(" 审批方式 badge "),
1939
+ detail.type === "mode" ? (openBlock(), createElementBlock("span", {
1940
+ key: 0,
1941
+ class: normalizeClass(["mode-badge", detail.modeKey])
1942
+ }, toDisplayString(detail.value), 3)) : detail.type === "users" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createCommentVNode(" 人员 tags "), (openBlock(true), createElementBlock(Fragment, null, renderList(detail.users, (user) => {
1943
+ return openBlock(), createBlock(unref(NTag), {
1944
+ key: user.name,
1945
+ size: "small",
1946
+ bordered: false,
1947
+ round: "",
1948
+ class: "user-tag"
1949
+ }, {
1950
+ icon: withCtx(() => [createVNode(unref(C_Icon_default), {
1951
+ name: "mdi:account",
1952
+ size: 12
1953
+ })]),
1954
+ default: withCtx(() => [createTextVNode(" " + toDisplayString(user.name), 1)]),
1955
+ _: 2
1956
+ }, 1024);
1957
+ }), 128))], 64)) : detail.type === "warning" ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [createCommentVNode(" 警告文案 "), createElementVNode("span", _hoisted_42, " ⚠️ " + toDisplayString(detail.value), 1)], 2112)) : (openBlock(), createElementBlock(Fragment, { key: 3 }, [createCommentVNode(" 普通文本 "), createElementVNode("span", null, toDisplayString(detail.value), 1)], 2112))
1958
+ ], 2);
1959
+ }), 128))])) : createCommentVNode("v-if", true)
1960
+ ])
1961
+ ], 2);
1962
+ }), 128))]),
1963
+ unref(previewSteps).length === 0 ? (openBlock(), createElementBlock("div", _hoisted_43, [createVNode(unref(C_Icon_default), {
1964
+ name: "mdi:file-document-outline",
1965
+ size: 48,
1966
+ color: "#d1d5db"
1967
+ }), _cache[23] || (_cache[23] = createElementVNode("p", null, "暂无流程节点", -1))])) : createCommentVNode("v-if", true)
1968
+ ]),
1969
+ _: 1
1970
+ })]),
1971
+ _: 1
1972
+ }, 8, ["show"])
1973
+ ]);
1974
+ };
1975
+ }
1976
+ });
1977
+
1978
+ //#endregion
1979
+ //#region src/components/C_WorkFlow/index.vue
1980
+ var C_WorkFlow_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-55983af8"]]);
1981
+
1982
+ //#endregion
1983
+ export { useWorkflowNodes as i, useWorkflowPreview as n, useWorkflowValidation as r, C_WorkFlow_default as t };
1984
+ //# sourceMappingURL=C_WorkFlow2.js.map