@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,1433 @@
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, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, nextTick, normalizeClass, normalizeStyle, onMounted, openBlock, ref, renderList, toDisplayString, unref, vShow, watch, withCtx, withDirectives } from "vue";
4
+ import { NDivider, NEmpty, NInput, NScrollbar, NTag } from "naive-ui";
5
+ import { Parser } from "expr-eval";
6
+
7
+ //#region src/components/C_FormulaEditor/constants.ts
8
+ /** 运算符区(5 列 × 3 行) */
9
+ const OPERATOR_KEYS = [
10
+ {
11
+ label: "?",
12
+ value: " ? ",
13
+ type: "logic",
14
+ color: "warning"
15
+ },
16
+ {
17
+ label: ":",
18
+ value: " : ",
19
+ type: "logic",
20
+ color: "warning"
21
+ },
22
+ {
23
+ label: "and",
24
+ value: " AND ",
25
+ type: "logic",
26
+ color: "warning"
27
+ },
28
+ {
29
+ label: "or",
30
+ value: " OR ",
31
+ type: "logic",
32
+ color: "warning"
33
+ },
34
+ {
35
+ label: "(",
36
+ value: "(",
37
+ type: "paren"
38
+ },
39
+ {
40
+ label: ")",
41
+ value: ")",
42
+ type: "paren"
43
+ },
44
+ {
45
+ label: ",",
46
+ value: ", ",
47
+ type: "paren"
48
+ },
49
+ {
50
+ label: "==",
51
+ value: " == ",
52
+ type: "compare"
53
+ },
54
+ {
55
+ label: ">",
56
+ value: " > ",
57
+ type: "compare"
58
+ },
59
+ {
60
+ label: "<",
61
+ value: " < ",
62
+ type: "compare"
63
+ },
64
+ {
65
+ label: "≥",
66
+ value: " >= ",
67
+ type: "compare"
68
+ },
69
+ {
70
+ label: "≤",
71
+ value: " <= ",
72
+ type: "compare"
73
+ },
74
+ {
75
+ label: "≠",
76
+ value: " != ",
77
+ type: "compare"
78
+ },
79
+ {
80
+ label: "%",
81
+ value: " % ",
82
+ type: "operator"
83
+ }
84
+ ];
85
+ /** 数字区(5 列 × 3 行) */
86
+ const NUMBER_KEYS = [
87
+ {
88
+ label: "1",
89
+ value: "1",
90
+ type: "number"
91
+ },
92
+ {
93
+ label: "2",
94
+ value: "2",
95
+ type: "number"
96
+ },
97
+ {
98
+ label: "3",
99
+ value: "3",
100
+ type: "number"
101
+ },
102
+ {
103
+ label: "+",
104
+ value: " + ",
105
+ type: "operator",
106
+ color: "primary"
107
+ },
108
+ {
109
+ label: "−",
110
+ value: " - ",
111
+ type: "operator",
112
+ color: "primary"
113
+ },
114
+ {
115
+ label: "4",
116
+ value: "4",
117
+ type: "number"
118
+ },
119
+ {
120
+ label: "5",
121
+ value: "5",
122
+ type: "number"
123
+ },
124
+ {
125
+ label: "6",
126
+ value: "6",
127
+ type: "number"
128
+ },
129
+ {
130
+ label: "×",
131
+ value: " * ",
132
+ type: "operator",
133
+ color: "primary"
134
+ },
135
+ {
136
+ label: "÷",
137
+ value: " / ",
138
+ type: "operator",
139
+ color: "primary"
140
+ },
141
+ {
142
+ label: "7",
143
+ value: "7",
144
+ type: "number"
145
+ },
146
+ {
147
+ label: "8",
148
+ value: "8",
149
+ type: "number"
150
+ },
151
+ {
152
+ label: "9",
153
+ value: "9",
154
+ type: "number"
155
+ },
156
+ {
157
+ label: "0",
158
+ value: "0",
159
+ type: "number"
160
+ },
161
+ {
162
+ label: ".",
163
+ value: ".",
164
+ type: "number"
165
+ }
166
+ ];
167
+ /** 动作键(⌫ + 清空) */
168
+ const ACTION_KEYS = [{
169
+ label: "⌫",
170
+ value: "BACKSPACE",
171
+ type: "action",
172
+ isAction: true
173
+ }, {
174
+ label: "清空",
175
+ value: "CLEAR",
176
+ type: "action",
177
+ isAction: true
178
+ }];
179
+ /** 默认可用函数列表 */
180
+ const DEFAULT_FUNCTIONS = [
181
+ {
182
+ name: "IF",
183
+ signature: "IF(条件, 真值, 假值)",
184
+ description: "根据条件返回不同的值",
185
+ category: "逻辑"
186
+ },
187
+ {
188
+ name: "AND",
189
+ signature: "AND(条件1, 条件2)",
190
+ description: "全部条件为真时返回真",
191
+ category: "逻辑"
192
+ },
193
+ {
194
+ name: "OR",
195
+ signature: "OR(条件1, 条件2)",
196
+ description: "任一条件为真时返回真",
197
+ category: "逻辑"
198
+ },
199
+ {
200
+ name: "NOT",
201
+ signature: "NOT(条件)",
202
+ description: "对条件取反",
203
+ category: "逻辑"
204
+ },
205
+ {
206
+ name: "SUM",
207
+ signature: "SUM(值1, 值2, ...)",
208
+ description: "计算所有值的总和",
209
+ category: "数学"
210
+ },
211
+ {
212
+ name: "AVG",
213
+ signature: "AVG(值1, 值2, ...)",
214
+ description: "计算所有值的平均值",
215
+ category: "数学"
216
+ },
217
+ {
218
+ name: "MAX",
219
+ signature: "MAX(值1, 值2, ...)",
220
+ description: "返回最大值",
221
+ category: "数学"
222
+ },
223
+ {
224
+ name: "MIN",
225
+ signature: "MIN(值1, 值2, ...)",
226
+ description: "返回最小值",
227
+ category: "数学"
228
+ },
229
+ {
230
+ name: "ABS",
231
+ signature: "ABS(数值)",
232
+ description: "返回绝对值",
233
+ category: "数学"
234
+ },
235
+ {
236
+ name: "ROUND",
237
+ signature: "ROUND(数值, 小数位)",
238
+ description: "四舍五入到指定小数位",
239
+ category: "数学"
240
+ },
241
+ {
242
+ name: "CEIL",
243
+ signature: "CEIL(数值)",
244
+ description: "向上取整",
245
+ category: "数学"
246
+ },
247
+ {
248
+ name: "FLOOR",
249
+ signature: "FLOOR(数值)",
250
+ description: "向下取整",
251
+ category: "数学"
252
+ }
253
+ ];
254
+ /** 所有可识别的运算符 */
255
+ const OPERATORS = new Set([
256
+ "+",
257
+ "-",
258
+ "*",
259
+ "/",
260
+ "%",
261
+ ">",
262
+ "<",
263
+ ">=",
264
+ "<=",
265
+ "==",
266
+ "!=",
267
+ "?",
268
+ ":",
269
+ "AND",
270
+ "OR",
271
+ "NOT"
272
+ ]);
273
+ /** 需要在两侧加空格的运算符 */
274
+ const SPACED_OPERATORS = new Set([
275
+ "+",
276
+ "-",
277
+ "*",
278
+ "/",
279
+ "%",
280
+ ">",
281
+ "<",
282
+ ">=",
283
+ "<=",
284
+ "==",
285
+ "!=",
286
+ "?",
287
+ ":",
288
+ "AND",
289
+ "OR"
290
+ ]);
291
+
292
+ //#endregion
293
+ //#region src/components/C_FormulaEditor/composables/useFormulaParser.ts
294
+ /**
295
+ * 匹配规则(有优先级):
296
+ * 1. [变量名] → variable
297
+ * 2. >= <= == != → operator(多字符运算符优先)
298
+ * 3. AND OR NOT → operator(逻辑关键词)
299
+ * 4. 数字(含小数) → number
300
+ * 5. 函数名( → function(字母序列接左括号)
301
+ * 6. + - * / % > < ? : → operator
302
+ * 7. ( ) , → paren/comma
303
+ * 8. 空白 → space
304
+ * 9. 其他 → text
305
+ */
306
+ const TOKEN_REGEX = /(\[([^\]]+)\])|(>=|<=|==|!=)|\b(AND|OR|NOT)\b|(\d+(?:\.\d+)?)|([A-Za-z_]\w*)(?=\s*\()|([+\-*/%><?:])|([(),])|(\s+)/g;
307
+ /**
308
+ * 公式解析 & 校验引擎
309
+ */
310
+ function useFormulaParser(variables, functions) {
311
+ /** 有效变量名集合 */
312
+ const variableNames = computed(() => new Set(variables.value.map((v) => v.name)));
313
+ /** 有效函数名集合(大写) */
314
+ const functionNames = computed(() => new Set(functions.value.map((f) => f.name.toUpperCase())));
315
+ /** 根据正则匹配组分类 Token */
316
+ function classifyMatch(match, start, end) {
317
+ if (match[1]) return {
318
+ type: "variable",
319
+ value: match[2],
320
+ start,
321
+ end
322
+ };
323
+ if (match[3]) return {
324
+ type: "operator",
325
+ value: match[3],
326
+ start,
327
+ end
328
+ };
329
+ if (match[4]) return {
330
+ type: "operator",
331
+ value: match[4],
332
+ start,
333
+ end
334
+ };
335
+ if (match[5]) return {
336
+ type: "number",
337
+ value: match[5],
338
+ start,
339
+ end
340
+ };
341
+ if (match[6]) return {
342
+ type: "function",
343
+ value: match[6],
344
+ start,
345
+ end
346
+ };
347
+ if (match[7]) return {
348
+ type: "operator",
349
+ value: match[7],
350
+ start,
351
+ end
352
+ };
353
+ if (match[8]) {
354
+ const v = match[8];
355
+ return {
356
+ type: v === "," ? "comma" : "paren",
357
+ value: v,
358
+ start,
359
+ end
360
+ };
361
+ }
362
+ return {
363
+ type: "space",
364
+ value: match[9] ?? " ",
365
+ start,
366
+ end
367
+ };
368
+ }
369
+ /** 将公式字符串解析为 Token 数组 */
370
+ function tokenize(formula) {
371
+ const tokens = [];
372
+ const regex = new RegExp(TOKEN_REGEX.source, "g");
373
+ let match;
374
+ let lastIndex = 0;
375
+ while ((match = regex.exec(formula)) !== null) {
376
+ if (match.index > lastIndex) tokens.push({
377
+ type: "text",
378
+ value: formula.slice(lastIndex, match.index),
379
+ start: lastIndex,
380
+ end: match.index
381
+ });
382
+ tokens.push(classifyMatch(match, match.index, match.index + match[0].length));
383
+ lastIndex = match.index + match[0].length;
384
+ }
385
+ if (lastIndex < formula.length) tokens.push({
386
+ type: "text",
387
+ value: formula.slice(lastIndex),
388
+ start: lastIndex,
389
+ end: formula.length
390
+ });
391
+ return tokens;
392
+ }
393
+ /** 校验括号平衡 */
394
+ function checkParentheses(formula) {
395
+ let depth = 0;
396
+ for (let i = 0; i < formula.length; i++) {
397
+ if (formula[i] === "(") depth++;
398
+ else if (formula[i] === ")") depth--;
399
+ if (depth < 0) return {
400
+ valid: false,
401
+ message: `第 ${i + 1} 个字符处有多余的右括号 )`,
402
+ position: i
403
+ };
404
+ }
405
+ if (depth > 0) return {
406
+ valid: false,
407
+ message: `缺少 ${depth} 个右括号 )`
408
+ };
409
+ return {
410
+ valid: true,
411
+ message: ""
412
+ };
413
+ }
414
+ /** 校验变量是否都已定义 */
415
+ function checkVariables(tokens) {
416
+ for (const token of tokens) if (token.type === "variable" && !variableNames.value.has(token.value)) return {
417
+ valid: false,
418
+ message: `未知变量「${token.value}」`,
419
+ position: token.start
420
+ };
421
+ return {
422
+ valid: true,
423
+ message: ""
424
+ };
425
+ }
426
+ /** 校验函数是否已注册 */
427
+ function checkFunctions(tokens) {
428
+ for (const token of tokens) if (token.type === "function" && !functionNames.value.has(token.value.toUpperCase())) return {
429
+ valid: false,
430
+ message: `未知函数「${token.value}」`,
431
+ position: token.start
432
+ };
433
+ return {
434
+ valid: true,
435
+ message: ""
436
+ };
437
+ }
438
+ /** 完整校验公式 */
439
+ function validate(formula) {
440
+ if (!formula.trim()) return {
441
+ valid: true,
442
+ message: "公式为空"
443
+ };
444
+ const parenCheck = checkParentheses(formula);
445
+ if (!parenCheck.valid) return parenCheck;
446
+ const tokens = tokenize(formula);
447
+ const varCheck = checkVariables(tokens);
448
+ if (!varCheck.valid) return varCheck;
449
+ const funcCheck = checkFunctions(tokens);
450
+ if (!funcCheck.valid) return funcCheck;
451
+ const meaningful = tokens.filter((t) => t.type !== "space");
452
+ if (meaningful.length > 0) {
453
+ const first = meaningful[0];
454
+ if (first.type === "operator" && first.value !== "-" && !OPERATORS.has(first.value) === false) return {
455
+ valid: false,
456
+ message: `公式不能以运算符「${first.value}」开头`,
457
+ position: first.start
458
+ };
459
+ }
460
+ return {
461
+ valid: true,
462
+ message: "公式合法"
463
+ };
464
+ }
465
+ /**
466
+ * 将公式字符串转换为 expr-eval 可识别的表达式
467
+ * [变量名] → 变量.field 标识符
468
+ */
469
+ function toEvalExpression(formula, variableMap) {
470
+ return formula.replace(/\[([^\]]+)\]/g, (_, name) => {
471
+ return variableMap.get(name) ?? `__unknown_${name}__`;
472
+ });
473
+ }
474
+ return {
475
+ tokenize,
476
+ validate,
477
+ toEvalExpression,
478
+ variableNames,
479
+ functionNames
480
+ };
481
+ }
482
+
483
+ //#endregion
484
+ //#region src/components/C_FormulaEditor/composables/useFormulaEvaluator.ts
485
+ /**
486
+ * 公式求值引擎
487
+ * 将公式中的 [变量名] 替换为实际值后计算结果
488
+ */
489
+ function useFormulaEvaluator(variables) {
490
+ /** expr-eval 解析器实例 */
491
+ const parser = new Parser({ operators: {
492
+ logical: true,
493
+ comparison: true,
494
+ conditional: true,
495
+ add: true,
496
+ subtract: true,
497
+ multiply: true,
498
+ divide: true,
499
+ remainder: true
500
+ } });
501
+ parser.functions.IF = (cond, t, f) => cond ? t : f;
502
+ parser.functions.AND = (...args) => args.every(Boolean);
503
+ parser.functions.OR = (...args) => args.some(Boolean);
504
+ parser.functions.NOT = (v) => !v;
505
+ parser.functions.SUM = (...args) => args.reduce((a, b) => a + b, 0);
506
+ parser.functions.AVG = (...args) => args.length > 0 ? args.reduce((a, b) => a + b, 0) / args.length : 0;
507
+ parser.functions.MAX = (...args) => Math.max(...args);
508
+ parser.functions.MIN = (...args) => Math.min(...args);
509
+ parser.functions.ABS = Math.abs;
510
+ parser.functions.ROUND = (v, d = 0) => {
511
+ const f = 10 ** d;
512
+ return Math.round(v * f) / f;
513
+ };
514
+ parser.functions.CEIL = Math.ceil;
515
+ parser.functions.FLOOR = Math.floor;
516
+ /** 构建 变量名 → field 映射 */
517
+ const variableMap = computed(() => {
518
+ const map = /* @__PURE__ */ new Map();
519
+ for (const v of variables.value) map.set(v.name, v.field);
520
+ return map;
521
+ });
522
+ /**
523
+ * 将公式中的 [变量名] 替换为 field 标识符
524
+ * 例:[完成值] → completion_value
525
+ */
526
+ function replaceVariables(formula) {
527
+ return formula.replace(/\[([^\]]+)\]/g, (_, name) => {
528
+ return variableMap.value.get(name) ?? `__unknown__`;
529
+ });
530
+ }
531
+ /**
532
+ * 求值:用样例数据计算公式结果
533
+ */
534
+ function evaluate(formula, sampleData) {
535
+ if (!formula.trim()) return {
536
+ success: true,
537
+ result: void 0
538
+ };
539
+ try {
540
+ const evalExpr = replaceVariables(formula);
541
+ return {
542
+ success: true,
543
+ result: parser.parse(evalExpr).evaluate(sampleData)
544
+ };
545
+ } catch (e) {
546
+ return {
547
+ success: false,
548
+ result: void 0,
549
+ error: e instanceof Error ? e.message : String(e)
550
+ };
551
+ }
552
+ }
553
+ /**
554
+ * 从公式中提取使用到的变量名列表
555
+ */
556
+ function extractVariableNames(formula) {
557
+ const names = [];
558
+ const regex = /\[([^\]]+)\]/g;
559
+ let match;
560
+ while ((match = regex.exec(formula)) !== null) if (!names.includes(match[1])) names.push(match[1]);
561
+ return names;
562
+ }
563
+ return {
564
+ evaluate,
565
+ extractVariableNames,
566
+ variableMap
567
+ };
568
+ }
569
+
570
+ //#endregion
571
+ //#region src/components/C_FormulaEditor/components/FormulaInput.vue?vue&type=script&setup=true&lang.ts
572
+ const _hoisted_1$4 = { class: "formula-input__header" };
573
+ const _hoisted_2$4 = ["data-placeholder"];
574
+ const _hoisted_3$4 = { class: "formula-input__validation" };
575
+ const _hoisted_4$4 = {
576
+ key: 0,
577
+ class: "formula-input__validation-hint"
578
+ };
579
+ const _hoisted_5$4 = { class: "formula-input__validation-success" };
580
+ const _hoisted_6$4 = { class: "formula-input__validation-error" };
581
+ var FormulaInput_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
582
+ __name: "FormulaInput",
583
+ props: {
584
+ formula: {},
585
+ tokens: {},
586
+ validation: {},
587
+ variableNames: {},
588
+ disabled: {
589
+ type: Boolean,
590
+ default: false
591
+ },
592
+ placeholder: { default: "点击变量或使用键盘输入公式,变量用 [变量名] 包裹" }
593
+ },
594
+ emits: [
595
+ "update:formula",
596
+ "focus",
597
+ "blur"
598
+ ],
599
+ setup(__props, { expose: __expose, emit: __emit }) {
600
+ const props = __props;
601
+ const emit = __emit;
602
+ const editorRef = ref();
603
+ const isFocused = ref(false);
604
+ /** 是否正在由外部更新内容(防止循环触发) */
605
+ let isExternalUpdate = false;
606
+ /** 保存 blur 前的光标 Range,供外部调用 insertAtCursor 时恢复 */
607
+ let savedRange = null;
608
+ /** 将公式字符串渲染为 HTML(变量显示为 chip) */
609
+ function renderFormula(formula) {
610
+ if (!formula) return "";
611
+ const { tokens } = props;
612
+ if (tokens.length === 0 && formula.trim()) return escapeHtml(formula);
613
+ let html = "";
614
+ for (const token of tokens) switch (token.type) {
615
+ case "variable":
616
+ html += `<span class="formula-chip" contenteditable="false" data-variable="${escapeAttr(token.value)}">${escapeHtml(token.value)}</span>`;
617
+ break;
618
+ case "function":
619
+ html += `<span class="formula-func">${escapeHtml(token.value)}</span>`;
620
+ break;
621
+ case "operator":
622
+ html += `<span class="formula-op">${escapeHtml(token.value)}</span>`;
623
+ break;
624
+ case "number":
625
+ html += `<span class="formula-num">${escapeHtml(token.value)}</span>`;
626
+ break;
627
+ case "paren":
628
+ html += `<span class="formula-paren">${escapeHtml(token.value)}</span>`;
629
+ break;
630
+ default: html += escapeHtml(token.value);
631
+ }
632
+ return html;
633
+ }
634
+ /** HTML 转义 */
635
+ function escapeHtml(str) {
636
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
637
+ }
638
+ /** 属性值转义 */
639
+ function escapeAttr(str) {
640
+ return str.replace(/"/g, "&quot;").replace(/'/g, "&#39;");
641
+ }
642
+ /** 从 contenteditable DOM 提取纯公式字符串 */
643
+ function extractFormula() {
644
+ const el = editorRef.value;
645
+ if (!el) return "";
646
+ let result = "";
647
+ for (const node of el.childNodes) if (node.nodeType === Node.TEXT_NODE) result += node.textContent ?? "";
648
+ else if (node.nodeType === Node.ELEMENT_NODE) {
649
+ const element = node;
650
+ if (element.classList.contains("formula-chip")) {
651
+ const varName = element.getAttribute("data-variable") ?? element.textContent;
652
+ result += `[${varName}]`;
653
+ } else result += element.textContent ?? "";
654
+ }
655
+ return result;
656
+ }
657
+ /** 保存当前光标位置 */
658
+ function saveCursorPosition() {
659
+ const sel = window.getSelection();
660
+ if (!sel || sel.rangeCount === 0 || !editorRef.value) return -1;
661
+ const range = sel.getRangeAt(0);
662
+ const preRange = document.createRange();
663
+ preRange.selectNodeContents(editorRef.value);
664
+ preRange.setEnd(range.startContainer, range.startOffset);
665
+ return preRange.toString().length;
666
+ }
667
+ /** 在文本节点中查找目标位置 */
668
+ function findInTextNode(node, currentPos, charPos) {
669
+ const len = node.textContent?.length ?? 0;
670
+ if (currentPos + len >= charPos) return {
671
+ found: true,
672
+ node,
673
+ offset: charPos - currentPos,
674
+ pos: currentPos
675
+ };
676
+ return {
677
+ found: false,
678
+ node,
679
+ offset: 0,
680
+ pos: currentPos + len
681
+ };
682
+ }
683
+ /** 在 chip 节点中查找目标位置 */
684
+ function findInChipNode(node, currentPos, charPos, walker) {
685
+ const fullLen = (node.getAttribute("data-variable")?.length ?? 0) + 2;
686
+ if (currentPos + fullLen >= charPos) {
687
+ const parent = node.parentNode;
688
+ return {
689
+ found: true,
690
+ node: parent,
691
+ offset: Array.from(parent?.childNodes ?? []).indexOf(node) + 1,
692
+ pos: currentPos
693
+ };
694
+ }
695
+ walker.nextNode();
696
+ return {
697
+ found: false,
698
+ node: null,
699
+ offset: 0,
700
+ pos: currentPos + fullLen
701
+ };
702
+ }
703
+ /** 恢复光标到指定字符位置 */
704
+ function restoreCursorPosition(charPos) {
705
+ const el = editorRef.value;
706
+ if (!el || charPos < 0) return;
707
+ const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT);
708
+ let currentPos = 0;
709
+ let targetNode = null;
710
+ let targetOffset = 0;
711
+ while (walker.nextNode()) {
712
+ const node = walker.currentNode;
713
+ if (node.nodeType === Node.TEXT_NODE) {
714
+ const result = findInTextNode(node, currentPos, charPos);
715
+ if (result.found) {
716
+ targetNode = result.node;
717
+ targetOffset = result.offset;
718
+ break;
719
+ }
720
+ currentPos = result.pos;
721
+ } else if (node.nodeType === Node.ELEMENT_NODE && node.classList?.contains("formula-chip")) {
722
+ const result = findInChipNode(node, currentPos, charPos, walker);
723
+ if (result.found) {
724
+ targetNode = result.node;
725
+ targetOffset = result.offset;
726
+ break;
727
+ }
728
+ currentPos = result.pos;
729
+ }
730
+ }
731
+ setCursorAt(el, targetNode, targetOffset);
732
+ }
733
+ /** 设置光标到目标节点或末尾 */
734
+ function setCursorAt(container, node, offset) {
735
+ const range = document.createRange();
736
+ if (!node) {
737
+ range.selectNodeContents(container);
738
+ range.collapse(false);
739
+ } else try {
740
+ range.setStart(node, offset);
741
+ range.collapse(true);
742
+ } catch {
743
+ range.selectNodeContents(container);
744
+ range.collapse(false);
745
+ }
746
+ const sel = window.getSelection();
747
+ sel?.removeAllRanges();
748
+ sel?.addRange(range);
749
+ }
750
+ /** 将光标移到末尾 */
751
+ function moveCursorToEnd() {
752
+ const el = editorRef.value;
753
+ if (!el) return;
754
+ const range = document.createRange();
755
+ range.selectNodeContents(el);
756
+ range.collapse(false);
757
+ const sel = window.getSelection();
758
+ sel?.removeAllRanges();
759
+ sel?.addRange(range);
760
+ }
761
+ /** 输入事件 */
762
+ function handleInput() {
763
+ if (isExternalUpdate) return;
764
+ emit("update:formula", extractFormula());
765
+ }
766
+ /** 键盘事件 */
767
+ function handleKeyDown(e) {
768
+ if (props.disabled) {
769
+ e.preventDefault();
770
+ return;
771
+ }
772
+ if (e.key === "Tab") e.preventDefault();
773
+ }
774
+ /** 粘贴事件 — 只保留纯文本 */
775
+ function handlePaste(e) {
776
+ e.preventDefault();
777
+ const text = e.clipboardData?.getData("text/plain") ?? "";
778
+ document.execCommand("insertText", false, text);
779
+ }
780
+ /** blur 时保存光标位置 Range */
781
+ function handleBlur() {
782
+ isFocused.value = false;
783
+ const sel = window.getSelection();
784
+ if (sel && sel.rangeCount > 0) savedRange = sel.getRangeAt(0).cloneRange();
785
+ }
786
+ /** 清空 */
787
+ function handleClear() {
788
+ emit("update:formula", "");
789
+ nextTick(() => {
790
+ if (editorRef.value) editorRef.value.innerHTML = "";
791
+ });
792
+ }
793
+ /** 在光标位置插入文本 */
794
+ function insertAtCursor(text) {
795
+ const el = editorRef.value;
796
+ if (!el) return;
797
+ el.focus();
798
+ if (savedRange) {
799
+ const sel = window.getSelection();
800
+ sel?.removeAllRanges();
801
+ sel?.addRange(savedRange);
802
+ }
803
+ const varMatch = text.match(/^\[(.+)\]$/);
804
+ if (varMatch) {
805
+ const chip = document.createElement("span");
806
+ chip.className = "formula-chip";
807
+ chip.contentEditable = "false";
808
+ chip.setAttribute("data-variable", varMatch[1]);
809
+ chip.textContent = varMatch[1];
810
+ const sel = window.getSelection();
811
+ if (sel && sel.rangeCount > 0) {
812
+ const range = sel.getRangeAt(0);
813
+ range.deleteContents();
814
+ range.insertNode(chip);
815
+ const space = document.createTextNode(" ");
816
+ range.setStartAfter(chip);
817
+ range.insertNode(space);
818
+ range.setStartAfter(space);
819
+ range.collapse(true);
820
+ sel.removeAllRanges();
821
+ sel.addRange(range);
822
+ savedRange = range.cloneRange();
823
+ }
824
+ } else {
825
+ document.execCommand("insertText", false, text);
826
+ const sel = window.getSelection();
827
+ if (sel && sel.rangeCount > 0) savedRange = sel.getRangeAt(0).cloneRange();
828
+ }
829
+ emit("update:formula", extractFormula());
830
+ }
831
+ /** 退格(删除光标前一个字符或 chip) */
832
+ function backspace() {
833
+ const el = editorRef.value;
834
+ if (!el) return;
835
+ el.focus();
836
+ const sel = window.getSelection();
837
+ if (!sel || sel.rangeCount === 0) return;
838
+ const range = sel.getRangeAt(0);
839
+ if (range.startOffset > 0 && range.startContainer === el) {
840
+ const prevNode = el.childNodes[range.startOffset - 1];
841
+ if (prevNode && prevNode.nodeType === Node.ELEMENT_NODE && prevNode.classList?.contains("formula-chip")) {
842
+ prevNode.remove();
843
+ emit("update:formula", extractFormula());
844
+ return;
845
+ }
846
+ }
847
+ document.execCommand("delete", false);
848
+ emit("update:formula", extractFormula());
849
+ }
850
+ /** 聚焦 */
851
+ function focus() {
852
+ editorRef.value?.focus();
853
+ moveCursorToEnd();
854
+ }
855
+ watch(() => props.formula, (newFormula) => {
856
+ const el = editorRef.value;
857
+ if (!el) return;
858
+ if (extractFormula() === newFormula) return;
859
+ isExternalUpdate = true;
860
+ const pos = saveCursorPosition();
861
+ el.innerHTML = renderFormula(newFormula);
862
+ nextTick(() => {
863
+ restoreCursorPosition(pos);
864
+ isExternalUpdate = false;
865
+ });
866
+ });
867
+ onMounted(() => {
868
+ if (editorRef.value && props.formula) editorRef.value.innerHTML = renderFormula(props.formula);
869
+ });
870
+ __expose({
871
+ insertAtCursor,
872
+ backspace,
873
+ focus,
874
+ moveCursorToEnd
875
+ });
876
+ return (_ctx, _cache) => {
877
+ return openBlock(), createElementBlock("div", { class: normalizeClass(["formula-input", {
878
+ "formula-input--disabled": _ctx.disabled,
879
+ "formula-input--error": !_ctx.validation.valid && _ctx.formula.trim()
880
+ }]) }, [
881
+ createCommentVNode(" 标题行 "),
882
+ createElementVNode("div", _hoisted_1$4, [_cache[1] || (_cache[1] = createElementVNode("span", { class: "formula-input__label" }, "公式编辑", -1)), _ctx.formula.trim() && !_ctx.disabled ? (openBlock(), createElementBlock("a", {
883
+ key: 0,
884
+ class: "formula-input__clear",
885
+ onClick: handleClear
886
+ }, " 清空 ")) : createCommentVNode("v-if", true)]),
887
+ createCommentVNode(" 编辑器 "),
888
+ createElementVNode("div", {
889
+ ref_key: "editorRef",
890
+ ref: editorRef,
891
+ class: "formula-input__editor",
892
+ contenteditable: "true",
893
+ "data-placeholder": _ctx.placeholder,
894
+ spellcheck: "false",
895
+ onInput: handleInput,
896
+ onKeydown: handleKeyDown,
897
+ onPaste: handlePaste,
898
+ onFocus: _cache[0] || (_cache[0] = ($event) => isFocused.value = true),
899
+ onBlur: handleBlur
900
+ }, null, 40, _hoisted_2$4),
901
+ createCommentVNode(" 问题(校验信息)三态:空 / 合法 / 错误 "),
902
+ createElementVNode("div", _hoisted_3$4, [
903
+ _cache[4] || (_cache[4] = createElementVNode("span", { class: "formula-input__validation-label" }, "问题", -1)),
904
+ createCommentVNode(" 空公式:提示占位 "),
905
+ !_ctx.formula.trim() ? (openBlock(), createElementBlock("span", _hoisted_4$4, [createVNode(C_Icon_default, {
906
+ name: "mdi:information-outline",
907
+ size: 13
908
+ }), _cache[2] || (_cache[2] = createTextVNode(" 请输入公式,公式合法后可计算预览 ", -1))])) : _ctx.validation.valid ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createCommentVNode(" 合法:绿色通过 "), createElementVNode("span", _hoisted_5$4, [createVNode(C_Icon_default, {
909
+ name: "mdi:check-circle-outline",
910
+ size: 13
911
+ }), _cache[3] || (_cache[3] = createTextVNode(" 公式合法,语法正确 ", -1))])], 2112)) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [createCommentVNode(" 错误:红色提示 "), createElementVNode("span", _hoisted_6$4, [createVNode(C_Icon_default, {
912
+ name: "mdi:alert-circle-outline",
913
+ size: 13
914
+ }), createTextVNode(" " + toDisplayString(_ctx.validation.message), 1)])], 2112))
915
+ ])
916
+ ], 2);
917
+ };
918
+ }
919
+ });
920
+
921
+ //#endregion
922
+ //#region src/components/C_FormulaEditor/components/FormulaInput.vue
923
+ var FormulaInput_default = /* @__PURE__ */ export_helper_default(FormulaInput_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-b5e9ecca"]]);
924
+
925
+ //#endregion
926
+ //#region src/components/C_FormulaEditor/components/VariablePanel.vue?vue&type=script&setup=true&lang.ts
927
+ const _hoisted_1$3 = { class: "variable-panel" };
928
+ const _hoisted_2$3 = { class: "variable-panel__tabs" };
929
+ const _hoisted_3$3 = { class: "variable-panel__search" };
930
+ const _hoisted_4$3 = ["onClick"];
931
+ const _hoisted_5$3 = { class: "variable-panel__items" };
932
+ const _hoisted_6$3 = ["onClick"];
933
+ const _hoisted_7$2 = ["onClick"];
934
+ const _hoisted_8$2 = { class: "variable-panel__func-name" };
935
+ const _hoisted_9$1 = { class: "variable-panel__func-desc" };
936
+ const _hoisted_10$1 = { class: "variable-panel__func-sig" };
937
+ /** 过滤并按 group 分组变量 */
938
+ var VariablePanel_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
939
+ __name: "VariablePanel",
940
+ props: {
941
+ variables: {},
942
+ functions: {}
943
+ },
944
+ emits: ["select-variable", "select-function"],
945
+ setup(__props) {
946
+ const props = __props;
947
+ const activeTab = ref("variable");
948
+ const searchText = ref("");
949
+ const expandedGroups = ref(/* @__PURE__ */ new Set());
950
+ const groupedVariables = computed(() => {
951
+ const keyword = searchText.value.toLowerCase();
952
+ const filtered = keyword ? props.variables.filter((v) => v.name.toLowerCase().includes(keyword) || v.field.toLowerCase().includes(keyword) || (v.description ?? "").toLowerCase().includes(keyword)) : props.variables;
953
+ const map = /* @__PURE__ */ new Map();
954
+ for (const v of filtered) {
955
+ const group = v.group ?? "其他";
956
+ const list = map.get(group);
957
+ if (list) list.push(v);
958
+ else map.set(group, [v]);
959
+ }
960
+ return Array.from(map, ([name, items]) => ({
961
+ name,
962
+ items
963
+ }));
964
+ });
965
+ watch(groupedVariables, (groups) => {
966
+ for (const g of groups) expandedGroups.value.add(g.name);
967
+ }, { immediate: true });
968
+ /** 切换分组折叠 */
969
+ function toggleGroup(name) {
970
+ if (expandedGroups.value.has(name)) expandedGroups.value.delete(name);
971
+ else expandedGroups.value.add(name);
972
+ }
973
+ const filteredFunctions = computed(() => {
974
+ const keyword = searchText.value.toLowerCase();
975
+ if (!keyword) return props.functions;
976
+ return props.functions.filter((f) => f.name.toLowerCase().includes(keyword) || f.description.toLowerCase().includes(keyword));
977
+ });
978
+ /** 根据变量类型返回图标 */
979
+ function getTypeIcon(type) {
980
+ switch (type) {
981
+ case "number": return "mdi:numeric";
982
+ case "text": return "mdi:format-text";
983
+ case "boolean": return "mdi:toggle-switch-outline";
984
+ default: return "mdi:variable";
985
+ }
986
+ }
987
+ return (_ctx, _cache) => {
988
+ return openBlock(), createElementBlock("div", _hoisted_1$3, [
989
+ createCommentVNode(" 切换 Tab:变量 / 函数 "),
990
+ createElementVNode("div", _hoisted_2$3, [createElementVNode("div", {
991
+ class: normalizeClass(["variable-panel__tab", { "variable-panel__tab--active": activeTab.value === "variable" }]),
992
+ onClick: _cache[0] || (_cache[0] = ($event) => activeTab.value = "variable")
993
+ }, " 表单项目 ", 2), createElementVNode("div", {
994
+ class: normalizeClass(["variable-panel__tab", { "variable-panel__tab--active": activeTab.value === "function" }]),
995
+ onClick: _cache[1] || (_cache[1] = ($event) => activeTab.value = "function")
996
+ }, " 常用函数 ", 2)]),
997
+ createCommentVNode(" 搜索框 "),
998
+ createElementVNode("div", _hoisted_3$3, [createVNode(unref(NInput), {
999
+ value: searchText.value,
1000
+ "onUpdate:value": _cache[2] || (_cache[2] = ($event) => searchText.value = $event),
1001
+ size: "small",
1002
+ placeholder: "搜索...",
1003
+ clearable: ""
1004
+ }, {
1005
+ prefix: withCtx(() => [createVNode(C_Icon_default, {
1006
+ name: "mdi:magnify",
1007
+ size: 16
1008
+ })]),
1009
+ _: 1
1010
+ }, 8, ["value"])]),
1011
+ createCommentVNode(" 变量列表 "),
1012
+ activeTab.value === "variable" ? (openBlock(), createBlock(unref(NScrollbar), {
1013
+ key: 0,
1014
+ class: "variable-panel__list"
1015
+ }, {
1016
+ default: withCtx(() => [groupedVariables.value.length > 0 ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(groupedVariables.value, (group) => {
1017
+ return openBlock(), createElementBlock("div", {
1018
+ key: group.name,
1019
+ class: "variable-panel__group"
1020
+ }, [createElementVNode("div", {
1021
+ class: "variable-panel__group-title",
1022
+ onClick: ($event) => toggleGroup(group.name)
1023
+ }, [createVNode(C_Icon_default, {
1024
+ name: expandedGroups.value.has(group.name) ? "mdi:chevron-down" : "mdi:chevron-right",
1025
+ size: 16
1026
+ }, null, 8, ["name"]), createTextVNode(" " + toDisplayString(group.name), 1)], 8, _hoisted_4$3), withDirectives(createElementVNode("div", _hoisted_5$3, [(openBlock(true), createElementBlock(Fragment, null, renderList(group.items, (variable) => {
1027
+ return openBlock(), createElementBlock("div", {
1028
+ key: variable.field,
1029
+ class: "variable-panel__item",
1030
+ onClick: ($event) => _ctx.$emit("select-variable", variable)
1031
+ }, [createVNode(C_Icon_default, {
1032
+ name: getTypeIcon(variable.type),
1033
+ size: 15,
1034
+ class: "variable-panel__item-icon"
1035
+ }, null, 8, ["name"]), createElementVNode("span", null, toDisplayString(variable.name), 1)], 8, _hoisted_6$3);
1036
+ }), 128))], 512), [[vShow, expandedGroups.value.has(group.name)]])]);
1037
+ }), 128)) : (openBlock(), createBlock(unref(NEmpty), {
1038
+ key: 1,
1039
+ size: "small",
1040
+ description: "无匹配变量"
1041
+ }))]),
1042
+ _: 1
1043
+ })) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createCommentVNode(" 函数列表 "), createVNode(unref(NScrollbar), { class: "variable-panel__list" }, {
1044
+ default: withCtx(() => [filteredFunctions.value.length > 0 ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(filteredFunctions.value, (func) => {
1045
+ return openBlock(), createElementBlock("div", {
1046
+ key: func.name,
1047
+ class: "variable-panel__func",
1048
+ onClick: ($event) => _ctx.$emit("select-function", func)
1049
+ }, [
1050
+ createElementVNode("div", _hoisted_8$2, [_cache[3] || (_cache[3] = createElementVNode("span", { class: "variable-panel__func-badge" }, "ƒ", -1)), createTextVNode(" " + toDisplayString(func.name), 1)]),
1051
+ createElementVNode("div", _hoisted_9$1, toDisplayString(func.description), 1),
1052
+ createElementVNode("div", _hoisted_10$1, toDisplayString(func.signature), 1)
1053
+ ], 8, _hoisted_7$2);
1054
+ }), 128)) : (openBlock(), createBlock(unref(NEmpty), {
1055
+ key: 1,
1056
+ size: "small",
1057
+ description: "无匹配函数"
1058
+ }))]),
1059
+ _: 1
1060
+ })], 2112))
1061
+ ]);
1062
+ };
1063
+ }
1064
+ });
1065
+
1066
+ //#endregion
1067
+ //#region src/components/C_FormulaEditor/components/VariablePanel.vue
1068
+ var VariablePanel_default = /* @__PURE__ */ export_helper_default(VariablePanel_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-571e979a"]]);
1069
+
1070
+ //#endregion
1071
+ //#region src/components/C_FormulaEditor/components/VirtualKeyboard.vue?vue&type=script&setup=true&lang.ts
1072
+ const _hoisted_1$2 = { class: "vk" };
1073
+ const _hoisted_2$2 = { class: "vk__body" };
1074
+ const _hoisted_3$2 = { class: "vk__half vk__half--ops" };
1075
+ const _hoisted_4$2 = ["disabled", "onClick"];
1076
+ const _hoisted_5$2 = { class: "vk__half vk__half--nums" };
1077
+ const _hoisted_6$2 = ["disabled", "onClick"];
1078
+ const _hoisted_7$1 = { class: "vk__actions" };
1079
+ const _hoisted_8$1 = ["disabled", "onClick"];
1080
+ var VirtualKeyboard_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
1081
+ __name: "VirtualKeyboard",
1082
+ props: { disabled: {
1083
+ type: Boolean,
1084
+ default: false
1085
+ } },
1086
+ emits: ["key-press", "action"],
1087
+ setup(__props) {
1088
+ const operatorKeys = OPERATOR_KEYS;
1089
+ const numberKeys = NUMBER_KEYS;
1090
+ const actionKeys = ACTION_KEYS;
1091
+ return (_ctx, _cache) => {
1092
+ return openBlock(), createElementBlock("div", _hoisted_1$2, [
1093
+ createCommentVNode(" ═══════ 标题行 ═══════ "),
1094
+ _cache[0] || (_cache[0] = createElementVNode("div", { class: "vk__title" }, "计算公式", -1)),
1095
+ createCommentVNode(" ═══════ 键盘主体:运算符 | 数字 ═══════ "),
1096
+ createElementVNode("div", _hoisted_2$2, [
1097
+ createCommentVNode(" 运算符区 5 列 "),
1098
+ createElementVNode("div", _hoisted_3$2, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(operatorKeys), (key) => {
1099
+ return openBlock(), createElementBlock("button", {
1100
+ key: key.value,
1101
+ class: normalizeClass(["vk__key", [key.color ? `vk__key--${key.color}` : ""]]),
1102
+ disabled: _ctx.disabled,
1103
+ onClick: ($event) => _ctx.$emit("key-press", key)
1104
+ }, toDisplayString(key.label), 11, _hoisted_4$2);
1105
+ }), 128))]),
1106
+ createCommentVNode(" 数字区 5 列 "),
1107
+ createElementVNode("div", _hoisted_5$2, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(numberKeys), (key) => {
1108
+ return openBlock(), createElementBlock("button", {
1109
+ key: key.label + key.value,
1110
+ class: normalizeClass(["vk__key", [key.color ? `vk__key--${key.color}` : ""]]),
1111
+ disabled: _ctx.disabled,
1112
+ onClick: ($event) => _ctx.$emit("key-press", key)
1113
+ }, toDisplayString(key.label), 11, _hoisted_6$2);
1114
+ }), 128))])
1115
+ ]),
1116
+ createCommentVNode(" ═══════ 动作行:⌫ + 清空 ═══════ "),
1117
+ createElementVNode("div", _hoisted_7$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(actionKeys), (key) => {
1118
+ return openBlock(), createElementBlock("button", {
1119
+ key: key.value,
1120
+ class: "vk__key vk__key--action",
1121
+ disabled: _ctx.disabled,
1122
+ onClick: ($event) => _ctx.$emit("action", key.value)
1123
+ }, toDisplayString(key.label), 9, _hoisted_8$1);
1124
+ }), 128))])
1125
+ ]);
1126
+ };
1127
+ }
1128
+ });
1129
+
1130
+ //#endregion
1131
+ //#region src/components/C_FormulaEditor/components/VirtualKeyboard.vue
1132
+ var VirtualKeyboard_default = /* @__PURE__ */ export_helper_default(VirtualKeyboard_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-f7d1dceb"]]);
1133
+
1134
+ //#endregion
1135
+ //#region src/components/C_FormulaEditor/components/FormulaPreview.vue?vue&type=script&setup=true&lang.ts
1136
+ const _hoisted_1$1 = { class: "formula-preview" };
1137
+ const _hoisted_2$1 = { class: "formula-preview__header" };
1138
+ const _hoisted_3$1 = {
1139
+ key: 0,
1140
+ class: "formula-preview__empty"
1141
+ };
1142
+ const _hoisted_4$1 = {
1143
+ key: 0,
1144
+ class: "formula-preview__vars"
1145
+ };
1146
+ const _hoisted_5$1 = { class: "formula-preview__var-name" };
1147
+ const _hoisted_6$1 = { class: "formula-preview__var-value" };
1148
+ const _hoisted_7 = { class: "formula-preview__result" };
1149
+ const _hoisted_8 = {
1150
+ key: 0,
1151
+ class: "formula-preview__result-value"
1152
+ };
1153
+ const _hoisted_9 = {
1154
+ key: 1,
1155
+ class: "formula-preview__result-error"
1156
+ };
1157
+ const _hoisted_10 = {
1158
+ key: 2,
1159
+ class: "formula-preview__result-empty"
1160
+ };
1161
+ var FormulaPreview_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
1162
+ __name: "FormulaPreview",
1163
+ props: {
1164
+ formula: {},
1165
+ evalResult: {},
1166
+ usedVariables: {},
1167
+ hasSampleData: { type: Boolean }
1168
+ },
1169
+ setup(__props) {
1170
+ /** 格式化计算结果 */
1171
+ function formatResult(value) {
1172
+ if (typeof value === "number") {
1173
+ if (Number.isInteger(value)) return String(value);
1174
+ return Number(value.toFixed(6)).toString();
1175
+ }
1176
+ if (typeof value === "boolean") return value ? "真 (true)" : "假 (false)";
1177
+ return String(value);
1178
+ }
1179
+ return (_ctx, _cache) => {
1180
+ return openBlock(), createElementBlock("div", _hoisted_1$1, [
1181
+ createElementVNode("div", _hoisted_2$1, [createVNode(C_Icon_default, {
1182
+ name: "mdi:calculator-variant-outline",
1183
+ size: 15
1184
+ }), _cache[0] || (_cache[0] = createElementVNode("span", null, "计算预览", -1))]),
1185
+ createCommentVNode(" 当没有公式时 "),
1186
+ !_ctx.formula.trim() ? (openBlock(), createElementBlock("div", _hoisted_3$1, " 输入公式后可预览计算结果 ")) : !_ctx.hasSampleData ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createCommentVNode(" 没有样例数据时 "), _cache[1] || (_cache[1] = createElementVNode("div", { class: "formula-preview__empty" }, " 传入 sampleData 后可预览计算结果 ", -1))], 2112)) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [
1187
+ createCommentVNode(" 有结果 "),
1188
+ createCommentVNode(" 使用到的变量值 "),
1189
+ _ctx.usedVariables.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_4$1, [_cache[3] || (_cache[3] = createElementVNode("div", { class: "formula-preview__vars-title" }, "变量值", -1)), (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.usedVariables, (item) => {
1190
+ return openBlock(), createElementBlock("div", {
1191
+ key: item.name,
1192
+ class: "formula-preview__var-row"
1193
+ }, [
1194
+ createElementVNode("span", _hoisted_5$1, toDisplayString(item.name), 1),
1195
+ _cache[2] || (_cache[2] = createElementVNode("span", { class: "formula-preview__var-eq" }, "=", -1)),
1196
+ createElementVNode("span", _hoisted_6$1, toDisplayString(item.value), 1)
1197
+ ]);
1198
+ }), 128))])) : createCommentVNode("v-if", true),
1199
+ createVNode(unref(NDivider), { style: { "margin": "8px 0" } }),
1200
+ createCommentVNode(" 计算结果 "),
1201
+ createElementVNode("div", _hoisted_7, [_cache[4] || (_cache[4] = createElementVNode("span", { class: "formula-preview__result-label" }, "结果", -1)), _ctx.evalResult.success && _ctx.evalResult.result !== void 0 ? (openBlock(), createElementBlock("span", _hoisted_8, toDisplayString(formatResult(_ctx.evalResult.result)), 1)) : _ctx.evalResult.error ? (openBlock(), createElementBlock("span", _hoisted_9, [createVNode(C_Icon_default, {
1202
+ name: "mdi:alert-circle-outline",
1203
+ size: 14
1204
+ }), createTextVNode(" " + toDisplayString(_ctx.evalResult.error), 1)])) : (openBlock(), createElementBlock("span", _hoisted_10, " — "))])
1205
+ ], 64))
1206
+ ]);
1207
+ };
1208
+ }
1209
+ });
1210
+
1211
+ //#endregion
1212
+ //#region src/components/C_FormulaEditor/components/FormulaPreview.vue
1213
+ var FormulaPreview_default = /* @__PURE__ */ export_helper_default(FormulaPreview_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-72ecc4d7"]]);
1214
+
1215
+ //#endregion
1216
+ //#region src/components/C_FormulaEditor/index.vue?vue&type=script&setup=true&lang.ts
1217
+ const _hoisted_1 = { class: "c-formula__title-row" };
1218
+ const _hoisted_2 = { class: "c-formula__title" };
1219
+ const _hoisted_3 = { class: "c-formula__body" };
1220
+ const _hoisted_4 = {
1221
+ key: 0,
1222
+ class: "c-formula__sidebar"
1223
+ };
1224
+ const _hoisted_5 = { class: "c-formula__main" };
1225
+ const _hoisted_6 = {
1226
+ key: 0,
1227
+ class: "c-formula__keyboard"
1228
+ };
1229
+ var index_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
1230
+ name: "C_FormulaEditor",
1231
+ __name: "index",
1232
+ props: {
1233
+ modelValue: { default: "" },
1234
+ variables: { default: () => [] },
1235
+ functions: { default: void 0 },
1236
+ sampleData: { default: void 0 },
1237
+ disabled: {
1238
+ type: Boolean,
1239
+ default: false
1240
+ },
1241
+ placeholder: { default: "点击变量或使用键盘输入公式,变量用 [变量名] 包裹" },
1242
+ height: { default: "auto" },
1243
+ showPreview: {
1244
+ type: Boolean,
1245
+ default: true
1246
+ },
1247
+ showKeyboard: {
1248
+ type: Boolean,
1249
+ default: true
1250
+ },
1251
+ showVariablePanel: {
1252
+ type: Boolean,
1253
+ default: true
1254
+ }
1255
+ },
1256
+ emits: [
1257
+ "update:modelValue",
1258
+ "change",
1259
+ "validation-change"
1260
+ ],
1261
+ setup(__props, { expose: __expose, emit: __emit }) {
1262
+ const props = __props;
1263
+ const emit = __emit;
1264
+ const formulaInputRef = ref();
1265
+ const variableList = computed(() => props.variables ?? []);
1266
+ const functionList = computed(() => props.functions ?? DEFAULT_FUNCTIONS);
1267
+ const parser = useFormulaParser(variableList, functionList);
1268
+ const evaluator = useFormulaEvaluator(variableList);
1269
+ /** 公式字符串 */
1270
+ const formula = ref(props.modelValue || "");
1271
+ /** Token 列表 */
1272
+ const tokens = computed(() => parser.tokenize(formula.value));
1273
+ /** 校验结果 */
1274
+ const validation = computed(() => parser.validate(formula.value));
1275
+ const containerHeight = computed(() => {
1276
+ if (typeof props.height === "number") return `${props.height}px`;
1277
+ return props.height;
1278
+ });
1279
+ /** 是否有样例数据 */
1280
+ const hasSampleData = computed(() => !!props.sampleData && Object.keys(props.sampleData).length > 0);
1281
+ /** 求值结果 */
1282
+ const evalResult = computed(() => {
1283
+ if (!formula.value.trim() || !hasSampleData.value || !validation.value.valid) return {
1284
+ success: true,
1285
+ result: void 0
1286
+ };
1287
+ return evaluator.evaluate(formula.value, props.sampleData);
1288
+ });
1289
+ /** 提取公式中使用到的变量 + 对应样例数据值 */
1290
+ const usedVariableValues = computed(() => {
1291
+ if (!hasSampleData.value) return [];
1292
+ return evaluator.extractVariableNames(formula.value).map((name) => {
1293
+ const field = variableList.value.find((v) => v.name === name)?.field ?? name;
1294
+ return {
1295
+ name,
1296
+ value: props.sampleData?.[field] ?? "未提供"
1297
+ };
1298
+ });
1299
+ });
1300
+ onMounted(() => {
1301
+ if (props.modelValue) formula.value = props.modelValue;
1302
+ });
1303
+ watch(() => props.modelValue, (newVal) => {
1304
+ if (newVal !== void 0 && newVal !== formula.value) formula.value = newVal;
1305
+ });
1306
+ watch(formula, (newFormula) => {
1307
+ emit("update:modelValue", newFormula);
1308
+ emit("change", newFormula);
1309
+ });
1310
+ watch(validation, (v) => {
1311
+ emit("validation-change", v);
1312
+ });
1313
+ /** FormulaInput 输入更新 */
1314
+ function handleFormulaUpdate(value) {
1315
+ formula.value = value;
1316
+ }
1317
+ /** 选择变量 → 插入到光标 */
1318
+ function handleSelectVariable(variable) {
1319
+ formulaInputRef.value?.insertAtCursor(`[${variable.name}]`);
1320
+ }
1321
+ /** 选择函数 → 插入到光标 */
1322
+ function handleSelectFunction(func) {
1323
+ formulaInputRef.value?.insertAtCursor(`${func.name}(`);
1324
+ }
1325
+ /** 按键 → 插入值到光标 */
1326
+ function handleKeyPress(key) {
1327
+ formulaInputRef.value?.insertAtCursor(key.value);
1328
+ }
1329
+ /** 动作键处理 */
1330
+ function handleAction(action) {
1331
+ if (action === "BACKSPACE") formulaInputRef.value?.backspace();
1332
+ else if (action === "CLEAR") formula.value = "";
1333
+ }
1334
+ __expose({
1335
+ getValue: () => formula.value,
1336
+ setValue: (expr) => {
1337
+ formula.value = expr;
1338
+ },
1339
+ reset: () => {
1340
+ formula.value = props.modelValue || "";
1341
+ },
1342
+ validate: () => parser.validate(formula.value),
1343
+ insertAtCursor: (text) => {
1344
+ formulaInputRef.value?.insertAtCursor(text);
1345
+ },
1346
+ focus: () => {
1347
+ formulaInputRef.value?.focus();
1348
+ }
1349
+ });
1350
+ return (_ctx, _cache) => {
1351
+ return openBlock(), createElementBlock("div", {
1352
+ class: "c-formula",
1353
+ style: normalizeStyle({ height: containerHeight.value })
1354
+ }, [
1355
+ createCommentVNode(" ═══════ 顶部标题行 ═══════ "),
1356
+ createElementVNode("div", _hoisted_1, [createElementVNode("div", _hoisted_2, [createVNode(C_Icon_default, {
1357
+ name: "mdi:function-variant",
1358
+ size: 18
1359
+ }), _cache[0] || (_cache[0] = createElementVNode("span", null, "公式编辑器", -1))]), createVNode(unref(NTag), {
1360
+ type: validation.value.valid ? "success" : "error",
1361
+ size: "small",
1362
+ round: ""
1363
+ }, {
1364
+ icon: withCtx(() => [createVNode(C_Icon_default, {
1365
+ name: validation.value.valid ? "mdi:check-circle" : "mdi:alert-circle",
1366
+ size: 14
1367
+ }, null, 8, ["name"])]),
1368
+ default: withCtx(() => [createTextVNode(" " + toDisplayString(validation.value.valid ? "合法" : "错误"), 1)]),
1369
+ _: 1
1370
+ }, 8, ["type"])]),
1371
+ createCommentVNode(" ═══════ 主内容区域 ═══════ "),
1372
+ createElementVNode("div", _hoisted_3, [
1373
+ createCommentVNode(" 左侧:变量面板 "),
1374
+ props.showVariablePanel ? (openBlock(), createElementBlock("div", _hoisted_4, [createVNode(VariablePanel_default, {
1375
+ variables: variableList.value,
1376
+ functions: functionList.value,
1377
+ onSelectVariable: handleSelectVariable,
1378
+ onSelectFunction: handleSelectFunction
1379
+ }, null, 8, ["variables", "functions"])])) : createCommentVNode("v-if", true),
1380
+ createCommentVNode(" 右侧:编辑区 + 键盘 + 预览 "),
1381
+ createElementVNode("div", _hoisted_5, [
1382
+ createCommentVNode(" 公式输入区 "),
1383
+ createVNode(FormulaInput_default, {
1384
+ ref_key: "formulaInputRef",
1385
+ ref: formulaInputRef,
1386
+ formula: formula.value,
1387
+ tokens: tokens.value,
1388
+ validation: validation.value,
1389
+ "variable-names": unref(parser).variableNames.value,
1390
+ disabled: props.disabled,
1391
+ placeholder: props.placeholder,
1392
+ "onUpdate:formula": handleFormulaUpdate
1393
+ }, null, 8, [
1394
+ "formula",
1395
+ "tokens",
1396
+ "validation",
1397
+ "variable-names",
1398
+ "disabled",
1399
+ "placeholder"
1400
+ ]),
1401
+ createCommentVNode(" 虚拟键盘 "),
1402
+ props.showKeyboard ? (openBlock(), createElementBlock("div", _hoisted_6, [createVNode(VirtualKeyboard_default, {
1403
+ disabled: props.disabled,
1404
+ onKeyPress: handleKeyPress,
1405
+ onAction: handleAction
1406
+ }, null, 8, ["disabled"])])) : createCommentVNode("v-if", true),
1407
+ createCommentVNode(" 计算预览 "),
1408
+ props.showPreview && hasSampleData.value ? (openBlock(), createBlock(FormulaPreview_default, {
1409
+ key: 1,
1410
+ formula: formula.value,
1411
+ "eval-result": evalResult.value,
1412
+ "used-variables": usedVariableValues.value,
1413
+ "has-sample-data": hasSampleData.value
1414
+ }, null, 8, [
1415
+ "formula",
1416
+ "eval-result",
1417
+ "used-variables",
1418
+ "has-sample-data"
1419
+ ])) : createCommentVNode("v-if", true)
1420
+ ])
1421
+ ])
1422
+ ], 4);
1423
+ };
1424
+ }
1425
+ });
1426
+
1427
+ //#endregion
1428
+ //#region src/components/C_FormulaEditor/index.vue
1429
+ var C_FormulaEditor_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-7080e1fb"]]);
1430
+
1431
+ //#endregion
1432
+ export { DEFAULT_FUNCTIONS as a, OPERATOR_KEYS as c, ACTION_KEYS as i, SPACED_OPERATORS as l, useFormulaEvaluator as n, NUMBER_KEYS as o, useFormulaParser as r, OPERATORS as s, C_FormulaEditor_default as t };
1433
+ //# sourceMappingURL=C_FormulaEditor2.js.map