@robot-admin/naive-ui-components 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/dist/C_ActionBar-nnfbZCea.css.map +1 -0
  2. package/dist/C_ActionBar2.js +2 -2
  3. package/dist/C_ActionBar2.js.map +1 -1
  4. package/dist/C_AntV-DGjscTWa.css.map +1 -0
  5. package/dist/C_AntV2.js +6 -6
  6. package/dist/C_AntV2.js.map +1 -1
  7. package/dist/C_Barcode-DjTmDkbQ.css.map +1 -0
  8. package/dist/C_Barcode2.js +1 -1
  9. package/dist/C_Barcode2.js.map +1 -1
  10. package/dist/C_Captcha-Ccq3DMrR.css.map +1 -0
  11. package/dist/C_Captcha2.js +1 -1
  12. package/dist/C_Captcha2.js.map +1 -1
  13. package/dist/C_Cascade-IUUHIh7r.css.map +1 -0
  14. package/dist/C_Cascade2.js +2 -2
  15. package/dist/C_Cascade2.js.map +1 -1
  16. package/dist/C_City-Cv5BESaN.css.map +1 -0
  17. package/dist/C_City2.js +2 -2
  18. package/dist/C_City2.js.map +1 -1
  19. package/dist/C_Code-DPZlNSxL.css.map +1 -0
  20. package/dist/C_Code2.js +8 -7
  21. package/dist/C_Code2.js.map +1 -1
  22. package/dist/C_CollapsePanel-Fap-lv_5.css.map +1 -0
  23. package/dist/C_CollapsePanel2.js +1 -1
  24. package/dist/C_CollapsePanel2.js.map +1 -1
  25. package/dist/C_Cron-C0-8b5af.css.map +1 -0
  26. package/dist/C_Cron2.js +15 -14
  27. package/dist/C_Cron2.js.map +1 -1
  28. package/dist/C_Date2.js +1 -1
  29. package/dist/C_Date2.js.map +1 -1
  30. package/dist/C_Draggable-Bq6o0qXn.css.map +1 -0
  31. package/dist/C_Draggable2.js +1 -1
  32. package/dist/C_Draggable2.js.map +1 -1
  33. package/dist/C_Editor-OlxIF9-5.css.map +1 -0
  34. package/dist/C_Editor2.js +1 -1
  35. package/dist/C_Editor2.js.map +1 -1
  36. package/dist/C_FilePreview-B4XgTv-h.css.map +1 -0
  37. package/dist/C_FilePreview.cjs +1 -0
  38. package/dist/C_FilePreview.js +1 -0
  39. package/dist/C_FilePreview2.js +10 -9
  40. package/dist/C_FilePreview2.js.map +1 -1
  41. package/dist/C_Form-Cr9oX037.css.map +1 -0
  42. package/dist/C_Form.cjs +1 -0
  43. package/dist/C_Form.js +1 -0
  44. package/dist/C_Form2.js +69 -72
  45. package/dist/C_Form2.js.map +1 -1
  46. package/dist/C_FormSearch-DlIEoh7X.css.map +1 -0
  47. package/dist/C_FormSearch2.js +2 -2
  48. package/dist/C_FormSearch2.js.map +1 -1
  49. package/dist/C_FormulaEditor-Cm0CokN5.css.map +1 -0
  50. package/dist/C_FormulaEditor2.js +6 -6
  51. package/dist/C_FormulaEditor2.js.map +1 -1
  52. package/dist/C_FullCalendar-BULCIlVK.css.map +1 -0
  53. package/dist/C_FullCalendar2.js +2 -2
  54. package/dist/C_FullCalendar2.js.map +1 -1
  55. package/dist/C_Guide2.js +1 -1
  56. package/dist/C_Guide2.js.map +1 -1
  57. package/dist/C_Icon2.js.map +1 -1
  58. package/dist/C_ImageCropper-DrmUlaLi.css.map +1 -0
  59. package/dist/C_ImageCropper2.js +4 -4
  60. package/dist/C_ImageCropper2.js.map +1 -1
  61. package/dist/C_Language2.js +1 -1
  62. package/dist/C_Language2.js.map +1 -1
  63. package/dist/C_Map-WUMXSAfy.css.map +1 -0
  64. package/dist/C_Map2.js +2 -2
  65. package/dist/C_Map2.js.map +1 -1
  66. package/dist/C_Markdown-Dmv8yaM4.css.map +1 -0
  67. package/dist/C_Markdown2.js +4 -4
  68. package/dist/C_Markdown2.js.map +1 -1
  69. package/dist/C_NotificationCenter-DbgBiyqB.css.map +1 -0
  70. package/dist/C_NotificationCenter2.js +21 -20
  71. package/dist/C_NotificationCenter2.js.map +1 -1
  72. package/dist/C_Progress2.js +1 -1
  73. package/dist/C_Progress2.js.map +1 -1
  74. package/dist/C_QRCode-G7fiAkm4.css.map +1 -0
  75. package/dist/C_QRCode2.js +1 -1
  76. package/dist/C_QRCode2.js.map +1 -1
  77. package/dist/C_Signature-es-ZNPzr.css.map +1 -0
  78. package/dist/C_Signature2.js +2 -2
  79. package/dist/C_Signature2.js.map +1 -1
  80. package/dist/C_SplitPane-Br2eK8IG.css.map +1 -0
  81. package/dist/C_SplitPane2.js +1 -1
  82. package/dist/C_SplitPane2.js.map +1 -1
  83. package/dist/C_Steps-P9Qj9iDd.css.map +1 -0
  84. package/dist/C_Steps2.js +1 -1
  85. package/dist/C_Steps2.js.map +1 -1
  86. package/dist/C_Table-DAwAxr72.css.map +1 -0
  87. package/dist/C_Table.cjs +1 -0
  88. package/dist/C_Table.js +1 -0
  89. package/dist/C_Table2.js +3 -3
  90. package/dist/C_Table2.js.map +1 -1
  91. package/dist/C_Theme2.js +1 -1
  92. package/dist/C_Theme2.js.map +1 -1
  93. package/dist/C_Time-Bd_e1YDN.css.map +1 -0
  94. package/dist/C_Time2.js +2 -2
  95. package/dist/C_Time2.js.map +1 -1
  96. package/dist/C_Tree-DnGc_MPb.css.map +1 -0
  97. package/dist/C_Tree2.js +2 -2
  98. package/dist/C_Tree2.js.map +1 -1
  99. package/dist/C_Upload-i8LB_29U.css.map +1 -0
  100. package/dist/C_Upload2.js +5 -5
  101. package/dist/C_Upload2.js.map +1 -1
  102. package/dist/C_VideoPlayer-rm0MODUv.css.map +1 -0
  103. package/dist/C_VideoPlayer2.js +21 -20
  104. package/dist/C_VideoPlayer2.js.map +1 -1
  105. package/dist/C_VtableGantt-BpY-Rng3.css.map +1 -0
  106. package/dist/C_VtableGantt2.js +2 -2
  107. package/dist/C_VtableGantt2.js.map +1 -1
  108. package/dist/C_WaterFall-HWB-gPON.css.map +1 -0
  109. package/dist/C_WaterFall2.js +2 -2
  110. package/dist/C_WaterFall2.js.map +1 -1
  111. package/dist/C_WorkFlow-CSO86Cuc.css.map +1 -0
  112. package/dist/C_WorkFlow2.js +6 -6
  113. package/dist/C_WorkFlow2.js.map +1 -1
  114. package/dist/constants.d.ts +4 -4
  115. package/dist/constants2.d.ts +4 -4
  116. package/dist/constants3.d.ts +4 -4
  117. package/dist/constants4.d.ts +5 -5
  118. package/dist/constants5.d.ts +2 -2
  119. package/dist/data.d.ts +1 -1
  120. package/dist/index.js.map +1 -1
  121. package/dist/index.vue.d.ts +1 -1
  122. package/dist/index10.vue.d.ts +7 -7
  123. package/dist/index11.vue.d.ts +2 -2
  124. package/dist/index12.vue.d.ts +5 -5
  125. package/dist/index12.vue.d.ts.map +1 -1
  126. package/dist/index13.vue.d.ts +1 -1
  127. package/dist/index14.vue.d.ts +1 -1
  128. package/dist/index16.vue.d.ts +1 -1
  129. package/dist/index2.vue.d.ts +6 -6
  130. package/dist/index3.vue.d.ts +2 -2
  131. package/dist/index4.vue.d.ts +2 -2
  132. package/dist/index5.vue.d.ts +2 -2
  133. package/dist/index6.vue.d.ts +1 -1
  134. package/dist/index8.vue.d.ts +3 -3
  135. package/dist/resolver.js.map +1 -1
  136. package/dist/style.css +1555 -1555
  137. package/dist/useCalendarEvents.d.ts +2 -2
  138. package/dist/useCollapsePanel.d.ts +2 -2
  139. package/dist/useCropperCore.d.ts +3 -3
  140. package/dist/useDraggableLayout.d.ts +8 -8
  141. package/dist/useDynamicFormState.d.ts +111 -111
  142. package/dist/useDynamicFormState.d.ts.map +1 -1
  143. package/dist/useEdgeInteraction.d.ts +2 -2
  144. package/dist/useInfiniteScroll.d.ts +1 -1
  145. package/dist/useModalEdit.d.ts +4 -4
  146. package/dist/useModalEdit.d.ts.map +1 -1
  147. package/dist/useQRCode.d.ts +4 -4
  148. package/dist/useQRCode.d.ts.map +1 -1
  149. package/dist/useSearchState.d.ts +2 -2
  150. package/dist/useSignatureHistory.d.ts +4 -4
  151. package/dist/useSplitResize.d.ts +6 -6
  152. package/dist/useSplitResize.d.ts.map +1 -1
  153. package/dist/useTimeSelection.d.ts +2 -2
  154. package/dist/useTreeOperations.d.ts +6 -6
  155. package/dist/useWorkflowValidation.d.ts +5 -5
  156. package/package.json +2 -1
  157. package/dist/C_ActionBar-DWN-woTc.css.map +0 -1
  158. package/dist/C_AntV-AFKyK6hH.css.map +0 -1
  159. package/dist/C_Barcode-P_EFj8dC.css.map +0 -1
  160. package/dist/C_Captcha-C-ef41xw.css.map +0 -1
  161. package/dist/C_Cascade-D9kNsjsV.css.map +0 -1
  162. package/dist/C_City-BCQ4ipiK.css.map +0 -1
  163. package/dist/C_Code-C9kvvEmO.css.map +0 -1
  164. package/dist/C_CollapsePanel-BUJHuYcU.css.map +0 -1
  165. package/dist/C_Cron-yx2Ob4Jl.css.map +0 -1
  166. package/dist/C_Draggable-C483syRC.css.map +0 -1
  167. package/dist/C_Editor-Bp0SyIEw.css.map +0 -1
  168. package/dist/C_FilePreview-CPqvhoCy.css.map +0 -1
  169. package/dist/C_Form-Jx7PY3sT.css.map +0 -1
  170. package/dist/C_FormSearch-DvRgxlRn.css.map +0 -1
  171. package/dist/C_FormulaEditor-DtGkt4T_.css.map +0 -1
  172. package/dist/C_FullCalendar-BF7H0YIx.css.map +0 -1
  173. package/dist/C_ImageCropper-BVJfUufl.css.map +0 -1
  174. package/dist/C_Map-DpzeuWdX.css.map +0 -1
  175. package/dist/C_Markdown-BEjxknqd.css.map +0 -1
  176. package/dist/C_NotificationCenter-0l3TY2Gn.css.map +0 -1
  177. package/dist/C_QRCode-DbdiAIPg.css.map +0 -1
  178. package/dist/C_Signature-zhHCbra9.css.map +0 -1
  179. package/dist/C_SplitPane-C6sBsfKY.css.map +0 -1
  180. package/dist/C_Steps-CODHN5Hs.css.map +0 -1
  181. package/dist/C_Table-DSNsntmT.css.map +0 -1
  182. package/dist/C_Time-BvZLYraL.css.map +0 -1
  183. package/dist/C_Tree-0GDv--jX.css.map +0 -1
  184. package/dist/C_Upload-BXd3YYLx.css.map +0 -1
  185. package/dist/C_VideoPlayer-DYG3RL0Q.css.map +0 -1
  186. package/dist/C_VtableGantt-fhItIiHE.css.map +0 -1
  187. package/dist/C_WaterFall-8sQDFXKg.css.map +0 -1
  188. package/dist/C_WorkFlow-J-dyIuh9.css.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"C_Cron2.js","names":["modelValue","computing","nextExecutions","formatDate","formatWeekDay","templates","currentValue","$emit"],"sources":["../src/components/C_Cron/constants.ts","../src/components/C_Cron/composables/useCronParser.ts","../src/components/C_Cron/composables/useCronPreview.ts","../src/components/C_Cron/composables/useCronDescription.ts","../src/components/C_Cron/components/CronFieldEditor.vue","../src/components/C_Cron/components/CronFieldEditor.vue","../src/components/C_Cron/components/CronFieldEditor.vue","../src/components/C_Cron/components/CronPreview.vue","../src/components/C_Cron/components/CronPreview.vue","../src/components/C_Cron/components/CronPreview.vue","../src/components/C_Cron/components/CronTemplates.vue","../src/components/C_Cron/components/CronTemplates.vue","../src/components/C_Cron/components/CronTemplates.vue","../src/components/C_Cron/index.vue","../src/components/C_Cron/index.vue","../src/components/C_Cron/index.vue"],"sourcesContent":["/*\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 表达式编辑器常量\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n */\r\n\r\nimport type {\r\n CronFieldMeta,\r\n CronFieldValue,\r\n CronTemplate,\r\n CronValue,\r\n} from \"./types\";\r\n\r\n/* ─── 字段元数据 ────────────────────────────────── */\r\n\r\nexport const CRON_FIELD_META: CronFieldMeta[] = [\r\n { type: \"second\", label: \"秒\", min: 0, max: 59 },\r\n { type: \"minute\", label: \"分\", min: 0, max: 59 },\r\n { type: \"hour\", label: \"时\", min: 0, max: 23 },\r\n { type: \"day\", label: \"日\", min: 1, max: 31 },\r\n { type: \"month\", label: \"月\", min: 1, max: 12 },\r\n {\r\n type: \"week\",\r\n label: \"周\",\r\n min: 1,\r\n max: 7,\r\n valueLabels: {\r\n 1: \"周日\",\r\n 2: \"周一\",\r\n 3: \"周二\",\r\n 4: \"周三\",\r\n 5: \"周四\",\r\n 6: \"周五\",\r\n 7: \"周六\",\r\n },\r\n },\r\n];\r\n\r\n/* ─── 默认字段值 ────────────────────────────────── */\r\n\r\nexport const DEFAULT_FIELD_VALUE: CronFieldValue = {\r\n mode: \"every\",\r\n rangeStart: 0,\r\n rangeEnd: 0,\r\n stepStart: 0,\r\n stepInterval: 1,\r\n specificValues: [],\r\n};\r\n\r\n/* ─── 默认 Cron 值(每秒执行) ────────────────── */\r\n\r\nexport const DEFAULT_CRON_VALUE: CronValue = {\r\n second: { ...DEFAULT_FIELD_VALUE, rangeEnd: 59 },\r\n minute: { ...DEFAULT_FIELD_VALUE, rangeEnd: 59 },\r\n hour: { ...DEFAULT_FIELD_VALUE, rangeEnd: 23 },\r\n day: { ...DEFAULT_FIELD_VALUE, rangeStart: 1, rangeEnd: 31 },\r\n month: { ...DEFAULT_FIELD_VALUE, rangeStart: 1, rangeEnd: 12 },\r\n week: { ...DEFAULT_FIELD_VALUE, mode: \"none\", rangeStart: 1, rangeEnd: 7 },\r\n};\r\n\r\n/* ─── 默认表达式 ─────────────────────────────────── */\r\n\r\nexport const DEFAULT_CRON_EXPRESSION = \"0 0 0 * * ?\";\r\n\r\n/* ─── 常用模板 ───────────────────────────────────── */\r\n\r\nexport const CRON_TEMPLATES: CronTemplate[] = [\r\n {\r\n label: \"每秒执行\",\r\n value: \"* * * * * ?\",\r\n description: \"每秒执行一次\",\r\n icon: \"mdi:timer-sand\",\r\n },\r\n {\r\n label: \"每分钟执行\",\r\n value: \"0 * * * * ?\",\r\n description: \"每分钟第 0 秒执行\",\r\n icon: \"mdi:clock-outline\",\r\n },\r\n {\r\n label: \"每小时执行\",\r\n value: \"0 0 * * * ?\",\r\n description: \"每小时整点执行\",\r\n icon: \"mdi:clock-time-twelve-outline\",\r\n },\r\n {\r\n label: \"每天 0 点\",\r\n value: \"0 0 0 * * ?\",\r\n description: \"每天凌晨 00:00 执行\",\r\n icon: \"mdi:weather-night\",\r\n },\r\n {\r\n label: \"每天 8:30\",\r\n value: \"0 30 8 * * ?\",\r\n description: \"每天早上 08:30 执行\",\r\n icon: \"mdi:weather-sunny\",\r\n },\r\n {\r\n label: \"每天 12:00\",\r\n value: \"0 0 12 * * ?\",\r\n description: \"每天中午 12:00 执行\",\r\n icon: \"mdi:food\",\r\n },\r\n {\r\n label: \"工作日 9:00\",\r\n value: \"0 0 9 ? * 2-6\",\r\n description: \"周一至周五 09:00 执行\",\r\n icon: \"mdi:briefcase-outline\",\r\n },\r\n {\r\n label: \"每周一 0 点\",\r\n value: \"0 0 0 ? * 2\",\r\n description: \"每周一凌晨 00:00 执行\",\r\n icon: \"mdi:calendar-week\",\r\n },\r\n {\r\n label: \"每月 1 号 0 点\",\r\n value: \"0 0 0 1 * ?\",\r\n description: \"每月 1 号凌晨 00:00 执行\",\r\n icon: \"mdi:calendar-month\",\r\n },\r\n {\r\n label: \"每 5 分钟\",\r\n value: \"0 0/5 * * * ?\",\r\n description: \"每隔 5 分钟执行一次\",\r\n icon: \"mdi:timer-5\",\r\n },\r\n {\r\n label: \"每 30 分钟\",\r\n value: \"0 0/30 * * * ?\",\r\n description: \"每隔 30 分钟执行一次\",\r\n icon: \"mdi:timer-30\",\r\n },\r\n {\r\n label: \"每 2 小时\",\r\n value: \"0 0 0/2 * * ?\",\r\n description: \"每隔 2 小时执行一次\",\r\n icon: \"mdi:timer-2\",\r\n },\r\n];\r\n\r\n/* ─── 月份名称 ───────────────────────────────────── */\r\n\r\nexport const MONTH_LABELS: Record<number, string> = {\r\n 1: \"一月\",\r\n 2: \"二月\",\r\n 3: \"三月\",\r\n 4: \"四月\",\r\n 5: \"五月\",\r\n 6: \"六月\",\r\n 7: \"七月\",\r\n 8: \"八月\",\r\n 9: \"九月\",\r\n 10: \"十月\",\r\n 11: \"十一月\",\r\n 12: \"十二月\",\r\n};\r\n\r\n/* ─── 周名称 ─────────────────────────────────────── */\r\n\r\nexport const WEEK_LABELS: Record<number, string> = {\r\n 1: \"周日\",\r\n 2: \"周一\",\r\n 3: \"周二\",\r\n 4: \"周三\",\r\n 5: \"周四\",\r\n 6: \"周五\",\r\n 7: \"周六\",\r\n};\r\n","/*\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 解析 & 生成引擎\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n */\r\n\r\nimport { ref, computed } from \"vue\";\r\nimport type {\r\n CronFieldMeta,\r\n CronFieldType,\r\n CronFieldValue,\r\n CronValidation,\r\n CronValue,\r\n} from \"../types\";\r\nimport { CRON_FIELD_META, DEFAULT_CRON_VALUE } from \"../constants\";\r\n\r\n/* ─── 字段顺序 ────────────────────────────────── */\r\n\r\nconst FIELD_ORDER: CronFieldType[] = [\r\n \"second\",\r\n \"minute\",\r\n \"hour\",\r\n \"day\",\r\n \"month\",\r\n \"week\",\r\n];\r\n\r\n/**\r\n * Cron 解析 & 生成引擎\r\n */\r\nexport function useCronParser() {\r\n /** 当前 Cron 对象 */\r\n const cronValue = ref<CronValue>(structuredClone(DEFAULT_CRON_VALUE));\r\n\r\n /* ─── 单字段 → 表达式片段 ────────────────────── */\r\n\r\n /** 将单个字段值转为 Cron 表达式片段 */\r\n function fieldToExpression(field: CronFieldValue): string {\r\n switch (field.mode) {\r\n case \"every\":\r\n return \"*\";\r\n case \"range\":\r\n return `${field.rangeStart}-${field.rangeEnd}`;\r\n case \"step\":\r\n return `${field.stepStart}/${field.stepInterval}`;\r\n case \"specific\":\r\n return field.specificValues.length > 0\r\n ? field.specificValues.sort((a, b) => a - b).join(\",\")\r\n : \"*\";\r\n case \"none\":\r\n return \"?\";\r\n default:\r\n return \"*\";\r\n }\r\n }\r\n\r\n /* ─── 表达式片段 → 单字段 ────────────────────── */\r\n\r\n /** 创建默认字段值 */\r\n function createFieldValue(\r\n meta: CronFieldMeta,\r\n mode: CronFieldValue[\"mode\"],\r\n overrides: Partial<CronFieldValue> = {},\r\n ): CronFieldValue {\r\n return {\r\n mode,\r\n rangeStart: meta.min,\r\n rangeEnd: meta.max,\r\n stepStart: meta.min,\r\n stepInterval: 1,\r\n specificValues: [],\r\n ...overrides,\r\n };\r\n }\r\n\r\n /** 解析步进表达式为字段值 */\r\n function parseStepExpr(expr: string, meta: CronFieldMeta): CronFieldValue {\r\n const [start, interval] = expr.split(\"/\").map(Number);\r\n return createFieldValue(meta, \"step\", {\r\n stepStart: isNaN(start) ? meta.min : start,\r\n stepInterval: isNaN(interval) ? 1 : interval,\r\n });\r\n }\r\n\r\n /** 解析范围表达式为字段值 */\r\n function parseRangeExpr(expr: string, meta: CronFieldMeta): CronFieldValue {\r\n const [start, end] = expr.split(\"-\").map(Number);\r\n return createFieldValue(meta, \"range\", {\r\n rangeStart: isNaN(start) ? meta.min : start,\r\n rangeEnd: isNaN(end) ? meta.max : end,\r\n });\r\n }\r\n\r\n /** 将 Cron 表达式片段解析为字段值对象 */\r\n function expressionToField(\r\n expr: string,\r\n type: CronFieldType,\r\n ): CronFieldValue {\r\n const meta = CRON_FIELD_META.find((m) => m.type === type)!;\r\n\r\n if (expr === \"?\") return createFieldValue(meta, \"none\");\r\n if (expr === \"*\") return createFieldValue(meta, \"every\");\r\n if (expr.includes(\"/\")) return parseStepExpr(expr, meta);\r\n if (expr.includes(\"-\") && !expr.includes(\",\"))\r\n return parseRangeExpr(expr, meta);\r\n\r\n /* x,y,z 或单个数字(指定值) */\r\n const values = expr\r\n .split(\",\")\r\n .map(Number)\r\n .filter((n) => !isNaN(n));\r\n if (values.length > 0)\r\n return createFieldValue(meta, \"specific\", { specificValues: values });\r\n\r\n return createFieldValue(meta, \"every\");\r\n }\r\n\r\n /* ─── CronValue → 完整表达式 ────────────────── */\r\n\r\n /** 由 CronValue 生成完整 Cron 表达式 */\r\n function generate(): string {\r\n return FIELD_ORDER.map((type) =>\r\n fieldToExpression(cronValue.value[type]),\r\n ).join(\" \");\r\n }\r\n\r\n /* ─── 完整表达式 → CronValue ────────────────── */\r\n\r\n /** 解析 Cron 表达式字符串为 CronValue */\r\n function parse(expression: string): void {\r\n const parts = expression.trim().split(/\\s+/);\r\n if (parts.length < 6) return;\r\n\r\n FIELD_ORDER.forEach((type, index) => {\r\n cronValue.value[type] = expressionToField(parts[index], type);\r\n });\r\n }\r\n\r\n /* ─── 日/周互斥处理 ─────────────────────────── */\r\n\r\n /** 日/周互斥:修改一方时另一方自动设为 ? */\r\n function handleDayWeekExclusion(changedField: \"day\" | \"week\"): void {\r\n if (changedField === \"day\") {\r\n if (cronValue.value.day.mode !== \"none\") {\r\n cronValue.value.week = { ...cronValue.value.week, mode: \"none\" };\r\n }\r\n } else {\r\n if (cronValue.value.week.mode !== \"none\") {\r\n cronValue.value.day = { ...cronValue.value.day, mode: \"none\" };\r\n }\r\n }\r\n }\r\n\r\n /* ─── 校验 ──────────────────────────────────── */\r\n\r\n /** 校验 Cron 表达式合法性 */\r\n function validate(expression?: string): CronValidation {\r\n const expr = expression ?? generate();\r\n const parts = expr.trim().split(/\\s+/);\r\n\r\n if (parts.length !== 6) {\r\n return {\r\n valid: false,\r\n message: `表达式应包含 6 个字段,当前为 ${parts.length} 个`,\r\n };\r\n }\r\n\r\n /* 日和周必须有一个为 ? */\r\n const dayPart = parts[3];\r\n const weekPart = parts[5];\r\n if (dayPart !== \"?\" && weekPart !== \"?\") {\r\n return {\r\n valid: false,\r\n message: \"日和周不能同时指定,其中一个必须为 ?\",\r\n field: \"day\",\r\n };\r\n }\r\n if (dayPart === \"?\" && weekPart === \"?\") {\r\n return {\r\n valid: false,\r\n message: \"日和周不能同时为 ?,至少指定一个\",\r\n field: \"day\",\r\n };\r\n }\r\n\r\n /* 逐字段校验 */\r\n for (let i = 0; i < FIELD_ORDER.length; i++) {\r\n const type = FIELD_ORDER[i];\r\n const part = parts[i];\r\n const meta = CRON_FIELD_META.find((m) => m.type === type)!;\r\n const result = validateField(part, meta);\r\n if (!result.valid) {\r\n return { ...result, field: type };\r\n }\r\n }\r\n\r\n return { valid: true, message: \"表达式合法\" };\r\n }\r\n\r\n /** 校验步进表达式 */\r\n function validateStep(part: string, meta: CronFieldMeta): CronValidation {\r\n const [s, i] = part.split(\"/\");\r\n const start = s === \"*\" ? meta.min : Number(s);\r\n const interval = Number(i);\r\n if (isNaN(start) || isNaN(interval))\r\n return { valid: false, message: `${meta.label}字段步进格式错误` };\r\n if (start < meta.min || start > meta.max)\r\n return {\r\n valid: false,\r\n message: `${meta.label}字段步进起始值超出范围 (${meta.min}-${meta.max})`,\r\n };\r\n if (interval < 1)\r\n return { valid: false, message: `${meta.label}字段步进间隔必须大于 0` };\r\n return { valid: true, message: \"\" };\r\n }\r\n\r\n /** 校验范围表达式 */\r\n function validateRange(part: string, meta: CronFieldMeta): CronValidation {\r\n const [s, e] = part.split(\"-\").map(Number);\r\n if (isNaN(s) || isNaN(e))\r\n return { valid: false, message: `${meta.label}字段范围格式错误` };\r\n if (s < meta.min || e > meta.max)\r\n return {\r\n valid: false,\r\n message: `${meta.label}字段范围超出 (${meta.min}-${meta.max})`,\r\n };\r\n if (s > e)\r\n return { valid: false, message: `${meta.label}字段范围起始不能大于结束` };\r\n return { valid: true, message: \"\" };\r\n }\r\n\r\n /** 校验指定值表达式 */\r\n function validateSpecific(part: string, meta: CronFieldMeta): CronValidation {\r\n const values = part.split(\",\").map(Number);\r\n if (values.some(isNaN))\r\n return { valid: false, message: `${meta.label}字段包含非数字字符` };\r\n if (values.some((v) => v < meta.min || v > meta.max)) {\r\n return {\r\n valid: false,\r\n message: `${meta.label}字段值超出范围 (${meta.min}-${meta.max})`,\r\n };\r\n }\r\n return { valid: true, message: \"\" };\r\n }\r\n\r\n /** 校验单个字段表达式 */\r\n function validateField(part: string, meta: CronFieldMeta): CronValidation {\r\n if (part === \"*\" || part === \"?\") return { valid: true, message: \"\" };\r\n if (part.includes(\"/\")) return validateStep(part, meta);\r\n if (part.includes(\"-\") && !part.includes(\",\"))\r\n return validateRange(part, meta);\r\n return validateSpecific(part, meta);\r\n }\r\n\r\n /* ─── 计算属性:自动生成表达式 ────────────────── */\r\n\r\n const expression = computed(() => generate());\r\n\r\n /* ─── 校验结果 ──────────────────────────────── */\r\n\r\n const validation = computed(() => validate());\r\n\r\n return {\r\n cronValue,\r\n expression,\r\n validation,\r\n parse,\r\n generate,\r\n validate,\r\n handleDayWeekExclusion,\r\n };\r\n}\r\n","/*\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 执行时间预测\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n */\r\n\r\nimport { ref, watch, type Ref } from 'vue'\r\nimport type { CronValidation } from '../types'\r\n\r\n/**\r\n * 解析 Cron 表达式,预测未来 N 次执行时间\r\n * 纯逻辑实现,不依赖外部库\r\n */\r\nexport function useCronPreview(\r\n expression: Ref<string>,\r\n validation: Ref<CronValidation>,\r\n count: Ref<number>\r\n) {\r\n /** 预测的执行时间列表 */\r\n const nextExecutions = ref<Date[]>([])\r\n\r\n /** 是否正在计算 */\r\n const computing = ref(false)\r\n\r\n /* ─── 匹配检查工具 ─────────────────────────── */\r\n\r\n /** 检查单个值是否匹配 Cron 字段片段 */\r\n function matchesPart(value: number, part: string): boolean {\r\n if (part === '*' || part === '?') return true\r\n\r\n /* 步进 x/y */\r\n if (part.includes('/')) {\r\n const [s, i] = part.split('/')\r\n const start = s === '*' ? 0 : Number(s)\r\n const interval = Number(i)\r\n return value - start >= 0 && (value - start) % interval === 0\r\n }\r\n\r\n /* 范围 x-y */\r\n if (part.includes('-') && !part.includes(',')) {\r\n const [start, end] = part.split('-').map(Number)\r\n return value >= start && value <= end\r\n }\r\n\r\n /* 指定值 x,y,z */\r\n return part.split(',').map(Number).includes(value)\r\n }\r\n\r\n /** 检查日期是否匹配 Cron 表达式 */\r\n function matchesCron(date: Date, parts: string[]): boolean {\r\n if (parts.length !== 6) return false\r\n\r\n const [secPart, minPart, hourPart, dayPart, monthPart, weekPart] = parts\r\n\r\n /* 月 (1-12) */\r\n if (!matchesPart(date.getMonth() + 1, monthPart)) return false\r\n\r\n /* 日/周(互斥) */\r\n if (dayPart !== '?') {\r\n if (!matchesPart(date.getDate(), dayPart)) return false\r\n }\r\n if (weekPart !== '?') {\r\n /* JS: 0=周日, 1=周一… → Cron: 1=周日, 2=周一… */\r\n if (!matchesPart(date.getDay() + 1, weekPart)) return false\r\n }\r\n\r\n /* 时 */\r\n if (!matchesPart(date.getHours(), hourPart)) return false\r\n /* 分 */\r\n if (!matchesPart(date.getMinutes(), minPart)) return false\r\n /* 秒 */\r\n if (!matchesPart(date.getSeconds(), secPart)) return false\r\n\r\n return true\r\n }\r\n\r\n /** 计算未来 N 次执行时间 */\r\n function computeNextExecutions(): Date[] {\r\n const expr = expression.value\r\n if (!expr || !validation.value.valid) return []\r\n\r\n const parts = expr.trim().split(/\\s+/)\r\n if (parts.length !== 6) return []\r\n\r\n const results: Date[] = []\r\n const now = new Date()\r\n const cursor = new Date(now.getTime() + 1000) /* 从下一秒开始 */\r\n cursor.setMilliseconds(0)\r\n\r\n /* 判断是否包含秒级调度(秒字段不是 0) */\r\n const hasSecond = parts[0] !== '0'\r\n const stepMs = hasSecond ? 1000 : 60_000 /* 秒级/分钟级步进 */\r\n\r\n /* 分钟级步进时,对齐到整分(秒归零),否则秒位永远无法匹配 '0' */\r\n if (!hasSecond) {\r\n cursor.setSeconds(0)\r\n if (cursor.getTime() <= now.getTime()) {\r\n cursor.setTime(cursor.getTime() + 60_000)\r\n }\r\n }\r\n\r\n const maxIterations = 525_600 /* 最多遍历 1 年的分钟数 */\r\n const target = count.value\r\n\r\n for (let i = 0; i < maxIterations && results.length < target; i++) {\r\n if (matchesCron(cursor, parts)) {\r\n results.push(new Date(cursor))\r\n }\r\n cursor.setTime(cursor.getTime() + stepMs)\r\n }\r\n\r\n return results\r\n }\r\n\r\n /* ─── 监听表达式变化自动计算 ─────────────────── */\r\n\r\n watch(\r\n [expression, count],\r\n () => {\r\n if (!validation.value.valid) {\r\n nextExecutions.value = []\r\n return\r\n }\r\n computing.value = true\r\n /* 使用 setTimeout 避免阻塞 UI */\r\n setTimeout(() => {\r\n nextExecutions.value = computeNextExecutions()\r\n computing.value = false\r\n }, 0)\r\n },\r\n { immediate: true }\r\n )\r\n\r\n /* ─── 格式化输出 ───────────────────────────── */\r\n\r\n /** 格式化日期为字符串 */\r\n function formatDate(date: Date): string {\r\n const pad = (n: number) => String(n).padStart(2, '0')\r\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`\r\n }\r\n\r\n /** 获取日期的中文星期名称 */\r\n function formatWeekDay(date: Date): string {\r\n const days = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']\r\n return days[date.getDay()]\r\n }\r\n\r\n return {\r\n nextExecutions,\r\n computing,\r\n formatDate,\r\n formatWeekDay,\r\n }\r\n}\r\n","/*\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 中文描述生成\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n */\r\n\r\nimport { computed } from \"vue\";\r\nimport type { Ref } from \"vue\";\r\nimport type { CronValidation } from \"../types\";\r\nimport { MONTH_LABELS, WEEK_LABELS } from \"../constants\";\r\n\r\n/** 获取周名称 */\r\nfunction weekLabel(n: number | string): string {\r\n return WEEK_LABELS[Number(n)] || `周${n}`;\r\n}\r\n\r\n/**\r\n * 将 Cron 表达式自动转换为中文可读描述\r\n */\r\nexport function useCronDescription(\r\n expression: Ref<string>,\r\n validation: Ref<CronValidation>,\r\n) {\r\n /** 中文描述 */\r\n const description = computed(() => {\r\n if (!validation.value.valid) return \"表达式不合法\";\r\n return generateDescription(expression.value);\r\n });\r\n\r\n /* ─── 核心转换 ──────────────────────────────── */\r\n\r\n /** 将完整 Cron 表达式转为中文描述 */\r\n function generateDescription(expr: string): string {\r\n const parts = expr.trim().split(/\\s+/);\r\n if (parts.length !== 6) return \"表达式格式错误\";\r\n\r\n const [sec, min, hour, day, month, week] = parts;\r\n\r\n const fragments: string[] = [];\r\n\r\n /* 月 */\r\n fragments.push(describeMonth(month));\r\n /* 周 or 日 */\r\n if (week !== \"?\") {\r\n fragments.push(describeWeek(week));\r\n } else {\r\n fragments.push(describeDay(day));\r\n }\r\n /* 时 */\r\n fragments.push(describeHour(hour));\r\n /* 分 */\r\n fragments.push(describeMinute(min));\r\n /* 秒 */\r\n fragments.push(describeSecond(sec));\r\n\r\n return fragments.filter(Boolean).join(\" \") + \" 执行\";\r\n }\r\n\r\n /* ─── 各字段描述 ────────────────────────────── */\r\n\r\n /** 描述秒字段 */\r\n function describeSecond(part: string): string {\r\n if (part === \"0\") return \"\";\r\n if (part === \"*\") return \"每秒\";\r\n return describeFieldGeneric(part, \"秒\");\r\n }\r\n\r\n /** 描述分字段 */\r\n function describeMinute(part: string): string {\r\n if (part === \"*\") return \"每分钟\";\r\n if (part === \"0\") return \"\";\r\n return describeFieldGeneric(part, \"分\");\r\n }\r\n\r\n /** 描述时字段 */\r\n function describeHour(part: string): string {\r\n if (part === \"*\") return \"每小时\";\r\n if (/^\\d+$/.test(part)) return `${part.padStart(2, \"0\")}:`;\r\n return describeFieldGeneric(part, \"时\");\r\n }\r\n\r\n /** 描述日字段 */\r\n function describeDay(part: string): string {\r\n if (part === \"*\" || part === \"?\") return \"每天\";\r\n if (/^\\d+$/.test(part)) return `每月 ${part} 号`;\r\n if (part.includes(\"/\")) {\r\n const [s, i] = part.split(\"/\");\r\n return `从 ${s} 号开始每 ${i} 天`;\r\n }\r\n if (part.includes(\"-\")) {\r\n const [s, e] = part.split(\"-\");\r\n return `${s} 号到 ${e} 号`;\r\n }\r\n if (part.includes(\",\")) {\r\n return `每月 ${part} 号`;\r\n }\r\n return \"\";\r\n }\r\n\r\n /** 描述月字段 */\r\n function describeMonth(part: string): string {\r\n if (part === \"*\") return \"\";\r\n if (/^\\d+$/.test(part)) {\r\n const n = Number(part);\r\n return MONTH_LABELS[n] ? `${MONTH_LABELS[n]}` : `${n} 月`;\r\n }\r\n if (part.includes(\"/\")) {\r\n const [s, i] = part.split(\"/\");\r\n return `从 ${s} 月开始每 ${i} 个月`;\r\n }\r\n if (part.includes(\"-\")) {\r\n const [s, e] = part.split(\"-\");\r\n return `${s} 月到 ${e} 月`;\r\n }\r\n if (part.includes(\",\")) {\r\n const months = part\r\n .split(\",\")\r\n .map((n) => MONTH_LABELS[Number(n)] || `${n}月`)\r\n .join(\"、\");\r\n return months;\r\n }\r\n return \"\";\r\n }\r\n\r\n /** 描述周字段 */\r\n function describeWeek(part: string): string {\r\n if (part === \"*\" || part === \"?\") return \"\";\r\n if (/^\\d+$/.test(part)) return `每${weekLabel(part)}`;\r\n if (part.includes(\"/\"))\r\n return `从${weekLabel(part.split(\"/\")[0])}开始每 ${part.split(\"/\")[1]} 天`;\r\n if (part.includes(\"-\"))\r\n return `${weekLabel(part.split(\"-\")[0])}到${weekLabel(part.split(\"-\")[1])}`;\r\n if (part.includes(\",\"))\r\n return `每${part.split(\",\").map(weekLabel).join(\"、\")}`;\r\n return \"\";\r\n }\r\n\r\n /** 通用字段描述 */\r\n function describeFieldGeneric(part: string, unit: string): string {\r\n if (part.includes(\"/\")) {\r\n const [s, i] = part.split(\"/\");\r\n const startDesc = s === \"*\" || s === \"0\" ? \"\" : `从第 ${s} ${unit}开始`;\r\n return `${startDesc}每 ${i} ${unit}`;\r\n }\r\n if (part.includes(\"-\")) {\r\n const [s, e] = part.split(\"-\");\r\n return `${s} ${unit}到 ${e} ${unit}`;\r\n }\r\n if (part.includes(\",\")) {\r\n return `第 ${part} ${unit}`;\r\n }\r\n if (/^\\d+$/.test(part)) {\r\n return `${part.padStart(2, \"0\")}`;\r\n }\r\n return \"\";\r\n }\r\n\r\n return {\r\n description,\r\n };\r\n}\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 字段值网格(始终可见,根据模式自动高亮对应值)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-field-editor\">\r\n <div class=\"cron-field-editor__grid\" :style=\"{ '--cols': gridColumns }\">\r\n <div\r\n v-for=\"item in valueOptions\"\r\n :key=\"item.value\"\r\n class=\"cron-field-editor__cell\"\r\n :class=\"{\r\n 'cron-field-editor__cell--on': highlightedValues.has(item.value),\r\n 'cron-field-editor__cell--pick': modelValue.mode === 'specific',\r\n }\"\r\n @click=\"handleCellClick(item.value)\"\r\n >\r\n {{ item.label }}\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from \"vue\";\r\nimport type { CronFieldMeta, CronFieldValue } from \"../types\";\r\n\r\ninterface Props {\r\n modelValue: CronFieldValue;\r\n meta: CronFieldMeta;\r\n}\r\n\r\nconst props = defineProps<Props>();\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: CronFieldValue];\r\n}>();\r\n\r\n/** 网格列数 */\r\nconst gridColumns = computed(() => {\r\n switch (props.meta.type) {\r\n case \"second\":\r\n case \"minute\":\r\n return 10;\r\n case \"hour\":\r\n return 12;\r\n case \"day\":\r\n return 7;\r\n case \"month\":\r\n return 6;\r\n case \"week\":\r\n return 7;\r\n default:\r\n return 10;\r\n }\r\n});\r\n\r\n/** 可选值列表 */\r\nconst valueOptions = computed(() => {\r\n const items: { value: number; label: string }[] = [];\r\n for (let i = props.meta.min; i <= props.meta.max; i++) {\r\n items.push({\r\n value: i,\r\n label: props.meta.valueLabels?.[i] ?? String(i),\r\n });\r\n }\r\n return items;\r\n});\r\n\r\n/** 根据当前模式计算高亮值集合 */\r\nconst highlightedValues = computed(() => {\r\n const { modelValue: f, meta } = props;\r\n const set = new Set<number>();\r\n switch (f.mode) {\r\n case \"every\":\r\n for (let i = meta.min; i <= meta.max; i++) set.add(i);\r\n break;\r\n case \"none\":\r\n break;\r\n case \"range\":\r\n for (let i = f.rangeStart; i <= f.rangeEnd; i++) set.add(i);\r\n break;\r\n case \"step\":\r\n for (let i = f.stepStart; i <= meta.max; i += f.stepInterval) set.add(i);\r\n break;\r\n case \"specific\":\r\n f.specificValues.forEach((v) => set.add(v));\r\n break;\r\n }\r\n return set;\r\n});\r\n\r\n/** 点击单元格(仅 specific 模式生效) */\r\nfunction handleCellClick(value: number) {\r\n if (props.modelValue.mode !== \"specific\") return;\r\n const current = [...props.modelValue.specificValues];\r\n const idx = current.indexOf(value);\r\n if (idx >= 0) current.splice(idx, 1);\r\n else current.push(value);\r\n emit(\"update:modelValue\", {\r\n ...props.modelValue,\r\n specificValues: current,\r\n });\r\n}\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-field-editor {\r\n &__grid {\r\n display: grid;\r\n grid-template-columns: repeat(var(--cols, 10), 1fr);\r\n gap: 4px;\r\n }\r\n\r\n &__cell {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n height: 34px;\r\n border-radius: 6px;\r\n font-size: 13px;\r\n font-variant-numeric: tabular-nums;\r\n transition: all var(--c-transition, 0.2s ease);\r\n user-select: none;\r\n color: var(--c-text-2);\r\n\r\n /* 非交互高亮(every / range / step 的视觉反馈) */\r\n &--on:not(&--pick) {\r\n background: color-mix(in srgb, var(--c-primary) 12%, transparent);\r\n color: var(--c-primary);\r\n }\r\n\r\n /* 可交互模式(specific) */\r\n &--pick {\r\n cursor: pointer;\r\n\r\n &:hover:not(.cron-field-editor__cell--on) {\r\n background: var(--c-bg-card);\r\n }\r\n\r\n &.cron-field-editor__cell--on {\r\n background: var(--c-primary);\r\n color: #fff;\r\n font-weight: 600;\r\n }\r\n }\r\n }\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 字段值网格(始终可见,根据模式自动高亮对应值)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-field-editor\">\r\n <div class=\"cron-field-editor__grid\" :style=\"{ '--cols': gridColumns }\">\r\n <div\r\n v-for=\"item in valueOptions\"\r\n :key=\"item.value\"\r\n class=\"cron-field-editor__cell\"\r\n :class=\"{\r\n 'cron-field-editor__cell--on': highlightedValues.has(item.value),\r\n 'cron-field-editor__cell--pick': modelValue.mode === 'specific',\r\n }\"\r\n @click=\"handleCellClick(item.value)\"\r\n >\r\n {{ item.label }}\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from \"vue\";\r\nimport type { CronFieldMeta, CronFieldValue } from \"../types\";\r\n\r\ninterface Props {\r\n modelValue: CronFieldValue;\r\n meta: CronFieldMeta;\r\n}\r\n\r\nconst props = defineProps<Props>();\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: CronFieldValue];\r\n}>();\r\n\r\n/** 网格列数 */\r\nconst gridColumns = computed(() => {\r\n switch (props.meta.type) {\r\n case \"second\":\r\n case \"minute\":\r\n return 10;\r\n case \"hour\":\r\n return 12;\r\n case \"day\":\r\n return 7;\r\n case \"month\":\r\n return 6;\r\n case \"week\":\r\n return 7;\r\n default:\r\n return 10;\r\n }\r\n});\r\n\r\n/** 可选值列表 */\r\nconst valueOptions = computed(() => {\r\n const items: { value: number; label: string }[] = [];\r\n for (let i = props.meta.min; i <= props.meta.max; i++) {\r\n items.push({\r\n value: i,\r\n label: props.meta.valueLabels?.[i] ?? String(i),\r\n });\r\n }\r\n return items;\r\n});\r\n\r\n/** 根据当前模式计算高亮值集合 */\r\nconst highlightedValues = computed(() => {\r\n const { modelValue: f, meta } = props;\r\n const set = new Set<number>();\r\n switch (f.mode) {\r\n case \"every\":\r\n for (let i = meta.min; i <= meta.max; i++) set.add(i);\r\n break;\r\n case \"none\":\r\n break;\r\n case \"range\":\r\n for (let i = f.rangeStart; i <= f.rangeEnd; i++) set.add(i);\r\n break;\r\n case \"step\":\r\n for (let i = f.stepStart; i <= meta.max; i += f.stepInterval) set.add(i);\r\n break;\r\n case \"specific\":\r\n f.specificValues.forEach((v) => set.add(v));\r\n break;\r\n }\r\n return set;\r\n});\r\n\r\n/** 点击单元格(仅 specific 模式生效) */\r\nfunction handleCellClick(value: number) {\r\n if (props.modelValue.mode !== \"specific\") return;\r\n const current = [...props.modelValue.specificValues];\r\n const idx = current.indexOf(value);\r\n if (idx >= 0) current.splice(idx, 1);\r\n else current.push(value);\r\n emit(\"update:modelValue\", {\r\n ...props.modelValue,\r\n specificValues: current,\r\n });\r\n}\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-field-editor {\r\n &__grid {\r\n display: grid;\r\n grid-template-columns: repeat(var(--cols, 10), 1fr);\r\n gap: 4px;\r\n }\r\n\r\n &__cell {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n height: 34px;\r\n border-radius: 6px;\r\n font-size: 13px;\r\n font-variant-numeric: tabular-nums;\r\n transition: all var(--c-transition, 0.2s ease);\r\n user-select: none;\r\n color: var(--c-text-2);\r\n\r\n /* 非交互高亮(every / range / step 的视觉反馈) */\r\n &--on:not(&--pick) {\r\n background: color-mix(in srgb, var(--c-primary) 12%, transparent);\r\n color: var(--c-primary);\r\n }\r\n\r\n /* 可交互模式(specific) */\r\n &--pick {\r\n cursor: pointer;\r\n\r\n &:hover:not(.cron-field-editor__cell--on) {\r\n background: var(--c-bg-card);\r\n }\r\n\r\n &.cron-field-editor__cell--on {\r\n background: var(--c-primary);\r\n color: #fff;\r\n font-weight: 600;\r\n }\r\n }\r\n }\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 字段值网格(始终可见,根据模式自动高亮对应值)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-field-editor\">\r\n <div class=\"cron-field-editor__grid\" :style=\"{ '--cols': gridColumns }\">\r\n <div\r\n v-for=\"item in valueOptions\"\r\n :key=\"item.value\"\r\n class=\"cron-field-editor__cell\"\r\n :class=\"{\r\n 'cron-field-editor__cell--on': highlightedValues.has(item.value),\r\n 'cron-field-editor__cell--pick': modelValue.mode === 'specific',\r\n }\"\r\n @click=\"handleCellClick(item.value)\"\r\n >\r\n {{ item.label }}\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from \"vue\";\r\nimport type { CronFieldMeta, CronFieldValue } from \"../types\";\r\n\r\ninterface Props {\r\n modelValue: CronFieldValue;\r\n meta: CronFieldMeta;\r\n}\r\n\r\nconst props = defineProps<Props>();\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: CronFieldValue];\r\n}>();\r\n\r\n/** 网格列数 */\r\nconst gridColumns = computed(() => {\r\n switch (props.meta.type) {\r\n case \"second\":\r\n case \"minute\":\r\n return 10;\r\n case \"hour\":\r\n return 12;\r\n case \"day\":\r\n return 7;\r\n case \"month\":\r\n return 6;\r\n case \"week\":\r\n return 7;\r\n default:\r\n return 10;\r\n }\r\n});\r\n\r\n/** 可选值列表 */\r\nconst valueOptions = computed(() => {\r\n const items: { value: number; label: string }[] = [];\r\n for (let i = props.meta.min; i <= props.meta.max; i++) {\r\n items.push({\r\n value: i,\r\n label: props.meta.valueLabels?.[i] ?? String(i),\r\n });\r\n }\r\n return items;\r\n});\r\n\r\n/** 根据当前模式计算高亮值集合 */\r\nconst highlightedValues = computed(() => {\r\n const { modelValue: f, meta } = props;\r\n const set = new Set<number>();\r\n switch (f.mode) {\r\n case \"every\":\r\n for (let i = meta.min; i <= meta.max; i++) set.add(i);\r\n break;\r\n case \"none\":\r\n break;\r\n case \"range\":\r\n for (let i = f.rangeStart; i <= f.rangeEnd; i++) set.add(i);\r\n break;\r\n case \"step\":\r\n for (let i = f.stepStart; i <= meta.max; i += f.stepInterval) set.add(i);\r\n break;\r\n case \"specific\":\r\n f.specificValues.forEach((v) => set.add(v));\r\n break;\r\n }\r\n return set;\r\n});\r\n\r\n/** 点击单元格(仅 specific 模式生效) */\r\nfunction handleCellClick(value: number) {\r\n if (props.modelValue.mode !== \"specific\") return;\r\n const current = [...props.modelValue.specificValues];\r\n const idx = current.indexOf(value);\r\n if (idx >= 0) current.splice(idx, 1);\r\n else current.push(value);\r\n emit(\"update:modelValue\", {\r\n ...props.modelValue,\r\n specificValues: current,\r\n });\r\n}\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-field-editor {\r\n &__grid {\r\n display: grid;\r\n grid-template-columns: repeat(var(--cols, 10), 1fr);\r\n gap: 4px;\r\n }\r\n\r\n &__cell {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n height: 34px;\r\n border-radius: 6px;\r\n font-size: 13px;\r\n font-variant-numeric: tabular-nums;\r\n transition: all var(--c-transition, 0.2s ease);\r\n user-select: none;\r\n color: var(--c-text-2);\r\n\r\n /* 非交互高亮(every / range / step 的视觉反馈) */\r\n &--on:not(&--pick) {\r\n background: color-mix(in srgb, var(--c-primary) 12%, transparent);\r\n color: var(--c-primary);\r\n }\r\n\r\n /* 可交互模式(specific) */\r\n &--pick {\r\n cursor: pointer;\r\n\r\n &:hover:not(.cron-field-editor__cell--on) {\r\n background: var(--c-bg-card);\r\n }\r\n\r\n &.cron-field-editor__cell--on {\r\n background: var(--c-primary);\r\n color: #fff;\r\n font-weight: 600;\r\n }\r\n }\r\n }\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 执行时间预览(紧凑布局)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-preview\">\r\n <div class=\"cron-preview__header\">\r\n <C_Icon name=\"mdi:calendar-clock\" :size=\"15\" />\r\n <span>未来执行</span>\r\n <NSpin v-if=\"computing\" :size=\"14\" />\r\n </div>\r\n\r\n <NScrollbar style=\"max-height: 220px\">\r\n <div v-if=\"nextExecutions.length > 0\" class=\"cron-preview__list\">\r\n <div\r\n v-for=\"(date, index) in nextExecutions\"\r\n :key=\"index\"\r\n class=\"cron-preview__item\"\r\n >\r\n <span class=\"cron-preview__idx\">{{ index + 1 }}</span>\r\n <span class=\"cron-preview__date\">{{ formatDate(date) }}</span>\r\n <span class=\"cron-preview__week\">{{ formatWeekDay(date) }}</span>\r\n </div>\r\n </div>\r\n <NEmpty v-else size=\"small\" description=\"暂无匹配\" />\r\n </NScrollbar>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport C_Icon from \"../../C_Icon/index.vue\";\r\n\r\ninterface Props {\r\n nextExecutions: Date[];\r\n computing: boolean;\r\n count: number;\r\n formatDate: (date: Date) => string;\r\n formatWeekDay: (date: Date) => string;\r\n}\r\n\r\ndefineProps<Props>();\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-preview {\r\n &__header {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n margin-bottom: 6px;\r\n color: var(--c-text-1);\r\n }\r\n\r\n &__list {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 2px;\r\n }\r\n\r\n &__item {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 3px 4px;\r\n border-radius: 4px;\r\n font-size: 12px;\r\n transition: background var(--c-transition, 0.2s ease);\r\n\r\n &:hover {\r\n background: var(--c-bg-card);\r\n }\r\n }\r\n\r\n &__idx {\r\n width: 16px;\r\n text-align: center;\r\n color: var(--c-text-4);\r\n flex-shrink: 0;\r\n font-size: 11px;\r\n }\r\n\r\n &__date {\r\n font-family: \"Courier New\", Courier, monospace;\r\n flex: 1;\r\n font-size: 12px;\r\n }\r\n\r\n &__week {\r\n color: var(--c-text-4);\r\n font-size: 12px;\r\n flex-shrink: 0;\r\n }\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 执行时间预览(紧凑布局)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-preview\">\r\n <div class=\"cron-preview__header\">\r\n <C_Icon name=\"mdi:calendar-clock\" :size=\"15\" />\r\n <span>未来执行</span>\r\n <NSpin v-if=\"computing\" :size=\"14\" />\r\n </div>\r\n\r\n <NScrollbar style=\"max-height: 220px\">\r\n <div v-if=\"nextExecutions.length > 0\" class=\"cron-preview__list\">\r\n <div\r\n v-for=\"(date, index) in nextExecutions\"\r\n :key=\"index\"\r\n class=\"cron-preview__item\"\r\n >\r\n <span class=\"cron-preview__idx\">{{ index + 1 }}</span>\r\n <span class=\"cron-preview__date\">{{ formatDate(date) }}</span>\r\n <span class=\"cron-preview__week\">{{ formatWeekDay(date) }}</span>\r\n </div>\r\n </div>\r\n <NEmpty v-else size=\"small\" description=\"暂无匹配\" />\r\n </NScrollbar>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport C_Icon from \"../../C_Icon/index.vue\";\r\n\r\ninterface Props {\r\n nextExecutions: Date[];\r\n computing: boolean;\r\n count: number;\r\n formatDate: (date: Date) => string;\r\n formatWeekDay: (date: Date) => string;\r\n}\r\n\r\ndefineProps<Props>();\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-preview {\r\n &__header {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n margin-bottom: 6px;\r\n color: var(--c-text-1);\r\n }\r\n\r\n &__list {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 2px;\r\n }\r\n\r\n &__item {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 3px 4px;\r\n border-radius: 4px;\r\n font-size: 12px;\r\n transition: background var(--c-transition, 0.2s ease);\r\n\r\n &:hover {\r\n background: var(--c-bg-card);\r\n }\r\n }\r\n\r\n &__idx {\r\n width: 16px;\r\n text-align: center;\r\n color: var(--c-text-4);\r\n flex-shrink: 0;\r\n font-size: 11px;\r\n }\r\n\r\n &__date {\r\n font-family: \"Courier New\", Courier, monospace;\r\n flex: 1;\r\n font-size: 12px;\r\n }\r\n\r\n &__week {\r\n color: var(--c-text-4);\r\n font-size: 12px;\r\n flex-shrink: 0;\r\n }\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 执行时间预览(紧凑布局)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-preview\">\r\n <div class=\"cron-preview__header\">\r\n <C_Icon name=\"mdi:calendar-clock\" :size=\"15\" />\r\n <span>未来执行</span>\r\n <NSpin v-if=\"computing\" :size=\"14\" />\r\n </div>\r\n\r\n <NScrollbar style=\"max-height: 220px\">\r\n <div v-if=\"nextExecutions.length > 0\" class=\"cron-preview__list\">\r\n <div\r\n v-for=\"(date, index) in nextExecutions\"\r\n :key=\"index\"\r\n class=\"cron-preview__item\"\r\n >\r\n <span class=\"cron-preview__idx\">{{ index + 1 }}</span>\r\n <span class=\"cron-preview__date\">{{ formatDate(date) }}</span>\r\n <span class=\"cron-preview__week\">{{ formatWeekDay(date) }}</span>\r\n </div>\r\n </div>\r\n <NEmpty v-else size=\"small\" description=\"暂无匹配\" />\r\n </NScrollbar>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport C_Icon from \"../../C_Icon/index.vue\";\r\n\r\ninterface Props {\r\n nextExecutions: Date[];\r\n computing: boolean;\r\n count: number;\r\n formatDate: (date: Date) => string;\r\n formatWeekDay: (date: Date) => string;\r\n}\r\n\r\ndefineProps<Props>();\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-preview {\r\n &__header {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n margin-bottom: 6px;\r\n color: var(--c-text-1);\r\n }\r\n\r\n &__list {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 2px;\r\n }\r\n\r\n &__item {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 3px 4px;\r\n border-radius: 4px;\r\n font-size: 12px;\r\n transition: background var(--c-transition, 0.2s ease);\r\n\r\n &:hover {\r\n background: var(--c-bg-card);\r\n }\r\n }\r\n\r\n &__idx {\r\n width: 16px;\r\n text-align: center;\r\n color: var(--c-text-4);\r\n flex-shrink: 0;\r\n font-size: 11px;\r\n }\r\n\r\n &__date {\r\n font-family: \"Courier New\", Courier, monospace;\r\n flex: 1;\r\n font-size: 12px;\r\n }\r\n\r\n &__week {\r\n color: var(--c-text-4);\r\n font-size: 12px;\r\n flex-shrink: 0;\r\n }\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 常用模板(底部卡片网格)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-templates\">\r\n <div class=\"cron-templates__header\">\r\n <C_Icon name=\"mdi:lightning-bolt\" :size=\"15\" />\r\n <span>常用模板</span>\r\n </div>\r\n\r\n <div class=\"cron-templates__cards\">\r\n <div\r\n v-for=\"template in templates\"\r\n :key=\"template.value\"\r\n class=\"cron-templates__card\"\r\n :class=\"{\r\n 'cron-templates__card--active': template.value === currentValue,\r\n }\"\r\n @click=\"$emit('select', template.value)\"\r\n >\r\n <div class=\"cron-templates__card-name\">{{ template.label }}</div>\r\n <div class=\"cron-templates__card-expr\">{{ template.value }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport C_Icon from \"../../C_Icon/index.vue\";\r\nimport type { CronTemplate } from \"../types\";\r\n\r\ninterface Props {\r\n templates: CronTemplate[];\r\n currentValue: string;\r\n}\r\n\r\ndefineProps<Props>();\r\ndefineEmits<{\r\n select: [value: string];\r\n}>();\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-templates {\r\n &__header {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n margin-bottom: 10px;\r\n color: var(--c-text-1);\r\n }\r\n\r\n &__cards {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\r\n gap: 8px;\r\n }\r\n\r\n &__card {\r\n padding: 10px 12px;\r\n border-radius: 8px;\r\n border: 1px solid var(--c-border);\r\n cursor: pointer;\r\n transition: all var(--c-transition, 0.2s ease);\r\n\r\n &:hover {\r\n border-color: var(--c-primary);\r\n background: color-mix(in srgb, var(--c-primary) 4%, transparent);\r\n }\r\n\r\n &--active {\r\n border-color: var(--c-primary);\r\n background: color-mix(in srgb, var(--c-primary) 8%, transparent);\r\n }\r\n }\r\n\r\n &__card-name {\r\n font-size: 13px;\r\n font-weight: 500;\r\n line-height: 1.4;\r\n }\r\n\r\n &__card-expr {\r\n font-family: \"Courier New\", Courier, monospace;\r\n font-size: 11px;\r\n color: var(--c-text-4);\r\n margin-top: 2px;\r\n }\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 常用模板(底部卡片网格)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-templates\">\r\n <div class=\"cron-templates__header\">\r\n <C_Icon name=\"mdi:lightning-bolt\" :size=\"15\" />\r\n <span>常用模板</span>\r\n </div>\r\n\r\n <div class=\"cron-templates__cards\">\r\n <div\r\n v-for=\"template in templates\"\r\n :key=\"template.value\"\r\n class=\"cron-templates__card\"\r\n :class=\"{\r\n 'cron-templates__card--active': template.value === currentValue,\r\n }\"\r\n @click=\"$emit('select', template.value)\"\r\n >\r\n <div class=\"cron-templates__card-name\">{{ template.label }}</div>\r\n <div class=\"cron-templates__card-expr\">{{ template.value }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport C_Icon from \"../../C_Icon/index.vue\";\r\nimport type { CronTemplate } from \"../types\";\r\n\r\ninterface Props {\r\n templates: CronTemplate[];\r\n currentValue: string;\r\n}\r\n\r\ndefineProps<Props>();\r\ndefineEmits<{\r\n select: [value: string];\r\n}>();\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-templates {\r\n &__header {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n margin-bottom: 10px;\r\n color: var(--c-text-1);\r\n }\r\n\r\n &__cards {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\r\n gap: 8px;\r\n }\r\n\r\n &__card {\r\n padding: 10px 12px;\r\n border-radius: 8px;\r\n border: 1px solid var(--c-border);\r\n cursor: pointer;\r\n transition: all var(--c-transition, 0.2s ease);\r\n\r\n &:hover {\r\n border-color: var(--c-primary);\r\n background: color-mix(in srgb, var(--c-primary) 4%, transparent);\r\n }\r\n\r\n &--active {\r\n border-color: var(--c-primary);\r\n background: color-mix(in srgb, var(--c-primary) 8%, transparent);\r\n }\r\n }\r\n\r\n &__card-name {\r\n font-size: 13px;\r\n font-weight: 500;\r\n line-height: 1.4;\r\n }\r\n\r\n &__card-expr {\r\n font-family: \"Courier New\", Courier, monospace;\r\n font-size: 11px;\r\n color: var(--c-text-4);\r\n margin-top: 2px;\r\n }\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 常用模板(底部卡片网格)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-templates\">\r\n <div class=\"cron-templates__header\">\r\n <C_Icon name=\"mdi:lightning-bolt\" :size=\"15\" />\r\n <span>常用模板</span>\r\n </div>\r\n\r\n <div class=\"cron-templates__cards\">\r\n <div\r\n v-for=\"template in templates\"\r\n :key=\"template.value\"\r\n class=\"cron-templates__card\"\r\n :class=\"{\r\n 'cron-templates__card--active': template.value === currentValue,\r\n }\"\r\n @click=\"$emit('select', template.value)\"\r\n >\r\n <div class=\"cron-templates__card-name\">{{ template.label }}</div>\r\n <div class=\"cron-templates__card-expr\">{{ template.value }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport C_Icon from \"../../C_Icon/index.vue\";\r\nimport type { CronTemplate } from \"../types\";\r\n\r\ninterface Props {\r\n templates: CronTemplate[];\r\n currentValue: string;\r\n}\r\n\r\ndefineProps<Props>();\r\ndefineEmits<{\r\n select: [value: string];\r\n}>();\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-templates {\r\n &__header {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n margin-bottom: 10px;\r\n color: var(--c-text-1);\r\n }\r\n\r\n &__cards {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\r\n gap: 8px;\r\n }\r\n\r\n &__card {\r\n padding: 10px 12px;\r\n border-radius: 8px;\r\n border: 1px solid var(--c-border);\r\n cursor: pointer;\r\n transition: all var(--c-transition, 0.2s ease);\r\n\r\n &:hover {\r\n border-color: var(--c-primary);\r\n background: color-mix(in srgb, var(--c-primary) 4%, transparent);\r\n }\r\n\r\n &--active {\r\n border-color: var(--c-primary);\r\n background: color-mix(in srgb, var(--c-primary) 8%, transparent);\r\n }\r\n }\r\n\r\n &__card-name {\r\n font-size: 13px;\r\n font-weight: 500;\r\n line-height: 1.4;\r\n }\r\n\r\n &__card-expr {\r\n font-family: \"Courier New\", Courier, monospace;\r\n font-size: 11px;\r\n color: var(--c-text-4);\r\n margin-top: 2px;\r\n }\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 表达式编辑器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"c-cron\" :style=\"{ height: containerHeight }\">\r\n <!-- ═══════ 顶部 ═══════ -->\r\n <div class=\"c-cron__header\">\r\n <!-- 标题行 -->\r\n <div class=\"c-cron__title-row\">\r\n <div class=\"c-cron__title\">\r\n <C_Icon name=\"mdi:clock-edit-outline\" :size=\"18\" />\r\n <span>Cron 表达式</span>\r\n </div>\r\n <NTag :type=\"validation.valid ? 'success' : 'error'\" size=\"small\" round>\r\n <template #icon>\r\n <C_Icon\r\n :name=\"validation.valid ? 'mdi:check-circle' : 'mdi:alert-circle'\"\r\n />\r\n </template>\r\n {{ validation.valid ? \"合法\" : \"错误\" }}\r\n </NTag>\r\n </div>\r\n\r\n <!-- 分段式字段选择器 -->\r\n <div class=\"c-cron__segments\">\r\n <div\r\n v-for=\"meta in visibleFields\"\r\n :key=\"meta.type\"\r\n class=\"c-cron__segment\"\r\n :class=\"{\r\n 'c-cron__segment--active': activeField === meta.type,\r\n 'c-cron__segment--wildcard':\r\n fieldExpressions[meta.type] === '*' ||\r\n fieldExpressions[meta.type] === '?',\r\n }\"\r\n @click=\"activeField = meta.type\"\r\n >\r\n <div class=\"c-cron__segment-value\">\r\n {{ fieldExpressions[meta.type] }}\r\n </div>\r\n <div class=\"c-cron__segment-label\">{{ meta.label }}</div>\r\n </div>\r\n </div>\r\n\r\n <!-- 表达式行:输入 + 重置 + 描述 -->\r\n <div class=\"c-cron__expr-row\">\r\n <NInput\r\n :value=\"manualInput\"\r\n :status=\"validation.valid ? undefined : 'error'\"\r\n placeholder=\"秒 分 时 日 月 周\"\r\n :disabled=\"props.disabled\"\r\n font=\"mono\"\r\n size=\"small\"\r\n clearable\r\n class=\"c-cron__expr-input\"\r\n @update:value=\"handleManualInput\"\r\n @blur=\"handleManualBlur\"\r\n @keydown.enter=\"handleManualBlur\"\r\n >\r\n <template #prefix>\r\n <C_Icon name=\"mdi:console\" :size=\"14\" style=\"opacity: 0.4\" />\r\n </template>\r\n </NInput>\r\n <NButton\r\n size=\"small\"\r\n quaternary\r\n :disabled=\"props.disabled\"\r\n @click=\"handleReset\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:refresh\" />\r\n </template>\r\n </NButton>\r\n <div class=\"c-cron__expr-desc\">\r\n <span v-if=\"validation.valid\" class=\"c-cron__description\">\r\n {{ description }}\r\n </span>\r\n <span v-else class=\"c-cron__error\">\r\n {{ validation.message }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ═══════ 主内容 ═══════ -->\r\n <div class=\"c-cron__body\">\r\n <!-- 左侧:值网格 -->\r\n <div class=\"c-cron__main\">\r\n <CronFieldEditor\r\n v-for=\"meta in visibleFields\"\r\n v-show=\"activeField === meta.type\"\r\n :key=\"meta.type\"\r\n :model-value=\"cronValue[meta.type]\"\r\n :meta=\"meta\"\r\n @update:model-value=\"(v) => handleFieldChange(meta.type, v)\"\r\n />\r\n </div>\r\n\r\n <!-- 右侧:控制面板 -->\r\n <div class=\"c-cron__panel\">\r\n <NRadioGroup\r\n :value=\"activeFieldValue.mode\"\r\n size=\"small\"\r\n @update:value=\"handleActiveFieldModeChange\"\r\n >\r\n <NRadioButton value=\"every\">\r\n 每{{ activeFieldMeta.label }}\r\n </NRadioButton>\r\n <NRadioButton\r\n v-if=\"activeField === 'day' || activeField === 'week'\"\r\n value=\"none\"\r\n >\r\n 不指定\r\n </NRadioButton>\r\n <NRadioButton value=\"range\">范围</NRadioButton>\r\n <NRadioButton value=\"step\">步进</NRadioButton>\r\n <NRadioButton value=\"specific\">指定</NRadioButton>\r\n </NRadioGroup>\r\n\r\n <!-- 范围配置 -->\r\n <div v-if=\"activeFieldValue.mode === 'range'\" class=\"c-cron__config\">\r\n <div class=\"c-cron__config-row\">\r\n <span>从</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.rangeStart\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n rangeStart: v ?? activeFieldMeta.min,\r\n })\r\n \"\r\n />\r\n <span>到</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.rangeEnd\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n rangeEnd: v ?? activeFieldMeta.max,\r\n })\r\n \"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 步进配置 -->\r\n <div v-if=\"activeFieldValue.mode === 'step'\" class=\"c-cron__config\">\r\n <div class=\"c-cron__config-row\">\r\n <span>从第</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.stepStart\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n stepStart: v ?? activeFieldMeta.min,\r\n })\r\n \"\r\n />\r\n <span>{{ activeFieldMeta.label }}起,每</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.stepInterval\"\r\n :min=\"1\"\r\n :max=\"activeFieldMeta.max - activeFieldMeta.min + 1\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({ stepInterval: v ?? 1 })\r\n \"\r\n />\r\n <span>{{ activeFieldMeta.label }}执行</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 指定快捷操作 -->\r\n <div v-if=\"activeFieldValue.mode === 'specific'\" class=\"c-cron__quick\">\r\n <a @click=\"handleSelectAll\">全选</a>\r\n <span class=\"c-cron__quick-sep\">·</span>\r\n <a @click=\"handleClearAll\">清空</a>\r\n <span\r\n v-if=\"activeFieldValue.specificValues.length > 0\"\r\n class=\"c-cron__quick-count\"\r\n >\r\n 已选 {{ activeFieldValue.specificValues.length }}\r\n </span>\r\n </div>\r\n\r\n <!-- 执行预览 -->\r\n <template v-if=\"props.showPreview\">\r\n <div class=\"c-cron__panel-line\" />\r\n <CronPreview\r\n :next-executions=\"nextExecutions\"\r\n :computing=\"computing\"\r\n :count=\"props.previewCount ?? 5\"\r\n :format-date=\"formatDate\"\r\n :format-week-day=\"formatWeekDay\"\r\n />\r\n </template>\r\n </div>\r\n </div>\r\n\r\n <!-- ═══════ 底部模板 ═══════ -->\r\n <div v-if=\"props.showTemplates\" class=\"c-cron__footer\">\r\n <CronTemplates\r\n :templates=\"CRON_TEMPLATES\"\r\n :current-value=\"expression\"\r\n @select=\"handleTemplateSelect\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, onMounted } from \"vue\";\r\nimport type {\r\n CronFieldMode,\r\n CronFieldType,\r\n CronFieldValue,\r\n CronProps,\r\n CronValidation,\r\n} from \"./types\";\r\nimport {\r\n CRON_FIELD_META,\r\n CRON_TEMPLATES,\r\n DEFAULT_CRON_EXPRESSION,\r\n} from \"./constants\";\r\nimport { useCronParser } from \"./composables/useCronParser\";\r\nimport { useCronPreview } from \"./composables/useCronPreview\";\r\nimport { useCronDescription } from \"./composables/useCronDescription\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport CronFieldEditor from \"./components/CronFieldEditor.vue\";\r\nimport CronPreview from \"./components/CronPreview.vue\";\r\nimport CronTemplates from \"./components/CronTemplates.vue\";\r\n\r\ndefineOptions({ name: \"C_Cron\" });\r\n\r\n/* ─── Props & Emits ─────────────────────────── */\r\n\r\nconst props = withDefaults(defineProps<CronProps>(), {\r\n modelValue: DEFAULT_CRON_EXPRESSION,\r\n disabled: false,\r\n previewCount: 10,\r\n showTemplates: true,\r\n showPreview: true,\r\n showSecond: true,\r\n height: \"auto\",\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: string];\r\n change: [value: string];\r\n \"validation-change\": [result: CronValidation];\r\n}>();\r\n\r\n/* ─── 组合函数 ──────────────────────────────── */\r\n\r\nconst {\r\n cronValue,\r\n expression,\r\n validation,\r\n parse,\r\n validate,\r\n handleDayWeekExclusion,\r\n} = useCronParser();\r\n\r\nconst previewCount = computed(() => props.previewCount ?? 10);\r\nconst { nextExecutions, computing, formatDate, formatWeekDay } = useCronPreview(\r\n expression,\r\n validation,\r\n previewCount,\r\n);\r\n\r\nconst { description } = useCronDescription(expression, validation);\r\n\r\n/* ─── 本地状态 ──────────────────────────────── */\r\n\r\n/** 手动输入框值(与 expression 解耦,输入完成后同步) */\r\nconst manualInput = ref(props.modelValue || DEFAULT_CRON_EXPRESSION);\r\n\r\n/** 当前激活的字段 Tab */\r\nconst activeField = ref<CronFieldType>(props.showSecond ? \"second\" : \"minute\");\r\n\r\n/* ─── 容器高度 ──────────────────────────────── */\r\n\r\nconst containerHeight = computed(() => {\r\n if (typeof props.height === \"number\") return `${props.height}px`;\r\n return props.height;\r\n});\r\n\r\n/* ─── 可见字段(是否显示秒) ────────────────── */\r\n\r\nconst visibleFields = computed(() => {\r\n return props.showSecond\r\n ? CRON_FIELD_META\r\n : CRON_FIELD_META.filter((m) => m.type !== \"second\");\r\n});\r\n\r\n/* ─── 当前激活字段快捷访问 ─────────────────── */\r\n\r\n/** 当前激活字段元数据 */\r\nconst activeFieldMeta = computed(\r\n () => CRON_FIELD_META.find((m) => m.type === activeField.value)!,\r\n);\r\n\r\n/** 当前激活字段值 */\r\nconst activeFieldValue = computed(() => cronValue.value[activeField.value]);\r\n\r\n/* ─── 分段式表达式(逐字段计算) ────────────── */\r\n\r\n/** 计算单字段表达式文本 */\r\nfunction computeFieldExpr(f: CronFieldValue): string {\r\n switch (f.mode) {\r\n case \"every\":\r\n return \"*\";\r\n case \"none\":\r\n return \"?\";\r\n case \"range\":\r\n return `${f.rangeStart}-${f.rangeEnd}`;\r\n case \"step\":\r\n return `${f.stepStart}/${f.stepInterval}`;\r\n case \"specific\":\r\n return f.specificValues.length > 0\r\n ? [...f.specificValues].sort((a, b) => a - b).join(\",\")\r\n : \"*\";\r\n default:\r\n return \"*\";\r\n }\r\n}\r\n\r\n/** 各字段表达式映射 */\r\nconst fieldExpressions = computed(() => {\r\n const map = {} as Record<CronFieldType, string>;\r\n for (const meta of CRON_FIELD_META) {\r\n map[meta.type] = computeFieldExpr(cronValue.value[meta.type]);\r\n }\r\n return map;\r\n});\r\n\r\n/* ─── 初始化解析 ────────────────────────────── */\r\n\r\nonMounted(() => {\r\n const initial = props.modelValue || DEFAULT_CRON_EXPRESSION;\r\n parse(initial);\r\n manualInput.value = initial;\r\n});\r\n\r\n/* ─── 监听外部 v-model 变更 ─────────────────── */\r\n\r\nwatch(\r\n () => props.modelValue,\r\n (newVal) => {\r\n if (newVal && newVal !== expression.value) {\r\n parse(newVal);\r\n manualInput.value = newVal;\r\n }\r\n },\r\n);\r\n\r\n/* ─── 监听 showSecond 变更 ──────────────────── */\r\n\r\nwatch(\r\n () => props.showSecond,\r\n (show) => {\r\n if (!show && activeField.value === \"second\") {\r\n activeField.value = \"minute\";\r\n }\r\n },\r\n);\r\n\r\n/* ─── 监听内部表达式变更 → 同步到外部 ───────── */\r\n\r\nwatch(expression, (newExpr) => {\r\n manualInput.value = newExpr;\r\n emit(\"update:modelValue\", newExpr);\r\n emit(\"change\", newExpr);\r\n});\r\n\r\n/* ─── 监听校验状态变更 ──────────────────────── */\r\n\r\nwatch(validation, (v) => {\r\n emit(\"validation-change\", v);\r\n});\r\n\r\n/* ─── 字段变更处理 ──────────────────────────── */\r\n\r\n/** 字段编辑变更处理 */\r\nfunction handleFieldChange(type: CronFieldType, value: CronFieldValue) {\r\n cronValue.value[type] = value;\r\n if (type === \"day\" || type === \"week\") {\r\n handleDayWeekExclusion(type);\r\n }\r\n}\r\n\r\n/* ─── 右侧面板操作 ─────────────────────────── */\r\n\r\n/** 切换当前字段模式 */\r\nfunction handleActiveFieldModeChange(mode: CronFieldMode) {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n mode,\r\n });\r\n}\r\n\r\n/** 更新当前字段属性 */\r\nfunction handleActiveFieldUpdate(partial: Partial<CronFieldValue>) {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n ...partial,\r\n });\r\n}\r\n\r\n/** 全选当前字段所有值 */\r\nfunction handleSelectAll() {\r\n const { min, max } = activeFieldMeta.value;\r\n const allValues = Array.from({ length: max - min + 1 }, (_, i) => min + i);\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n specificValues: allValues,\r\n });\r\n}\r\n\r\n/** 清空当前字段所有选中值 */\r\nfunction handleClearAll() {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n specificValues: [],\r\n });\r\n}\r\n\r\n/* ─── 手动输入处理 ──────────────────────────── */\r\n\r\n/** 手动输入更新 */\r\nfunction handleManualInput(value: string) {\r\n manualInput.value = value;\r\n}\r\n\r\n/** 输入框失焦时同步 */\r\nfunction handleManualBlur() {\r\n const trimmed = manualInput.value.trim();\r\n if (trimmed && trimmed !== expression.value) {\r\n parse(trimmed);\r\n }\r\n}\r\n\r\n/* ─── 模板选择 ──────────────────────────────── */\r\n\r\n/** 选择常用模板 */\r\nfunction handleTemplateSelect(expr: string) {\r\n parse(expr);\r\n manualInput.value = expr;\r\n}\r\n\r\n/* ─── 重置 ──────────────────────────────────── */\r\n\r\n/** 重置为初始值 */\r\nfunction handleReset() {\r\n const initial = props.modelValue || DEFAULT_CRON_EXPRESSION;\r\n parse(initial);\r\n manualInput.value = initial;\r\n}\r\n\r\n/* ─── Expose ────────────────────────────────── */\r\n\r\ndefineExpose({\r\n getValue: () => expression.value,\r\n setValue: (expr: string) => {\r\n parse(expr);\r\n manualInput.value = expr;\r\n },\r\n reset: handleReset,\r\n validate: () => validate(),\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 表达式编辑器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"c-cron\" :style=\"{ height: containerHeight }\">\r\n <!-- ═══════ 顶部 ═══════ -->\r\n <div class=\"c-cron__header\">\r\n <!-- 标题行 -->\r\n <div class=\"c-cron__title-row\">\r\n <div class=\"c-cron__title\">\r\n <C_Icon name=\"mdi:clock-edit-outline\" :size=\"18\" />\r\n <span>Cron 表达式</span>\r\n </div>\r\n <NTag :type=\"validation.valid ? 'success' : 'error'\" size=\"small\" round>\r\n <template #icon>\r\n <C_Icon\r\n :name=\"validation.valid ? 'mdi:check-circle' : 'mdi:alert-circle'\"\r\n />\r\n </template>\r\n {{ validation.valid ? \"合法\" : \"错误\" }}\r\n </NTag>\r\n </div>\r\n\r\n <!-- 分段式字段选择器 -->\r\n <div class=\"c-cron__segments\">\r\n <div\r\n v-for=\"meta in visibleFields\"\r\n :key=\"meta.type\"\r\n class=\"c-cron__segment\"\r\n :class=\"{\r\n 'c-cron__segment--active': activeField === meta.type,\r\n 'c-cron__segment--wildcard':\r\n fieldExpressions[meta.type] === '*' ||\r\n fieldExpressions[meta.type] === '?',\r\n }\"\r\n @click=\"activeField = meta.type\"\r\n >\r\n <div class=\"c-cron__segment-value\">\r\n {{ fieldExpressions[meta.type] }}\r\n </div>\r\n <div class=\"c-cron__segment-label\">{{ meta.label }}</div>\r\n </div>\r\n </div>\r\n\r\n <!-- 表达式行:输入 + 重置 + 描述 -->\r\n <div class=\"c-cron__expr-row\">\r\n <NInput\r\n :value=\"manualInput\"\r\n :status=\"validation.valid ? undefined : 'error'\"\r\n placeholder=\"秒 分 时 日 月 周\"\r\n :disabled=\"props.disabled\"\r\n font=\"mono\"\r\n size=\"small\"\r\n clearable\r\n class=\"c-cron__expr-input\"\r\n @update:value=\"handleManualInput\"\r\n @blur=\"handleManualBlur\"\r\n @keydown.enter=\"handleManualBlur\"\r\n >\r\n <template #prefix>\r\n <C_Icon name=\"mdi:console\" :size=\"14\" style=\"opacity: 0.4\" />\r\n </template>\r\n </NInput>\r\n <NButton\r\n size=\"small\"\r\n quaternary\r\n :disabled=\"props.disabled\"\r\n @click=\"handleReset\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:refresh\" />\r\n </template>\r\n </NButton>\r\n <div class=\"c-cron__expr-desc\">\r\n <span v-if=\"validation.valid\" class=\"c-cron__description\">\r\n {{ description }}\r\n </span>\r\n <span v-else class=\"c-cron__error\">\r\n {{ validation.message }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ═══════ 主内容 ═══════ -->\r\n <div class=\"c-cron__body\">\r\n <!-- 左侧:值网格 -->\r\n <div class=\"c-cron__main\">\r\n <CronFieldEditor\r\n v-for=\"meta in visibleFields\"\r\n v-show=\"activeField === meta.type\"\r\n :key=\"meta.type\"\r\n :model-value=\"cronValue[meta.type]\"\r\n :meta=\"meta\"\r\n @update:model-value=\"(v) => handleFieldChange(meta.type, v)\"\r\n />\r\n </div>\r\n\r\n <!-- 右侧:控制面板 -->\r\n <div class=\"c-cron__panel\">\r\n <NRadioGroup\r\n :value=\"activeFieldValue.mode\"\r\n size=\"small\"\r\n @update:value=\"handleActiveFieldModeChange\"\r\n >\r\n <NRadioButton value=\"every\">\r\n 每{{ activeFieldMeta.label }}\r\n </NRadioButton>\r\n <NRadioButton\r\n v-if=\"activeField === 'day' || activeField === 'week'\"\r\n value=\"none\"\r\n >\r\n 不指定\r\n </NRadioButton>\r\n <NRadioButton value=\"range\">范围</NRadioButton>\r\n <NRadioButton value=\"step\">步进</NRadioButton>\r\n <NRadioButton value=\"specific\">指定</NRadioButton>\r\n </NRadioGroup>\r\n\r\n <!-- 范围配置 -->\r\n <div v-if=\"activeFieldValue.mode === 'range'\" class=\"c-cron__config\">\r\n <div class=\"c-cron__config-row\">\r\n <span>从</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.rangeStart\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n rangeStart: v ?? activeFieldMeta.min,\r\n })\r\n \"\r\n />\r\n <span>到</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.rangeEnd\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n rangeEnd: v ?? activeFieldMeta.max,\r\n })\r\n \"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 步进配置 -->\r\n <div v-if=\"activeFieldValue.mode === 'step'\" class=\"c-cron__config\">\r\n <div class=\"c-cron__config-row\">\r\n <span>从第</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.stepStart\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n stepStart: v ?? activeFieldMeta.min,\r\n })\r\n \"\r\n />\r\n <span>{{ activeFieldMeta.label }}起,每</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.stepInterval\"\r\n :min=\"1\"\r\n :max=\"activeFieldMeta.max - activeFieldMeta.min + 1\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({ stepInterval: v ?? 1 })\r\n \"\r\n />\r\n <span>{{ activeFieldMeta.label }}执行</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 指定快捷操作 -->\r\n <div v-if=\"activeFieldValue.mode === 'specific'\" class=\"c-cron__quick\">\r\n <a @click=\"handleSelectAll\">全选</a>\r\n <span class=\"c-cron__quick-sep\">·</span>\r\n <a @click=\"handleClearAll\">清空</a>\r\n <span\r\n v-if=\"activeFieldValue.specificValues.length > 0\"\r\n class=\"c-cron__quick-count\"\r\n >\r\n 已选 {{ activeFieldValue.specificValues.length }}\r\n </span>\r\n </div>\r\n\r\n <!-- 执行预览 -->\r\n <template v-if=\"props.showPreview\">\r\n <div class=\"c-cron__panel-line\" />\r\n <CronPreview\r\n :next-executions=\"nextExecutions\"\r\n :computing=\"computing\"\r\n :count=\"props.previewCount ?? 5\"\r\n :format-date=\"formatDate\"\r\n :format-week-day=\"formatWeekDay\"\r\n />\r\n </template>\r\n </div>\r\n </div>\r\n\r\n <!-- ═══════ 底部模板 ═══════ -->\r\n <div v-if=\"props.showTemplates\" class=\"c-cron__footer\">\r\n <CronTemplates\r\n :templates=\"CRON_TEMPLATES\"\r\n :current-value=\"expression\"\r\n @select=\"handleTemplateSelect\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, onMounted } from \"vue\";\r\nimport type {\r\n CronFieldMode,\r\n CronFieldType,\r\n CronFieldValue,\r\n CronProps,\r\n CronValidation,\r\n} from \"./types\";\r\nimport {\r\n CRON_FIELD_META,\r\n CRON_TEMPLATES,\r\n DEFAULT_CRON_EXPRESSION,\r\n} from \"./constants\";\r\nimport { useCronParser } from \"./composables/useCronParser\";\r\nimport { useCronPreview } from \"./composables/useCronPreview\";\r\nimport { useCronDescription } from \"./composables/useCronDescription\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport CronFieldEditor from \"./components/CronFieldEditor.vue\";\r\nimport CronPreview from \"./components/CronPreview.vue\";\r\nimport CronTemplates from \"./components/CronTemplates.vue\";\r\n\r\ndefineOptions({ name: \"C_Cron\" });\r\n\r\n/* ─── Props & Emits ─────────────────────────── */\r\n\r\nconst props = withDefaults(defineProps<CronProps>(), {\r\n modelValue: DEFAULT_CRON_EXPRESSION,\r\n disabled: false,\r\n previewCount: 10,\r\n showTemplates: true,\r\n showPreview: true,\r\n showSecond: true,\r\n height: \"auto\",\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: string];\r\n change: [value: string];\r\n \"validation-change\": [result: CronValidation];\r\n}>();\r\n\r\n/* ─── 组合函数 ──────────────────────────────── */\r\n\r\nconst {\r\n cronValue,\r\n expression,\r\n validation,\r\n parse,\r\n validate,\r\n handleDayWeekExclusion,\r\n} = useCronParser();\r\n\r\nconst previewCount = computed(() => props.previewCount ?? 10);\r\nconst { nextExecutions, computing, formatDate, formatWeekDay } = useCronPreview(\r\n expression,\r\n validation,\r\n previewCount,\r\n);\r\n\r\nconst { description } = useCronDescription(expression, validation);\r\n\r\n/* ─── 本地状态 ──────────────────────────────── */\r\n\r\n/** 手动输入框值(与 expression 解耦,输入完成后同步) */\r\nconst manualInput = ref(props.modelValue || DEFAULT_CRON_EXPRESSION);\r\n\r\n/** 当前激活的字段 Tab */\r\nconst activeField = ref<CronFieldType>(props.showSecond ? \"second\" : \"minute\");\r\n\r\n/* ─── 容器高度 ──────────────────────────────── */\r\n\r\nconst containerHeight = computed(() => {\r\n if (typeof props.height === \"number\") return `${props.height}px`;\r\n return props.height;\r\n});\r\n\r\n/* ─── 可见字段(是否显示秒) ────────────────── */\r\n\r\nconst visibleFields = computed(() => {\r\n return props.showSecond\r\n ? CRON_FIELD_META\r\n : CRON_FIELD_META.filter((m) => m.type !== \"second\");\r\n});\r\n\r\n/* ─── 当前激活字段快捷访问 ─────────────────── */\r\n\r\n/** 当前激活字段元数据 */\r\nconst activeFieldMeta = computed(\r\n () => CRON_FIELD_META.find((m) => m.type === activeField.value)!,\r\n);\r\n\r\n/** 当前激活字段值 */\r\nconst activeFieldValue = computed(() => cronValue.value[activeField.value]);\r\n\r\n/* ─── 分段式表达式(逐字段计算) ────────────── */\r\n\r\n/** 计算单字段表达式文本 */\r\nfunction computeFieldExpr(f: CronFieldValue): string {\r\n switch (f.mode) {\r\n case \"every\":\r\n return \"*\";\r\n case \"none\":\r\n return \"?\";\r\n case \"range\":\r\n return `${f.rangeStart}-${f.rangeEnd}`;\r\n case \"step\":\r\n return `${f.stepStart}/${f.stepInterval}`;\r\n case \"specific\":\r\n return f.specificValues.length > 0\r\n ? [...f.specificValues].sort((a, b) => a - b).join(\",\")\r\n : \"*\";\r\n default:\r\n return \"*\";\r\n }\r\n}\r\n\r\n/** 各字段表达式映射 */\r\nconst fieldExpressions = computed(() => {\r\n const map = {} as Record<CronFieldType, string>;\r\n for (const meta of CRON_FIELD_META) {\r\n map[meta.type] = computeFieldExpr(cronValue.value[meta.type]);\r\n }\r\n return map;\r\n});\r\n\r\n/* ─── 初始化解析 ────────────────────────────── */\r\n\r\nonMounted(() => {\r\n const initial = props.modelValue || DEFAULT_CRON_EXPRESSION;\r\n parse(initial);\r\n manualInput.value = initial;\r\n});\r\n\r\n/* ─── 监听外部 v-model 变更 ─────────────────── */\r\n\r\nwatch(\r\n () => props.modelValue,\r\n (newVal) => {\r\n if (newVal && newVal !== expression.value) {\r\n parse(newVal);\r\n manualInput.value = newVal;\r\n }\r\n },\r\n);\r\n\r\n/* ─── 监听 showSecond 变更 ──────────────────── */\r\n\r\nwatch(\r\n () => props.showSecond,\r\n (show) => {\r\n if (!show && activeField.value === \"second\") {\r\n activeField.value = \"minute\";\r\n }\r\n },\r\n);\r\n\r\n/* ─── 监听内部表达式变更 → 同步到外部 ───────── */\r\n\r\nwatch(expression, (newExpr) => {\r\n manualInput.value = newExpr;\r\n emit(\"update:modelValue\", newExpr);\r\n emit(\"change\", newExpr);\r\n});\r\n\r\n/* ─── 监听校验状态变更 ──────────────────────── */\r\n\r\nwatch(validation, (v) => {\r\n emit(\"validation-change\", v);\r\n});\r\n\r\n/* ─── 字段变更处理 ──────────────────────────── */\r\n\r\n/** 字段编辑变更处理 */\r\nfunction handleFieldChange(type: CronFieldType, value: CronFieldValue) {\r\n cronValue.value[type] = value;\r\n if (type === \"day\" || type === \"week\") {\r\n handleDayWeekExclusion(type);\r\n }\r\n}\r\n\r\n/* ─── 右侧面板操作 ─────────────────────────── */\r\n\r\n/** 切换当前字段模式 */\r\nfunction handleActiveFieldModeChange(mode: CronFieldMode) {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n mode,\r\n });\r\n}\r\n\r\n/** 更新当前字段属性 */\r\nfunction handleActiveFieldUpdate(partial: Partial<CronFieldValue>) {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n ...partial,\r\n });\r\n}\r\n\r\n/** 全选当前字段所有值 */\r\nfunction handleSelectAll() {\r\n const { min, max } = activeFieldMeta.value;\r\n const allValues = Array.from({ length: max - min + 1 }, (_, i) => min + i);\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n specificValues: allValues,\r\n });\r\n}\r\n\r\n/** 清空当前字段所有选中值 */\r\nfunction handleClearAll() {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n specificValues: [],\r\n });\r\n}\r\n\r\n/* ─── 手动输入处理 ──────────────────────────── */\r\n\r\n/** 手动输入更新 */\r\nfunction handleManualInput(value: string) {\r\n manualInput.value = value;\r\n}\r\n\r\n/** 输入框失焦时同步 */\r\nfunction handleManualBlur() {\r\n const trimmed = manualInput.value.trim();\r\n if (trimmed && trimmed !== expression.value) {\r\n parse(trimmed);\r\n }\r\n}\r\n\r\n/* ─── 模板选择 ──────────────────────────────── */\r\n\r\n/** 选择常用模板 */\r\nfunction handleTemplateSelect(expr: string) {\r\n parse(expr);\r\n manualInput.value = expr;\r\n}\r\n\r\n/* ─── 重置 ──────────────────────────────────── */\r\n\r\n/** 重置为初始值 */\r\nfunction handleReset() {\r\n const initial = props.modelValue || DEFAULT_CRON_EXPRESSION;\r\n parse(initial);\r\n manualInput.value = initial;\r\n}\r\n\r\n/* ─── Expose ────────────────────────────────── */\r\n\r\ndefineExpose({\r\n getValue: () => expression.value,\r\n setValue: (expr: string) => {\r\n parse(expr);\r\n manualInput.value = expr;\r\n },\r\n reset: handleReset,\r\n validate: () => validate(),\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 表达式编辑器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"c-cron\" :style=\"{ height: containerHeight }\">\r\n <!-- ═══════ 顶部 ═══════ -->\r\n <div class=\"c-cron__header\">\r\n <!-- 标题行 -->\r\n <div class=\"c-cron__title-row\">\r\n <div class=\"c-cron__title\">\r\n <C_Icon name=\"mdi:clock-edit-outline\" :size=\"18\" />\r\n <span>Cron 表达式</span>\r\n </div>\r\n <NTag :type=\"validation.valid ? 'success' : 'error'\" size=\"small\" round>\r\n <template #icon>\r\n <C_Icon\r\n :name=\"validation.valid ? 'mdi:check-circle' : 'mdi:alert-circle'\"\r\n />\r\n </template>\r\n {{ validation.valid ? \"合法\" : \"错误\" }}\r\n </NTag>\r\n </div>\r\n\r\n <!-- 分段式字段选择器 -->\r\n <div class=\"c-cron__segments\">\r\n <div\r\n v-for=\"meta in visibleFields\"\r\n :key=\"meta.type\"\r\n class=\"c-cron__segment\"\r\n :class=\"{\r\n 'c-cron__segment--active': activeField === meta.type,\r\n 'c-cron__segment--wildcard':\r\n fieldExpressions[meta.type] === '*' ||\r\n fieldExpressions[meta.type] === '?',\r\n }\"\r\n @click=\"activeField = meta.type\"\r\n >\r\n <div class=\"c-cron__segment-value\">\r\n {{ fieldExpressions[meta.type] }}\r\n </div>\r\n <div class=\"c-cron__segment-label\">{{ meta.label }}</div>\r\n </div>\r\n </div>\r\n\r\n <!-- 表达式行:输入 + 重置 + 描述 -->\r\n <div class=\"c-cron__expr-row\">\r\n <NInput\r\n :value=\"manualInput\"\r\n :status=\"validation.valid ? undefined : 'error'\"\r\n placeholder=\"秒 分 时 日 月 周\"\r\n :disabled=\"props.disabled\"\r\n font=\"mono\"\r\n size=\"small\"\r\n clearable\r\n class=\"c-cron__expr-input\"\r\n @update:value=\"handleManualInput\"\r\n @blur=\"handleManualBlur\"\r\n @keydown.enter=\"handleManualBlur\"\r\n >\r\n <template #prefix>\r\n <C_Icon name=\"mdi:console\" :size=\"14\" style=\"opacity: 0.4\" />\r\n </template>\r\n </NInput>\r\n <NButton\r\n size=\"small\"\r\n quaternary\r\n :disabled=\"props.disabled\"\r\n @click=\"handleReset\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:refresh\" />\r\n </template>\r\n </NButton>\r\n <div class=\"c-cron__expr-desc\">\r\n <span v-if=\"validation.valid\" class=\"c-cron__description\">\r\n {{ description }}\r\n </span>\r\n <span v-else class=\"c-cron__error\">\r\n {{ validation.message }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ═══════ 主内容 ═══════ -->\r\n <div class=\"c-cron__body\">\r\n <!-- 左侧:值网格 -->\r\n <div class=\"c-cron__main\">\r\n <CronFieldEditor\r\n v-for=\"meta in visibleFields\"\r\n v-show=\"activeField === meta.type\"\r\n :key=\"meta.type\"\r\n :model-value=\"cronValue[meta.type]\"\r\n :meta=\"meta\"\r\n @update:model-value=\"(v) => handleFieldChange(meta.type, v)\"\r\n />\r\n </div>\r\n\r\n <!-- 右侧:控制面板 -->\r\n <div class=\"c-cron__panel\">\r\n <NRadioGroup\r\n :value=\"activeFieldValue.mode\"\r\n size=\"small\"\r\n @update:value=\"handleActiveFieldModeChange\"\r\n >\r\n <NRadioButton value=\"every\">\r\n 每{{ activeFieldMeta.label }}\r\n </NRadioButton>\r\n <NRadioButton\r\n v-if=\"activeField === 'day' || activeField === 'week'\"\r\n value=\"none\"\r\n >\r\n 不指定\r\n </NRadioButton>\r\n <NRadioButton value=\"range\">范围</NRadioButton>\r\n <NRadioButton value=\"step\">步进</NRadioButton>\r\n <NRadioButton value=\"specific\">指定</NRadioButton>\r\n </NRadioGroup>\r\n\r\n <!-- 范围配置 -->\r\n <div v-if=\"activeFieldValue.mode === 'range'\" class=\"c-cron__config\">\r\n <div class=\"c-cron__config-row\">\r\n <span>从</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.rangeStart\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n rangeStart: v ?? activeFieldMeta.min,\r\n })\r\n \"\r\n />\r\n <span>到</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.rangeEnd\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n rangeEnd: v ?? activeFieldMeta.max,\r\n })\r\n \"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 步进配置 -->\r\n <div v-if=\"activeFieldValue.mode === 'step'\" class=\"c-cron__config\">\r\n <div class=\"c-cron__config-row\">\r\n <span>从第</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.stepStart\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n stepStart: v ?? activeFieldMeta.min,\r\n })\r\n \"\r\n />\r\n <span>{{ activeFieldMeta.label }}起,每</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.stepInterval\"\r\n :min=\"1\"\r\n :max=\"activeFieldMeta.max - activeFieldMeta.min + 1\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({ stepInterval: v ?? 1 })\r\n \"\r\n />\r\n <span>{{ activeFieldMeta.label }}执行</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 指定快捷操作 -->\r\n <div v-if=\"activeFieldValue.mode === 'specific'\" class=\"c-cron__quick\">\r\n <a @click=\"handleSelectAll\">全选</a>\r\n <span class=\"c-cron__quick-sep\">·</span>\r\n <a @click=\"handleClearAll\">清空</a>\r\n <span\r\n v-if=\"activeFieldValue.specificValues.length > 0\"\r\n class=\"c-cron__quick-count\"\r\n >\r\n 已选 {{ activeFieldValue.specificValues.length }}\r\n </span>\r\n </div>\r\n\r\n <!-- 执行预览 -->\r\n <template v-if=\"props.showPreview\">\r\n <div class=\"c-cron__panel-line\" />\r\n <CronPreview\r\n :next-executions=\"nextExecutions\"\r\n :computing=\"computing\"\r\n :count=\"props.previewCount ?? 5\"\r\n :format-date=\"formatDate\"\r\n :format-week-day=\"formatWeekDay\"\r\n />\r\n </template>\r\n </div>\r\n </div>\r\n\r\n <!-- ═══════ 底部模板 ═══════ -->\r\n <div v-if=\"props.showTemplates\" class=\"c-cron__footer\">\r\n <CronTemplates\r\n :templates=\"CRON_TEMPLATES\"\r\n :current-value=\"expression\"\r\n @select=\"handleTemplateSelect\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, onMounted } from \"vue\";\r\nimport type {\r\n CronFieldMode,\r\n CronFieldType,\r\n CronFieldValue,\r\n CronProps,\r\n CronValidation,\r\n} from \"./types\";\r\nimport {\r\n CRON_FIELD_META,\r\n CRON_TEMPLATES,\r\n DEFAULT_CRON_EXPRESSION,\r\n} from \"./constants\";\r\nimport { useCronParser } from \"./composables/useCronParser\";\r\nimport { useCronPreview } from \"./composables/useCronPreview\";\r\nimport { useCronDescription } from \"./composables/useCronDescription\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport CronFieldEditor from \"./components/CronFieldEditor.vue\";\r\nimport CronPreview from \"./components/CronPreview.vue\";\r\nimport CronTemplates from \"./components/CronTemplates.vue\";\r\n\r\ndefineOptions({ name: \"C_Cron\" });\r\n\r\n/* ─── Props & Emits ─────────────────────────── */\r\n\r\nconst props = withDefaults(defineProps<CronProps>(), {\r\n modelValue: DEFAULT_CRON_EXPRESSION,\r\n disabled: false,\r\n previewCount: 10,\r\n showTemplates: true,\r\n showPreview: true,\r\n showSecond: true,\r\n height: \"auto\",\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: string];\r\n change: [value: string];\r\n \"validation-change\": [result: CronValidation];\r\n}>();\r\n\r\n/* ─── 组合函数 ──────────────────────────────── */\r\n\r\nconst {\r\n cronValue,\r\n expression,\r\n validation,\r\n parse,\r\n validate,\r\n handleDayWeekExclusion,\r\n} = useCronParser();\r\n\r\nconst previewCount = computed(() => props.previewCount ?? 10);\r\nconst { nextExecutions, computing, formatDate, formatWeekDay } = useCronPreview(\r\n expression,\r\n validation,\r\n previewCount,\r\n);\r\n\r\nconst { description } = useCronDescription(expression, validation);\r\n\r\n/* ─── 本地状态 ──────────────────────────────── */\r\n\r\n/** 手动输入框值(与 expression 解耦,输入完成后同步) */\r\nconst manualInput = ref(props.modelValue || DEFAULT_CRON_EXPRESSION);\r\n\r\n/** 当前激活的字段 Tab */\r\nconst activeField = ref<CronFieldType>(props.showSecond ? \"second\" : \"minute\");\r\n\r\n/* ─── 容器高度 ──────────────────────────────── */\r\n\r\nconst containerHeight = computed(() => {\r\n if (typeof props.height === \"number\") return `${props.height}px`;\r\n return props.height;\r\n});\r\n\r\n/* ─── 可见字段(是否显示秒) ────────────────── */\r\n\r\nconst visibleFields = computed(() => {\r\n return props.showSecond\r\n ? CRON_FIELD_META\r\n : CRON_FIELD_META.filter((m) => m.type !== \"second\");\r\n});\r\n\r\n/* ─── 当前激活字段快捷访问 ─────────────────── */\r\n\r\n/** 当前激活字段元数据 */\r\nconst activeFieldMeta = computed(\r\n () => CRON_FIELD_META.find((m) => m.type === activeField.value)!,\r\n);\r\n\r\n/** 当前激活字段值 */\r\nconst activeFieldValue = computed(() => cronValue.value[activeField.value]);\r\n\r\n/* ─── 分段式表达式(逐字段计算) ────────────── */\r\n\r\n/** 计算单字段表达式文本 */\r\nfunction computeFieldExpr(f: CronFieldValue): string {\r\n switch (f.mode) {\r\n case \"every\":\r\n return \"*\";\r\n case \"none\":\r\n return \"?\";\r\n case \"range\":\r\n return `${f.rangeStart}-${f.rangeEnd}`;\r\n case \"step\":\r\n return `${f.stepStart}/${f.stepInterval}`;\r\n case \"specific\":\r\n return f.specificValues.length > 0\r\n ? [...f.specificValues].sort((a, b) => a - b).join(\",\")\r\n : \"*\";\r\n default:\r\n return \"*\";\r\n }\r\n}\r\n\r\n/** 各字段表达式映射 */\r\nconst fieldExpressions = computed(() => {\r\n const map = {} as Record<CronFieldType, string>;\r\n for (const meta of CRON_FIELD_META) {\r\n map[meta.type] = computeFieldExpr(cronValue.value[meta.type]);\r\n }\r\n return map;\r\n});\r\n\r\n/* ─── 初始化解析 ────────────────────────────── */\r\n\r\nonMounted(() => {\r\n const initial = props.modelValue || DEFAULT_CRON_EXPRESSION;\r\n parse(initial);\r\n manualInput.value = initial;\r\n});\r\n\r\n/* ─── 监听外部 v-model 变更 ─────────────────── */\r\n\r\nwatch(\r\n () => props.modelValue,\r\n (newVal) => {\r\n if (newVal && newVal !== expression.value) {\r\n parse(newVal);\r\n manualInput.value = newVal;\r\n }\r\n },\r\n);\r\n\r\n/* ─── 监听 showSecond 变更 ──────────────────── */\r\n\r\nwatch(\r\n () => props.showSecond,\r\n (show) => {\r\n if (!show && activeField.value === \"second\") {\r\n activeField.value = \"minute\";\r\n }\r\n },\r\n);\r\n\r\n/* ─── 监听内部表达式变更 → 同步到外部 ───────── */\r\n\r\nwatch(expression, (newExpr) => {\r\n manualInput.value = newExpr;\r\n emit(\"update:modelValue\", newExpr);\r\n emit(\"change\", newExpr);\r\n});\r\n\r\n/* ─── 监听校验状态变更 ──────────────────────── */\r\n\r\nwatch(validation, (v) => {\r\n emit(\"validation-change\", v);\r\n});\r\n\r\n/* ─── 字段变更处理 ──────────────────────────── */\r\n\r\n/** 字段编辑变更处理 */\r\nfunction handleFieldChange(type: CronFieldType, value: CronFieldValue) {\r\n cronValue.value[type] = value;\r\n if (type === \"day\" || type === \"week\") {\r\n handleDayWeekExclusion(type);\r\n }\r\n}\r\n\r\n/* ─── 右侧面板操作 ─────────────────────────── */\r\n\r\n/** 切换当前字段模式 */\r\nfunction handleActiveFieldModeChange(mode: CronFieldMode) {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n mode,\r\n });\r\n}\r\n\r\n/** 更新当前字段属性 */\r\nfunction handleActiveFieldUpdate(partial: Partial<CronFieldValue>) {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n ...partial,\r\n });\r\n}\r\n\r\n/** 全选当前字段所有值 */\r\nfunction handleSelectAll() {\r\n const { min, max } = activeFieldMeta.value;\r\n const allValues = Array.from({ length: max - min + 1 }, (_, i) => min + i);\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n specificValues: allValues,\r\n });\r\n}\r\n\r\n/** 清空当前字段所有选中值 */\r\nfunction handleClearAll() {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n specificValues: [],\r\n });\r\n}\r\n\r\n/* ─── 手动输入处理 ──────────────────────────── */\r\n\r\n/** 手动输入更新 */\r\nfunction handleManualInput(value: string) {\r\n manualInput.value = value;\r\n}\r\n\r\n/** 输入框失焦时同步 */\r\nfunction handleManualBlur() {\r\n const trimmed = manualInput.value.trim();\r\n if (trimmed && trimmed !== expression.value) {\r\n parse(trimmed);\r\n }\r\n}\r\n\r\n/* ─── 模板选择 ──────────────────────────────── */\r\n\r\n/** 选择常用模板 */\r\nfunction handleTemplateSelect(expr: string) {\r\n parse(expr);\r\n manualInput.value = expr;\r\n}\r\n\r\n/* ─── 重置 ──────────────────────────────────── */\r\n\r\n/** 重置为初始值 */\r\nfunction handleReset() {\r\n const initial = props.modelValue || DEFAULT_CRON_EXPRESSION;\r\n parse(initial);\r\n manualInput.value = initial;\r\n}\r\n\r\n/* ─── Expose ────────────────────────────────── */\r\n\r\ndefineExpose({\r\n getValue: () => expression.value,\r\n setValue: (expr: string) => {\r\n parse(expr);\r\n manualInput.value = expr;\r\n },\r\n reset: handleReset,\r\n validate: () => validate(),\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"C_Cron2.js","names":["modelValue","computing","nextExecutions","formatDate","formatWeekDay","templates","currentValue","$emit"],"sources":["../src/components/C_Cron/constants.ts","../src/components/C_Cron/composables/useCronParser.ts","../src/components/C_Cron/composables/useCronPreview.ts","../src/components/C_Cron/composables/useCronDescription.ts","../src/components/C_Cron/components/CronFieldEditor.vue","../src/components/C_Cron/components/CronFieldEditor.vue","../src/components/C_Cron/components/CronFieldEditor.vue","../src/components/C_Cron/components/CronPreview.vue","../src/components/C_Cron/components/CronPreview.vue","../src/components/C_Cron/components/CronPreview.vue","../src/components/C_Cron/components/CronTemplates.vue","../src/components/C_Cron/components/CronTemplates.vue","../src/components/C_Cron/components/CronTemplates.vue","../src/components/C_Cron/index.vue","../src/components/C_Cron/index.vue","../src/components/C_Cron/index.vue"],"sourcesContent":["/*\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 表达式编辑器常量\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n */\r\n\r\nimport type {\r\n CronFieldMeta,\r\n CronFieldValue,\r\n CronTemplate,\r\n CronValue,\r\n} from \"./types\";\r\n\r\n/* ─── 字段元数据 ────────────────────────────────── */\r\n\r\nexport const CRON_FIELD_META: CronFieldMeta[] = [\r\n { type: \"second\", label: \"秒\", min: 0, max: 59 },\r\n { type: \"minute\", label: \"分\", min: 0, max: 59 },\r\n { type: \"hour\", label: \"时\", min: 0, max: 23 },\r\n { type: \"day\", label: \"日\", min: 1, max: 31 },\r\n { type: \"month\", label: \"月\", min: 1, max: 12 },\r\n {\r\n type: \"week\",\r\n label: \"周\",\r\n min: 1,\r\n max: 7,\r\n valueLabels: {\r\n 1: \"周日\",\r\n 2: \"周一\",\r\n 3: \"周二\",\r\n 4: \"周三\",\r\n 5: \"周四\",\r\n 6: \"周五\",\r\n 7: \"周六\",\r\n },\r\n },\r\n];\r\n\r\n/* ─── 默认字段值 ────────────────────────────────── */\r\n\r\nexport const DEFAULT_FIELD_VALUE: CronFieldValue = {\r\n mode: \"every\",\r\n rangeStart: 0,\r\n rangeEnd: 0,\r\n stepStart: 0,\r\n stepInterval: 1,\r\n specificValues: [],\r\n};\r\n\r\n/* ─── 默认 Cron 值(每秒执行) ────────────────── */\r\n\r\nexport const DEFAULT_CRON_VALUE: CronValue = {\r\n second: { ...DEFAULT_FIELD_VALUE, rangeEnd: 59 },\r\n minute: { ...DEFAULT_FIELD_VALUE, rangeEnd: 59 },\r\n hour: { ...DEFAULT_FIELD_VALUE, rangeEnd: 23 },\r\n day: { ...DEFAULT_FIELD_VALUE, rangeStart: 1, rangeEnd: 31 },\r\n month: { ...DEFAULT_FIELD_VALUE, rangeStart: 1, rangeEnd: 12 },\r\n week: { ...DEFAULT_FIELD_VALUE, mode: \"none\", rangeStart: 1, rangeEnd: 7 },\r\n};\r\n\r\n/* ─── 默认表达式 ─────────────────────────────────── */\r\n\r\nexport const DEFAULT_CRON_EXPRESSION = \"0 0 0 * * ?\";\r\n\r\n/* ─── 常用模板 ───────────────────────────────────── */\r\n\r\nexport const CRON_TEMPLATES: CronTemplate[] = [\r\n {\r\n label: \"每秒执行\",\r\n value: \"* * * * * ?\",\r\n description: \"每秒执行一次\",\r\n icon: \"mdi:timer-sand\",\r\n },\r\n {\r\n label: \"每分钟执行\",\r\n value: \"0 * * * * ?\",\r\n description: \"每分钟第 0 秒执行\",\r\n icon: \"mdi:clock-outline\",\r\n },\r\n {\r\n label: \"每小时执行\",\r\n value: \"0 0 * * * ?\",\r\n description: \"每小时整点执行\",\r\n icon: \"mdi:clock-time-twelve-outline\",\r\n },\r\n {\r\n label: \"每天 0 点\",\r\n value: \"0 0 0 * * ?\",\r\n description: \"每天凌晨 00:00 执行\",\r\n icon: \"mdi:weather-night\",\r\n },\r\n {\r\n label: \"每天 8:30\",\r\n value: \"0 30 8 * * ?\",\r\n description: \"每天早上 08:30 执行\",\r\n icon: \"mdi:weather-sunny\",\r\n },\r\n {\r\n label: \"每天 12:00\",\r\n value: \"0 0 12 * * ?\",\r\n description: \"每天中午 12:00 执行\",\r\n icon: \"mdi:food\",\r\n },\r\n {\r\n label: \"工作日 9:00\",\r\n value: \"0 0 9 ? * 2-6\",\r\n description: \"周一至周五 09:00 执行\",\r\n icon: \"mdi:briefcase-outline\",\r\n },\r\n {\r\n label: \"每周一 0 点\",\r\n value: \"0 0 0 ? * 2\",\r\n description: \"每周一凌晨 00:00 执行\",\r\n icon: \"mdi:calendar-week\",\r\n },\r\n {\r\n label: \"每月 1 号 0 点\",\r\n value: \"0 0 0 1 * ?\",\r\n description: \"每月 1 号凌晨 00:00 执行\",\r\n icon: \"mdi:calendar-month\",\r\n },\r\n {\r\n label: \"每 5 分钟\",\r\n value: \"0 0/5 * * * ?\",\r\n description: \"每隔 5 分钟执行一次\",\r\n icon: \"mdi:timer-5\",\r\n },\r\n {\r\n label: \"每 30 分钟\",\r\n value: \"0 0/30 * * * ?\",\r\n description: \"每隔 30 分钟执行一次\",\r\n icon: \"mdi:timer-30\",\r\n },\r\n {\r\n label: \"每 2 小时\",\r\n value: \"0 0 0/2 * * ?\",\r\n description: \"每隔 2 小时执行一次\",\r\n icon: \"mdi:timer-2\",\r\n },\r\n];\r\n\r\n/* ─── 月份名称 ───────────────────────────────────── */\r\n\r\nexport const MONTH_LABELS: Record<number, string> = {\r\n 1: \"一月\",\r\n 2: \"二月\",\r\n 3: \"三月\",\r\n 4: \"四月\",\r\n 5: \"五月\",\r\n 6: \"六月\",\r\n 7: \"七月\",\r\n 8: \"八月\",\r\n 9: \"九月\",\r\n 10: \"十月\",\r\n 11: \"十一月\",\r\n 12: \"十二月\",\r\n};\r\n\r\n/* ─── 周名称 ─────────────────────────────────────── */\r\n\r\nexport const WEEK_LABELS: Record<number, string> = {\r\n 1: \"周日\",\r\n 2: \"周一\",\r\n 3: \"周二\",\r\n 4: \"周三\",\r\n 5: \"周四\",\r\n 6: \"周五\",\r\n 7: \"周六\",\r\n};\r\n","/*\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 解析 & 生成引擎\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n */\r\n\r\nimport { ref, computed } from \"vue\";\r\nimport type {\r\n CronFieldMeta,\r\n CronFieldType,\r\n CronFieldValue,\r\n CronValidation,\r\n CronValue,\r\n} from \"../types\";\r\nimport { CRON_FIELD_META, DEFAULT_CRON_VALUE } from \"../constants\";\r\n\r\n/* ─── 字段顺序 ────────────────────────────────── */\r\n\r\nconst FIELD_ORDER: CronFieldType[] = [\r\n \"second\",\r\n \"minute\",\r\n \"hour\",\r\n \"day\",\r\n \"month\",\r\n \"week\",\r\n];\r\n\r\n/**\r\n * Cron 解析 & 生成引擎\r\n */\r\nexport function useCronParser() {\r\n /** 当前 Cron 对象 */\r\n const cronValue = ref<CronValue>(structuredClone(DEFAULT_CRON_VALUE));\r\n\r\n /* ─── 单字段 → 表达式片段 ────────────────────── */\r\n\r\n /** 将单个字段值转为 Cron 表达式片段 */\r\n function fieldToExpression(field: CronFieldValue): string {\r\n switch (field.mode) {\r\n case \"every\":\r\n return \"*\";\r\n case \"range\":\r\n return `${field.rangeStart}-${field.rangeEnd}`;\r\n case \"step\":\r\n return `${field.stepStart}/${field.stepInterval}`;\r\n case \"specific\":\r\n return field.specificValues.length > 0\r\n ? field.specificValues.sort((a, b) => a - b).join(\",\")\r\n : \"*\";\r\n case \"none\":\r\n return \"?\";\r\n default:\r\n return \"*\";\r\n }\r\n }\r\n\r\n /* ─── 表达式片段 → 单字段 ────────────────────── */\r\n\r\n /** 创建默认字段值 */\r\n function createFieldValue(\r\n meta: CronFieldMeta,\r\n mode: CronFieldValue[\"mode\"],\r\n overrides: Partial<CronFieldValue> = {},\r\n ): CronFieldValue {\r\n return {\r\n mode,\r\n rangeStart: meta.min,\r\n rangeEnd: meta.max,\r\n stepStart: meta.min,\r\n stepInterval: 1,\r\n specificValues: [],\r\n ...overrides,\r\n };\r\n }\r\n\r\n /** 解析步进表达式为字段值 */\r\n function parseStepExpr(expr: string, meta: CronFieldMeta): CronFieldValue {\r\n const [start, interval] = expr.split(\"/\").map(Number);\r\n return createFieldValue(meta, \"step\", {\r\n stepStart: isNaN(start) ? meta.min : start,\r\n stepInterval: isNaN(interval) ? 1 : interval,\r\n });\r\n }\r\n\r\n /** 解析范围表达式为字段值 */\r\n function parseRangeExpr(expr: string, meta: CronFieldMeta): CronFieldValue {\r\n const [start, end] = expr.split(\"-\").map(Number);\r\n return createFieldValue(meta, \"range\", {\r\n rangeStart: isNaN(start) ? meta.min : start,\r\n rangeEnd: isNaN(end) ? meta.max : end,\r\n });\r\n }\r\n\r\n /** 将 Cron 表达式片段解析为字段值对象 */\r\n function expressionToField(\r\n expr: string,\r\n type: CronFieldType,\r\n ): CronFieldValue {\r\n const meta = CRON_FIELD_META.find((m) => m.type === type)!;\r\n\r\n if (expr === \"?\") return createFieldValue(meta, \"none\");\r\n if (expr === \"*\") return createFieldValue(meta, \"every\");\r\n if (expr.includes(\"/\")) return parseStepExpr(expr, meta);\r\n if (expr.includes(\"-\") && !expr.includes(\",\"))\r\n return parseRangeExpr(expr, meta);\r\n\r\n /* x,y,z 或单个数字(指定值) */\r\n const values = expr\r\n .split(\",\")\r\n .map(Number)\r\n .filter((n) => !isNaN(n));\r\n if (values.length > 0)\r\n return createFieldValue(meta, \"specific\", { specificValues: values });\r\n\r\n return createFieldValue(meta, \"every\");\r\n }\r\n\r\n /* ─── CronValue → 完整表达式 ────────────────── */\r\n\r\n /** 由 CronValue 生成完整 Cron 表达式 */\r\n function generate(): string {\r\n return FIELD_ORDER.map((type) =>\r\n fieldToExpression(cronValue.value[type]),\r\n ).join(\" \");\r\n }\r\n\r\n /* ─── 完整表达式 → CronValue ────────────────── */\r\n\r\n /** 解析 Cron 表达式字符串为 CronValue */\r\n function parse(expression: string): void {\r\n const parts = expression.trim().split(/\\s+/);\r\n if (parts.length < 6) return;\r\n\r\n FIELD_ORDER.forEach((type, index) => {\r\n cronValue.value[type] = expressionToField(parts[index], type);\r\n });\r\n }\r\n\r\n /* ─── 日/周互斥处理 ─────────────────────────── */\r\n\r\n /** 日/周互斥:修改一方时另一方自动设为 ? */\r\n function handleDayWeekExclusion(changedField: \"day\" | \"week\"): void {\r\n if (changedField === \"day\") {\r\n if (cronValue.value.day.mode !== \"none\") {\r\n cronValue.value.week = { ...cronValue.value.week, mode: \"none\" };\r\n }\r\n } else {\r\n if (cronValue.value.week.mode !== \"none\") {\r\n cronValue.value.day = { ...cronValue.value.day, mode: \"none\" };\r\n }\r\n }\r\n }\r\n\r\n /* ─── 校验 ──────────────────────────────────── */\r\n\r\n /** 校验 Cron 表达式合法性 */\r\n function validate(expression?: string): CronValidation {\r\n const expr = expression ?? generate();\r\n const parts = expr.trim().split(/\\s+/);\r\n\r\n if (parts.length !== 6) {\r\n return {\r\n valid: false,\r\n message: `表达式应包含 6 个字段,当前为 ${parts.length} 个`,\r\n };\r\n }\r\n\r\n /* 日和周必须有一个为 ? */\r\n const dayPart = parts[3];\r\n const weekPart = parts[5];\r\n if (dayPart !== \"?\" && weekPart !== \"?\") {\r\n return {\r\n valid: false,\r\n message: \"日和周不能同时指定,其中一个必须为 ?\",\r\n field: \"day\",\r\n };\r\n }\r\n if (dayPart === \"?\" && weekPart === \"?\") {\r\n return {\r\n valid: false,\r\n message: \"日和周不能同时为 ?,至少指定一个\",\r\n field: \"day\",\r\n };\r\n }\r\n\r\n /* 逐字段校验 */\r\n for (let i = 0; i < FIELD_ORDER.length; i++) {\r\n const type = FIELD_ORDER[i];\r\n const part = parts[i];\r\n const meta = CRON_FIELD_META.find((m) => m.type === type)!;\r\n const result = validateField(part, meta);\r\n if (!result.valid) {\r\n return { ...result, field: type };\r\n }\r\n }\r\n\r\n return { valid: true, message: \"表达式合法\" };\r\n }\r\n\r\n /** 校验步进表达式 */\r\n function validateStep(part: string, meta: CronFieldMeta): CronValidation {\r\n const [s, i] = part.split(\"/\");\r\n const start = s === \"*\" ? meta.min : Number(s);\r\n const interval = Number(i);\r\n if (isNaN(start) || isNaN(interval))\r\n return { valid: false, message: `${meta.label}字段步进格式错误` };\r\n if (start < meta.min || start > meta.max)\r\n return {\r\n valid: false,\r\n message: `${meta.label}字段步进起始值超出范围 (${meta.min}-${meta.max})`,\r\n };\r\n if (interval < 1)\r\n return { valid: false, message: `${meta.label}字段步进间隔必须大于 0` };\r\n return { valid: true, message: \"\" };\r\n }\r\n\r\n /** 校验范围表达式 */\r\n function validateRange(part: string, meta: CronFieldMeta): CronValidation {\r\n const [s, e] = part.split(\"-\").map(Number);\r\n if (isNaN(s) || isNaN(e))\r\n return { valid: false, message: `${meta.label}字段范围格式错误` };\r\n if (s < meta.min || e > meta.max)\r\n return {\r\n valid: false,\r\n message: `${meta.label}字段范围超出 (${meta.min}-${meta.max})`,\r\n };\r\n if (s > e)\r\n return { valid: false, message: `${meta.label}字段范围起始不能大于结束` };\r\n return { valid: true, message: \"\" };\r\n }\r\n\r\n /** 校验指定值表达式 */\r\n function validateSpecific(part: string, meta: CronFieldMeta): CronValidation {\r\n const values = part.split(\",\").map(Number);\r\n if (values.some(isNaN))\r\n return { valid: false, message: `${meta.label}字段包含非数字字符` };\r\n if (values.some((v) => v < meta.min || v > meta.max)) {\r\n return {\r\n valid: false,\r\n message: `${meta.label}字段值超出范围 (${meta.min}-${meta.max})`,\r\n };\r\n }\r\n return { valid: true, message: \"\" };\r\n }\r\n\r\n /** 校验单个字段表达式 */\r\n function validateField(part: string, meta: CronFieldMeta): CronValidation {\r\n if (part === \"*\" || part === \"?\") return { valid: true, message: \"\" };\r\n if (part.includes(\"/\")) return validateStep(part, meta);\r\n if (part.includes(\"-\") && !part.includes(\",\"))\r\n return validateRange(part, meta);\r\n return validateSpecific(part, meta);\r\n }\r\n\r\n /* ─── 计算属性:自动生成表达式 ────────────────── */\r\n\r\n const expression = computed(() => generate());\r\n\r\n /* ─── 校验结果 ──────────────────────────────── */\r\n\r\n const validation = computed(() => validate());\r\n\r\n return {\r\n cronValue,\r\n expression,\r\n validation,\r\n parse,\r\n generate,\r\n validate,\r\n handleDayWeekExclusion,\r\n };\r\n}\r\n","/*\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 执行时间预测\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n */\r\n\r\nimport { ref, watch, type Ref } from 'vue'\r\nimport type { CronValidation } from '../types'\r\n\r\n/**\r\n * 解析 Cron 表达式,预测未来 N 次执行时间\r\n * 纯逻辑实现,不依赖外部库\r\n */\r\nexport function useCronPreview(\r\n expression: Ref<string>,\r\n validation: Ref<CronValidation>,\r\n count: Ref<number>\r\n) {\r\n /** 预测的执行时间列表 */\r\n const nextExecutions = ref<Date[]>([])\r\n\r\n /** 是否正在计算 */\r\n const computing = ref(false)\r\n\r\n /* ─── 匹配检查工具 ─────────────────────────── */\r\n\r\n /** 检查单个值是否匹配 Cron 字段片段 */\r\n function matchesPart(value: number, part: string): boolean {\r\n if (part === '*' || part === '?') return true\r\n\r\n /* 步进 x/y */\r\n if (part.includes('/')) {\r\n const [s, i] = part.split('/')\r\n const start = s === '*' ? 0 : Number(s)\r\n const interval = Number(i)\r\n return value - start >= 0 && (value - start) % interval === 0\r\n }\r\n\r\n /* 范围 x-y */\r\n if (part.includes('-') && !part.includes(',')) {\r\n const [start, end] = part.split('-').map(Number)\r\n return value >= start && value <= end\r\n }\r\n\r\n /* 指定值 x,y,z */\r\n return part.split(',').map(Number).includes(value)\r\n }\r\n\r\n /** 检查日期是否匹配 Cron 表达式 */\r\n function matchesCron(date: Date, parts: string[]): boolean {\r\n if (parts.length !== 6) return false\r\n\r\n const [secPart, minPart, hourPart, dayPart, monthPart, weekPart] = parts\r\n\r\n /* 月 (1-12) */\r\n if (!matchesPart(date.getMonth() + 1, monthPart)) return false\r\n\r\n /* 日/周(互斥) */\r\n if (dayPart !== '?') {\r\n if (!matchesPart(date.getDate(), dayPart)) return false\r\n }\r\n if (weekPart !== '?') {\r\n /* JS: 0=周日, 1=周一… → Cron: 1=周日, 2=周一… */\r\n if (!matchesPart(date.getDay() + 1, weekPart)) return false\r\n }\r\n\r\n /* 时 */\r\n if (!matchesPart(date.getHours(), hourPart)) return false\r\n /* 分 */\r\n if (!matchesPart(date.getMinutes(), minPart)) return false\r\n /* 秒 */\r\n if (!matchesPart(date.getSeconds(), secPart)) return false\r\n\r\n return true\r\n }\r\n\r\n /** 计算未来 N 次执行时间 */\r\n function computeNextExecutions(): Date[] {\r\n const expr = expression.value\r\n if (!expr || !validation.value.valid) return []\r\n\r\n const parts = expr.trim().split(/\\s+/)\r\n if (parts.length !== 6) return []\r\n\r\n const results: Date[] = []\r\n const now = new Date()\r\n const cursor = new Date(now.getTime() + 1000) /* 从下一秒开始 */\r\n cursor.setMilliseconds(0)\r\n\r\n /* 判断是否包含秒级调度(秒字段不是 0) */\r\n const hasSecond = parts[0] !== '0'\r\n const stepMs = hasSecond ? 1000 : 60_000 /* 秒级/分钟级步进 */\r\n\r\n /* 分钟级步进时,对齐到整分(秒归零),否则秒位永远无法匹配 '0' */\r\n if (!hasSecond) {\r\n cursor.setSeconds(0)\r\n if (cursor.getTime() <= now.getTime()) {\r\n cursor.setTime(cursor.getTime() + 60_000)\r\n }\r\n }\r\n\r\n const maxIterations = 525_600 /* 最多遍历 1 年的分钟数 */\r\n const target = count.value\r\n\r\n for (let i = 0; i < maxIterations && results.length < target; i++) {\r\n if (matchesCron(cursor, parts)) {\r\n results.push(new Date(cursor))\r\n }\r\n cursor.setTime(cursor.getTime() + stepMs)\r\n }\r\n\r\n return results\r\n }\r\n\r\n /* ─── 监听表达式变化自动计算 ─────────────────── */\r\n\r\n watch(\r\n [expression, count],\r\n () => {\r\n if (!validation.value.valid) {\r\n nextExecutions.value = []\r\n return\r\n }\r\n computing.value = true\r\n /* 使用 setTimeout 避免阻塞 UI */\r\n setTimeout(() => {\r\n nextExecutions.value = computeNextExecutions()\r\n computing.value = false\r\n }, 0)\r\n },\r\n { immediate: true }\r\n )\r\n\r\n /* ─── 格式化输出 ───────────────────────────── */\r\n\r\n /** 格式化日期为字符串 */\r\n function formatDate(date: Date): string {\r\n const pad = (n: number) => String(n).padStart(2, '0')\r\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`\r\n }\r\n\r\n /** 获取日期的中文星期名称 */\r\n function formatWeekDay(date: Date): string {\r\n const days = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']\r\n return days[date.getDay()]\r\n }\r\n\r\n return {\r\n nextExecutions,\r\n computing,\r\n formatDate,\r\n formatWeekDay,\r\n }\r\n}\r\n","/*\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 中文描述生成\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n */\r\n\r\nimport { computed } from \"vue\";\r\nimport type { Ref } from \"vue\";\r\nimport type { CronValidation } from \"../types\";\r\nimport { MONTH_LABELS, WEEK_LABELS } from \"../constants\";\r\n\r\n/** 获取周名称 */\r\nfunction weekLabel(n: number | string): string {\r\n return WEEK_LABELS[Number(n)] || `周${n}`;\r\n}\r\n\r\n/**\r\n * 将 Cron 表达式自动转换为中文可读描述\r\n */\r\nexport function useCronDescription(\r\n expression: Ref<string>,\r\n validation: Ref<CronValidation>,\r\n) {\r\n /** 中文描述 */\r\n const description = computed(() => {\r\n if (!validation.value.valid) return \"表达式不合法\";\r\n return generateDescription(expression.value);\r\n });\r\n\r\n /* ─── 核心转换 ──────────────────────────────── */\r\n\r\n /** 将完整 Cron 表达式转为中文描述 */\r\n function generateDescription(expr: string): string {\r\n const parts = expr.trim().split(/\\s+/);\r\n if (parts.length !== 6) return \"表达式格式错误\";\r\n\r\n const [sec, min, hour, day, month, week] = parts;\r\n\r\n const fragments: string[] = [];\r\n\r\n /* 月 */\r\n fragments.push(describeMonth(month));\r\n /* 周 or 日 */\r\n if (week !== \"?\") {\r\n fragments.push(describeWeek(week));\r\n } else {\r\n fragments.push(describeDay(day));\r\n }\r\n /* 时 */\r\n fragments.push(describeHour(hour));\r\n /* 分 */\r\n fragments.push(describeMinute(min));\r\n /* 秒 */\r\n fragments.push(describeSecond(sec));\r\n\r\n return fragments.filter(Boolean).join(\" \") + \" 执行\";\r\n }\r\n\r\n /* ─── 各字段描述 ────────────────────────────── */\r\n\r\n /** 描述秒字段 */\r\n function describeSecond(part: string): string {\r\n if (part === \"0\") return \"\";\r\n if (part === \"*\") return \"每秒\";\r\n return describeFieldGeneric(part, \"秒\");\r\n }\r\n\r\n /** 描述分字段 */\r\n function describeMinute(part: string): string {\r\n if (part === \"*\") return \"每分钟\";\r\n if (part === \"0\") return \"\";\r\n return describeFieldGeneric(part, \"分\");\r\n }\r\n\r\n /** 描述时字段 */\r\n function describeHour(part: string): string {\r\n if (part === \"*\") return \"每小时\";\r\n if (/^\\d+$/.test(part)) return `${part.padStart(2, \"0\")}:`;\r\n return describeFieldGeneric(part, \"时\");\r\n }\r\n\r\n /** 描述日字段 */\r\n function describeDay(part: string): string {\r\n if (part === \"*\" || part === \"?\") return \"每天\";\r\n if (/^\\d+$/.test(part)) return `每月 ${part} 号`;\r\n if (part.includes(\"/\")) {\r\n const [s, i] = part.split(\"/\");\r\n return `从 ${s} 号开始每 ${i} 天`;\r\n }\r\n if (part.includes(\"-\")) {\r\n const [s, e] = part.split(\"-\");\r\n return `${s} 号到 ${e} 号`;\r\n }\r\n if (part.includes(\",\")) {\r\n return `每月 ${part} 号`;\r\n }\r\n return \"\";\r\n }\r\n\r\n /** 描述月字段 */\r\n function describeMonth(part: string): string {\r\n if (part === \"*\") return \"\";\r\n if (/^\\d+$/.test(part)) {\r\n const n = Number(part);\r\n return MONTH_LABELS[n] ? `${MONTH_LABELS[n]}` : `${n} 月`;\r\n }\r\n if (part.includes(\"/\")) {\r\n const [s, i] = part.split(\"/\");\r\n return `从 ${s} 月开始每 ${i} 个月`;\r\n }\r\n if (part.includes(\"-\")) {\r\n const [s, e] = part.split(\"-\");\r\n return `${s} 月到 ${e} 月`;\r\n }\r\n if (part.includes(\",\")) {\r\n const months = part\r\n .split(\",\")\r\n .map((n) => MONTH_LABELS[Number(n)] || `${n}月`)\r\n .join(\"、\");\r\n return months;\r\n }\r\n return \"\";\r\n }\r\n\r\n /** 描述周字段 */\r\n function describeWeek(part: string): string {\r\n if (part === \"*\" || part === \"?\") return \"\";\r\n if (/^\\d+$/.test(part)) return `每${weekLabel(part)}`;\r\n if (part.includes(\"/\"))\r\n return `从${weekLabel(part.split(\"/\")[0])}开始每 ${part.split(\"/\")[1]} 天`;\r\n if (part.includes(\"-\"))\r\n return `${weekLabel(part.split(\"-\")[0])}到${weekLabel(part.split(\"-\")[1])}`;\r\n if (part.includes(\",\"))\r\n return `每${part.split(\",\").map(weekLabel).join(\"、\")}`;\r\n return \"\";\r\n }\r\n\r\n /** 通用字段描述 */\r\n function describeFieldGeneric(part: string, unit: string): string {\r\n if (part.includes(\"/\")) {\r\n const [s, i] = part.split(\"/\");\r\n const startDesc = s === \"*\" || s === \"0\" ? \"\" : `从第 ${s} ${unit}开始`;\r\n return `${startDesc}每 ${i} ${unit}`;\r\n }\r\n if (part.includes(\"-\")) {\r\n const [s, e] = part.split(\"-\");\r\n return `${s} ${unit}到 ${e} ${unit}`;\r\n }\r\n if (part.includes(\",\")) {\r\n return `第 ${part} ${unit}`;\r\n }\r\n if (/^\\d+$/.test(part)) {\r\n return `${part.padStart(2, \"0\")}`;\r\n }\r\n return \"\";\r\n }\r\n\r\n return {\r\n description,\r\n };\r\n}\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 字段值网格(始终可见,根据模式自动高亮对应值)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-field-editor\">\r\n <div class=\"cron-field-editor__grid\" :style=\"{ '--cols': gridColumns }\">\r\n <div\r\n v-for=\"item in valueOptions\"\r\n :key=\"item.value\"\r\n class=\"cron-field-editor__cell\"\r\n :class=\"{\r\n 'cron-field-editor__cell--on': highlightedValues.has(item.value),\r\n 'cron-field-editor__cell--pick': modelValue.mode === 'specific',\r\n }\"\r\n @click=\"handleCellClick(item.value)\"\r\n >\r\n {{ item.label }}\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from \"vue\";\r\nimport type { CronFieldMeta, CronFieldValue } from \"../types\";\r\n\r\ninterface Props {\r\n modelValue: CronFieldValue;\r\n meta: CronFieldMeta;\r\n}\r\n\r\nconst props = defineProps<Props>();\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: CronFieldValue];\r\n}>();\r\n\r\n/** 网格列数 */\r\nconst gridColumns = computed(() => {\r\n switch (props.meta.type) {\r\n case \"second\":\r\n case \"minute\":\r\n return 10;\r\n case \"hour\":\r\n return 12;\r\n case \"day\":\r\n return 7;\r\n case \"month\":\r\n return 6;\r\n case \"week\":\r\n return 7;\r\n default:\r\n return 10;\r\n }\r\n});\r\n\r\n/** 可选值列表 */\r\nconst valueOptions = computed(() => {\r\n const items: { value: number; label: string }[] = [];\r\n for (let i = props.meta.min; i <= props.meta.max; i++) {\r\n items.push({\r\n value: i,\r\n label: props.meta.valueLabels?.[i] ?? String(i),\r\n });\r\n }\r\n return items;\r\n});\r\n\r\n/** 根据当前模式计算高亮值集合 */\r\nconst highlightedValues = computed(() => {\r\n const { modelValue: f, meta } = props;\r\n const set = new Set<number>();\r\n switch (f.mode) {\r\n case \"every\":\r\n for (let i = meta.min; i <= meta.max; i++) set.add(i);\r\n break;\r\n case \"none\":\r\n break;\r\n case \"range\":\r\n for (let i = f.rangeStart; i <= f.rangeEnd; i++) set.add(i);\r\n break;\r\n case \"step\":\r\n for (let i = f.stepStart; i <= meta.max; i += f.stepInterval) set.add(i);\r\n break;\r\n case \"specific\":\r\n f.specificValues.forEach((v) => set.add(v));\r\n break;\r\n }\r\n return set;\r\n});\r\n\r\n/** 点击单元格(仅 specific 模式生效) */\r\nfunction handleCellClick(value: number) {\r\n if (props.modelValue.mode !== \"specific\") return;\r\n const current = [...props.modelValue.specificValues];\r\n const idx = current.indexOf(value);\r\n if (idx >= 0) current.splice(idx, 1);\r\n else current.push(value);\r\n emit(\"update:modelValue\", {\r\n ...props.modelValue,\r\n specificValues: current,\r\n });\r\n}\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-field-editor {\r\n &__grid {\r\n display: grid;\r\n grid-template-columns: repeat(var(--cols, 10), 1fr);\r\n gap: 4px;\r\n }\r\n\r\n &__cell {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n height: 34px;\r\n border-radius: 6px;\r\n font-size: 13px;\r\n font-variant-numeric: tabular-nums;\r\n transition: all var(--c-transition, 0.2s ease);\r\n user-select: none;\r\n color: var(--c-text-2);\r\n\r\n /* 非交互高亮(every / range / step 的视觉反馈) */\r\n &--on:not(&--pick) {\r\n background: color-mix(in srgb, var(--c-primary) 12%, transparent);\r\n color: var(--c-primary);\r\n }\r\n\r\n /* 可交互模式(specific) */\r\n &--pick {\r\n cursor: pointer;\r\n\r\n &:hover:not(.cron-field-editor__cell--on) {\r\n background: var(--c-bg-card);\r\n }\r\n\r\n &.cron-field-editor__cell--on {\r\n background: var(--c-primary);\r\n color: #fff;\r\n font-weight: 600;\r\n }\r\n }\r\n }\r\n}\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 字段值网格(始终可见,根据模式自动高亮对应值)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-field-editor\">\r\n <div class=\"cron-field-editor__grid\" :style=\"{ '--cols': gridColumns }\">\r\n <div\r\n v-for=\"item in valueOptions\"\r\n :key=\"item.value\"\r\n class=\"cron-field-editor__cell\"\r\n :class=\"{\r\n 'cron-field-editor__cell--on': highlightedValues.has(item.value),\r\n 'cron-field-editor__cell--pick': modelValue.mode === 'specific',\r\n }\"\r\n @click=\"handleCellClick(item.value)\"\r\n >\r\n {{ item.label }}\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from \"vue\";\r\nimport type { CronFieldMeta, CronFieldValue } from \"../types\";\r\n\r\ninterface Props {\r\n modelValue: CronFieldValue;\r\n meta: CronFieldMeta;\r\n}\r\n\r\nconst props = defineProps<Props>();\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: CronFieldValue];\r\n}>();\r\n\r\n/** 网格列数 */\r\nconst gridColumns = computed(() => {\r\n switch (props.meta.type) {\r\n case \"second\":\r\n case \"minute\":\r\n return 10;\r\n case \"hour\":\r\n return 12;\r\n case \"day\":\r\n return 7;\r\n case \"month\":\r\n return 6;\r\n case \"week\":\r\n return 7;\r\n default:\r\n return 10;\r\n }\r\n});\r\n\r\n/** 可选值列表 */\r\nconst valueOptions = computed(() => {\r\n const items: { value: number; label: string }[] = [];\r\n for (let i = props.meta.min; i <= props.meta.max; i++) {\r\n items.push({\r\n value: i,\r\n label: props.meta.valueLabels?.[i] ?? String(i),\r\n });\r\n }\r\n return items;\r\n});\r\n\r\n/** 根据当前模式计算高亮值集合 */\r\nconst highlightedValues = computed(() => {\r\n const { modelValue: f, meta } = props;\r\n const set = new Set<number>();\r\n switch (f.mode) {\r\n case \"every\":\r\n for (let i = meta.min; i <= meta.max; i++) set.add(i);\r\n break;\r\n case \"none\":\r\n break;\r\n case \"range\":\r\n for (let i = f.rangeStart; i <= f.rangeEnd; i++) set.add(i);\r\n break;\r\n case \"step\":\r\n for (let i = f.stepStart; i <= meta.max; i += f.stepInterval) set.add(i);\r\n break;\r\n case \"specific\":\r\n f.specificValues.forEach((v) => set.add(v));\r\n break;\r\n }\r\n return set;\r\n});\r\n\r\n/** 点击单元格(仅 specific 模式生效) */\r\nfunction handleCellClick(value: number) {\r\n if (props.modelValue.mode !== \"specific\") return;\r\n const current = [...props.modelValue.specificValues];\r\n const idx = current.indexOf(value);\r\n if (idx >= 0) current.splice(idx, 1);\r\n else current.push(value);\r\n emit(\"update:modelValue\", {\r\n ...props.modelValue,\r\n specificValues: current,\r\n });\r\n}\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-field-editor {\r\n &__grid {\r\n display: grid;\r\n grid-template-columns: repeat(var(--cols, 10), 1fr);\r\n gap: 4px;\r\n }\r\n\r\n &__cell {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n height: 34px;\r\n border-radius: 6px;\r\n font-size: 13px;\r\n font-variant-numeric: tabular-nums;\r\n transition: all var(--c-transition, 0.2s ease);\r\n user-select: none;\r\n color: var(--c-text-2);\r\n\r\n /* 非交互高亮(every / range / step 的视觉反馈) */\r\n &--on:not(&--pick) {\r\n background: color-mix(in srgb, var(--c-primary) 12%, transparent);\r\n color: var(--c-primary);\r\n }\r\n\r\n /* 可交互模式(specific) */\r\n &--pick {\r\n cursor: pointer;\r\n\r\n &:hover:not(.cron-field-editor__cell--on) {\r\n background: var(--c-bg-card);\r\n }\r\n\r\n &.cron-field-editor__cell--on {\r\n background: var(--c-primary);\r\n color: #fff;\r\n font-weight: 600;\r\n }\r\n }\r\n }\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 字段值网格(始终可见,根据模式自动高亮对应值)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-field-editor\">\r\n <div class=\"cron-field-editor__grid\" :style=\"{ '--cols': gridColumns }\">\r\n <div\r\n v-for=\"item in valueOptions\"\r\n :key=\"item.value\"\r\n class=\"cron-field-editor__cell\"\r\n :class=\"{\r\n 'cron-field-editor__cell--on': highlightedValues.has(item.value),\r\n 'cron-field-editor__cell--pick': modelValue.mode === 'specific',\r\n }\"\r\n @click=\"handleCellClick(item.value)\"\r\n >\r\n {{ item.label }}\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from \"vue\";\r\nimport type { CronFieldMeta, CronFieldValue } from \"../types\";\r\n\r\ninterface Props {\r\n modelValue: CronFieldValue;\r\n meta: CronFieldMeta;\r\n}\r\n\r\nconst props = defineProps<Props>();\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: CronFieldValue];\r\n}>();\r\n\r\n/** 网格列数 */\r\nconst gridColumns = computed(() => {\r\n switch (props.meta.type) {\r\n case \"second\":\r\n case \"minute\":\r\n return 10;\r\n case \"hour\":\r\n return 12;\r\n case \"day\":\r\n return 7;\r\n case \"month\":\r\n return 6;\r\n case \"week\":\r\n return 7;\r\n default:\r\n return 10;\r\n }\r\n});\r\n\r\n/** 可选值列表 */\r\nconst valueOptions = computed(() => {\r\n const items: { value: number; label: string }[] = [];\r\n for (let i = props.meta.min; i <= props.meta.max; i++) {\r\n items.push({\r\n value: i,\r\n label: props.meta.valueLabels?.[i] ?? String(i),\r\n });\r\n }\r\n return items;\r\n});\r\n\r\n/** 根据当前模式计算高亮值集合 */\r\nconst highlightedValues = computed(() => {\r\n const { modelValue: f, meta } = props;\r\n const set = new Set<number>();\r\n switch (f.mode) {\r\n case \"every\":\r\n for (let i = meta.min; i <= meta.max; i++) set.add(i);\r\n break;\r\n case \"none\":\r\n break;\r\n case \"range\":\r\n for (let i = f.rangeStart; i <= f.rangeEnd; i++) set.add(i);\r\n break;\r\n case \"step\":\r\n for (let i = f.stepStart; i <= meta.max; i += f.stepInterval) set.add(i);\r\n break;\r\n case \"specific\":\r\n f.specificValues.forEach((v) => set.add(v));\r\n break;\r\n }\r\n return set;\r\n});\r\n\r\n/** 点击单元格(仅 specific 模式生效) */\r\nfunction handleCellClick(value: number) {\r\n if (props.modelValue.mode !== \"specific\") return;\r\n const current = [...props.modelValue.specificValues];\r\n const idx = current.indexOf(value);\r\n if (idx >= 0) current.splice(idx, 1);\r\n else current.push(value);\r\n emit(\"update:modelValue\", {\r\n ...props.modelValue,\r\n specificValues: current,\r\n });\r\n}\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-field-editor {\r\n &__grid {\r\n display: grid;\r\n grid-template-columns: repeat(var(--cols, 10), 1fr);\r\n gap: 4px;\r\n }\r\n\r\n &__cell {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n height: 34px;\r\n border-radius: 6px;\r\n font-size: 13px;\r\n font-variant-numeric: tabular-nums;\r\n transition: all var(--c-transition, 0.2s ease);\r\n user-select: none;\r\n color: var(--c-text-2);\r\n\r\n /* 非交互高亮(every / range / step 的视觉反馈) */\r\n &--on:not(&--pick) {\r\n background: color-mix(in srgb, var(--c-primary) 12%, transparent);\r\n color: var(--c-primary);\r\n }\r\n\r\n /* 可交互模式(specific) */\r\n &--pick {\r\n cursor: pointer;\r\n\r\n &:hover:not(.cron-field-editor__cell--on) {\r\n background: var(--c-bg-card);\r\n }\r\n\r\n &.cron-field-editor__cell--on {\r\n background: var(--c-primary);\r\n color: #fff;\r\n font-weight: 600;\r\n }\r\n }\r\n }\r\n}\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 执行时间预览(紧凑布局)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-preview\">\r\n <div class=\"cron-preview__header\">\r\n <C_Icon name=\"mdi:calendar-clock\" :size=\"15\" />\r\n <span>未来执行</span>\r\n <NSpin v-if=\"computing\" :size=\"14\" />\r\n </div>\r\n\r\n <NScrollbar style=\"max-height: 220px\">\r\n <div v-if=\"nextExecutions.length > 0\" class=\"cron-preview__list\">\r\n <div\r\n v-for=\"(date, index) in nextExecutions\"\r\n :key=\"index\"\r\n class=\"cron-preview__item\"\r\n >\r\n <span class=\"cron-preview__idx\">{{ index + 1 }}</span>\r\n <span class=\"cron-preview__date\">{{ formatDate(date) }}</span>\r\n <span class=\"cron-preview__week\">{{ formatWeekDay(date) }}</span>\r\n </div>\r\n </div>\r\n <NEmpty v-else size=\"small\" description=\"暂无匹配\" />\r\n </NScrollbar>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport C_Icon from \"../../C_Icon/index.vue\";\r\n\r\ninterface Props {\r\n nextExecutions: Date[];\r\n computing: boolean;\r\n count: number;\r\n formatDate: (date: Date) => string;\r\n formatWeekDay: (date: Date) => string;\r\n}\r\n\r\ndefineProps<Props>();\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-preview {\r\n &__header {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n margin-bottom: 6px;\r\n color: var(--c-text-1);\r\n }\r\n\r\n &__list {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 2px;\r\n }\r\n\r\n &__item {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 3px 4px;\r\n border-radius: 4px;\r\n font-size: 12px;\r\n transition: background var(--c-transition, 0.2s ease);\r\n\r\n &:hover {\r\n background: var(--c-bg-card);\r\n }\r\n }\r\n\r\n &__idx {\r\n width: 16px;\r\n text-align: center;\r\n color: var(--c-text-4);\r\n flex-shrink: 0;\r\n font-size: 11px;\r\n }\r\n\r\n &__date {\r\n font-family: \"Courier New\", Courier, monospace;\r\n flex: 1;\r\n font-size: 12px;\r\n }\r\n\r\n &__week {\r\n color: var(--c-text-4);\r\n font-size: 12px;\r\n flex-shrink: 0;\r\n }\r\n}\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 执行时间预览(紧凑布局)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-preview\">\r\n <div class=\"cron-preview__header\">\r\n <C_Icon name=\"mdi:calendar-clock\" :size=\"15\" />\r\n <span>未来执行</span>\r\n <NSpin v-if=\"computing\" :size=\"14\" />\r\n </div>\r\n\r\n <NScrollbar style=\"max-height: 220px\">\r\n <div v-if=\"nextExecutions.length > 0\" class=\"cron-preview__list\">\r\n <div\r\n v-for=\"(date, index) in nextExecutions\"\r\n :key=\"index\"\r\n class=\"cron-preview__item\"\r\n >\r\n <span class=\"cron-preview__idx\">{{ index + 1 }}</span>\r\n <span class=\"cron-preview__date\">{{ formatDate(date) }}</span>\r\n <span class=\"cron-preview__week\">{{ formatWeekDay(date) }}</span>\r\n </div>\r\n </div>\r\n <NEmpty v-else size=\"small\" description=\"暂无匹配\" />\r\n </NScrollbar>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport C_Icon from \"../../C_Icon/index.vue\";\r\n\r\ninterface Props {\r\n nextExecutions: Date[];\r\n computing: boolean;\r\n count: number;\r\n formatDate: (date: Date) => string;\r\n formatWeekDay: (date: Date) => string;\r\n}\r\n\r\ndefineProps<Props>();\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-preview {\r\n &__header {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n margin-bottom: 6px;\r\n color: var(--c-text-1);\r\n }\r\n\r\n &__list {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 2px;\r\n }\r\n\r\n &__item {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 3px 4px;\r\n border-radius: 4px;\r\n font-size: 12px;\r\n transition: background var(--c-transition, 0.2s ease);\r\n\r\n &:hover {\r\n background: var(--c-bg-card);\r\n }\r\n }\r\n\r\n &__idx {\r\n width: 16px;\r\n text-align: center;\r\n color: var(--c-text-4);\r\n flex-shrink: 0;\r\n font-size: 11px;\r\n }\r\n\r\n &__date {\r\n font-family: \"Courier New\", Courier, monospace;\r\n flex: 1;\r\n font-size: 12px;\r\n }\r\n\r\n &__week {\r\n color: var(--c-text-4);\r\n font-size: 12px;\r\n flex-shrink: 0;\r\n }\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 执行时间预览(紧凑布局)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-preview\">\r\n <div class=\"cron-preview__header\">\r\n <C_Icon name=\"mdi:calendar-clock\" :size=\"15\" />\r\n <span>未来执行</span>\r\n <NSpin v-if=\"computing\" :size=\"14\" />\r\n </div>\r\n\r\n <NScrollbar style=\"max-height: 220px\">\r\n <div v-if=\"nextExecutions.length > 0\" class=\"cron-preview__list\">\r\n <div\r\n v-for=\"(date, index) in nextExecutions\"\r\n :key=\"index\"\r\n class=\"cron-preview__item\"\r\n >\r\n <span class=\"cron-preview__idx\">{{ index + 1 }}</span>\r\n <span class=\"cron-preview__date\">{{ formatDate(date) }}</span>\r\n <span class=\"cron-preview__week\">{{ formatWeekDay(date) }}</span>\r\n </div>\r\n </div>\r\n <NEmpty v-else size=\"small\" description=\"暂无匹配\" />\r\n </NScrollbar>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport C_Icon from \"../../C_Icon/index.vue\";\r\n\r\ninterface Props {\r\n nextExecutions: Date[];\r\n computing: boolean;\r\n count: number;\r\n formatDate: (date: Date) => string;\r\n formatWeekDay: (date: Date) => string;\r\n}\r\n\r\ndefineProps<Props>();\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-preview {\r\n &__header {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n margin-bottom: 6px;\r\n color: var(--c-text-1);\r\n }\r\n\r\n &__list {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 2px;\r\n }\r\n\r\n &__item {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 3px 4px;\r\n border-radius: 4px;\r\n font-size: 12px;\r\n transition: background var(--c-transition, 0.2s ease);\r\n\r\n &:hover {\r\n background: var(--c-bg-card);\r\n }\r\n }\r\n\r\n &__idx {\r\n width: 16px;\r\n text-align: center;\r\n color: var(--c-text-4);\r\n flex-shrink: 0;\r\n font-size: 11px;\r\n }\r\n\r\n &__date {\r\n font-family: \"Courier New\", Courier, monospace;\r\n flex: 1;\r\n font-size: 12px;\r\n }\r\n\r\n &__week {\r\n color: var(--c-text-4);\r\n font-size: 12px;\r\n flex-shrink: 0;\r\n }\r\n}\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 常用模板(底部卡片网格)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-templates\">\r\n <div class=\"cron-templates__header\">\r\n <C_Icon name=\"mdi:lightning-bolt\" :size=\"15\" />\r\n <span>常用模板</span>\r\n </div>\r\n\r\n <div class=\"cron-templates__cards\">\r\n <div\r\n v-for=\"template in templates\"\r\n :key=\"template.value\"\r\n class=\"cron-templates__card\"\r\n :class=\"{\r\n 'cron-templates__card--active': template.value === currentValue,\r\n }\"\r\n @click=\"$emit('select', template.value)\"\r\n >\r\n <div class=\"cron-templates__card-name\">{{ template.label }}</div>\r\n <div class=\"cron-templates__card-expr\">{{ template.value }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport C_Icon from \"../../C_Icon/index.vue\";\r\nimport type { CronTemplate } from \"../types\";\r\n\r\ninterface Props {\r\n templates: CronTemplate[];\r\n currentValue: string;\r\n}\r\n\r\ndefineProps<Props>();\r\ndefineEmits<{\r\n select: [value: string];\r\n}>();\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-templates {\r\n &__header {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n margin-bottom: 10px;\r\n color: var(--c-text-1);\r\n }\r\n\r\n &__cards {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\r\n gap: 8px;\r\n }\r\n\r\n &__card {\r\n padding: 10px 12px;\r\n border-radius: 8px;\r\n border: 1px solid var(--c-border);\r\n cursor: pointer;\r\n transition: all var(--c-transition, 0.2s ease);\r\n\r\n &:hover {\r\n border-color: var(--c-primary);\r\n background: color-mix(in srgb, var(--c-primary) 4%, transparent);\r\n }\r\n\r\n &--active {\r\n border-color: var(--c-primary);\r\n background: color-mix(in srgb, var(--c-primary) 8%, transparent);\r\n }\r\n }\r\n\r\n &__card-name {\r\n font-size: 13px;\r\n font-weight: 500;\r\n line-height: 1.4;\r\n }\r\n\r\n &__card-expr {\r\n font-family: \"Courier New\", Courier, monospace;\r\n font-size: 11px;\r\n color: var(--c-text-4);\r\n margin-top: 2px;\r\n }\r\n}\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 常用模板(底部卡片网格)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-templates\">\r\n <div class=\"cron-templates__header\">\r\n <C_Icon name=\"mdi:lightning-bolt\" :size=\"15\" />\r\n <span>常用模板</span>\r\n </div>\r\n\r\n <div class=\"cron-templates__cards\">\r\n <div\r\n v-for=\"template in templates\"\r\n :key=\"template.value\"\r\n class=\"cron-templates__card\"\r\n :class=\"{\r\n 'cron-templates__card--active': template.value === currentValue,\r\n }\"\r\n @click=\"$emit('select', template.value)\"\r\n >\r\n <div class=\"cron-templates__card-name\">{{ template.label }}</div>\r\n <div class=\"cron-templates__card-expr\">{{ template.value }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport C_Icon from \"../../C_Icon/index.vue\";\r\nimport type { CronTemplate } from \"../types\";\r\n\r\ninterface Props {\r\n templates: CronTemplate[];\r\n currentValue: string;\r\n}\r\n\r\ndefineProps<Props>();\r\ndefineEmits<{\r\n select: [value: string];\r\n}>();\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-templates {\r\n &__header {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n margin-bottom: 10px;\r\n color: var(--c-text-1);\r\n }\r\n\r\n &__cards {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\r\n gap: 8px;\r\n }\r\n\r\n &__card {\r\n padding: 10px 12px;\r\n border-radius: 8px;\r\n border: 1px solid var(--c-border);\r\n cursor: pointer;\r\n transition: all var(--c-transition, 0.2s ease);\r\n\r\n &:hover {\r\n border-color: var(--c-primary);\r\n background: color-mix(in srgb, var(--c-primary) 4%, transparent);\r\n }\r\n\r\n &--active {\r\n border-color: var(--c-primary);\r\n background: color-mix(in srgb, var(--c-primary) 8%, transparent);\r\n }\r\n }\r\n\r\n &__card-name {\r\n font-size: 13px;\r\n font-weight: 500;\r\n line-height: 1.4;\r\n }\r\n\r\n &__card-expr {\r\n font-family: \"Courier New\", Courier, monospace;\r\n font-size: 11px;\r\n color: var(--c-text-4);\r\n margin-top: 2px;\r\n }\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 常用模板(底部卡片网格)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"cron-templates\">\r\n <div class=\"cron-templates__header\">\r\n <C_Icon name=\"mdi:lightning-bolt\" :size=\"15\" />\r\n <span>常用模板</span>\r\n </div>\r\n\r\n <div class=\"cron-templates__cards\">\r\n <div\r\n v-for=\"template in templates\"\r\n :key=\"template.value\"\r\n class=\"cron-templates__card\"\r\n :class=\"{\r\n 'cron-templates__card--active': template.value === currentValue,\r\n }\"\r\n @click=\"$emit('select', template.value)\"\r\n >\r\n <div class=\"cron-templates__card-name\">{{ template.label }}</div>\r\n <div class=\"cron-templates__card-expr\">{{ template.value }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport C_Icon from \"../../C_Icon/index.vue\";\r\nimport type { CronTemplate } from \"../types\";\r\n\r\ninterface Props {\r\n templates: CronTemplate[];\r\n currentValue: string;\r\n}\r\n\r\ndefineProps<Props>();\r\ndefineEmits<{\r\n select: [value: string];\r\n}>();\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.cron-templates {\r\n &__header {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-weight: 600;\r\n font-size: 13px;\r\n margin-bottom: 10px;\r\n color: var(--c-text-1);\r\n }\r\n\r\n &__cards {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\r\n gap: 8px;\r\n }\r\n\r\n &__card {\r\n padding: 10px 12px;\r\n border-radius: 8px;\r\n border: 1px solid var(--c-border);\r\n cursor: pointer;\r\n transition: all var(--c-transition, 0.2s ease);\r\n\r\n &:hover {\r\n border-color: var(--c-primary);\r\n background: color-mix(in srgb, var(--c-primary) 4%, transparent);\r\n }\r\n\r\n &--active {\r\n border-color: var(--c-primary);\r\n background: color-mix(in srgb, var(--c-primary) 8%, transparent);\r\n }\r\n }\r\n\r\n &__card-name {\r\n font-size: 13px;\r\n font-weight: 500;\r\n line-height: 1.4;\r\n }\r\n\r\n &__card-expr {\r\n font-family: \"Courier New\", Courier, monospace;\r\n font-size: 11px;\r\n color: var(--c-text-4);\r\n margin-top: 2px;\r\n }\r\n}\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 表达式编辑器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"c-cron\" :style=\"{ height: containerHeight }\">\r\n <!-- ═══════ 顶部 ═══════ -->\r\n <div class=\"c-cron__header\">\r\n <!-- 标题行 -->\r\n <div class=\"c-cron__title-row\">\r\n <div class=\"c-cron__title\">\r\n <C_Icon name=\"mdi:clock-edit-outline\" :size=\"18\" />\r\n <span>Cron 表达式</span>\r\n </div>\r\n <NTag :type=\"validation.valid ? 'success' : 'error'\" size=\"small\" round>\r\n <template #icon>\r\n <C_Icon\r\n :name=\"validation.valid ? 'mdi:check-circle' : 'mdi:alert-circle'\"\r\n />\r\n </template>\r\n {{ validation.valid ? \"合法\" : \"错误\" }}\r\n </NTag>\r\n </div>\r\n\r\n <!-- 分段式字段选择器 -->\r\n <div class=\"c-cron__segments\">\r\n <div\r\n v-for=\"meta in visibleFields\"\r\n :key=\"meta.type\"\r\n class=\"c-cron__segment\"\r\n :class=\"{\r\n 'c-cron__segment--active': activeField === meta.type,\r\n 'c-cron__segment--wildcard':\r\n fieldExpressions[meta.type] === '*' ||\r\n fieldExpressions[meta.type] === '?',\r\n }\"\r\n @click=\"activeField = meta.type\"\r\n >\r\n <div class=\"c-cron__segment-value\">\r\n {{ fieldExpressions[meta.type] }}\r\n </div>\r\n <div class=\"c-cron__segment-label\">{{ meta.label }}</div>\r\n </div>\r\n </div>\r\n\r\n <!-- 表达式行:输入 + 重置 + 描述 -->\r\n <div class=\"c-cron__expr-row\">\r\n <NInput\r\n :value=\"manualInput\"\r\n :status=\"validation.valid ? undefined : 'error'\"\r\n placeholder=\"秒 分 时 日 月 周\"\r\n :disabled=\"props.disabled\"\r\n font=\"mono\"\r\n size=\"small\"\r\n clearable\r\n class=\"c-cron__expr-input\"\r\n @update:value=\"handleManualInput\"\r\n @blur=\"handleManualBlur\"\r\n @keydown.enter=\"handleManualBlur\"\r\n >\r\n <template #prefix>\r\n <C_Icon name=\"mdi:console\" :size=\"14\" style=\"opacity: 0.4\" />\r\n </template>\r\n </NInput>\r\n <NButton\r\n size=\"small\"\r\n quaternary\r\n :disabled=\"props.disabled\"\r\n @click=\"handleReset\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:refresh\" />\r\n </template>\r\n </NButton>\r\n <div class=\"c-cron__expr-desc\">\r\n <span v-if=\"validation.valid\" class=\"c-cron__description\">\r\n {{ description }}\r\n </span>\r\n <span v-else class=\"c-cron__error\">\r\n {{ validation.message }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ═══════ 主内容 ═══════ -->\r\n <div class=\"c-cron__body\">\r\n <!-- 左侧:值网格 -->\r\n <div class=\"c-cron__main\">\r\n <CronFieldEditor\r\n v-for=\"meta in visibleFields\"\r\n v-show=\"activeField === meta.type\"\r\n :key=\"meta.type\"\r\n :model-value=\"cronValue[meta.type]\"\r\n :meta=\"meta\"\r\n @update:model-value=\"(v) => handleFieldChange(meta.type, v)\"\r\n />\r\n </div>\r\n\r\n <!-- 右侧:控制面板 -->\r\n <div class=\"c-cron__panel\">\r\n <NRadioGroup\r\n :value=\"activeFieldValue.mode\"\r\n size=\"small\"\r\n @update:value=\"handleActiveFieldModeChange\"\r\n >\r\n <NRadioButton value=\"every\">\r\n 每{{ activeFieldMeta.label }}\r\n </NRadioButton>\r\n <NRadioButton\r\n v-if=\"activeField === 'day' || activeField === 'week'\"\r\n value=\"none\"\r\n >\r\n 不指定\r\n </NRadioButton>\r\n <NRadioButton value=\"range\">范围</NRadioButton>\r\n <NRadioButton value=\"step\">步进</NRadioButton>\r\n <NRadioButton value=\"specific\">指定</NRadioButton>\r\n </NRadioGroup>\r\n\r\n <!-- 范围配置 -->\r\n <div v-if=\"activeFieldValue.mode === 'range'\" class=\"c-cron__config\">\r\n <div class=\"c-cron__config-row\">\r\n <span>从</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.rangeStart\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n rangeStart: v ?? activeFieldMeta.min,\r\n })\r\n \"\r\n />\r\n <span>到</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.rangeEnd\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n rangeEnd: v ?? activeFieldMeta.max,\r\n })\r\n \"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 步进配置 -->\r\n <div v-if=\"activeFieldValue.mode === 'step'\" class=\"c-cron__config\">\r\n <div class=\"c-cron__config-row\">\r\n <span>从第</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.stepStart\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n stepStart: v ?? activeFieldMeta.min,\r\n })\r\n \"\r\n />\r\n <span>{{ activeFieldMeta.label }}起,每</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.stepInterval\"\r\n :min=\"1\"\r\n :max=\"activeFieldMeta.max - activeFieldMeta.min + 1\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({ stepInterval: v ?? 1 })\r\n \"\r\n />\r\n <span>{{ activeFieldMeta.label }}执行</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 指定快捷操作 -->\r\n <div v-if=\"activeFieldValue.mode === 'specific'\" class=\"c-cron__quick\">\r\n <a @click=\"handleSelectAll\">全选</a>\r\n <span class=\"c-cron__quick-sep\">·</span>\r\n <a @click=\"handleClearAll\">清空</a>\r\n <span\r\n v-if=\"activeFieldValue.specificValues.length > 0\"\r\n class=\"c-cron__quick-count\"\r\n >\r\n 已选 {{ activeFieldValue.specificValues.length }}\r\n </span>\r\n </div>\r\n\r\n <!-- 执行预览 -->\r\n <template v-if=\"props.showPreview\">\r\n <div class=\"c-cron__panel-line\" />\r\n <CronPreview\r\n :next-executions=\"nextExecutions\"\r\n :computing=\"computing\"\r\n :count=\"props.previewCount ?? 5\"\r\n :format-date=\"formatDate\"\r\n :format-week-day=\"formatWeekDay\"\r\n />\r\n </template>\r\n </div>\r\n </div>\r\n\r\n <!-- ═══════ 底部模板 ═══════ -->\r\n <div v-if=\"props.showTemplates\" class=\"c-cron__footer\">\r\n <CronTemplates\r\n :templates=\"CRON_TEMPLATES\"\r\n :current-value=\"expression\"\r\n @select=\"handleTemplateSelect\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, onMounted } from \"vue\";\r\nimport type {\r\n CronFieldMode,\r\n CronFieldType,\r\n CronFieldValue,\r\n CronProps,\r\n CronValidation,\r\n} from \"./types\";\r\nimport {\r\n CRON_FIELD_META,\r\n CRON_TEMPLATES,\r\n DEFAULT_CRON_EXPRESSION,\r\n} from \"./constants\";\r\nimport { useCronParser } from \"./composables/useCronParser\";\r\nimport { useCronPreview } from \"./composables/useCronPreview\";\r\nimport { useCronDescription } from \"./composables/useCronDescription\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport CronFieldEditor from \"./components/CronFieldEditor.vue\";\r\nimport CronPreview from \"./components/CronPreview.vue\";\r\nimport CronTemplates from \"./components/CronTemplates.vue\";\r\n\r\ndefineOptions({ name: \"C_Cron\" });\r\n\r\n/* ─── Props & Emits ─────────────────────────── */\r\n\r\nconst props = withDefaults(defineProps<CronProps>(), {\r\n modelValue: DEFAULT_CRON_EXPRESSION,\r\n disabled: false,\r\n previewCount: 10,\r\n showTemplates: true,\r\n showPreview: true,\r\n showSecond: true,\r\n height: \"auto\",\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: string];\r\n change: [value: string];\r\n \"validation-change\": [result: CronValidation];\r\n}>();\r\n\r\n/* ─── 组合函数 ──────────────────────────────── */\r\n\r\nconst {\r\n cronValue,\r\n expression,\r\n validation,\r\n parse,\r\n validate,\r\n handleDayWeekExclusion,\r\n} = useCronParser();\r\n\r\nconst previewCount = computed(() => props.previewCount ?? 10);\r\nconst { nextExecutions, computing, formatDate, formatWeekDay } = useCronPreview(\r\n expression,\r\n validation,\r\n previewCount,\r\n);\r\n\r\nconst { description } = useCronDescription(expression, validation);\r\n\r\n/* ─── 本地状态 ──────────────────────────────── */\r\n\r\n/** 手动输入框值(与 expression 解耦,输入完成后同步) */\r\nconst manualInput = ref(props.modelValue || DEFAULT_CRON_EXPRESSION);\r\n\r\n/** 当前激活的字段 Tab */\r\nconst activeField = ref<CronFieldType>(props.showSecond ? \"second\" : \"minute\");\r\n\r\n/* ─── 容器高度 ──────────────────────────────── */\r\n\r\nconst containerHeight = computed(() => {\r\n if (typeof props.height === \"number\") return `${props.height}px`;\r\n return props.height;\r\n});\r\n\r\n/* ─── 可见字段(是否显示秒) ────────────────── */\r\n\r\nconst visibleFields = computed(() => {\r\n return props.showSecond\r\n ? CRON_FIELD_META\r\n : CRON_FIELD_META.filter((m) => m.type !== \"second\");\r\n});\r\n\r\n/* ─── 当前激活字段快捷访问 ─────────────────── */\r\n\r\n/** 当前激活字段元数据 */\r\nconst activeFieldMeta = computed(\r\n () => CRON_FIELD_META.find((m) => m.type === activeField.value)!,\r\n);\r\n\r\n/** 当前激活字段值 */\r\nconst activeFieldValue = computed(() => cronValue.value[activeField.value]);\r\n\r\n/* ─── 分段式表达式(逐字段计算) ────────────── */\r\n\r\n/** 计算单字段表达式文本 */\r\nfunction computeFieldExpr(f: CronFieldValue): string {\r\n switch (f.mode) {\r\n case \"every\":\r\n return \"*\";\r\n case \"none\":\r\n return \"?\";\r\n case \"range\":\r\n return `${f.rangeStart}-${f.rangeEnd}`;\r\n case \"step\":\r\n return `${f.stepStart}/${f.stepInterval}`;\r\n case \"specific\":\r\n return f.specificValues.length > 0\r\n ? [...f.specificValues].sort((a, b) => a - b).join(\",\")\r\n : \"*\";\r\n default:\r\n return \"*\";\r\n }\r\n}\r\n\r\n/** 各字段表达式映射 */\r\nconst fieldExpressions = computed(() => {\r\n const map = {} as Record<CronFieldType, string>;\r\n for (const meta of CRON_FIELD_META) {\r\n map[meta.type] = computeFieldExpr(cronValue.value[meta.type]);\r\n }\r\n return map;\r\n});\r\n\r\n/* ─── 初始化解析 ────────────────────────────── */\r\n\r\nonMounted(() => {\r\n const initial = props.modelValue || DEFAULT_CRON_EXPRESSION;\r\n parse(initial);\r\n manualInput.value = initial;\r\n});\r\n\r\n/* ─── 监听外部 v-model 变更 ─────────────────── */\r\n\r\nwatch(\r\n () => props.modelValue,\r\n (newVal) => {\r\n if (newVal && newVal !== expression.value) {\r\n parse(newVal);\r\n manualInput.value = newVal;\r\n }\r\n },\r\n);\r\n\r\n/* ─── 监听 showSecond 变更 ──────────────────── */\r\n\r\nwatch(\r\n () => props.showSecond,\r\n (show) => {\r\n if (!show && activeField.value === \"second\") {\r\n activeField.value = \"minute\";\r\n }\r\n },\r\n);\r\n\r\n/* ─── 监听内部表达式变更 → 同步到外部 ───────── */\r\n\r\nwatch(expression, (newExpr) => {\r\n manualInput.value = newExpr;\r\n emit(\"update:modelValue\", newExpr);\r\n emit(\"change\", newExpr);\r\n});\r\n\r\n/* ─── 监听校验状态变更 ──────────────────────── */\r\n\r\nwatch(validation, (v) => {\r\n emit(\"validation-change\", v);\r\n});\r\n\r\n/* ─── 字段变更处理 ──────────────────────────── */\r\n\r\n/** 字段编辑变更处理 */\r\nfunction handleFieldChange(type: CronFieldType, value: CronFieldValue) {\r\n cronValue.value[type] = value;\r\n if (type === \"day\" || type === \"week\") {\r\n handleDayWeekExclusion(type);\r\n }\r\n}\r\n\r\n/* ─── 右侧面板操作 ─────────────────────────── */\r\n\r\n/** 切换当前字段模式 */\r\nfunction handleActiveFieldModeChange(mode: CronFieldMode) {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n mode,\r\n });\r\n}\r\n\r\n/** 更新当前字段属性 */\r\nfunction handleActiveFieldUpdate(partial: Partial<CronFieldValue>) {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n ...partial,\r\n });\r\n}\r\n\r\n/** 全选当前字段所有值 */\r\nfunction handleSelectAll() {\r\n const { min, max } = activeFieldMeta.value;\r\n const allValues = Array.from({ length: max - min + 1 }, (_, i) => min + i);\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n specificValues: allValues,\r\n });\r\n}\r\n\r\n/** 清空当前字段所有选中值 */\r\nfunction handleClearAll() {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n specificValues: [],\r\n });\r\n}\r\n\r\n/* ─── 手动输入处理 ──────────────────────────── */\r\n\r\n/** 手动输入更新 */\r\nfunction handleManualInput(value: string) {\r\n manualInput.value = value;\r\n}\r\n\r\n/** 输入框失焦时同步 */\r\nfunction handleManualBlur() {\r\n const trimmed = manualInput.value.trim();\r\n if (trimmed && trimmed !== expression.value) {\r\n parse(trimmed);\r\n }\r\n}\r\n\r\n/* ─── 模板选择 ──────────────────────────────── */\r\n\r\n/** 选择常用模板 */\r\nfunction handleTemplateSelect(expr: string) {\r\n parse(expr);\r\n manualInput.value = expr;\r\n}\r\n\r\n/* ─── 重置 ──────────────────────────────────── */\r\n\r\n/** 重置为初始值 */\r\nfunction handleReset() {\r\n const initial = props.modelValue || DEFAULT_CRON_EXPRESSION;\r\n parse(initial);\r\n manualInput.value = initial;\r\n}\r\n\r\n/* ─── Expose ────────────────────────────────── */\r\n\r\ndefineExpose({\r\n getValue: () => expression.value,\r\n setValue: (expr: string) => {\r\n parse(expr);\r\n manualInput.value = expr;\r\n },\r\n reset: handleReset,\r\n validate: () => validate(),\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 表达式编辑器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"c-cron\" :style=\"{ height: containerHeight }\">\r\n <!-- ═══════ 顶部 ═══════ -->\r\n <div class=\"c-cron__header\">\r\n <!-- 标题行 -->\r\n <div class=\"c-cron__title-row\">\r\n <div class=\"c-cron__title\">\r\n <C_Icon name=\"mdi:clock-edit-outline\" :size=\"18\" />\r\n <span>Cron 表达式</span>\r\n </div>\r\n <NTag :type=\"validation.valid ? 'success' : 'error'\" size=\"small\" round>\r\n <template #icon>\r\n <C_Icon\r\n :name=\"validation.valid ? 'mdi:check-circle' : 'mdi:alert-circle'\"\r\n />\r\n </template>\r\n {{ validation.valid ? \"合法\" : \"错误\" }}\r\n </NTag>\r\n </div>\r\n\r\n <!-- 分段式字段选择器 -->\r\n <div class=\"c-cron__segments\">\r\n <div\r\n v-for=\"meta in visibleFields\"\r\n :key=\"meta.type\"\r\n class=\"c-cron__segment\"\r\n :class=\"{\r\n 'c-cron__segment--active': activeField === meta.type,\r\n 'c-cron__segment--wildcard':\r\n fieldExpressions[meta.type] === '*' ||\r\n fieldExpressions[meta.type] === '?',\r\n }\"\r\n @click=\"activeField = meta.type\"\r\n >\r\n <div class=\"c-cron__segment-value\">\r\n {{ fieldExpressions[meta.type] }}\r\n </div>\r\n <div class=\"c-cron__segment-label\">{{ meta.label }}</div>\r\n </div>\r\n </div>\r\n\r\n <!-- 表达式行:输入 + 重置 + 描述 -->\r\n <div class=\"c-cron__expr-row\">\r\n <NInput\r\n :value=\"manualInput\"\r\n :status=\"validation.valid ? undefined : 'error'\"\r\n placeholder=\"秒 分 时 日 月 周\"\r\n :disabled=\"props.disabled\"\r\n font=\"mono\"\r\n size=\"small\"\r\n clearable\r\n class=\"c-cron__expr-input\"\r\n @update:value=\"handleManualInput\"\r\n @blur=\"handleManualBlur\"\r\n @keydown.enter=\"handleManualBlur\"\r\n >\r\n <template #prefix>\r\n <C_Icon name=\"mdi:console\" :size=\"14\" style=\"opacity: 0.4\" />\r\n </template>\r\n </NInput>\r\n <NButton\r\n size=\"small\"\r\n quaternary\r\n :disabled=\"props.disabled\"\r\n @click=\"handleReset\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:refresh\" />\r\n </template>\r\n </NButton>\r\n <div class=\"c-cron__expr-desc\">\r\n <span v-if=\"validation.valid\" class=\"c-cron__description\">\r\n {{ description }}\r\n </span>\r\n <span v-else class=\"c-cron__error\">\r\n {{ validation.message }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ═══════ 主内容 ═══════ -->\r\n <div class=\"c-cron__body\">\r\n <!-- 左侧:值网格 -->\r\n <div class=\"c-cron__main\">\r\n <CronFieldEditor\r\n v-for=\"meta in visibleFields\"\r\n v-show=\"activeField === meta.type\"\r\n :key=\"meta.type\"\r\n :model-value=\"cronValue[meta.type]\"\r\n :meta=\"meta\"\r\n @update:model-value=\"(v) => handleFieldChange(meta.type, v)\"\r\n />\r\n </div>\r\n\r\n <!-- 右侧:控制面板 -->\r\n <div class=\"c-cron__panel\">\r\n <NRadioGroup\r\n :value=\"activeFieldValue.mode\"\r\n size=\"small\"\r\n @update:value=\"handleActiveFieldModeChange\"\r\n >\r\n <NRadioButton value=\"every\">\r\n 每{{ activeFieldMeta.label }}\r\n </NRadioButton>\r\n <NRadioButton\r\n v-if=\"activeField === 'day' || activeField === 'week'\"\r\n value=\"none\"\r\n >\r\n 不指定\r\n </NRadioButton>\r\n <NRadioButton value=\"range\">范围</NRadioButton>\r\n <NRadioButton value=\"step\">步进</NRadioButton>\r\n <NRadioButton value=\"specific\">指定</NRadioButton>\r\n </NRadioGroup>\r\n\r\n <!-- 范围配置 -->\r\n <div v-if=\"activeFieldValue.mode === 'range'\" class=\"c-cron__config\">\r\n <div class=\"c-cron__config-row\">\r\n <span>从</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.rangeStart\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n rangeStart: v ?? activeFieldMeta.min,\r\n })\r\n \"\r\n />\r\n <span>到</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.rangeEnd\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n rangeEnd: v ?? activeFieldMeta.max,\r\n })\r\n \"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 步进配置 -->\r\n <div v-if=\"activeFieldValue.mode === 'step'\" class=\"c-cron__config\">\r\n <div class=\"c-cron__config-row\">\r\n <span>从第</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.stepStart\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n stepStart: v ?? activeFieldMeta.min,\r\n })\r\n \"\r\n />\r\n <span>{{ activeFieldMeta.label }}起,每</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.stepInterval\"\r\n :min=\"1\"\r\n :max=\"activeFieldMeta.max - activeFieldMeta.min + 1\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({ stepInterval: v ?? 1 })\r\n \"\r\n />\r\n <span>{{ activeFieldMeta.label }}执行</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 指定快捷操作 -->\r\n <div v-if=\"activeFieldValue.mode === 'specific'\" class=\"c-cron__quick\">\r\n <a @click=\"handleSelectAll\">全选</a>\r\n <span class=\"c-cron__quick-sep\">·</span>\r\n <a @click=\"handleClearAll\">清空</a>\r\n <span\r\n v-if=\"activeFieldValue.specificValues.length > 0\"\r\n class=\"c-cron__quick-count\"\r\n >\r\n 已选 {{ activeFieldValue.specificValues.length }}\r\n </span>\r\n </div>\r\n\r\n <!-- 执行预览 -->\r\n <template v-if=\"props.showPreview\">\r\n <div class=\"c-cron__panel-line\" />\r\n <CronPreview\r\n :next-executions=\"nextExecutions\"\r\n :computing=\"computing\"\r\n :count=\"props.previewCount ?? 5\"\r\n :format-date=\"formatDate\"\r\n :format-week-day=\"formatWeekDay\"\r\n />\r\n </template>\r\n </div>\r\n </div>\r\n\r\n <!-- ═══════ 底部模板 ═══════ -->\r\n <div v-if=\"props.showTemplates\" class=\"c-cron__footer\">\r\n <CronTemplates\r\n :templates=\"CRON_TEMPLATES\"\r\n :current-value=\"expression\"\r\n @select=\"handleTemplateSelect\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, onMounted } from \"vue\";\r\nimport type {\r\n CronFieldMode,\r\n CronFieldType,\r\n CronFieldValue,\r\n CronProps,\r\n CronValidation,\r\n} from \"./types\";\r\nimport {\r\n CRON_FIELD_META,\r\n CRON_TEMPLATES,\r\n DEFAULT_CRON_EXPRESSION,\r\n} from \"./constants\";\r\nimport { useCronParser } from \"./composables/useCronParser\";\r\nimport { useCronPreview } from \"./composables/useCronPreview\";\r\nimport { useCronDescription } from \"./composables/useCronDescription\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport CronFieldEditor from \"./components/CronFieldEditor.vue\";\r\nimport CronPreview from \"./components/CronPreview.vue\";\r\nimport CronTemplates from \"./components/CronTemplates.vue\";\r\n\r\ndefineOptions({ name: \"C_Cron\" });\r\n\r\n/* ─── Props & Emits ─────────────────────────── */\r\n\r\nconst props = withDefaults(defineProps<CronProps>(), {\r\n modelValue: DEFAULT_CRON_EXPRESSION,\r\n disabled: false,\r\n previewCount: 10,\r\n showTemplates: true,\r\n showPreview: true,\r\n showSecond: true,\r\n height: \"auto\",\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: string];\r\n change: [value: string];\r\n \"validation-change\": [result: CronValidation];\r\n}>();\r\n\r\n/* ─── 组合函数 ──────────────────────────────── */\r\n\r\nconst {\r\n cronValue,\r\n expression,\r\n validation,\r\n parse,\r\n validate,\r\n handleDayWeekExclusion,\r\n} = useCronParser();\r\n\r\nconst previewCount = computed(() => props.previewCount ?? 10);\r\nconst { nextExecutions, computing, formatDate, formatWeekDay } = useCronPreview(\r\n expression,\r\n validation,\r\n previewCount,\r\n);\r\n\r\nconst { description } = useCronDescription(expression, validation);\r\n\r\n/* ─── 本地状态 ──────────────────────────────── */\r\n\r\n/** 手动输入框值(与 expression 解耦,输入完成后同步) */\r\nconst manualInput = ref(props.modelValue || DEFAULT_CRON_EXPRESSION);\r\n\r\n/** 当前激活的字段 Tab */\r\nconst activeField = ref<CronFieldType>(props.showSecond ? \"second\" : \"minute\");\r\n\r\n/* ─── 容器高度 ──────────────────────────────── */\r\n\r\nconst containerHeight = computed(() => {\r\n if (typeof props.height === \"number\") return `${props.height}px`;\r\n return props.height;\r\n});\r\n\r\n/* ─── 可见字段(是否显示秒) ────────────────── */\r\n\r\nconst visibleFields = computed(() => {\r\n return props.showSecond\r\n ? CRON_FIELD_META\r\n : CRON_FIELD_META.filter((m) => m.type !== \"second\");\r\n});\r\n\r\n/* ─── 当前激活字段快捷访问 ─────────────────── */\r\n\r\n/** 当前激活字段元数据 */\r\nconst activeFieldMeta = computed(\r\n () => CRON_FIELD_META.find((m) => m.type === activeField.value)!,\r\n);\r\n\r\n/** 当前激活字段值 */\r\nconst activeFieldValue = computed(() => cronValue.value[activeField.value]);\r\n\r\n/* ─── 分段式表达式(逐字段计算) ────────────── */\r\n\r\n/** 计算单字段表达式文本 */\r\nfunction computeFieldExpr(f: CronFieldValue): string {\r\n switch (f.mode) {\r\n case \"every\":\r\n return \"*\";\r\n case \"none\":\r\n return \"?\";\r\n case \"range\":\r\n return `${f.rangeStart}-${f.rangeEnd}`;\r\n case \"step\":\r\n return `${f.stepStart}/${f.stepInterval}`;\r\n case \"specific\":\r\n return f.specificValues.length > 0\r\n ? [...f.specificValues].sort((a, b) => a - b).join(\",\")\r\n : \"*\";\r\n default:\r\n return \"*\";\r\n }\r\n}\r\n\r\n/** 各字段表达式映射 */\r\nconst fieldExpressions = computed(() => {\r\n const map = {} as Record<CronFieldType, string>;\r\n for (const meta of CRON_FIELD_META) {\r\n map[meta.type] = computeFieldExpr(cronValue.value[meta.type]);\r\n }\r\n return map;\r\n});\r\n\r\n/* ─── 初始化解析 ────────────────────────────── */\r\n\r\nonMounted(() => {\r\n const initial = props.modelValue || DEFAULT_CRON_EXPRESSION;\r\n parse(initial);\r\n manualInput.value = initial;\r\n});\r\n\r\n/* ─── 监听外部 v-model 变更 ─────────────────── */\r\n\r\nwatch(\r\n () => props.modelValue,\r\n (newVal) => {\r\n if (newVal && newVal !== expression.value) {\r\n parse(newVal);\r\n manualInput.value = newVal;\r\n }\r\n },\r\n);\r\n\r\n/* ─── 监听 showSecond 变更 ──────────────────── */\r\n\r\nwatch(\r\n () => props.showSecond,\r\n (show) => {\r\n if (!show && activeField.value === \"second\") {\r\n activeField.value = \"minute\";\r\n }\r\n },\r\n);\r\n\r\n/* ─── 监听内部表达式变更 → 同步到外部 ───────── */\r\n\r\nwatch(expression, (newExpr) => {\r\n manualInput.value = newExpr;\r\n emit(\"update:modelValue\", newExpr);\r\n emit(\"change\", newExpr);\r\n});\r\n\r\n/* ─── 监听校验状态变更 ──────────────────────── */\r\n\r\nwatch(validation, (v) => {\r\n emit(\"validation-change\", v);\r\n});\r\n\r\n/* ─── 字段变更处理 ──────────────────────────── */\r\n\r\n/** 字段编辑变更处理 */\r\nfunction handleFieldChange(type: CronFieldType, value: CronFieldValue) {\r\n cronValue.value[type] = value;\r\n if (type === \"day\" || type === \"week\") {\r\n handleDayWeekExclusion(type);\r\n }\r\n}\r\n\r\n/* ─── 右侧面板操作 ─────────────────────────── */\r\n\r\n/** 切换当前字段模式 */\r\nfunction handleActiveFieldModeChange(mode: CronFieldMode) {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n mode,\r\n });\r\n}\r\n\r\n/** 更新当前字段属性 */\r\nfunction handleActiveFieldUpdate(partial: Partial<CronFieldValue>) {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n ...partial,\r\n });\r\n}\r\n\r\n/** 全选当前字段所有值 */\r\nfunction handleSelectAll() {\r\n const { min, max } = activeFieldMeta.value;\r\n const allValues = Array.from({ length: max - min + 1 }, (_, i) => min + i);\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n specificValues: allValues,\r\n });\r\n}\r\n\r\n/** 清空当前字段所有选中值 */\r\nfunction handleClearAll() {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n specificValues: [],\r\n });\r\n}\r\n\r\n/* ─── 手动输入处理 ──────────────────────────── */\r\n\r\n/** 手动输入更新 */\r\nfunction handleManualInput(value: string) {\r\n manualInput.value = value;\r\n}\r\n\r\n/** 输入框失焦时同步 */\r\nfunction handleManualBlur() {\r\n const trimmed = manualInput.value.trim();\r\n if (trimmed && trimmed !== expression.value) {\r\n parse(trimmed);\r\n }\r\n}\r\n\r\n/* ─── 模板选择 ──────────────────────────────── */\r\n\r\n/** 选择常用模板 */\r\nfunction handleTemplateSelect(expr: string) {\r\n parse(expr);\r\n manualInput.value = expr;\r\n}\r\n\r\n/* ─── 重置 ──────────────────────────────────── */\r\n\r\n/** 重置为初始值 */\r\nfunction handleReset() {\r\n const initial = props.modelValue || DEFAULT_CRON_EXPRESSION;\r\n parse(initial);\r\n manualInput.value = initial;\r\n}\r\n\r\n/* ─── Expose ────────────────────────────────── */\r\n\r\ndefineExpose({\r\n getValue: () => expression.value,\r\n setValue: (expr: string) => {\r\n parse(expr);\r\n manualInput.value = expr;\r\n },\r\n reset: handleReset,\r\n validate: () => validate(),\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: Cron 表达式编辑器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"c-cron\" :style=\"{ height: containerHeight }\">\r\n <!-- ═══════ 顶部 ═══════ -->\r\n <div class=\"c-cron__header\">\r\n <!-- 标题行 -->\r\n <div class=\"c-cron__title-row\">\r\n <div class=\"c-cron__title\">\r\n <C_Icon name=\"mdi:clock-edit-outline\" :size=\"18\" />\r\n <span>Cron 表达式</span>\r\n </div>\r\n <NTag :type=\"validation.valid ? 'success' : 'error'\" size=\"small\" round>\r\n <template #icon>\r\n <C_Icon\r\n :name=\"validation.valid ? 'mdi:check-circle' : 'mdi:alert-circle'\"\r\n />\r\n </template>\r\n {{ validation.valid ? \"合法\" : \"错误\" }}\r\n </NTag>\r\n </div>\r\n\r\n <!-- 分段式字段选择器 -->\r\n <div class=\"c-cron__segments\">\r\n <div\r\n v-for=\"meta in visibleFields\"\r\n :key=\"meta.type\"\r\n class=\"c-cron__segment\"\r\n :class=\"{\r\n 'c-cron__segment--active': activeField === meta.type,\r\n 'c-cron__segment--wildcard':\r\n fieldExpressions[meta.type] === '*' ||\r\n fieldExpressions[meta.type] === '?',\r\n }\"\r\n @click=\"activeField = meta.type\"\r\n >\r\n <div class=\"c-cron__segment-value\">\r\n {{ fieldExpressions[meta.type] }}\r\n </div>\r\n <div class=\"c-cron__segment-label\">{{ meta.label }}</div>\r\n </div>\r\n </div>\r\n\r\n <!-- 表达式行:输入 + 重置 + 描述 -->\r\n <div class=\"c-cron__expr-row\">\r\n <NInput\r\n :value=\"manualInput\"\r\n :status=\"validation.valid ? undefined : 'error'\"\r\n placeholder=\"秒 分 时 日 月 周\"\r\n :disabled=\"props.disabled\"\r\n font=\"mono\"\r\n size=\"small\"\r\n clearable\r\n class=\"c-cron__expr-input\"\r\n @update:value=\"handleManualInput\"\r\n @blur=\"handleManualBlur\"\r\n @keydown.enter=\"handleManualBlur\"\r\n >\r\n <template #prefix>\r\n <C_Icon name=\"mdi:console\" :size=\"14\" style=\"opacity: 0.4\" />\r\n </template>\r\n </NInput>\r\n <NButton\r\n size=\"small\"\r\n quaternary\r\n :disabled=\"props.disabled\"\r\n @click=\"handleReset\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:refresh\" />\r\n </template>\r\n </NButton>\r\n <div class=\"c-cron__expr-desc\">\r\n <span v-if=\"validation.valid\" class=\"c-cron__description\">\r\n {{ description }}\r\n </span>\r\n <span v-else class=\"c-cron__error\">\r\n {{ validation.message }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ═══════ 主内容 ═══════ -->\r\n <div class=\"c-cron__body\">\r\n <!-- 左侧:值网格 -->\r\n <div class=\"c-cron__main\">\r\n <CronFieldEditor\r\n v-for=\"meta in visibleFields\"\r\n v-show=\"activeField === meta.type\"\r\n :key=\"meta.type\"\r\n :model-value=\"cronValue[meta.type]\"\r\n :meta=\"meta\"\r\n @update:model-value=\"(v) => handleFieldChange(meta.type, v)\"\r\n />\r\n </div>\r\n\r\n <!-- 右侧:控制面板 -->\r\n <div class=\"c-cron__panel\">\r\n <NRadioGroup\r\n :value=\"activeFieldValue.mode\"\r\n size=\"small\"\r\n @update:value=\"handleActiveFieldModeChange\"\r\n >\r\n <NRadioButton value=\"every\">\r\n 每{{ activeFieldMeta.label }}\r\n </NRadioButton>\r\n <NRadioButton\r\n v-if=\"activeField === 'day' || activeField === 'week'\"\r\n value=\"none\"\r\n >\r\n 不指定\r\n </NRadioButton>\r\n <NRadioButton value=\"range\">范围</NRadioButton>\r\n <NRadioButton value=\"step\">步进</NRadioButton>\r\n <NRadioButton value=\"specific\">指定</NRadioButton>\r\n </NRadioGroup>\r\n\r\n <!-- 范围配置 -->\r\n <div v-if=\"activeFieldValue.mode === 'range'\" class=\"c-cron__config\">\r\n <div class=\"c-cron__config-row\">\r\n <span>从</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.rangeStart\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n rangeStart: v ?? activeFieldMeta.min,\r\n })\r\n \"\r\n />\r\n <span>到</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.rangeEnd\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n rangeEnd: v ?? activeFieldMeta.max,\r\n })\r\n \"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 步进配置 -->\r\n <div v-if=\"activeFieldValue.mode === 'step'\" class=\"c-cron__config\">\r\n <div class=\"c-cron__config-row\">\r\n <span>从第</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.stepStart\"\r\n :min=\"activeFieldMeta.min\"\r\n :max=\"activeFieldMeta.max\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({\r\n stepStart: v ?? activeFieldMeta.min,\r\n })\r\n \"\r\n />\r\n <span>{{ activeFieldMeta.label }}起,每</span>\r\n <NInputNumber\r\n :value=\"activeFieldValue.stepInterval\"\r\n :min=\"1\"\r\n :max=\"activeFieldMeta.max - activeFieldMeta.min + 1\"\r\n size=\"small\"\r\n :show-button=\"false\"\r\n class=\"c-cron__config-num\"\r\n @update:value=\"\r\n (v: number | null) =>\r\n handleActiveFieldUpdate({ stepInterval: v ?? 1 })\r\n \"\r\n />\r\n <span>{{ activeFieldMeta.label }}执行</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 指定快捷操作 -->\r\n <div v-if=\"activeFieldValue.mode === 'specific'\" class=\"c-cron__quick\">\r\n <a @click=\"handleSelectAll\">全选</a>\r\n <span class=\"c-cron__quick-sep\">·</span>\r\n <a @click=\"handleClearAll\">清空</a>\r\n <span\r\n v-if=\"activeFieldValue.specificValues.length > 0\"\r\n class=\"c-cron__quick-count\"\r\n >\r\n 已选 {{ activeFieldValue.specificValues.length }}\r\n </span>\r\n </div>\r\n\r\n <!-- 执行预览 -->\r\n <template v-if=\"props.showPreview\">\r\n <div class=\"c-cron__panel-line\" />\r\n <CronPreview\r\n :next-executions=\"nextExecutions\"\r\n :computing=\"computing\"\r\n :count=\"props.previewCount ?? 5\"\r\n :format-date=\"formatDate\"\r\n :format-week-day=\"formatWeekDay\"\r\n />\r\n </template>\r\n </div>\r\n </div>\r\n\r\n <!-- ═══════ 底部模板 ═══════ -->\r\n <div v-if=\"props.showTemplates\" class=\"c-cron__footer\">\r\n <CronTemplates\r\n :templates=\"CRON_TEMPLATES\"\r\n :current-value=\"expression\"\r\n @select=\"handleTemplateSelect\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, onMounted } from \"vue\";\r\nimport type {\r\n CronFieldMode,\r\n CronFieldType,\r\n CronFieldValue,\r\n CronProps,\r\n CronValidation,\r\n} from \"./types\";\r\nimport {\r\n CRON_FIELD_META,\r\n CRON_TEMPLATES,\r\n DEFAULT_CRON_EXPRESSION,\r\n} from \"./constants\";\r\nimport { useCronParser } from \"./composables/useCronParser\";\r\nimport { useCronPreview } from \"./composables/useCronPreview\";\r\nimport { useCronDescription } from \"./composables/useCronDescription\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport CronFieldEditor from \"./components/CronFieldEditor.vue\";\r\nimport CronPreview from \"./components/CronPreview.vue\";\r\nimport CronTemplates from \"./components/CronTemplates.vue\";\r\n\r\ndefineOptions({ name: \"C_Cron\" });\r\n\r\n/* ─── Props & Emits ─────────────────────────── */\r\n\r\nconst props = withDefaults(defineProps<CronProps>(), {\r\n modelValue: DEFAULT_CRON_EXPRESSION,\r\n disabled: false,\r\n previewCount: 10,\r\n showTemplates: true,\r\n showPreview: true,\r\n showSecond: true,\r\n height: \"auto\",\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: string];\r\n change: [value: string];\r\n \"validation-change\": [result: CronValidation];\r\n}>();\r\n\r\n/* ─── 组合函数 ──────────────────────────────── */\r\n\r\nconst {\r\n cronValue,\r\n expression,\r\n validation,\r\n parse,\r\n validate,\r\n handleDayWeekExclusion,\r\n} = useCronParser();\r\n\r\nconst previewCount = computed(() => props.previewCount ?? 10);\r\nconst { nextExecutions, computing, formatDate, formatWeekDay } = useCronPreview(\r\n expression,\r\n validation,\r\n previewCount,\r\n);\r\n\r\nconst { description } = useCronDescription(expression, validation);\r\n\r\n/* ─── 本地状态 ──────────────────────────────── */\r\n\r\n/** 手动输入框值(与 expression 解耦,输入完成后同步) */\r\nconst manualInput = ref(props.modelValue || DEFAULT_CRON_EXPRESSION);\r\n\r\n/** 当前激活的字段 Tab */\r\nconst activeField = ref<CronFieldType>(props.showSecond ? \"second\" : \"minute\");\r\n\r\n/* ─── 容器高度 ──────────────────────────────── */\r\n\r\nconst containerHeight = computed(() => {\r\n if (typeof props.height === \"number\") return `${props.height}px`;\r\n return props.height;\r\n});\r\n\r\n/* ─── 可见字段(是否显示秒) ────────────────── */\r\n\r\nconst visibleFields = computed(() => {\r\n return props.showSecond\r\n ? CRON_FIELD_META\r\n : CRON_FIELD_META.filter((m) => m.type !== \"second\");\r\n});\r\n\r\n/* ─── 当前激活字段快捷访问 ─────────────────── */\r\n\r\n/** 当前激活字段元数据 */\r\nconst activeFieldMeta = computed(\r\n () => CRON_FIELD_META.find((m) => m.type === activeField.value)!,\r\n);\r\n\r\n/** 当前激活字段值 */\r\nconst activeFieldValue = computed(() => cronValue.value[activeField.value]);\r\n\r\n/* ─── 分段式表达式(逐字段计算) ────────────── */\r\n\r\n/** 计算单字段表达式文本 */\r\nfunction computeFieldExpr(f: CronFieldValue): string {\r\n switch (f.mode) {\r\n case \"every\":\r\n return \"*\";\r\n case \"none\":\r\n return \"?\";\r\n case \"range\":\r\n return `${f.rangeStart}-${f.rangeEnd}`;\r\n case \"step\":\r\n return `${f.stepStart}/${f.stepInterval}`;\r\n case \"specific\":\r\n return f.specificValues.length > 0\r\n ? [...f.specificValues].sort((a, b) => a - b).join(\",\")\r\n : \"*\";\r\n default:\r\n return \"*\";\r\n }\r\n}\r\n\r\n/** 各字段表达式映射 */\r\nconst fieldExpressions = computed(() => {\r\n const map = {} as Record<CronFieldType, string>;\r\n for (const meta of CRON_FIELD_META) {\r\n map[meta.type] = computeFieldExpr(cronValue.value[meta.type]);\r\n }\r\n return map;\r\n});\r\n\r\n/* ─── 初始化解析 ────────────────────────────── */\r\n\r\nonMounted(() => {\r\n const initial = props.modelValue || DEFAULT_CRON_EXPRESSION;\r\n parse(initial);\r\n manualInput.value = initial;\r\n});\r\n\r\n/* ─── 监听外部 v-model 变更 ─────────────────── */\r\n\r\nwatch(\r\n () => props.modelValue,\r\n (newVal) => {\r\n if (newVal && newVal !== expression.value) {\r\n parse(newVal);\r\n manualInput.value = newVal;\r\n }\r\n },\r\n);\r\n\r\n/* ─── 监听 showSecond 变更 ──────────────────── */\r\n\r\nwatch(\r\n () => props.showSecond,\r\n (show) => {\r\n if (!show && activeField.value === \"second\") {\r\n activeField.value = \"minute\";\r\n }\r\n },\r\n);\r\n\r\n/* ─── 监听内部表达式变更 → 同步到外部 ───────── */\r\n\r\nwatch(expression, (newExpr) => {\r\n manualInput.value = newExpr;\r\n emit(\"update:modelValue\", newExpr);\r\n emit(\"change\", newExpr);\r\n});\r\n\r\n/* ─── 监听校验状态变更 ──────────────────────── */\r\n\r\nwatch(validation, (v) => {\r\n emit(\"validation-change\", v);\r\n});\r\n\r\n/* ─── 字段变更处理 ──────────────────────────── */\r\n\r\n/** 字段编辑变更处理 */\r\nfunction handleFieldChange(type: CronFieldType, value: CronFieldValue) {\r\n cronValue.value[type] = value;\r\n if (type === \"day\" || type === \"week\") {\r\n handleDayWeekExclusion(type);\r\n }\r\n}\r\n\r\n/* ─── 右侧面板操作 ─────────────────────────── */\r\n\r\n/** 切换当前字段模式 */\r\nfunction handleActiveFieldModeChange(mode: CronFieldMode) {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n mode,\r\n });\r\n}\r\n\r\n/** 更新当前字段属性 */\r\nfunction handleActiveFieldUpdate(partial: Partial<CronFieldValue>) {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n ...partial,\r\n });\r\n}\r\n\r\n/** 全选当前字段所有值 */\r\nfunction handleSelectAll() {\r\n const { min, max } = activeFieldMeta.value;\r\n const allValues = Array.from({ length: max - min + 1 }, (_, i) => min + i);\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n specificValues: allValues,\r\n });\r\n}\r\n\r\n/** 清空当前字段所有选中值 */\r\nfunction handleClearAll() {\r\n handleFieldChange(activeField.value, {\r\n ...activeFieldValue.value,\r\n specificValues: [],\r\n });\r\n}\r\n\r\n/* ─── 手动输入处理 ──────────────────────────── */\r\n\r\n/** 手动输入更新 */\r\nfunction handleManualInput(value: string) {\r\n manualInput.value = value;\r\n}\r\n\r\n/** 输入框失焦时同步 */\r\nfunction handleManualBlur() {\r\n const trimmed = manualInput.value.trim();\r\n if (trimmed && trimmed !== expression.value) {\r\n parse(trimmed);\r\n }\r\n}\r\n\r\n/* ─── 模板选择 ──────────────────────────────── */\r\n\r\n/** 选择常用模板 */\r\nfunction handleTemplateSelect(expr: string) {\r\n parse(expr);\r\n manualInput.value = expr;\r\n}\r\n\r\n/* ─── 重置 ──────────────────────────────────── */\r\n\r\n/** 重置为初始值 */\r\nfunction handleReset() {\r\n const initial = props.modelValue || DEFAULT_CRON_EXPRESSION;\r\n parse(initial);\r\n manualInput.value = initial;\r\n}\r\n\r\n/* ─── Expose ────────────────────────────────── */\r\n\r\ndefineExpose({\r\n getValue: () => expression.value,\r\n setValue: (expr: string) => {\r\n parse(expr);\r\n manualInput.value = expr;\r\n },\r\n reset: handleReset,\r\n validate: () => validate(),\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":"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"}