@robot-admin/naive-ui-components 0.3.2 → 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 (175) 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_Form2.js +48 -48
  43. package/dist/C_Form2.js.map +1 -1
  44. package/dist/C_FormSearch-DlIEoh7X.css.map +1 -0
  45. package/dist/C_FormSearch2.js +2 -2
  46. package/dist/C_FormSearch2.js.map +1 -1
  47. package/dist/C_FormulaEditor-Cm0CokN5.css.map +1 -0
  48. package/dist/C_FormulaEditor2.js +6 -6
  49. package/dist/C_FormulaEditor2.js.map +1 -1
  50. package/dist/C_FullCalendar-BULCIlVK.css.map +1 -0
  51. package/dist/C_FullCalendar2.js +2 -2
  52. package/dist/C_FullCalendar2.js.map +1 -1
  53. package/dist/C_Guide2.js +1 -1
  54. package/dist/C_Guide2.js.map +1 -1
  55. package/dist/C_Icon2.js.map +1 -1
  56. package/dist/C_ImageCropper-DrmUlaLi.css.map +1 -0
  57. package/dist/C_ImageCropper2.js +4 -4
  58. package/dist/C_ImageCropper2.js.map +1 -1
  59. package/dist/C_Language2.js +1 -1
  60. package/dist/C_Language2.js.map +1 -1
  61. package/dist/C_Map-WUMXSAfy.css.map +1 -0
  62. package/dist/C_Map2.js +2 -2
  63. package/dist/C_Map2.js.map +1 -1
  64. package/dist/C_Markdown-Dmv8yaM4.css.map +1 -0
  65. package/dist/C_Markdown2.js +4 -4
  66. package/dist/C_Markdown2.js.map +1 -1
  67. package/dist/C_NotificationCenter-DbgBiyqB.css.map +1 -0
  68. package/dist/C_NotificationCenter2.js +21 -20
  69. package/dist/C_NotificationCenter2.js.map +1 -1
  70. package/dist/C_Progress2.js +1 -1
  71. package/dist/C_Progress2.js.map +1 -1
  72. package/dist/C_QRCode-G7fiAkm4.css.map +1 -0
  73. package/dist/C_QRCode2.js +1 -1
  74. package/dist/C_QRCode2.js.map +1 -1
  75. package/dist/C_Signature-es-ZNPzr.css.map +1 -0
  76. package/dist/C_Signature2.js +2 -2
  77. package/dist/C_Signature2.js.map +1 -1
  78. package/dist/C_SplitPane-Br2eK8IG.css.map +1 -0
  79. package/dist/C_SplitPane2.js +1 -1
  80. package/dist/C_SplitPane2.js.map +1 -1
  81. package/dist/C_Steps-P9Qj9iDd.css.map +1 -0
  82. package/dist/C_Steps2.js +1 -1
  83. package/dist/C_Steps2.js.map +1 -1
  84. package/dist/C_Table-DAwAxr72.css.map +1 -0
  85. package/dist/C_Table2.js +3 -3
  86. package/dist/C_Table2.js.map +1 -1
  87. package/dist/C_Theme2.js +1 -1
  88. package/dist/C_Theme2.js.map +1 -1
  89. package/dist/C_Time-Bd_e1YDN.css.map +1 -0
  90. package/dist/C_Time2.js +2 -2
  91. package/dist/C_Time2.js.map +1 -1
  92. package/dist/C_Tree-DnGc_MPb.css.map +1 -0
  93. package/dist/C_Tree2.js +2 -2
  94. package/dist/C_Tree2.js.map +1 -1
  95. package/dist/C_Upload-i8LB_29U.css.map +1 -0
  96. package/dist/C_Upload2.js +5 -5
  97. package/dist/C_Upload2.js.map +1 -1
  98. package/dist/C_VideoPlayer-rm0MODUv.css.map +1 -0
  99. package/dist/C_VideoPlayer2.js +21 -20
  100. package/dist/C_VideoPlayer2.js.map +1 -1
  101. package/dist/C_VtableGantt-BpY-Rng3.css.map +1 -0
  102. package/dist/C_VtableGantt2.js +2 -2
  103. package/dist/C_VtableGantt2.js.map +1 -1
  104. package/dist/C_WaterFall-HWB-gPON.css.map +1 -0
  105. package/dist/C_WaterFall2.js +2 -2
  106. package/dist/C_WaterFall2.js.map +1 -1
  107. package/dist/C_WorkFlow-CSO86Cuc.css.map +1 -0
  108. package/dist/C_WorkFlow2.js +6 -6
  109. package/dist/C_WorkFlow2.js.map +1 -1
  110. package/dist/constants2.d.ts +2 -2
  111. package/dist/constants3.d.ts +2 -2
  112. package/dist/constants4.d.ts +5 -5
  113. package/dist/constants5.d.ts +2 -2
  114. package/dist/data.d.ts +1 -1
  115. package/dist/index.vue.d.ts +1 -1
  116. package/dist/index10.vue.d.ts +5 -5
  117. package/dist/index12.vue.d.ts +1 -1
  118. package/dist/index12.vue.d.ts.map +1 -1
  119. package/dist/index13.vue.d.ts +1 -1
  120. package/dist/index16.vue.d.ts +3 -3
  121. package/dist/index16.vue.d.ts.map +1 -1
  122. package/dist/index2.vue.d.ts +5 -5
  123. package/dist/index3.vue.d.ts +4 -4
  124. package/dist/index6.vue.d.ts +3 -3
  125. package/dist/index8.vue.d.ts +2 -2
  126. package/dist/style.css +1555 -1555
  127. package/dist/useCropperCore.d.ts +7 -7
  128. package/dist/useDraggableLayout.d.ts +9 -9
  129. package/dist/useDynamicFormState.d.ts +9 -9
  130. package/dist/useDynamicFormState.d.ts.map +1 -1
  131. package/dist/useEdgeInteraction.d.ts +2 -2
  132. package/dist/useInfiniteScroll.d.ts +2 -2
  133. package/dist/useModalEdit.d.ts +2 -2
  134. package/dist/useModalEdit.d.ts.map +1 -1
  135. package/dist/useQRCode.d.ts +2 -2
  136. package/dist/useSearchState.d.ts +2 -2
  137. package/dist/useSignatureHistory.d.ts +3 -3
  138. package/dist/useSplitResize.d.ts +6 -6
  139. package/dist/useSplitResize.d.ts.map +1 -1
  140. package/dist/useTimeSelection.d.ts +1 -1
  141. package/dist/useTreeOperations.d.ts +3 -3
  142. package/dist/useWorkflowValidation.d.ts +1 -1
  143. package/package.json +2 -1
  144. package/dist/C_ActionBar-DWN-woTc.css.map +0 -1
  145. package/dist/C_AntV-AFKyK6hH.css.map +0 -1
  146. package/dist/C_Barcode-P_EFj8dC.css.map +0 -1
  147. package/dist/C_Captcha-C-ef41xw.css.map +0 -1
  148. package/dist/C_Cascade-D9kNsjsV.css.map +0 -1
  149. package/dist/C_City-BCQ4ipiK.css.map +0 -1
  150. package/dist/C_Code-C9kvvEmO.css.map +0 -1
  151. package/dist/C_CollapsePanel-BUJHuYcU.css.map +0 -1
  152. package/dist/C_Cron-yx2Ob4Jl.css.map +0 -1
  153. package/dist/C_Draggable-C483syRC.css.map +0 -1
  154. package/dist/C_Editor-Bp0SyIEw.css.map +0 -1
  155. package/dist/C_FilePreview-CPqvhoCy.css.map +0 -1
  156. package/dist/C_Form-Jx7PY3sT.css.map +0 -1
  157. package/dist/C_FormSearch-DvRgxlRn.css.map +0 -1
  158. package/dist/C_FormulaEditor-DtGkt4T_.css.map +0 -1
  159. package/dist/C_FullCalendar-BF7H0YIx.css.map +0 -1
  160. package/dist/C_ImageCropper-BVJfUufl.css.map +0 -1
  161. package/dist/C_Map-DpzeuWdX.css.map +0 -1
  162. package/dist/C_Markdown-BEjxknqd.css.map +0 -1
  163. package/dist/C_NotificationCenter-0l3TY2Gn.css.map +0 -1
  164. package/dist/C_QRCode-DbdiAIPg.css.map +0 -1
  165. package/dist/C_Signature-zhHCbra9.css.map +0 -1
  166. package/dist/C_SplitPane-C6sBsfKY.css.map +0 -1
  167. package/dist/C_Steps-CODHN5Hs.css.map +0 -1
  168. package/dist/C_Table-DSNsntmT.css.map +0 -1
  169. package/dist/C_Time-BvZLYraL.css.map +0 -1
  170. package/dist/C_Tree-0GDv--jX.css.map +0 -1
  171. package/dist/C_Upload-BXd3YYLx.css.map +0 -1
  172. package/dist/C_VideoPlayer-DYG3RL0Q.css.map +0 -1
  173. package/dist/C_VtableGantt-fhItIiHE.css.map +0 -1
  174. package/dist/C_WaterFall-8sQDFXKg.css.map +0 -1
  175. package/dist/C_WorkFlow-J-dyIuh9.css.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"C_Barcode-DjTmDkbQ.css","names":[],"sources":["../src/components/C_Barcode/index.vue?vue&type=style&index=0&scoped=e44c361d&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled */.c-barcode[data-v-e44c361d] {\n display: inline-flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n max-width: 100%;\n}\n.c-barcode .barcode-wrapper[data-v-e44c361d] {\n display: inline-block;\n padding: 8px;\n background: #ffffff;\n border-radius: 4px;\n transition: all 0.3s ease;\n overflow: hidden;\n max-width: 100%;\n}\n.c-barcode .barcode-wrapper.with-border[data-v-e44c361d] {\n border: 1px dashed #e0e0e0;\n}\n.c-barcode .barcode-wrapper[data-v-e44c361d]:hover {\n border-color: var(--c-primary, #409eff);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n.c-barcode .barcode-wrapper[data-v-e44c361d] svg {\n max-width: 100%;\n height: auto;\n display: block;\n overflow: visible;\n}\n.c-barcode .barcode-label[data-v-e44c361d] {\n font-size: 14px;\n color: #666;\n text-align: center;\n font-weight: 500;\n word-break: break-all;\n max-width: 100%;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
@@ -61,7 +61,7 @@ var index_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCo
61
61
 
62
62
  //#endregion
63
63
  //#region src/components/C_Barcode/index.vue
64
- var C_Barcode_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-b87e921b"]]);
64
+ var C_Barcode_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-e44c361d"]]);
65
65
 
66
66
  //#endregion
67
67
  export { C_Barcode_default as t };
@@ -1 +1 @@
1
- {"version":3,"file":"C_Barcode2.js","names":["showBorder","showLabel","label"],"sources":["../src/components/C_Barcode/index.vue","../src/components/C_Barcode/index.vue","../src/components/C_Barcode/index.vue"],"sourcesContent":["<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-12-02\r\n * @Description: 条形码组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-barcode\">\r\n <div class=\"barcode-wrapper\" :class=\"{ 'with-border': showBorder }\">\r\n <VueBarcode v-bind=\"barcodeProps\" @error=\"handleError\" />\r\n </div>\r\n <div v-if=\"showLabel && label\" class=\"barcode-label\">\r\n {{ label }}\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from \"vue\";\r\nimport VueBarcode from \"@chenfengyuan/vue-barcode\";\r\n\r\ndefineOptions({ name: \"C_Barcode\" });\r\n\r\ninterface Props {\r\n value: string;\r\n format?:\r\n | \"CODE128\"\r\n | \"CODE39\"\r\n | \"EAN13\"\r\n | \"EAN8\"\r\n | \"UPC\"\r\n | \"ITF14\"\r\n | \"MSI\"\r\n | \"pharmacode\";\r\n width?: number;\r\n height?: number;\r\n showText?: boolean;\r\n fontSize?: number;\r\n textPosition?: \"bottom\" | \"top\";\r\n lineColor?: string;\r\n background?: string;\r\n showBorder?: boolean;\r\n label?: string;\r\n showLabel?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n format: \"CODE128\",\r\n width: 2,\r\n height: 80,\r\n showText: true,\r\n fontSize: 20,\r\n textPosition: \"bottom\",\r\n lineColor: \"#000000\",\r\n background: \"#FFFFFF\",\r\n showBorder: true,\r\n label: \"\",\r\n showLabel: false,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n error: [error: Error];\r\n}>();\r\n\r\nconst barcodeProps = computed(() => ({\r\n value: props.value,\r\n format: props.format,\r\n width: props.width,\r\n height: props.height,\r\n displayValue: props.showText,\r\n fontSize: props.fontSize,\r\n textPosition: props.textPosition,\r\n lineColor: props.lineColor,\r\n background: props.background,\r\n}));\r\n\r\nconst handleError = (error: Error) => {\r\n console.error(\"条形码生成失败:\", error);\r\n emit(\"error\", error);\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: 2025-12-02\r\n * @Description: 条形码组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-barcode\">\r\n <div class=\"barcode-wrapper\" :class=\"{ 'with-border': showBorder }\">\r\n <VueBarcode v-bind=\"barcodeProps\" @error=\"handleError\" />\r\n </div>\r\n <div v-if=\"showLabel && label\" class=\"barcode-label\">\r\n {{ label }}\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from \"vue\";\r\nimport VueBarcode from \"@chenfengyuan/vue-barcode\";\r\n\r\ndefineOptions({ name: \"C_Barcode\" });\r\n\r\ninterface Props {\r\n value: string;\r\n format?:\r\n | \"CODE128\"\r\n | \"CODE39\"\r\n | \"EAN13\"\r\n | \"EAN8\"\r\n | \"UPC\"\r\n | \"ITF14\"\r\n | \"MSI\"\r\n | \"pharmacode\";\r\n width?: number;\r\n height?: number;\r\n showText?: boolean;\r\n fontSize?: number;\r\n textPosition?: \"bottom\" | \"top\";\r\n lineColor?: string;\r\n background?: string;\r\n showBorder?: boolean;\r\n label?: string;\r\n showLabel?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n format: \"CODE128\",\r\n width: 2,\r\n height: 80,\r\n showText: true,\r\n fontSize: 20,\r\n textPosition: \"bottom\",\r\n lineColor: \"#000000\",\r\n background: \"#FFFFFF\",\r\n showBorder: true,\r\n label: \"\",\r\n showLabel: false,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n error: [error: Error];\r\n}>();\r\n\r\nconst barcodeProps = computed(() => ({\r\n value: props.value,\r\n format: props.format,\r\n width: props.width,\r\n height: props.height,\r\n displayValue: props.showText,\r\n fontSize: props.fontSize,\r\n textPosition: props.textPosition,\r\n lineColor: props.lineColor,\r\n background: props.background,\r\n}));\r\n\r\nconst handleError = (error: Error) => {\r\n console.error(\"条形码生成失败:\", error);\r\n emit(\"error\", error);\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: 2025-12-02\r\n * @Description: 条形码组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-barcode\">\r\n <div class=\"barcode-wrapper\" :class=\"{ 'with-border': showBorder }\">\r\n <VueBarcode v-bind=\"barcodeProps\" @error=\"handleError\" />\r\n </div>\r\n <div v-if=\"showLabel && label\" class=\"barcode-label\">\r\n {{ label }}\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from \"vue\";\r\nimport VueBarcode from \"@chenfengyuan/vue-barcode\";\r\n\r\ndefineOptions({ name: \"C_Barcode\" });\r\n\r\ninterface Props {\r\n value: string;\r\n format?:\r\n | \"CODE128\"\r\n | \"CODE39\"\r\n | \"EAN13\"\r\n | \"EAN8\"\r\n | \"UPC\"\r\n | \"ITF14\"\r\n | \"MSI\"\r\n | \"pharmacode\";\r\n width?: number;\r\n height?: number;\r\n showText?: boolean;\r\n fontSize?: number;\r\n textPosition?: \"bottom\" | \"top\";\r\n lineColor?: string;\r\n background?: string;\r\n showBorder?: boolean;\r\n label?: string;\r\n showLabel?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n format: \"CODE128\",\r\n width: 2,\r\n height: 80,\r\n showText: true,\r\n fontSize: 20,\r\n textPosition: \"bottom\",\r\n lineColor: \"#000000\",\r\n background: \"#FFFFFF\",\r\n showBorder: true,\r\n label: \"\",\r\n showLabel: false,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n error: [error: Error];\r\n}>();\r\n\r\nconst barcodeProps = computed(() => ({\r\n value: props.value,\r\n format: props.format,\r\n width: props.width,\r\n height: props.height,\r\n displayValue: props.showText,\r\n fontSize: props.fontSize,\r\n textPosition: props.textPosition,\r\n lineColor: props.lineColor,\r\n background: props.background,\r\n}));\r\n\r\nconst handleError = (error: Error) => {\r\n console.error(\"条形码生成失败:\", error);\r\n emit(\"error\", error);\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC+CA,MAAM,QAAQ;EAcd,MAAM,OAAO;EAIb,MAAM,eAAe,gBAAgB;GACnC,OAAO,MAAM;GACb,QAAQ,MAAM;GACd,OAAO,MAAM;GACb,QAAQ,MAAM;GACd,cAAc,MAAM;GACpB,UAAU,MAAM;GAChB,cAAc,MAAM;GACpB,WAAW,MAAM;GACjB,YAAY,MAAM;GACnB,EAAE;EAEH,MAAM,eAAe,UAAiB;AACpC,WAAQ,MAAM,YAAY,MAAM;AAChC,QAAK,SAAS,MAAM;;;uBAvEpB,mBAOM,OAPN,YAOM,CANJ,mBAEM,OAAA,EAFD,OAAK,eAAA,CAAC,mBAAiB,EAAA,eAA0BA,KAAAA,YAAU,CAAA,CAAA,KAC9D,YAAyD,MAAA,WAAA,EAAzD,WAAoB,aAAqC,OAAzB,EAAG,SAAO,aAAW,CAAA,EAAA,MAAA,GAAA,OAE5CC,KAAAA,aAAaC,KAAAA,sBAAxB,mBAEM,OAFN,YAEM,gBADDA,KAAAA,MAAK,EAAA,EAAA"}
1
+ {"version":3,"file":"C_Barcode2.js","names":["showBorder","showLabel","label"],"sources":["../src/components/C_Barcode/index.vue","../src/components/C_Barcode/index.vue","../src/components/C_Barcode/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-12-02\r\n * @Description: 条形码组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-barcode\">\r\n <div class=\"barcode-wrapper\" :class=\"{ 'with-border': showBorder }\">\r\n <VueBarcode v-bind=\"barcodeProps\" @error=\"handleError\" />\r\n </div>\r\n <div v-if=\"showLabel && label\" class=\"barcode-label\">\r\n {{ label }}\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from \"vue\";\r\nimport VueBarcode from \"@chenfengyuan/vue-barcode\";\r\n\r\ndefineOptions({ name: \"C_Barcode\" });\r\n\r\ninterface Props {\r\n value: string;\r\n format?:\r\n | \"CODE128\"\r\n | \"CODE39\"\r\n | \"EAN13\"\r\n | \"EAN8\"\r\n | \"UPC\"\r\n | \"ITF14\"\r\n | \"MSI\"\r\n | \"pharmacode\";\r\n width?: number;\r\n height?: number;\r\n showText?: boolean;\r\n fontSize?: number;\r\n textPosition?: \"bottom\" | \"top\";\r\n lineColor?: string;\r\n background?: string;\r\n showBorder?: boolean;\r\n label?: string;\r\n showLabel?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n format: \"CODE128\",\r\n width: 2,\r\n height: 80,\r\n showText: true,\r\n fontSize: 20,\r\n textPosition: \"bottom\",\r\n lineColor: \"#000000\",\r\n background: \"#FFFFFF\",\r\n showBorder: true,\r\n label: \"\",\r\n showLabel: false,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n error: [error: Error];\r\n}>();\r\n\r\nconst barcodeProps = computed(() => ({\r\n value: props.value,\r\n format: props.format,\r\n width: props.width,\r\n height: props.height,\r\n displayValue: props.showText,\r\n fontSize: props.fontSize,\r\n textPosition: props.textPosition,\r\n lineColor: props.lineColor,\r\n background: props.background,\r\n}));\r\n\r\nconst handleError = (error: Error) => {\r\n console.error(\"条形码生成失败:\", error);\r\n emit(\"error\", error);\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: 2025-12-02\r\n * @Description: 条形码组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-barcode\">\r\n <div class=\"barcode-wrapper\" :class=\"{ 'with-border': showBorder }\">\r\n <VueBarcode v-bind=\"barcodeProps\" @error=\"handleError\" />\r\n </div>\r\n <div v-if=\"showLabel && label\" class=\"barcode-label\">\r\n {{ label }}\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from \"vue\";\r\nimport VueBarcode from \"@chenfengyuan/vue-barcode\";\r\n\r\ndefineOptions({ name: \"C_Barcode\" });\r\n\r\ninterface Props {\r\n value: string;\r\n format?:\r\n | \"CODE128\"\r\n | \"CODE39\"\r\n | \"EAN13\"\r\n | \"EAN8\"\r\n | \"UPC\"\r\n | \"ITF14\"\r\n | \"MSI\"\r\n | \"pharmacode\";\r\n width?: number;\r\n height?: number;\r\n showText?: boolean;\r\n fontSize?: number;\r\n textPosition?: \"bottom\" | \"top\";\r\n lineColor?: string;\r\n background?: string;\r\n showBorder?: boolean;\r\n label?: string;\r\n showLabel?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n format: \"CODE128\",\r\n width: 2,\r\n height: 80,\r\n showText: true,\r\n fontSize: 20,\r\n textPosition: \"bottom\",\r\n lineColor: \"#000000\",\r\n background: \"#FFFFFF\",\r\n showBorder: true,\r\n label: \"\",\r\n showLabel: false,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n error: [error: Error];\r\n}>();\r\n\r\nconst barcodeProps = computed(() => ({\r\n value: props.value,\r\n format: props.format,\r\n width: props.width,\r\n height: props.height,\r\n displayValue: props.showText,\r\n fontSize: props.fontSize,\r\n textPosition: props.textPosition,\r\n lineColor: props.lineColor,\r\n background: props.background,\r\n}));\r\n\r\nconst handleError = (error: Error) => {\r\n console.error(\"条形码生成失败:\", error);\r\n emit(\"error\", error);\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: 2025-12-02\r\n * @Description: 条形码组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-barcode\">\r\n <div class=\"barcode-wrapper\" :class=\"{ 'with-border': showBorder }\">\r\n <VueBarcode v-bind=\"barcodeProps\" @error=\"handleError\" />\r\n </div>\r\n <div v-if=\"showLabel && label\" class=\"barcode-label\">\r\n {{ label }}\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from \"vue\";\r\nimport VueBarcode from \"@chenfengyuan/vue-barcode\";\r\n\r\ndefineOptions({ name: \"C_Barcode\" });\r\n\r\ninterface Props {\r\n value: string;\r\n format?:\r\n | \"CODE128\"\r\n | \"CODE39\"\r\n | \"EAN13\"\r\n | \"EAN8\"\r\n | \"UPC\"\r\n | \"ITF14\"\r\n | \"MSI\"\r\n | \"pharmacode\";\r\n width?: number;\r\n height?: number;\r\n showText?: boolean;\r\n fontSize?: number;\r\n textPosition?: \"bottom\" | \"top\";\r\n lineColor?: string;\r\n background?: string;\r\n showBorder?: boolean;\r\n label?: string;\r\n showLabel?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n format: \"CODE128\",\r\n width: 2,\r\n height: 80,\r\n showText: true,\r\n fontSize: 20,\r\n textPosition: \"bottom\",\r\n lineColor: \"#000000\",\r\n background: \"#FFFFFF\",\r\n showBorder: true,\r\n label: \"\",\r\n showLabel: false,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n error: [error: Error];\r\n}>();\r\n\r\nconst barcodeProps = computed(() => ({\r\n value: props.value,\r\n format: props.format,\r\n width: props.width,\r\n height: props.height,\r\n displayValue: props.showText,\r\n fontSize: props.fontSize,\r\n textPosition: props.textPosition,\r\n lineColor: props.lineColor,\r\n background: props.background,\r\n}));\r\n\r\nconst handleError = (error: Error) => {\r\n console.error(\"条形码生成失败:\", error);\r\n emit(\"error\", error);\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC+CA,MAAM,QAAQ;EAcd,MAAM,OAAO;EAIb,MAAM,eAAe,gBAAgB;GACnC,OAAO,MAAM;GACb,QAAQ,MAAM;GACd,OAAO,MAAM;GACb,QAAQ,MAAM;GACd,cAAc,MAAM;GACpB,UAAU,MAAM;GAChB,cAAc,MAAM;GACpB,WAAW,MAAM;GACjB,YAAY,MAAM;GACnB,EAAE;EAEH,MAAM,eAAe,UAAiB;AACpC,WAAQ,MAAM,YAAY,MAAM;AAChC,QAAK,SAAS,MAAM;;;uBAvEpB,mBAOM,OAPN,YAOM,CANJ,mBAEM,OAAA,EAFD,OAAK,eAAA,CAAC,mBAAiB,EAAA,eAA0BA,KAAAA,YAAU,CAAA,CAAA,KAC9D,YAAyD,MAAA,WAAA,EAAzD,WAAoB,aAAqC,OAAzB,EAAG,SAAO,aAAW,CAAA,EAAA,MAAA,GAAA,OAE5CC,KAAAA,aAAaC,KAAAA,sBAAxB,mBAEM,OAFN,YAEM,gBADDA,KAAAA,MAAK,EAAA,EAAA"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"C_Captcha-Ccq3DMrR.css","names":[],"sources":["../src/components/C_Captcha/index.vue?vue&type=style&index=0&scoped=74f1f0d1&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled */.c-captcha-modern[data-v-74f1f0d1] {\n width: 100%;\n font-family: inherit;\n}\n.captcha-trigger[data-v-74f1f0d1] {\n width: 100%;\n max-width: 280px;\n margin: 0 auto;\n padding: 12px 16px;\n cursor: pointer;\n user-select: none;\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n.captcha-trigger[data-v-74f1f0d1]:hover:not(.disabled) {\n transform: translateY(-1px);\n}\n.captcha-trigger.disabled[data-v-74f1f0d1] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.captcha-content[data-v-74f1f0d1] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n flex: 1;\n}\n.captcha-icon[data-v-74f1f0d1] {\n font-size: 18px;\n width: 20px;\n height: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n.captcha-text[data-v-74f1f0d1] {\n color: rgba(255, 255, 255, 0.8);\n font-size: 14px;\n font-weight: 500;\n letter-spacing: 0.3px;\n text-align: center;\n white-space: nowrap;\n}\n.refresh-button[data-v-74f1f0d1] {\n position: absolute;\n right: 12px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.3s ease;\n color: rgba(255, 255, 255, 0.6);\n font-size: 14px;\n flex-shrink: 0;\n}\n.refresh-button[data-v-74f1f0d1]:hover {\n color: rgba(255, 255, 255, 0.9);\n transform: translateY(-50%) rotate(180deg);\n}\n.success-icon[data-v-74f1f0d1],\n.success-text[data-v-74f1f0d1] {\n color: #43c23a;\n}\n.error-icon[data-v-74f1f0d1],\n.error-text[data-v-74f1f0d1] {\n color: #f56c6c;\n}\n@keyframes shake-74f1f0d1 {\n0%, 100% {\n transform: translateX(0);\n}\n25% {\n transform: translateX(-4px);\n}\n75% {\n transform: translateX(4px);\n}\n}\n@media (max-width: 768px) {\n.captcha-trigger[data-v-74f1f0d1] {\n max-width: 240px;\n padding: 10px 14px;\n}\n.captcha-icon[data-v-74f1f0d1] {\n font-size: 16px;\n width: 18px;\n height: 18px;\n}\n.captcha-text[data-v-74f1f0d1] {\n font-size: 13px;\n}\n.refresh-button[data-v-74f1f0d1] {\n width: 24px;\n height: 24px;\n font-size: 12px;\n right: 10px;\n}\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
@@ -148,7 +148,7 @@ var index_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCo
148
148
 
149
149
  //#endregion
150
150
  //#region src/components/C_Captcha/index.vue
151
- var C_Captcha_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-c6e8ac8a"]]);
151
+ var C_Captcha_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-74f1f0d1"]]);
152
152
 
153
153
  //#endregion
154
154
  export { C_Captcha_default as t };
@@ -1 +1 @@
1
- {"version":3,"file":"C_Captcha2.js","names":["disabled","triggerText"],"sources":["../src/components/C_Captcha/index.vue","../src/components/C_Captcha/index.vue","../src/components/C_Captcha/index.vue"],"sourcesContent":["<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-07-23\r\n * @Description: 基于 vue3-puzzle-vcode 封装的验证器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-captcha-modern\">\r\n <div\r\n class=\"captcha-trigger\"\r\n @click=\"showCaptcha\"\r\n :class=\"{\r\n verified: isVerified,\r\n error: hasError,\r\n disabled: disabled,\r\n }\"\r\n >\r\n <div class=\"captcha-content\">\r\n <div class=\"captcha-icon\">\r\n <span v-if=\"!isVerified && !hasError\">🧩</span>\r\n <span v-if=\"isVerified\" class=\"success-icon\">✓</span>\r\n <span v-if=\"hasError\" class=\"error-icon\">⚠️</span>\r\n </div>\r\n <div class=\"captcha-text\">\r\n <span v-if=\"!isVerified && !hasError\">{{ triggerText }}</span>\r\n <span v-if=\"isVerified\" class=\"success-text\">验证成功</span>\r\n <span v-if=\"hasError\" class=\"error-text\">验证失败,请重试</span>\r\n </div>\r\n </div>\r\n <div\r\n v-if=\"isVerified || hasError\"\r\n class=\"refresh-button\"\r\n @click.stop=\"resetCaptcha\"\r\n title=\"重新验证\"\r\n >\r\n ⟲\r\n </div>\r\n </div>\r\n <PuzzleVcode\r\n :show=\"showModal\"\r\n :imgs=\"captchaImages\"\r\n @success=\"handleSuccess\"\r\n @close=\"handleClose\"\r\n @fail=\"handleFail\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onBeforeUnmount } from \"vue\";\r\nimport PuzzleVcode from \"vue3-puzzle-vcode\";\r\n\r\ndefineOptions({ name: \"C_Captcha\" });\r\n\r\ninterface CaptchaProps {\r\n triggerText?: string;\r\n images?: string[];\r\n disabled?: boolean;\r\n theme?: \"light\" | \"dark\";\r\n}\r\n\r\ninterface CaptchaEmits {\r\n (e: \"success\", data: { token: string; timestamp: number }): void;\r\n (e: \"fail\", error: string): void;\r\n (e: \"change\", valid: boolean): void;\r\n (e: \"reset\"): void;\r\n}\r\n\r\nconst props = withDefaults(defineProps<CaptchaProps>(), {\r\n triggerText: \"点击进行人机验证\",\r\n images: () => [],\r\n disabled: false,\r\n theme: \"dark\",\r\n});\r\n\r\nconst emit = defineEmits<CaptchaEmits>();\r\n\r\nconst showModal = ref(false);\r\nconst isVerified = ref(false);\r\nconst hasError = ref(false);\r\nconst verificationToken = ref(\"\");\r\nlet errorTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\nconst captchaImages = computed(() =>\r\n props.images.length > 0 ? props.images : undefined,\r\n);\r\n\r\nconst showCaptcha = () => {\r\n if (props.disabled || isVerified.value) return;\r\n hasError.value = false;\r\n showModal.value = true;\r\n};\r\n\r\nconst handleSuccess = () => {\r\n isVerified.value = true;\r\n hasError.value = false;\r\n showModal.value = false;\r\n const timestamp = Date.now();\r\n const token = `puzzle_${timestamp}_${Math.random().toString(36).substring(2, 9)}`;\r\n verificationToken.value = token;\r\n emit(\"success\", { token, timestamp });\r\n emit(\"change\", true);\r\n};\r\n\r\nconst handleFail = () => {\r\n isVerified.value = false;\r\n hasError.value = true;\r\n showModal.value = false;\r\n if (errorTimer) clearTimeout(errorTimer);\r\n errorTimer = setTimeout(() => {\r\n hasError.value = false;\r\n errorTimer = null;\r\n }, 3000);\r\n emit(\"fail\", \"拼图验证失败\");\r\n emit(\"change\", false);\r\n};\r\n\r\nconst handleClose = () => {\r\n showModal.value = false;\r\n};\r\n\r\nconst resetCaptcha = () => {\r\n isVerified.value = false;\r\n hasError.value = false;\r\n showModal.value = false;\r\n verificationToken.value = \"\";\r\n if (errorTimer) {\r\n clearTimeout(errorTimer);\r\n errorTimer = null;\r\n }\r\n emit(\"reset\");\r\n emit(\"change\", false);\r\n};\r\n\r\ndefineExpose({\r\n validate: () => isVerified.value,\r\n getToken: () => verificationToken.value,\r\n getVerificationData: () => {\r\n if (!isVerified.value) return null;\r\n return {\r\n token: verificationToken.value,\r\n timestamp: Date.now(),\r\n type: \"puzzle-captcha\",\r\n };\r\n },\r\n reset: resetCaptcha,\r\n show: showCaptcha,\r\n});\r\n\r\nonBeforeUnmount(() => {\r\n if (errorTimer) clearTimeout(errorTimer);\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-07-23\r\n * @Description: 基于 vue3-puzzle-vcode 封装的验证器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-captcha-modern\">\r\n <div\r\n class=\"captcha-trigger\"\r\n @click=\"showCaptcha\"\r\n :class=\"{\r\n verified: isVerified,\r\n error: hasError,\r\n disabled: disabled,\r\n }\"\r\n >\r\n <div class=\"captcha-content\">\r\n <div class=\"captcha-icon\">\r\n <span v-if=\"!isVerified && !hasError\">🧩</span>\r\n <span v-if=\"isVerified\" class=\"success-icon\">✓</span>\r\n <span v-if=\"hasError\" class=\"error-icon\">⚠️</span>\r\n </div>\r\n <div class=\"captcha-text\">\r\n <span v-if=\"!isVerified && !hasError\">{{ triggerText }}</span>\r\n <span v-if=\"isVerified\" class=\"success-text\">验证成功</span>\r\n <span v-if=\"hasError\" class=\"error-text\">验证失败,请重试</span>\r\n </div>\r\n </div>\r\n <div\r\n v-if=\"isVerified || hasError\"\r\n class=\"refresh-button\"\r\n @click.stop=\"resetCaptcha\"\r\n title=\"重新验证\"\r\n >\r\n ⟲\r\n </div>\r\n </div>\r\n <PuzzleVcode\r\n :show=\"showModal\"\r\n :imgs=\"captchaImages\"\r\n @success=\"handleSuccess\"\r\n @close=\"handleClose\"\r\n @fail=\"handleFail\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onBeforeUnmount } from \"vue\";\r\nimport PuzzleVcode from \"vue3-puzzle-vcode\";\r\n\r\ndefineOptions({ name: \"C_Captcha\" });\r\n\r\ninterface CaptchaProps {\r\n triggerText?: string;\r\n images?: string[];\r\n disabled?: boolean;\r\n theme?: \"light\" | \"dark\";\r\n}\r\n\r\ninterface CaptchaEmits {\r\n (e: \"success\", data: { token: string; timestamp: number }): void;\r\n (e: \"fail\", error: string): void;\r\n (e: \"change\", valid: boolean): void;\r\n (e: \"reset\"): void;\r\n}\r\n\r\nconst props = withDefaults(defineProps<CaptchaProps>(), {\r\n triggerText: \"点击进行人机验证\",\r\n images: () => [],\r\n disabled: false,\r\n theme: \"dark\",\r\n});\r\n\r\nconst emit = defineEmits<CaptchaEmits>();\r\n\r\nconst showModal = ref(false);\r\nconst isVerified = ref(false);\r\nconst hasError = ref(false);\r\nconst verificationToken = ref(\"\");\r\nlet errorTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\nconst captchaImages = computed(() =>\r\n props.images.length > 0 ? props.images : undefined,\r\n);\r\n\r\nconst showCaptcha = () => {\r\n if (props.disabled || isVerified.value) return;\r\n hasError.value = false;\r\n showModal.value = true;\r\n};\r\n\r\nconst handleSuccess = () => {\r\n isVerified.value = true;\r\n hasError.value = false;\r\n showModal.value = false;\r\n const timestamp = Date.now();\r\n const token = `puzzle_${timestamp}_${Math.random().toString(36).substring(2, 9)}`;\r\n verificationToken.value = token;\r\n emit(\"success\", { token, timestamp });\r\n emit(\"change\", true);\r\n};\r\n\r\nconst handleFail = () => {\r\n isVerified.value = false;\r\n hasError.value = true;\r\n showModal.value = false;\r\n if (errorTimer) clearTimeout(errorTimer);\r\n errorTimer = setTimeout(() => {\r\n hasError.value = false;\r\n errorTimer = null;\r\n }, 3000);\r\n emit(\"fail\", \"拼图验证失败\");\r\n emit(\"change\", false);\r\n};\r\n\r\nconst handleClose = () => {\r\n showModal.value = false;\r\n};\r\n\r\nconst resetCaptcha = () => {\r\n isVerified.value = false;\r\n hasError.value = false;\r\n showModal.value = false;\r\n verificationToken.value = \"\";\r\n if (errorTimer) {\r\n clearTimeout(errorTimer);\r\n errorTimer = null;\r\n }\r\n emit(\"reset\");\r\n emit(\"change\", false);\r\n};\r\n\r\ndefineExpose({\r\n validate: () => isVerified.value,\r\n getToken: () => verificationToken.value,\r\n getVerificationData: () => {\r\n if (!isVerified.value) return null;\r\n return {\r\n token: verificationToken.value,\r\n timestamp: Date.now(),\r\n type: \"puzzle-captcha\",\r\n };\r\n },\r\n reset: resetCaptcha,\r\n show: showCaptcha,\r\n});\r\n\r\nonBeforeUnmount(() => {\r\n if (errorTimer) clearTimeout(errorTimer);\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-07-23\r\n * @Description: 基于 vue3-puzzle-vcode 封装的验证器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-captcha-modern\">\r\n <div\r\n class=\"captcha-trigger\"\r\n @click=\"showCaptcha\"\r\n :class=\"{\r\n verified: isVerified,\r\n error: hasError,\r\n disabled: disabled,\r\n }\"\r\n >\r\n <div class=\"captcha-content\">\r\n <div class=\"captcha-icon\">\r\n <span v-if=\"!isVerified && !hasError\">🧩</span>\r\n <span v-if=\"isVerified\" class=\"success-icon\">✓</span>\r\n <span v-if=\"hasError\" class=\"error-icon\">⚠️</span>\r\n </div>\r\n <div class=\"captcha-text\">\r\n <span v-if=\"!isVerified && !hasError\">{{ triggerText }}</span>\r\n <span v-if=\"isVerified\" class=\"success-text\">验证成功</span>\r\n <span v-if=\"hasError\" class=\"error-text\">验证失败,请重试</span>\r\n </div>\r\n </div>\r\n <div\r\n v-if=\"isVerified || hasError\"\r\n class=\"refresh-button\"\r\n @click.stop=\"resetCaptcha\"\r\n title=\"重新验证\"\r\n >\r\n ⟲\r\n </div>\r\n </div>\r\n <PuzzleVcode\r\n :show=\"showModal\"\r\n :imgs=\"captchaImages\"\r\n @success=\"handleSuccess\"\r\n @close=\"handleClose\"\r\n @fail=\"handleFail\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onBeforeUnmount } from \"vue\";\r\nimport PuzzleVcode from \"vue3-puzzle-vcode\";\r\n\r\ndefineOptions({ name: \"C_Captcha\" });\r\n\r\ninterface CaptchaProps {\r\n triggerText?: string;\r\n images?: string[];\r\n disabled?: boolean;\r\n theme?: \"light\" | \"dark\";\r\n}\r\n\r\ninterface CaptchaEmits {\r\n (e: \"success\", data: { token: string; timestamp: number }): void;\r\n (e: \"fail\", error: string): void;\r\n (e: \"change\", valid: boolean): void;\r\n (e: \"reset\"): void;\r\n}\r\n\r\nconst props = withDefaults(defineProps<CaptchaProps>(), {\r\n triggerText: \"点击进行人机验证\",\r\n images: () => [],\r\n disabled: false,\r\n theme: \"dark\",\r\n});\r\n\r\nconst emit = defineEmits<CaptchaEmits>();\r\n\r\nconst showModal = ref(false);\r\nconst isVerified = ref(false);\r\nconst hasError = ref(false);\r\nconst verificationToken = ref(\"\");\r\nlet errorTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\nconst captchaImages = computed(() =>\r\n props.images.length > 0 ? props.images : undefined,\r\n);\r\n\r\nconst showCaptcha = () => {\r\n if (props.disabled || isVerified.value) return;\r\n hasError.value = false;\r\n showModal.value = true;\r\n};\r\n\r\nconst handleSuccess = () => {\r\n isVerified.value = true;\r\n hasError.value = false;\r\n showModal.value = false;\r\n const timestamp = Date.now();\r\n const token = `puzzle_${timestamp}_${Math.random().toString(36).substring(2, 9)}`;\r\n verificationToken.value = token;\r\n emit(\"success\", { token, timestamp });\r\n emit(\"change\", true);\r\n};\r\n\r\nconst handleFail = () => {\r\n isVerified.value = false;\r\n hasError.value = true;\r\n showModal.value = false;\r\n if (errorTimer) clearTimeout(errorTimer);\r\n errorTimer = setTimeout(() => {\r\n hasError.value = false;\r\n errorTimer = null;\r\n }, 3000);\r\n emit(\"fail\", \"拼图验证失败\");\r\n emit(\"change\", false);\r\n};\r\n\r\nconst handleClose = () => {\r\n showModal.value = false;\r\n};\r\n\r\nconst resetCaptcha = () => {\r\n isVerified.value = false;\r\n hasError.value = false;\r\n showModal.value = false;\r\n verificationToken.value = \"\";\r\n if (errorTimer) {\r\n clearTimeout(errorTimer);\r\n errorTimer = null;\r\n }\r\n emit(\"reset\");\r\n emit(\"change\", false);\r\n};\r\n\r\ndefineExpose({\r\n validate: () => isVerified.value,\r\n getToken: () => verificationToken.value,\r\n getVerificationData: () => {\r\n if (!isVerified.value) return null;\r\n return {\r\n token: verificationToken.value,\r\n timestamp: Date.now(),\r\n type: \"puzzle-captcha\",\r\n };\r\n },\r\n reset: resetCaptcha,\r\n show: showCaptcha,\r\n});\r\n\r\nonBeforeUnmount(() => {\r\n if (errorTimer) clearTimeout(errorTimer);\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECqEA,MAAM,QAAQ;EAOd,MAAM,OAAO;EAEb,MAAM,YAAY,IAAI,MAAM;EAC5B,MAAM,aAAa,IAAI,MAAM;EAC7B,MAAM,WAAW,IAAI,MAAM;EAC3B,MAAM,oBAAoB,IAAI,GAAG;EACjC,IAAI,aAAmD;EAEvD,MAAM,gBAAgB,eACpB,MAAM,OAAO,SAAS,IAAI,MAAM,SAAS,OAC1C;EAED,MAAM,oBAAoB;AACxB,OAAI,MAAM,YAAY,WAAW,MAAO;AACxC,YAAS,QAAQ;AACjB,aAAU,QAAQ;;EAGpB,MAAM,sBAAsB;AAC1B,cAAW,QAAQ;AACnB,YAAS,QAAQ;AACjB,aAAU,QAAQ;GAClB,MAAM,YAAY,KAAK,KAAK;GAC5B,MAAM,QAAQ,UAAU,UAAU,GAAG,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,UAAU,GAAG,EAAE;AAC/E,qBAAkB,QAAQ;AAC1B,QAAK,WAAW;IAAE;IAAO;IAAW,CAAC;AACrC,QAAK,UAAU,KAAK;;EAGtB,MAAM,mBAAmB;AACvB,cAAW,QAAQ;AACnB,YAAS,QAAQ;AACjB,aAAU,QAAQ;AAClB,OAAI,WAAY,cAAa,WAAW;AACxC,gBAAa,iBAAiB;AAC5B,aAAS,QAAQ;AACjB,iBAAa;MACZ,IAAK;AACR,QAAK,QAAQ,SAAS;AACtB,QAAK,UAAU,MAAM;;EAGvB,MAAM,oBAAoB;AACxB,aAAU,QAAQ;;EAGpB,MAAM,qBAAqB;AACzB,cAAW,QAAQ;AACnB,YAAS,QAAQ;AACjB,aAAU,QAAQ;AAClB,qBAAkB,QAAQ;AAC1B,OAAI,YAAY;AACd,iBAAa,WAAW;AACxB,iBAAa;;AAEf,QAAK,QAAQ;AACb,QAAK,UAAU,MAAM;;AAGvB,WAAa;GACX,gBAAgB,WAAW;GAC3B,gBAAgB,kBAAkB;GAClC,2BAA2B;AACzB,QAAI,CAAC,WAAW,MAAO,QAAO;AAC9B,WAAO;KACL,OAAO,kBAAkB;KACzB,WAAW,KAAK,KAAK;KACrB,MAAM;KACP;;GAEH,OAAO;GACP,MAAM;GACP,CAAC;AAEF,wBAAsB;AACpB,OAAI,WAAY,cAAa,WAAW;IACxC;;uBAhJA,mBAsCM,OAtCN,YAsCM,CArCJ,mBA6BM,OAAA;IA5BJ,OAAK,eAAA,CAAC,mBAAiB;eAEM,WAAA;YAA4B,SAAA;eAA6BA,KAAAA;;IADrF,SAAO;OAOR,mBAWM,OAXN,YAWM,CAVJ,mBAIM,OAJN,YAIM;KAHS,WAAA,SAAU,CAAK,SAAA,sBAA5B,mBAA+C,QAAA,YAAT,KAAE;IAC5B,WAAA,sBAAZ,mBAAqD,QAArD,YAA6C,IAAC;IAClC,SAAA,sBAAZ,mBAAkD,QAAlD,YAAyC,KAAE;OAE7C,mBAIM,OAJN,YAIM;KAHS,WAAA,SAAU,CAAK,SAAA,sBAA5B,mBAA8D,QAAA,YAAA,gBAArBC,KAAAA,YAAW,EAAA,EAAA;IACxC,WAAA,sBAAZ,mBAAwD,QAAxD,YAA6C,OAAI;IACrC,SAAA,sBAAZ,mBAAwD,QAAxD,aAAyC,WAAQ;SAI7C,WAAA,SAAc,SAAA,sBADtB,mBAOM,OAAA;;IALJ,OAAM;IACL,SAAK,cAAO,cAAY,CAAA,OAAA,CAAA;IACzB,OAAM;MACP,MAED,2CAEF,YAME,MAAA,YAAA,EAAA;IALC,MAAM,UAAA;IACN,MAAM,cAAA;IACN,WAAS;IACT,SAAO;IACP,QAAM"}
1
+ {"version":3,"file":"C_Captcha2.js","names":["disabled","triggerText"],"sources":["../src/components/C_Captcha/index.vue","../src/components/C_Captcha/index.vue","../src/components/C_Captcha/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-07-23\r\n * @Description: 基于 vue3-puzzle-vcode 封装的验证器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-captcha-modern\">\r\n <div\r\n class=\"captcha-trigger\"\r\n @click=\"showCaptcha\"\r\n :class=\"{\r\n verified: isVerified,\r\n error: hasError,\r\n disabled: disabled,\r\n }\"\r\n >\r\n <div class=\"captcha-content\">\r\n <div class=\"captcha-icon\">\r\n <span v-if=\"!isVerified && !hasError\">🧩</span>\r\n <span v-if=\"isVerified\" class=\"success-icon\">✓</span>\r\n <span v-if=\"hasError\" class=\"error-icon\">⚠️</span>\r\n </div>\r\n <div class=\"captcha-text\">\r\n <span v-if=\"!isVerified && !hasError\">{{ triggerText }}</span>\r\n <span v-if=\"isVerified\" class=\"success-text\">验证成功</span>\r\n <span v-if=\"hasError\" class=\"error-text\">验证失败,请重试</span>\r\n </div>\r\n </div>\r\n <div\r\n v-if=\"isVerified || hasError\"\r\n class=\"refresh-button\"\r\n @click.stop=\"resetCaptcha\"\r\n title=\"重新验证\"\r\n >\r\n ⟲\r\n </div>\r\n </div>\r\n <PuzzleVcode\r\n :show=\"showModal\"\r\n :imgs=\"captchaImages\"\r\n @success=\"handleSuccess\"\r\n @close=\"handleClose\"\r\n @fail=\"handleFail\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onBeforeUnmount } from \"vue\";\r\nimport PuzzleVcode from \"vue3-puzzle-vcode\";\r\n\r\ndefineOptions({ name: \"C_Captcha\" });\r\n\r\ninterface CaptchaProps {\r\n triggerText?: string;\r\n images?: string[];\r\n disabled?: boolean;\r\n theme?: \"light\" | \"dark\";\r\n}\r\n\r\ninterface CaptchaEmits {\r\n (e: \"success\", data: { token: string; timestamp: number }): void;\r\n (e: \"fail\", error: string): void;\r\n (e: \"change\", valid: boolean): void;\r\n (e: \"reset\"): void;\r\n}\r\n\r\nconst props = withDefaults(defineProps<CaptchaProps>(), {\r\n triggerText: \"点击进行人机验证\",\r\n images: () => [],\r\n disabled: false,\r\n theme: \"dark\",\r\n});\r\n\r\nconst emit = defineEmits<CaptchaEmits>();\r\n\r\nconst showModal = ref(false);\r\nconst isVerified = ref(false);\r\nconst hasError = ref(false);\r\nconst verificationToken = ref(\"\");\r\nlet errorTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\nconst captchaImages = computed(() =>\r\n props.images.length > 0 ? props.images : undefined,\r\n);\r\n\r\nconst showCaptcha = () => {\r\n if (props.disabled || isVerified.value) return;\r\n hasError.value = false;\r\n showModal.value = true;\r\n};\r\n\r\nconst handleSuccess = () => {\r\n isVerified.value = true;\r\n hasError.value = false;\r\n showModal.value = false;\r\n const timestamp = Date.now();\r\n const token = `puzzle_${timestamp}_${Math.random().toString(36).substring(2, 9)}`;\r\n verificationToken.value = token;\r\n emit(\"success\", { token, timestamp });\r\n emit(\"change\", true);\r\n};\r\n\r\nconst handleFail = () => {\r\n isVerified.value = false;\r\n hasError.value = true;\r\n showModal.value = false;\r\n if (errorTimer) clearTimeout(errorTimer);\r\n errorTimer = setTimeout(() => {\r\n hasError.value = false;\r\n errorTimer = null;\r\n }, 3000);\r\n emit(\"fail\", \"拼图验证失败\");\r\n emit(\"change\", false);\r\n};\r\n\r\nconst handleClose = () => {\r\n showModal.value = false;\r\n};\r\n\r\nconst resetCaptcha = () => {\r\n isVerified.value = false;\r\n hasError.value = false;\r\n showModal.value = false;\r\n verificationToken.value = \"\";\r\n if (errorTimer) {\r\n clearTimeout(errorTimer);\r\n errorTimer = null;\r\n }\r\n emit(\"reset\");\r\n emit(\"change\", false);\r\n};\r\n\r\ndefineExpose({\r\n validate: () => isVerified.value,\r\n getToken: () => verificationToken.value,\r\n getVerificationData: () => {\r\n if (!isVerified.value) return null;\r\n return {\r\n token: verificationToken.value,\r\n timestamp: Date.now(),\r\n type: \"puzzle-captcha\",\r\n };\r\n },\r\n reset: resetCaptcha,\r\n show: showCaptcha,\r\n});\r\n\r\nonBeforeUnmount(() => {\r\n if (errorTimer) clearTimeout(errorTimer);\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n@use \"./index.scss\";\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-07-23\r\n * @Description: 基于 vue3-puzzle-vcode 封装的验证器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-captcha-modern\">\r\n <div\r\n class=\"captcha-trigger\"\r\n @click=\"showCaptcha\"\r\n :class=\"{\r\n verified: isVerified,\r\n error: hasError,\r\n disabled: disabled,\r\n }\"\r\n >\r\n <div class=\"captcha-content\">\r\n <div class=\"captcha-icon\">\r\n <span v-if=\"!isVerified && !hasError\">🧩</span>\r\n <span v-if=\"isVerified\" class=\"success-icon\">✓</span>\r\n <span v-if=\"hasError\" class=\"error-icon\">⚠️</span>\r\n </div>\r\n <div class=\"captcha-text\">\r\n <span v-if=\"!isVerified && !hasError\">{{ triggerText }}</span>\r\n <span v-if=\"isVerified\" class=\"success-text\">验证成功</span>\r\n <span v-if=\"hasError\" class=\"error-text\">验证失败,请重试</span>\r\n </div>\r\n </div>\r\n <div\r\n v-if=\"isVerified || hasError\"\r\n class=\"refresh-button\"\r\n @click.stop=\"resetCaptcha\"\r\n title=\"重新验证\"\r\n >\r\n ⟲\r\n </div>\r\n </div>\r\n <PuzzleVcode\r\n :show=\"showModal\"\r\n :imgs=\"captchaImages\"\r\n @success=\"handleSuccess\"\r\n @close=\"handleClose\"\r\n @fail=\"handleFail\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onBeforeUnmount } from \"vue\";\r\nimport PuzzleVcode from \"vue3-puzzle-vcode\";\r\n\r\ndefineOptions({ name: \"C_Captcha\" });\r\n\r\ninterface CaptchaProps {\r\n triggerText?: string;\r\n images?: string[];\r\n disabled?: boolean;\r\n theme?: \"light\" | \"dark\";\r\n}\r\n\r\ninterface CaptchaEmits {\r\n (e: \"success\", data: { token: string; timestamp: number }): void;\r\n (e: \"fail\", error: string): void;\r\n (e: \"change\", valid: boolean): void;\r\n (e: \"reset\"): void;\r\n}\r\n\r\nconst props = withDefaults(defineProps<CaptchaProps>(), {\r\n triggerText: \"点击进行人机验证\",\r\n images: () => [],\r\n disabled: false,\r\n theme: \"dark\",\r\n});\r\n\r\nconst emit = defineEmits<CaptchaEmits>();\r\n\r\nconst showModal = ref(false);\r\nconst isVerified = ref(false);\r\nconst hasError = ref(false);\r\nconst verificationToken = ref(\"\");\r\nlet errorTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\nconst captchaImages = computed(() =>\r\n props.images.length > 0 ? props.images : undefined,\r\n);\r\n\r\nconst showCaptcha = () => {\r\n if (props.disabled || isVerified.value) return;\r\n hasError.value = false;\r\n showModal.value = true;\r\n};\r\n\r\nconst handleSuccess = () => {\r\n isVerified.value = true;\r\n hasError.value = false;\r\n showModal.value = false;\r\n const timestamp = Date.now();\r\n const token = `puzzle_${timestamp}_${Math.random().toString(36).substring(2, 9)}`;\r\n verificationToken.value = token;\r\n emit(\"success\", { token, timestamp });\r\n emit(\"change\", true);\r\n};\r\n\r\nconst handleFail = () => {\r\n isVerified.value = false;\r\n hasError.value = true;\r\n showModal.value = false;\r\n if (errorTimer) clearTimeout(errorTimer);\r\n errorTimer = setTimeout(() => {\r\n hasError.value = false;\r\n errorTimer = null;\r\n }, 3000);\r\n emit(\"fail\", \"拼图验证失败\");\r\n emit(\"change\", false);\r\n};\r\n\r\nconst handleClose = () => {\r\n showModal.value = false;\r\n};\r\n\r\nconst resetCaptcha = () => {\r\n isVerified.value = false;\r\n hasError.value = false;\r\n showModal.value = false;\r\n verificationToken.value = \"\";\r\n if (errorTimer) {\r\n clearTimeout(errorTimer);\r\n errorTimer = null;\r\n }\r\n emit(\"reset\");\r\n emit(\"change\", false);\r\n};\r\n\r\ndefineExpose({\r\n validate: () => isVerified.value,\r\n getToken: () => verificationToken.value,\r\n getVerificationData: () => {\r\n if (!isVerified.value) return null;\r\n return {\r\n token: verificationToken.value,\r\n timestamp: Date.now(),\r\n type: \"puzzle-captcha\",\r\n };\r\n },\r\n reset: resetCaptcha,\r\n show: showCaptcha,\r\n});\r\n\r\nonBeforeUnmount(() => {\r\n if (errorTimer) clearTimeout(errorTimer);\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-07-23\r\n * @Description: 基于 vue3-puzzle-vcode 封装的验证器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-captcha-modern\">\r\n <div\r\n class=\"captcha-trigger\"\r\n @click=\"showCaptcha\"\r\n :class=\"{\r\n verified: isVerified,\r\n error: hasError,\r\n disabled: disabled,\r\n }\"\r\n >\r\n <div class=\"captcha-content\">\r\n <div class=\"captcha-icon\">\r\n <span v-if=\"!isVerified && !hasError\">🧩</span>\r\n <span v-if=\"isVerified\" class=\"success-icon\">✓</span>\r\n <span v-if=\"hasError\" class=\"error-icon\">⚠️</span>\r\n </div>\r\n <div class=\"captcha-text\">\r\n <span v-if=\"!isVerified && !hasError\">{{ triggerText }}</span>\r\n <span v-if=\"isVerified\" class=\"success-text\">验证成功</span>\r\n <span v-if=\"hasError\" class=\"error-text\">验证失败,请重试</span>\r\n </div>\r\n </div>\r\n <div\r\n v-if=\"isVerified || hasError\"\r\n class=\"refresh-button\"\r\n @click.stop=\"resetCaptcha\"\r\n title=\"重新验证\"\r\n >\r\n ⟲\r\n </div>\r\n </div>\r\n <PuzzleVcode\r\n :show=\"showModal\"\r\n :imgs=\"captchaImages\"\r\n @success=\"handleSuccess\"\r\n @close=\"handleClose\"\r\n @fail=\"handleFail\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onBeforeUnmount } from \"vue\";\r\nimport PuzzleVcode from \"vue3-puzzle-vcode\";\r\n\r\ndefineOptions({ name: \"C_Captcha\" });\r\n\r\ninterface CaptchaProps {\r\n triggerText?: string;\r\n images?: string[];\r\n disabled?: boolean;\r\n theme?: \"light\" | \"dark\";\r\n}\r\n\r\ninterface CaptchaEmits {\r\n (e: \"success\", data: { token: string; timestamp: number }): void;\r\n (e: \"fail\", error: string): void;\r\n (e: \"change\", valid: boolean): void;\r\n (e: \"reset\"): void;\r\n}\r\n\r\nconst props = withDefaults(defineProps<CaptchaProps>(), {\r\n triggerText: \"点击进行人机验证\",\r\n images: () => [],\r\n disabled: false,\r\n theme: \"dark\",\r\n});\r\n\r\nconst emit = defineEmits<CaptchaEmits>();\r\n\r\nconst showModal = ref(false);\r\nconst isVerified = ref(false);\r\nconst hasError = ref(false);\r\nconst verificationToken = ref(\"\");\r\nlet errorTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\nconst captchaImages = computed(() =>\r\n props.images.length > 0 ? props.images : undefined,\r\n);\r\n\r\nconst showCaptcha = () => {\r\n if (props.disabled || isVerified.value) return;\r\n hasError.value = false;\r\n showModal.value = true;\r\n};\r\n\r\nconst handleSuccess = () => {\r\n isVerified.value = true;\r\n hasError.value = false;\r\n showModal.value = false;\r\n const timestamp = Date.now();\r\n const token = `puzzle_${timestamp}_${Math.random().toString(36).substring(2, 9)}`;\r\n verificationToken.value = token;\r\n emit(\"success\", { token, timestamp });\r\n emit(\"change\", true);\r\n};\r\n\r\nconst handleFail = () => {\r\n isVerified.value = false;\r\n hasError.value = true;\r\n showModal.value = false;\r\n if (errorTimer) clearTimeout(errorTimer);\r\n errorTimer = setTimeout(() => {\r\n hasError.value = false;\r\n errorTimer = null;\r\n }, 3000);\r\n emit(\"fail\", \"拼图验证失败\");\r\n emit(\"change\", false);\r\n};\r\n\r\nconst handleClose = () => {\r\n showModal.value = false;\r\n};\r\n\r\nconst resetCaptcha = () => {\r\n isVerified.value = false;\r\n hasError.value = false;\r\n showModal.value = false;\r\n verificationToken.value = \"\";\r\n if (errorTimer) {\r\n clearTimeout(errorTimer);\r\n errorTimer = null;\r\n }\r\n emit(\"reset\");\r\n emit(\"change\", false);\r\n};\r\n\r\ndefineExpose({\r\n validate: () => isVerified.value,\r\n getToken: () => verificationToken.value,\r\n getVerificationData: () => {\r\n if (!isVerified.value) return null;\r\n return {\r\n token: verificationToken.value,\r\n timestamp: Date.now(),\r\n type: \"puzzle-captcha\",\r\n };\r\n },\r\n reset: resetCaptcha,\r\n show: showCaptcha,\r\n});\r\n\r\nonBeforeUnmount(() => {\r\n if (errorTimer) clearTimeout(errorTimer);\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECqEA,MAAM,QAAQ;EAOd,MAAM,OAAO;EAEb,MAAM,YAAY,IAAI,MAAM;EAC5B,MAAM,aAAa,IAAI,MAAM;EAC7B,MAAM,WAAW,IAAI,MAAM;EAC3B,MAAM,oBAAoB,IAAI,GAAG;EACjC,IAAI,aAAmD;EAEvD,MAAM,gBAAgB,eACpB,MAAM,OAAO,SAAS,IAAI,MAAM,SAAS,OAC1C;EAED,MAAM,oBAAoB;AACxB,OAAI,MAAM,YAAY,WAAW,MAAO;AACxC,YAAS,QAAQ;AACjB,aAAU,QAAQ;;EAGpB,MAAM,sBAAsB;AAC1B,cAAW,QAAQ;AACnB,YAAS,QAAQ;AACjB,aAAU,QAAQ;GAClB,MAAM,YAAY,KAAK,KAAK;GAC5B,MAAM,QAAQ,UAAU,UAAU,GAAG,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,UAAU,GAAG,EAAE;AAC/E,qBAAkB,QAAQ;AAC1B,QAAK,WAAW;IAAE;IAAO;IAAW,CAAC;AACrC,QAAK,UAAU,KAAK;;EAGtB,MAAM,mBAAmB;AACvB,cAAW,QAAQ;AACnB,YAAS,QAAQ;AACjB,aAAU,QAAQ;AAClB,OAAI,WAAY,cAAa,WAAW;AACxC,gBAAa,iBAAiB;AAC5B,aAAS,QAAQ;AACjB,iBAAa;MACZ,IAAK;AACR,QAAK,QAAQ,SAAS;AACtB,QAAK,UAAU,MAAM;;EAGvB,MAAM,oBAAoB;AACxB,aAAU,QAAQ;;EAGpB,MAAM,qBAAqB;AACzB,cAAW,QAAQ;AACnB,YAAS,QAAQ;AACjB,aAAU,QAAQ;AAClB,qBAAkB,QAAQ;AAC1B,OAAI,YAAY;AACd,iBAAa,WAAW;AACxB,iBAAa;;AAEf,QAAK,QAAQ;AACb,QAAK,UAAU,MAAM;;AAGvB,WAAa;GACX,gBAAgB,WAAW;GAC3B,gBAAgB,kBAAkB;GAClC,2BAA2B;AACzB,QAAI,CAAC,WAAW,MAAO,QAAO;AAC9B,WAAO;KACL,OAAO,kBAAkB;KACzB,WAAW,KAAK,KAAK;KACrB,MAAM;KACP;;GAEH,OAAO;GACP,MAAM;GACP,CAAC;AAEF,wBAAsB;AACpB,OAAI,WAAY,cAAa,WAAW;IACxC;;uBAhJA,mBAsCM,OAtCN,YAsCM,CArCJ,mBA6BM,OAAA;IA5BJ,OAAK,eAAA,CAAC,mBAAiB;eAEM,WAAA;YAA4B,SAAA;eAA6BA,KAAAA;;IADrF,SAAO;OAOR,mBAWM,OAXN,YAWM,CAVJ,mBAIM,OAJN,YAIM;KAHS,WAAA,SAAU,CAAK,SAAA,sBAA5B,mBAA+C,QAAA,YAAT,KAAE;IAC5B,WAAA,sBAAZ,mBAAqD,QAArD,YAA6C,IAAC;IAClC,SAAA,sBAAZ,mBAAkD,QAAlD,YAAyC,KAAE;OAE7C,mBAIM,OAJN,YAIM;KAHS,WAAA,SAAU,CAAK,SAAA,sBAA5B,mBAA8D,QAAA,YAAA,gBAArBC,KAAAA,YAAW,EAAA,EAAA;IACxC,WAAA,sBAAZ,mBAAwD,QAAxD,YAA6C,OAAI;IACrC,SAAA,sBAAZ,mBAAwD,QAAxD,aAAyC,WAAQ;SAI7C,WAAA,SAAc,SAAA,sBADtB,mBAOM,OAAA;;IALJ,OAAM;IACL,SAAK,cAAO,cAAY,CAAA,OAAA,CAAA;IACzB,OAAM;MACP,MAED,2CAEF,YAME,MAAA,YAAA,EAAA;IALC,MAAM,UAAA;IACN,MAAM,cAAA;IACN,WAAS;IACT,SAAO;IACP,QAAM"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"C_Cascade-IUUHIh7r.css","names":[],"sources":["../src/components/C_Cascade/index.vue?vue&type=style&index=0&scoped=e3904f11&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled */.n-cascade-selector[data-v-e3904f11] {\n display: flex;\n gap: 12px;\n}\n.n-cascade-selector .n-select-item[data-v-e3904f11] {\n min-width: 140px;\n flex: 1;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
@@ -1,6 +1,6 @@
1
1
  import { t as export_helper_default } from "./export-helper.js";
2
- import { Fragment, computed, createElementBlock, createVNode, defineComponent, openBlock, ref, renderList, unref, watch } from "vue";
3
2
  import { NSelect } from "naive-ui";
3
+ import { Fragment, computed, createElementBlock, createVNode, defineComponent, openBlock, ref, renderList, unref, watch } from "vue";
4
4
 
5
5
  //#region src/components/C_Cascade/index.vue?vue&type=script&setup=true&lang.ts
6
6
  const _hoisted_1 = { class: "n-cascade-selector" };
@@ -96,7 +96,7 @@ var index_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCo
96
96
 
97
97
  //#endregion
98
98
  //#region src/components/C_Cascade/index.vue
99
- var C_Cascade_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-7219e099"]]);
99
+ var C_Cascade_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-e3904f11"]]);
100
100
 
101
101
  //#endregion
102
102
  export { C_Cascade_default as t };
@@ -1 +1 @@
1
- {"version":3,"file":"C_Cascade2.js","names":["placeholders"],"sources":["../src/components/C_Cascade/index.vue","../src/components/C_Cascade/index.vue","../src/components/C_Cascade/index.vue"],"sourcesContent":["<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-05-28\r\n * @Description: 级联选择组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"n-cascade-selector\">\r\n <NSelect\r\n v-for=\"(level, index) in levels\"\r\n :key=\"index\"\r\n v-model:value=\"selectedValues[index]\"\r\n :options=\"levelOptions[index]\"\r\n clearable\r\n :placeholder=\"placeholders[index]\"\r\n :disabled=\"index > 0 && !selectedValues[index - 1]\"\r\n @update:value=\"handleChange(index)\"\r\n class=\"n-select-item\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\" setup>\r\nimport { ref, computed, watch } from \"vue\";\r\nimport { NSelect } from \"naive-ui\";\r\n\r\ndefineOptions({ name: \"C_Cascade\" });\r\n\r\nexport interface CascadeItem {\r\n label: string;\r\n value: string | number;\r\n children?: CascadeItem[];\r\n}\r\n\r\ninterface CascadeValue {\r\n primary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n secondary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n tertiary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n}\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n data: CascadeItem[];\r\n placeholders?: string[];\r\n modelValue?: CascadeValue;\r\n }>(),\r\n {\r\n placeholders: () => [\"请选择\", \"请选择\", \"请选择\"],\r\n },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: CascadeValue];\r\n change: [value: CascadeValue];\r\n}>();\r\n\r\nconst levels = [0, 1, 2];\r\nconst selectedValues = ref<(string | number | null)[]>([null, null, null]);\r\n\r\nconst getLevelData = (level: number): CascadeItem[] => {\r\n if (level === 0) return props.data;\r\n if (!selectedValues.value[level - 1]) return [];\r\n const parentData = getLevelData(level - 1);\r\n return (\r\n parentData.find((x) => x.value === selectedValues.value[level - 1])\r\n ?.children || []\r\n );\r\n};\r\n\r\nconst levelOptions = computed(() =>\r\n levels.map((level) =>\r\n getLevelData(level).map((item) => ({\r\n label: item.label,\r\n value: item.value,\r\n })),\r\n ),\r\n);\r\n\r\nconst handleChange = (index: number) => {\r\n selectedValues.value.splice(\r\n index + 1,\r\n levels.length - index - 1,\r\n ...Array(levels.length - index - 1).fill(null),\r\n );\r\n emitValue();\r\n};\r\n\r\nconst getSelectedItem = (index: number) => {\r\n const value = selectedValues.value[index];\r\n if (!value) return null;\r\n const data = getLevelData(index);\r\n const item = data.find((i) => i.value === value);\r\n return item ? { label: item.label, value: item.value } : null;\r\n};\r\n\r\nconst emitValue = () => {\r\n const result: CascadeValue = {\r\n primary: getSelectedItem(0),\r\n secondary: getSelectedItem(1),\r\n tertiary: getSelectedItem(2),\r\n };\r\n emit(\"update:modelValue\", result);\r\n emit(\"change\", result);\r\n};\r\n\r\nwatch(\r\n () => props.modelValue,\r\n (val) => {\r\n selectedValues.value = [\r\n val?.primary?.value ?? null,\r\n val?.secondary?.value ?? null,\r\n val?.tertiary?.value ?? null,\r\n ];\r\n },\r\n { immediate: true, deep: true },\r\n);\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.n-cascade-selector {\r\n display: flex;\r\n gap: 12px;\r\n .n-select-item {\r\n min-width: 140px;\r\n flex: 1;\r\n }\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-05-28\r\n * @Description: 级联选择组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"n-cascade-selector\">\r\n <NSelect\r\n v-for=\"(level, index) in levels\"\r\n :key=\"index\"\r\n v-model:value=\"selectedValues[index]\"\r\n :options=\"levelOptions[index]\"\r\n clearable\r\n :placeholder=\"placeholders[index]\"\r\n :disabled=\"index > 0 && !selectedValues[index - 1]\"\r\n @update:value=\"handleChange(index)\"\r\n class=\"n-select-item\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\" setup>\r\nimport { ref, computed, watch } from \"vue\";\r\nimport { NSelect } from \"naive-ui\";\r\n\r\ndefineOptions({ name: \"C_Cascade\" });\r\n\r\nexport interface CascadeItem {\r\n label: string;\r\n value: string | number;\r\n children?: CascadeItem[];\r\n}\r\n\r\ninterface CascadeValue {\r\n primary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n secondary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n tertiary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n}\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n data: CascadeItem[];\r\n placeholders?: string[];\r\n modelValue?: CascadeValue;\r\n }>(),\r\n {\r\n placeholders: () => [\"请选择\", \"请选择\", \"请选择\"],\r\n },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: CascadeValue];\r\n change: [value: CascadeValue];\r\n}>();\r\n\r\nconst levels = [0, 1, 2];\r\nconst selectedValues = ref<(string | number | null)[]>([null, null, null]);\r\n\r\nconst getLevelData = (level: number): CascadeItem[] => {\r\n if (level === 0) return props.data;\r\n if (!selectedValues.value[level - 1]) return [];\r\n const parentData = getLevelData(level - 1);\r\n return (\r\n parentData.find((x) => x.value === selectedValues.value[level - 1])\r\n ?.children || []\r\n );\r\n};\r\n\r\nconst levelOptions = computed(() =>\r\n levels.map((level) =>\r\n getLevelData(level).map((item) => ({\r\n label: item.label,\r\n value: item.value,\r\n })),\r\n ),\r\n);\r\n\r\nconst handleChange = (index: number) => {\r\n selectedValues.value.splice(\r\n index + 1,\r\n levels.length - index - 1,\r\n ...Array(levels.length - index - 1).fill(null),\r\n );\r\n emitValue();\r\n};\r\n\r\nconst getSelectedItem = (index: number) => {\r\n const value = selectedValues.value[index];\r\n if (!value) return null;\r\n const data = getLevelData(index);\r\n const item = data.find((i) => i.value === value);\r\n return item ? { label: item.label, value: item.value } : null;\r\n};\r\n\r\nconst emitValue = () => {\r\n const result: CascadeValue = {\r\n primary: getSelectedItem(0),\r\n secondary: getSelectedItem(1),\r\n tertiary: getSelectedItem(2),\r\n };\r\n emit(\"update:modelValue\", result);\r\n emit(\"change\", result);\r\n};\r\n\r\nwatch(\r\n () => props.modelValue,\r\n (val) => {\r\n selectedValues.value = [\r\n val?.primary?.value ?? null,\r\n val?.secondary?.value ?? null,\r\n val?.tertiary?.value ?? null,\r\n ];\r\n },\r\n { immediate: true, deep: true },\r\n);\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.n-cascade-selector {\r\n display: flex;\r\n gap: 12px;\r\n .n-select-item {\r\n min-width: 140px;\r\n flex: 1;\r\n }\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-05-28\r\n * @Description: 级联选择组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"n-cascade-selector\">\r\n <NSelect\r\n v-for=\"(level, index) in levels\"\r\n :key=\"index\"\r\n v-model:value=\"selectedValues[index]\"\r\n :options=\"levelOptions[index]\"\r\n clearable\r\n :placeholder=\"placeholders[index]\"\r\n :disabled=\"index > 0 && !selectedValues[index - 1]\"\r\n @update:value=\"handleChange(index)\"\r\n class=\"n-select-item\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\" setup>\r\nimport { ref, computed, watch } from \"vue\";\r\nimport { NSelect } from \"naive-ui\";\r\n\r\ndefineOptions({ name: \"C_Cascade\" });\r\n\r\nexport interface CascadeItem {\r\n label: string;\r\n value: string | number;\r\n children?: CascadeItem[];\r\n}\r\n\r\ninterface CascadeValue {\r\n primary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n secondary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n tertiary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n}\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n data: CascadeItem[];\r\n placeholders?: string[];\r\n modelValue?: CascadeValue;\r\n }>(),\r\n {\r\n placeholders: () => [\"请选择\", \"请选择\", \"请选择\"],\r\n },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: CascadeValue];\r\n change: [value: CascadeValue];\r\n}>();\r\n\r\nconst levels = [0, 1, 2];\r\nconst selectedValues = ref<(string | number | null)[]>([null, null, null]);\r\n\r\nconst getLevelData = (level: number): CascadeItem[] => {\r\n if (level === 0) return props.data;\r\n if (!selectedValues.value[level - 1]) return [];\r\n const parentData = getLevelData(level - 1);\r\n return (\r\n parentData.find((x) => x.value === selectedValues.value[level - 1])\r\n ?.children || []\r\n );\r\n};\r\n\r\nconst levelOptions = computed(() =>\r\n levels.map((level) =>\r\n getLevelData(level).map((item) => ({\r\n label: item.label,\r\n value: item.value,\r\n })),\r\n ),\r\n);\r\n\r\nconst handleChange = (index: number) => {\r\n selectedValues.value.splice(\r\n index + 1,\r\n levels.length - index - 1,\r\n ...Array(levels.length - index - 1).fill(null),\r\n );\r\n emitValue();\r\n};\r\n\r\nconst getSelectedItem = (index: number) => {\r\n const value = selectedValues.value[index];\r\n if (!value) return null;\r\n const data = getLevelData(index);\r\n const item = data.find((i) => i.value === value);\r\n return item ? { label: item.label, value: item.value } : null;\r\n};\r\n\r\nconst emitValue = () => {\r\n const result: CascadeValue = {\r\n primary: getSelectedItem(0),\r\n secondary: getSelectedItem(1),\r\n tertiary: getSelectedItem(2),\r\n };\r\n emit(\"update:modelValue\", result);\r\n emit(\"change\", result);\r\n};\r\n\r\nwatch(\r\n () => props.modelValue,\r\n (val) => {\r\n selectedValues.value = [\r\n val?.primary?.value ?? null,\r\n val?.secondary?.value ?? null,\r\n val?.tertiary?.value ?? null,\r\n ];\r\n },\r\n { immediate: true, deep: true },\r\n);\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.n-cascade-selector {\r\n display: flex;\r\n gap: 12px;\r\n .n-select-item {\r\n min-width: 140px;\r\n flex: 1;\r\n }\r\n}\r\n</style>\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;ECyCA,MAAM,QAAQ;EAWd,MAAM,OAAO;EAKb,MAAM,SAAS;GAAC;GAAG;GAAG;GAAE;EACxB,MAAM,iBAAiB,IAAgC;GAAC;GAAM;GAAM;GAAK,CAAC;EAE1E,MAAM,gBAAgB,UAAiC;AACrD,OAAI,UAAU,EAAG,QAAO,MAAM;AAC9B,OAAI,CAAC,eAAe,MAAM,QAAQ,GAAI,QAAO,EAAE;AAE/C,UADmB,aAAa,QAAQ,EAAE,CAE7B,MAAM,MAAM,EAAE,UAAU,eAAe,MAAM,QAAQ,GAAG,EAC/D,YAAY,EAAE;;EAItB,MAAM,eAAe,eACnB,OAAO,KAAK,UACV,aAAa,MAAM,CAAC,KAAK,UAAU;GACjC,OAAO,KAAK;GACZ,OAAO,KAAK;GACb,EAAE,CACJ,CACF;EAED,MAAM,gBAAgB,UAAkB;AACtC,kBAAe,MAAM,OACnB,QAAQ,GACR,OAAO,SAAS,QAAQ,GACxB,GAAG,MAAM,OAAO,SAAS,QAAQ,EAAE,CAAC,KAAK,KAAK,CAC/C;AACD,cAAW;;EAGb,MAAM,mBAAmB,UAAkB;GACzC,MAAM,QAAQ,eAAe,MAAM;AACnC,OAAI,CAAC,MAAO,QAAO;GAEnB,MAAM,OADO,aAAa,MAAM,CACd,MAAM,MAAM,EAAE,UAAU,MAAM;AAChD,UAAO,OAAO;IAAE,OAAO,KAAK;IAAO,OAAO,KAAK;IAAO,GAAG;;EAG3D,MAAM,kBAAkB;GACtB,MAAM,SAAuB;IAC3B,SAAS,gBAAgB,EAAE;IAC3B,WAAW,gBAAgB,EAAE;IAC7B,UAAU,gBAAgB,EAAE;IAC7B;AACD,QAAK,qBAAqB,OAAO;AACjC,QAAK,UAAU,OAAO;;AAGxB,cACQ,MAAM,aACX,QAAQ;AACP,kBAAe,QAAQ;IACrB,KAAK,SAAS,SAAS;IACvB,KAAK,WAAW,SAAS;IACzB,KAAK,UAAU,SAAS;IACzB;KAEH;GAAE,WAAW;GAAM,MAAM;GAAM,CAChC;;uBA5GC,mBAYM,OAZN,YAYM,eAXJ,mBAUE,UAAA,MAAA,WATyB,SAAjB,OAAO,UAAK;WADtB,YAUE,MAAA,QAAA,EAAA;KARC,KAAK;KACE,OAAO,eAAA,MAAe;oCAAf,eAAA,MAAe,SAAK,SAAA,WAKpB,aAAa,MAAK,CAAA;KAJhC,SAAS,aAAA,MAAa;KACvB,WAAA;KACC,aAAaA,KAAAA,aAAa;KAC1B,UAAU,QAAK,KAAA,CAAS,eAAA,MAAe,QAAK;KAE7C,OAAM"}
1
+ {"version":3,"file":"C_Cascade2.js","names":["placeholders"],"sources":["../src/components/C_Cascade/index.vue","../src/components/C_Cascade/index.vue","../src/components/C_Cascade/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-05-28\r\n * @Description: 级联选择组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"n-cascade-selector\">\r\n <NSelect\r\n v-for=\"(level, index) in levels\"\r\n :key=\"index\"\r\n v-model:value=\"selectedValues[index]\"\r\n :options=\"levelOptions[index]\"\r\n clearable\r\n :placeholder=\"placeholders[index]\"\r\n :disabled=\"index > 0 && !selectedValues[index - 1]\"\r\n @update:value=\"handleChange(index)\"\r\n class=\"n-select-item\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\" setup>\r\nimport { ref, computed, watch } from \"vue\";\r\nimport { NSelect } from \"naive-ui\";\r\n\r\ndefineOptions({ name: \"C_Cascade\" });\r\n\r\nexport interface CascadeItem {\r\n label: string;\r\n value: string | number;\r\n children?: CascadeItem[];\r\n}\r\n\r\ninterface CascadeValue {\r\n primary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n secondary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n tertiary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n}\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n data: CascadeItem[];\r\n placeholders?: string[];\r\n modelValue?: CascadeValue;\r\n }>(),\r\n {\r\n placeholders: () => [\"请选择\", \"请选择\", \"请选择\"],\r\n },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: CascadeValue];\r\n change: [value: CascadeValue];\r\n}>();\r\n\r\nconst levels = [0, 1, 2];\r\nconst selectedValues = ref<(string | number | null)[]>([null, null, null]);\r\n\r\nconst getLevelData = (level: number): CascadeItem[] => {\r\n if (level === 0) return props.data;\r\n if (!selectedValues.value[level - 1]) return [];\r\n const parentData = getLevelData(level - 1);\r\n return (\r\n parentData.find((x) => x.value === selectedValues.value[level - 1])\r\n ?.children || []\r\n );\r\n};\r\n\r\nconst levelOptions = computed(() =>\r\n levels.map((level) =>\r\n getLevelData(level).map((item) => ({\r\n label: item.label,\r\n value: item.value,\r\n })),\r\n ),\r\n);\r\n\r\nconst handleChange = (index: number) => {\r\n selectedValues.value.splice(\r\n index + 1,\r\n levels.length - index - 1,\r\n ...Array(levels.length - index - 1).fill(null),\r\n );\r\n emitValue();\r\n};\r\n\r\nconst getSelectedItem = (index: number) => {\r\n const value = selectedValues.value[index];\r\n if (!value) return null;\r\n const data = getLevelData(index);\r\n const item = data.find((i) => i.value === value);\r\n return item ? { label: item.label, value: item.value } : null;\r\n};\r\n\r\nconst emitValue = () => {\r\n const result: CascadeValue = {\r\n primary: getSelectedItem(0),\r\n secondary: getSelectedItem(1),\r\n tertiary: getSelectedItem(2),\r\n };\r\n emit(\"update:modelValue\", result);\r\n emit(\"change\", result);\r\n};\r\n\r\nwatch(\r\n () => props.modelValue,\r\n (val) => {\r\n selectedValues.value = [\r\n val?.primary?.value ?? null,\r\n val?.secondary?.value ?? null,\r\n val?.tertiary?.value ?? null,\r\n ];\r\n },\r\n { immediate: true, deep: true },\r\n);\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.n-cascade-selector {\r\n display: flex;\r\n gap: 12px;\r\n .n-select-item {\r\n min-width: 140px;\r\n flex: 1;\r\n }\r\n}\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-05-28\r\n * @Description: 级联选择组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"n-cascade-selector\">\r\n <NSelect\r\n v-for=\"(level, index) in levels\"\r\n :key=\"index\"\r\n v-model:value=\"selectedValues[index]\"\r\n :options=\"levelOptions[index]\"\r\n clearable\r\n :placeholder=\"placeholders[index]\"\r\n :disabled=\"index > 0 && !selectedValues[index - 1]\"\r\n @update:value=\"handleChange(index)\"\r\n class=\"n-select-item\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\" setup>\r\nimport { ref, computed, watch } from \"vue\";\r\nimport { NSelect } from \"naive-ui\";\r\n\r\ndefineOptions({ name: \"C_Cascade\" });\r\n\r\nexport interface CascadeItem {\r\n label: string;\r\n value: string | number;\r\n children?: CascadeItem[];\r\n}\r\n\r\ninterface CascadeValue {\r\n primary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n secondary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n tertiary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n}\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n data: CascadeItem[];\r\n placeholders?: string[];\r\n modelValue?: CascadeValue;\r\n }>(),\r\n {\r\n placeholders: () => [\"请选择\", \"请选择\", \"请选择\"],\r\n },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: CascadeValue];\r\n change: [value: CascadeValue];\r\n}>();\r\n\r\nconst levels = [0, 1, 2];\r\nconst selectedValues = ref<(string | number | null)[]>([null, null, null]);\r\n\r\nconst getLevelData = (level: number): CascadeItem[] => {\r\n if (level === 0) return props.data;\r\n if (!selectedValues.value[level - 1]) return [];\r\n const parentData = getLevelData(level - 1);\r\n return (\r\n parentData.find((x) => x.value === selectedValues.value[level - 1])\r\n ?.children || []\r\n );\r\n};\r\n\r\nconst levelOptions = computed(() =>\r\n levels.map((level) =>\r\n getLevelData(level).map((item) => ({\r\n label: item.label,\r\n value: item.value,\r\n })),\r\n ),\r\n);\r\n\r\nconst handleChange = (index: number) => {\r\n selectedValues.value.splice(\r\n index + 1,\r\n levels.length - index - 1,\r\n ...Array(levels.length - index - 1).fill(null),\r\n );\r\n emitValue();\r\n};\r\n\r\nconst getSelectedItem = (index: number) => {\r\n const value = selectedValues.value[index];\r\n if (!value) return null;\r\n const data = getLevelData(index);\r\n const item = data.find((i) => i.value === value);\r\n return item ? { label: item.label, value: item.value } : null;\r\n};\r\n\r\nconst emitValue = () => {\r\n const result: CascadeValue = {\r\n primary: getSelectedItem(0),\r\n secondary: getSelectedItem(1),\r\n tertiary: getSelectedItem(2),\r\n };\r\n emit(\"update:modelValue\", result);\r\n emit(\"change\", result);\r\n};\r\n\r\nwatch(\r\n () => props.modelValue,\r\n (val) => {\r\n selectedValues.value = [\r\n val?.primary?.value ?? null,\r\n val?.secondary?.value ?? null,\r\n val?.tertiary?.value ?? null,\r\n ];\r\n },\r\n { immediate: true, deep: true },\r\n);\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.n-cascade-selector {\r\n display: flex;\r\n gap: 12px;\r\n .n-select-item {\r\n min-width: 140px;\r\n flex: 1;\r\n }\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-05-28\r\n * @Description: 级联选择组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"n-cascade-selector\">\r\n <NSelect\r\n v-for=\"(level, index) in levels\"\r\n :key=\"index\"\r\n v-model:value=\"selectedValues[index]\"\r\n :options=\"levelOptions[index]\"\r\n clearable\r\n :placeholder=\"placeholders[index]\"\r\n :disabled=\"index > 0 && !selectedValues[index - 1]\"\r\n @update:value=\"handleChange(index)\"\r\n class=\"n-select-item\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\" setup>\r\nimport { ref, computed, watch } from \"vue\";\r\nimport { NSelect } from \"naive-ui\";\r\n\r\ndefineOptions({ name: \"C_Cascade\" });\r\n\r\nexport interface CascadeItem {\r\n label: string;\r\n value: string | number;\r\n children?: CascadeItem[];\r\n}\r\n\r\ninterface CascadeValue {\r\n primary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n secondary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n tertiary?: Pick<CascadeItem, \"label\" | \"value\"> | null;\r\n}\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n data: CascadeItem[];\r\n placeholders?: string[];\r\n modelValue?: CascadeValue;\r\n }>(),\r\n {\r\n placeholders: () => [\"请选择\", \"请选择\", \"请选择\"],\r\n },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n \"update:modelValue\": [value: CascadeValue];\r\n change: [value: CascadeValue];\r\n}>();\r\n\r\nconst levels = [0, 1, 2];\r\nconst selectedValues = ref<(string | number | null)[]>([null, null, null]);\r\n\r\nconst getLevelData = (level: number): CascadeItem[] => {\r\n if (level === 0) return props.data;\r\n if (!selectedValues.value[level - 1]) return [];\r\n const parentData = getLevelData(level - 1);\r\n return (\r\n parentData.find((x) => x.value === selectedValues.value[level - 1])\r\n ?.children || []\r\n );\r\n};\r\n\r\nconst levelOptions = computed(() =>\r\n levels.map((level) =>\r\n getLevelData(level).map((item) => ({\r\n label: item.label,\r\n value: item.value,\r\n })),\r\n ),\r\n);\r\n\r\nconst handleChange = (index: number) => {\r\n selectedValues.value.splice(\r\n index + 1,\r\n levels.length - index - 1,\r\n ...Array(levels.length - index - 1).fill(null),\r\n );\r\n emitValue();\r\n};\r\n\r\nconst getSelectedItem = (index: number) => {\r\n const value = selectedValues.value[index];\r\n if (!value) return null;\r\n const data = getLevelData(index);\r\n const item = data.find((i) => i.value === value);\r\n return item ? { label: item.label, value: item.value } : null;\r\n};\r\n\r\nconst emitValue = () => {\r\n const result: CascadeValue = {\r\n primary: getSelectedItem(0),\r\n secondary: getSelectedItem(1),\r\n tertiary: getSelectedItem(2),\r\n };\r\n emit(\"update:modelValue\", result);\r\n emit(\"change\", result);\r\n};\r\n\r\nwatch(\r\n () => props.modelValue,\r\n (val) => {\r\n selectedValues.value = [\r\n val?.primary?.value ?? null,\r\n val?.secondary?.value ?? null,\r\n val?.tertiary?.value ?? null,\r\n ];\r\n },\r\n { immediate: true, deep: true },\r\n);\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.n-cascade-selector {\r\n display: flex;\r\n gap: 12px;\r\n .n-select-item {\r\n min-width: 140px;\r\n flex: 1;\r\n }\r\n}\r\n</style>\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;ECyCA,MAAM,QAAQ;EAWd,MAAM,OAAO;EAKb,MAAM,SAAS;GAAC;GAAG;GAAG;GAAE;EACxB,MAAM,iBAAiB,IAAgC;GAAC;GAAM;GAAM;GAAK,CAAC;EAE1E,MAAM,gBAAgB,UAAiC;AACrD,OAAI,UAAU,EAAG,QAAO,MAAM;AAC9B,OAAI,CAAC,eAAe,MAAM,QAAQ,GAAI,QAAO,EAAE;AAE/C,UADmB,aAAa,QAAQ,EAAE,CAE7B,MAAM,MAAM,EAAE,UAAU,eAAe,MAAM,QAAQ,GAAG,EAC/D,YAAY,EAAE;;EAItB,MAAM,eAAe,eACnB,OAAO,KAAK,UACV,aAAa,MAAM,CAAC,KAAK,UAAU;GACjC,OAAO,KAAK;GACZ,OAAO,KAAK;GACb,EAAE,CACJ,CACF;EAED,MAAM,gBAAgB,UAAkB;AACtC,kBAAe,MAAM,OACnB,QAAQ,GACR,OAAO,SAAS,QAAQ,GACxB,GAAG,MAAM,OAAO,SAAS,QAAQ,EAAE,CAAC,KAAK,KAAK,CAC/C;AACD,cAAW;;EAGb,MAAM,mBAAmB,UAAkB;GACzC,MAAM,QAAQ,eAAe,MAAM;AACnC,OAAI,CAAC,MAAO,QAAO;GAEnB,MAAM,OADO,aAAa,MAAM,CACd,MAAM,MAAM,EAAE,UAAU,MAAM;AAChD,UAAO,OAAO;IAAE,OAAO,KAAK;IAAO,OAAO,KAAK;IAAO,GAAG;;EAG3D,MAAM,kBAAkB;GACtB,MAAM,SAAuB;IAC3B,SAAS,gBAAgB,EAAE;IAC3B,WAAW,gBAAgB,EAAE;IAC7B,UAAU,gBAAgB,EAAE;IAC7B;AACD,QAAK,qBAAqB,OAAO;AACjC,QAAK,UAAU,OAAO;;AAGxB,cACQ,MAAM,aACX,QAAQ;AACP,kBAAe,QAAQ;IACrB,KAAK,SAAS,SAAS;IACvB,KAAK,WAAW,SAAS;IACzB,KAAK,UAAU,SAAS;IACzB;KAEH;GAAE,WAAW;GAAM,MAAM;GAAM,CAChC;;uBA5GC,mBAYM,OAZN,YAYM,eAXJ,mBAUE,UAAA,MAAA,WATyB,SAAjB,OAAO,UAAK;WADtB,YAUE,MAAA,QAAA,EAAA;KARC,KAAK;KACE,OAAO,eAAA,MAAe;oCAAf,eAAA,MAAe,SAAK,SAAA,WAKpB,aAAa,MAAK,CAAA;KAJhC,SAAS,aAAA,MAAa;KACvB,WAAA;KACC,aAAaA,KAAAA,aAAa;KAC1B,UAAU,QAAK,KAAA,CAAS,eAAA,MAAe,QAAK;KAE7C,OAAM"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"C_City-Cv5BESaN.css","names":[],"sources":["../src/components/C_City/index.vue?vue&type=style&index=0&scoped=06a335f4&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled */.city-selector-trigger[data-v-06a335f4] {\n display: inline-flex;\n align-items: center;\n justify-content: space-between;\n min-width: 200px;\n height: 34px;\n padding: 0 12px;\n border: 1px solid #e0e0e6;\n border-radius: 3px;\n cursor: pointer;\n transition: all 0.3s;\n}\n.city-selector-trigger[data-v-06a335f4]:hover {\n border-color: var(--c-primary, #1890ff);\n}\n.city-selector-trigger__text[data-v-06a335f4] {\n flex: 1;\n font-size: 14px;\n}\n.city-selector-trigger__icon[data-v-06a335f4] {\n margin-left: 8px;\n color: #999;\n font-size: 16px;\n transition: transform 0.3s;\n}\n.city-selector-trigger__icon.is-active[data-v-06a335f4] {\n transform: rotate(180deg);\n}\n.city-selector-content[data-v-06a335f4] {\n display: flex;\n flex-direction: column;\n height: 500px;\n padding: 0;\n}\n.city-selector-header[data-v-06a335f4] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n border-bottom: 1px solid rgba(247, 247, 247, 0.514);\n flex-shrink: 0;\n}\n.city-selector-header .city-selector-search[data-v-06a335f4] {\n flex: 1;\n}\n.city-selector-letters[data-v-06a335f4] {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin: 0 12px 10px;\n padding: 8px;\n flex-shrink: 0;\n}\n.city-selector-letters .city-selector-letter[data-v-06a335f4] {\n padding: 2px 6px;\n cursor: pointer;\n color: var(--c-primary, #1890ff);\n font-size: 13px;\n font-weight: 500;\n transition: all 0.3s;\n min-width: 24px;\n text-align: center;\n}\n.city-selector-letters .city-selector-letter[data-v-06a335f4]:hover {\n background-color: var(--c-primary, #1890ff);\n color: #fff;\n border-radius: 2px;\n}\n.city-selector-body[data-v-06a335f4] {\n flex: 1;\n margin: 12px;\n margin-top: 8px;\n overflow: hidden;\n}\n.city-list[data-v-06a335f4],\n.province-list[data-v-06a335f4] {\n padding: 0 8px;\n}\n.city-group[data-v-06a335f4],\n.province-group[data-v-06a335f4] {\n display: flex;\n margin-bottom: 12px;\n padding-bottom: 12px;\n border-bottom: 1px solid rgba(247, 247, 247, 0.514);\n}\n.city-group[data-v-06a335f4]:last-child,\n.province-group[data-v-06a335f4]:last-child {\n border-bottom: none;\n margin-bottom: 0;\n padding-bottom: 0;\n}\n.city-group__letter[data-v-06a335f4], .city-group__name[data-v-06a335f4],\n.province-group__letter[data-v-06a335f4],\n.province-group__name[data-v-06a335f4] {\n flex-shrink: 0;\n width: 70px;\n font-weight: 500;\n font-size: 14px;\n line-height: 28px;\n}\n.city-group__cities[data-v-06a335f4],\n.province-group__cities[data-v-06a335f4] {\n flex: 1;\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n align-items: flex-start;\n}\n.city-item[data-v-06a335f4] {\n padding: 3px 10px;\n cursor: pointer;\n font-size: 13px;\n border-radius: 2px;\n transition: all 0.3s;\n line-height: 20px;\n}\n.city-item[data-v-06a335f4]:hover {\n background-color: #f0f0f0;\n color: var(--c-primary, #1890ff);\n}\n.city-item.is-active[data-v-06a335f4] {\n background-color: var(--c-primary, #1890ff);\n color: #fff;\n}\n[data-v-06a335f4] .n-scrollbar .n-scrollbar-rail {\n right: 2px;\n}\n[data-v-06a335f4] .n-scrollbar .n-scrollbar-content {\n padding-right: 12px;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
package/dist/C_City2.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { t as export_helper_default } from "./export-helper.js";
2
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, onMounted, openBlock, ref, renderList, renderSlot, toDisplayString, unref, withCtx } from "vue";
3
2
  import { NPopover, NRadioButton, NRadioGroup, NScrollbar, NSelect } from "naive-ui";
3
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, onMounted, openBlock, ref, renderList, renderSlot, toDisplayString, unref, withCtx } from "vue";
4
4
 
5
5
  //#region src/components/C_City/province.json
6
6
  var province_default = {
@@ -834,7 +834,7 @@ var index_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCo
834
834
 
835
835
  //#endregion
836
836
  //#region src/components/C_City/index.vue
837
- var C_City_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-9639851e"]]);
837
+ var C_City_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-06a335f4"]]);
838
838
 
839
839
  //#endregion
840
840
  export { C_City_default as t };
@@ -1 +1 @@
1
- {"version":3,"file":"C_City2.js","names":["modelValue","placeholder","showLetters"],"sources":["../src/components/C_City/province.json","../src/components/C_City/index.vue","../src/components/C_City/index.vue","../src/components/C_City/index.vue"],"sourcesContent":["","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-05-30\r\n * @Description: 城市选择器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NPopover\r\n v-model:show=\"visible\"\r\n placement=\"bottom-start\"\r\n :width=\"430\"\r\n trigger=\"click\"\r\n :show-arrow=\"false\"\r\n >\r\n <template #trigger>\r\n <slot name=\"trigger\" :value=\"modelValue\" :visible=\"visible\">\r\n <div class=\"city-selector-trigger\">\r\n <span class=\"city-selector-trigger__text\">{{\r\n modelValue || placeholder\r\n }}</span>\r\n </div>\r\n </slot>\r\n </template>\r\n\r\n <div class=\"city-selector-content\">\r\n <div class=\"city-selector-header\">\r\n <NRadioGroup v-model:value=\"radioValue\" size=\"small\">\r\n <NRadioButton value=\"city\">按城市</NRadioButton>\r\n <NRadioButton value=\"province\">按省份</NRadioButton>\r\n </NRadioGroup>\r\n <NSelect\r\n v-model:value=\"searchValue\"\r\n class=\"city-selector-search\"\r\n :options=\"searchOptions\"\r\n filterable\r\n clearable\r\n placeholder=\"搜索城市\"\r\n @update:value=\"handleSearchSelect\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"showLetters\" class=\"city-selector-letters\">\r\n <span\r\n v-for=\"letter in letters\"\r\n :key=\"letter\"\r\n class=\"city-selector-letter\"\r\n @click=\"scrollToLetter(letter)\"\r\n >\r\n {{ letter }}\r\n </span>\r\n </div>\r\n\r\n <NScrollbar class=\"city-selector-body\">\r\n <div v-if=\"radioValue === 'city'\" class=\"city-list\">\r\n <div\r\n v-for=\"(cities, letter) in cityDataByLetter\"\r\n :key=\"letter\"\r\n :id=\"`letter-${letter}`\"\r\n class=\"city-group\"\r\n >\r\n <div class=\"city-group__letter\">{{ letter }}:</div>\r\n <div class=\"city-group__cities\">\r\n <span\r\n v-for=\"(city, index) in cities\"\r\n :key=\"`${letter}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city.name }\"\r\n @click=\"handleCitySelect(city.name)\"\r\n >\r\n {{ city.name }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div v-else class=\"province-list\">\r\n <div\r\n v-for=\"province in allProvinces\"\r\n :key=\"province.id\"\r\n :id=\"`letter-${province.id}`\"\r\n class=\"province-group\"\r\n >\r\n <div class=\"province-group__name\">{{ province.name }}:</div>\r\n <div class=\"province-group__cities\">\r\n <span\r\n v-for=\"(city, index) in province.data\"\r\n :key=\"`${province.id}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city }\"\r\n @click=\"handleCitySelect(city)\"\r\n >\r\n {{ city }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </NScrollbar>\r\n </div>\r\n </NPopover>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted } from \"vue\";\r\nimport {\r\n NPopover,\r\n NRadioGroup,\r\n NRadioButton,\r\n NSelect,\r\n NScrollbar,\r\n} from \"naive-ui\";\r\nimport type { SelectOption } from \"naive-ui\";\r\nimport provinceData from \"./province.json\";\r\n\r\ndefineOptions({ name: \"C_City\" });\r\n\r\ninterface CityItem {\r\n id: number;\r\n spell: string;\r\n name: string;\r\n}\r\n\r\n// 城市数据懒加载(83KB JSON 仅在组件挂载时加载)\r\nconst cityData = ref<{ cities: Record<string, CityItem[]> } | null>(null);\r\n\r\nonMounted(async () => {\r\n const mod = await import(\"./city.json\");\r\n cityData.value = mod.default ?? mod;\r\n});\r\n\r\ninterface ProvinceItem {\r\n id?: string;\r\n name: string;\r\n data: string[];\r\n}\r\n\r\ninterface Props {\r\n modelValue?: string;\r\n placeholder?: string;\r\n showLetters?: boolean;\r\n}\r\n\r\ninterface Emits {\r\n (e: \"update:modelValue\", value: string): void;\r\n (e: \"change\", value: string): void;\r\n}\r\n\r\nwithDefaults(defineProps<Props>(), {\r\n placeholder: \"请选择城市\",\r\n showLetters: true,\r\n});\r\n\r\nconst emit = defineEmits<Emits>();\r\n\r\nconst visible = ref(false);\r\nconst radioValue = ref<\"city\" | \"province\">(\"city\");\r\nconst searchValue = ref(\"\");\r\n\r\nconst allProvinces = computed(() => {\r\n const provinces: ProvinceItem[] = [];\r\n Object.values(provinceData).forEach((group) => {\r\n provinces.push(...(group as ProvinceItem[]));\r\n });\r\n return provinces;\r\n});\r\n\r\nconst cityDataByLetter = computed(() => {\r\n if (cityData.value?.cities) {\r\n return cityData.value.cities;\r\n }\r\n // 数据未加载时,从省份数据生成城市索引作为 fallback\r\n const cities: Record<string, CityItem[]> = {};\r\n let cityId = 1;\r\n const citySet = new Set<string>();\r\n allProvinces.value.forEach((province) => {\r\n province.data.forEach((cityName) => {\r\n citySet.add(cityName);\r\n });\r\n });\r\n Array.from(citySet).forEach((cityName) => {\r\n const letter = cityName[0].toUpperCase();\r\n if (!cities[letter]) cities[letter] = [];\r\n cities[letter].push({ id: cityId++, name: cityName, spell: \"\" });\r\n });\r\n const sortedCities: Record<string, CityItem[]> = {};\r\n Object.keys(cities)\r\n .sort()\r\n .forEach((letter) => {\r\n sortedCities[letter] = cities[letter].sort((a, b) =>\r\n a.name.localeCompare(b.name, \"zh-CN\"),\r\n );\r\n });\r\n return sortedCities;\r\n});\r\n\r\nconst letters = computed(() => {\r\n if (radioValue.value === \"city\") {\r\n return Object.keys(cityDataByLetter.value).sort();\r\n } else {\r\n const provinceLetters = new Set<string>();\r\n Object.keys(provinceData).forEach((key) => {\r\n if (key !== \"直辖市\" && key !== \"港澳\") {\r\n provinceLetters.add(key);\r\n }\r\n });\r\n const result = Array.from(provinceLetters).sort();\r\n result.push(\"直辖市\", \"港澳\");\r\n return result;\r\n }\r\n});\r\n\r\nconst searchOptions = computed((): SelectOption[] => {\r\n if (radioValue.value === \"city\") {\r\n const options: SelectOption[] = [];\r\n Object.values(cityDataByLetter.value).forEach((cities) => {\r\n (cities as CityItem[]).forEach((city) => {\r\n options.push({\r\n label: city.name,\r\n value: city.name,\r\n });\r\n });\r\n });\r\n return options;\r\n } else {\r\n return allProvinces.value.flatMap((province) =>\r\n province.data.map((city) => ({\r\n label: `${city} (${province.name})`,\r\n value: city,\r\n })),\r\n );\r\n }\r\n});\r\n\r\nconst handleCitySelect = (cityName: string): void => {\r\n emit(\"update:modelValue\", cityName);\r\n emit(\"change\", cityName);\r\n visible.value = false;\r\n};\r\n\r\nconst handleSearchSelect = (value: string): void => {\r\n if (value) {\r\n handleCitySelect(value);\r\n searchValue.value = \"\";\r\n }\r\n};\r\n\r\nconst scrollToLetter = (letter: string): void => {\r\n const element = document.getElementById(`letter-${letter}`);\r\n if (element) {\r\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\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: 2025-05-30\r\n * @Description: 城市选择器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NPopover\r\n v-model:show=\"visible\"\r\n placement=\"bottom-start\"\r\n :width=\"430\"\r\n trigger=\"click\"\r\n :show-arrow=\"false\"\r\n >\r\n <template #trigger>\r\n <slot name=\"trigger\" :value=\"modelValue\" :visible=\"visible\">\r\n <div class=\"city-selector-trigger\">\r\n <span class=\"city-selector-trigger__text\">{{\r\n modelValue || placeholder\r\n }}</span>\r\n </div>\r\n </slot>\r\n </template>\r\n\r\n <div class=\"city-selector-content\">\r\n <div class=\"city-selector-header\">\r\n <NRadioGroup v-model:value=\"radioValue\" size=\"small\">\r\n <NRadioButton value=\"city\">按城市</NRadioButton>\r\n <NRadioButton value=\"province\">按省份</NRadioButton>\r\n </NRadioGroup>\r\n <NSelect\r\n v-model:value=\"searchValue\"\r\n class=\"city-selector-search\"\r\n :options=\"searchOptions\"\r\n filterable\r\n clearable\r\n placeholder=\"搜索城市\"\r\n @update:value=\"handleSearchSelect\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"showLetters\" class=\"city-selector-letters\">\r\n <span\r\n v-for=\"letter in letters\"\r\n :key=\"letter\"\r\n class=\"city-selector-letter\"\r\n @click=\"scrollToLetter(letter)\"\r\n >\r\n {{ letter }}\r\n </span>\r\n </div>\r\n\r\n <NScrollbar class=\"city-selector-body\">\r\n <div v-if=\"radioValue === 'city'\" class=\"city-list\">\r\n <div\r\n v-for=\"(cities, letter) in cityDataByLetter\"\r\n :key=\"letter\"\r\n :id=\"`letter-${letter}`\"\r\n class=\"city-group\"\r\n >\r\n <div class=\"city-group__letter\">{{ letter }}:</div>\r\n <div class=\"city-group__cities\">\r\n <span\r\n v-for=\"(city, index) in cities\"\r\n :key=\"`${letter}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city.name }\"\r\n @click=\"handleCitySelect(city.name)\"\r\n >\r\n {{ city.name }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div v-else class=\"province-list\">\r\n <div\r\n v-for=\"province in allProvinces\"\r\n :key=\"province.id\"\r\n :id=\"`letter-${province.id}`\"\r\n class=\"province-group\"\r\n >\r\n <div class=\"province-group__name\">{{ province.name }}:</div>\r\n <div class=\"province-group__cities\">\r\n <span\r\n v-for=\"(city, index) in province.data\"\r\n :key=\"`${province.id}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city }\"\r\n @click=\"handleCitySelect(city)\"\r\n >\r\n {{ city }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </NScrollbar>\r\n </div>\r\n </NPopover>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted } from \"vue\";\r\nimport {\r\n NPopover,\r\n NRadioGroup,\r\n NRadioButton,\r\n NSelect,\r\n NScrollbar,\r\n} from \"naive-ui\";\r\nimport type { SelectOption } from \"naive-ui\";\r\nimport provinceData from \"./province.json\";\r\n\r\ndefineOptions({ name: \"C_City\" });\r\n\r\ninterface CityItem {\r\n id: number;\r\n spell: string;\r\n name: string;\r\n}\r\n\r\n// 城市数据懒加载(83KB JSON 仅在组件挂载时加载)\r\nconst cityData = ref<{ cities: Record<string, CityItem[]> } | null>(null);\r\n\r\nonMounted(async () => {\r\n const mod = await import(\"./city.json\");\r\n cityData.value = mod.default ?? mod;\r\n});\r\n\r\ninterface ProvinceItem {\r\n id?: string;\r\n name: string;\r\n data: string[];\r\n}\r\n\r\ninterface Props {\r\n modelValue?: string;\r\n placeholder?: string;\r\n showLetters?: boolean;\r\n}\r\n\r\ninterface Emits {\r\n (e: \"update:modelValue\", value: string): void;\r\n (e: \"change\", value: string): void;\r\n}\r\n\r\nwithDefaults(defineProps<Props>(), {\r\n placeholder: \"请选择城市\",\r\n showLetters: true,\r\n});\r\n\r\nconst emit = defineEmits<Emits>();\r\n\r\nconst visible = ref(false);\r\nconst radioValue = ref<\"city\" | \"province\">(\"city\");\r\nconst searchValue = ref(\"\");\r\n\r\nconst allProvinces = computed(() => {\r\n const provinces: ProvinceItem[] = [];\r\n Object.values(provinceData).forEach((group) => {\r\n provinces.push(...(group as ProvinceItem[]));\r\n });\r\n return provinces;\r\n});\r\n\r\nconst cityDataByLetter = computed(() => {\r\n if (cityData.value?.cities) {\r\n return cityData.value.cities;\r\n }\r\n // 数据未加载时,从省份数据生成城市索引作为 fallback\r\n const cities: Record<string, CityItem[]> = {};\r\n let cityId = 1;\r\n const citySet = new Set<string>();\r\n allProvinces.value.forEach((province) => {\r\n province.data.forEach((cityName) => {\r\n citySet.add(cityName);\r\n });\r\n });\r\n Array.from(citySet).forEach((cityName) => {\r\n const letter = cityName[0].toUpperCase();\r\n if (!cities[letter]) cities[letter] = [];\r\n cities[letter].push({ id: cityId++, name: cityName, spell: \"\" });\r\n });\r\n const sortedCities: Record<string, CityItem[]> = {};\r\n Object.keys(cities)\r\n .sort()\r\n .forEach((letter) => {\r\n sortedCities[letter] = cities[letter].sort((a, b) =>\r\n a.name.localeCompare(b.name, \"zh-CN\"),\r\n );\r\n });\r\n return sortedCities;\r\n});\r\n\r\nconst letters = computed(() => {\r\n if (radioValue.value === \"city\") {\r\n return Object.keys(cityDataByLetter.value).sort();\r\n } else {\r\n const provinceLetters = new Set<string>();\r\n Object.keys(provinceData).forEach((key) => {\r\n if (key !== \"直辖市\" && key !== \"港澳\") {\r\n provinceLetters.add(key);\r\n }\r\n });\r\n const result = Array.from(provinceLetters).sort();\r\n result.push(\"直辖市\", \"港澳\");\r\n return result;\r\n }\r\n});\r\n\r\nconst searchOptions = computed((): SelectOption[] => {\r\n if (radioValue.value === \"city\") {\r\n const options: SelectOption[] = [];\r\n Object.values(cityDataByLetter.value).forEach((cities) => {\r\n (cities as CityItem[]).forEach((city) => {\r\n options.push({\r\n label: city.name,\r\n value: city.name,\r\n });\r\n });\r\n });\r\n return options;\r\n } else {\r\n return allProvinces.value.flatMap((province) =>\r\n province.data.map((city) => ({\r\n label: `${city} (${province.name})`,\r\n value: city,\r\n })),\r\n );\r\n }\r\n});\r\n\r\nconst handleCitySelect = (cityName: string): void => {\r\n emit(\"update:modelValue\", cityName);\r\n emit(\"change\", cityName);\r\n visible.value = false;\r\n};\r\n\r\nconst handleSearchSelect = (value: string): void => {\r\n if (value) {\r\n handleCitySelect(value);\r\n searchValue.value = \"\";\r\n }\r\n};\r\n\r\nconst scrollToLetter = (letter: string): void => {\r\n const element = document.getElementById(`letter-${letter}`);\r\n if (element) {\r\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\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: 2025-05-30\r\n * @Description: 城市选择器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NPopover\r\n v-model:show=\"visible\"\r\n placement=\"bottom-start\"\r\n :width=\"430\"\r\n trigger=\"click\"\r\n :show-arrow=\"false\"\r\n >\r\n <template #trigger>\r\n <slot name=\"trigger\" :value=\"modelValue\" :visible=\"visible\">\r\n <div class=\"city-selector-trigger\">\r\n <span class=\"city-selector-trigger__text\">{{\r\n modelValue || placeholder\r\n }}</span>\r\n </div>\r\n </slot>\r\n </template>\r\n\r\n <div class=\"city-selector-content\">\r\n <div class=\"city-selector-header\">\r\n <NRadioGroup v-model:value=\"radioValue\" size=\"small\">\r\n <NRadioButton value=\"city\">按城市</NRadioButton>\r\n <NRadioButton value=\"province\">按省份</NRadioButton>\r\n </NRadioGroup>\r\n <NSelect\r\n v-model:value=\"searchValue\"\r\n class=\"city-selector-search\"\r\n :options=\"searchOptions\"\r\n filterable\r\n clearable\r\n placeholder=\"搜索城市\"\r\n @update:value=\"handleSearchSelect\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"showLetters\" class=\"city-selector-letters\">\r\n <span\r\n v-for=\"letter in letters\"\r\n :key=\"letter\"\r\n class=\"city-selector-letter\"\r\n @click=\"scrollToLetter(letter)\"\r\n >\r\n {{ letter }}\r\n </span>\r\n </div>\r\n\r\n <NScrollbar class=\"city-selector-body\">\r\n <div v-if=\"radioValue === 'city'\" class=\"city-list\">\r\n <div\r\n v-for=\"(cities, letter) in cityDataByLetter\"\r\n :key=\"letter\"\r\n :id=\"`letter-${letter}`\"\r\n class=\"city-group\"\r\n >\r\n <div class=\"city-group__letter\">{{ letter }}:</div>\r\n <div class=\"city-group__cities\">\r\n <span\r\n v-for=\"(city, index) in cities\"\r\n :key=\"`${letter}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city.name }\"\r\n @click=\"handleCitySelect(city.name)\"\r\n >\r\n {{ city.name }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div v-else class=\"province-list\">\r\n <div\r\n v-for=\"province in allProvinces\"\r\n :key=\"province.id\"\r\n :id=\"`letter-${province.id}`\"\r\n class=\"province-group\"\r\n >\r\n <div class=\"province-group__name\">{{ province.name }}:</div>\r\n <div class=\"province-group__cities\">\r\n <span\r\n v-for=\"(city, index) in province.data\"\r\n :key=\"`${province.id}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city }\"\r\n @click=\"handleCitySelect(city)\"\r\n >\r\n {{ city }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </NScrollbar>\r\n </div>\r\n </NPopover>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted } from \"vue\";\r\nimport {\r\n NPopover,\r\n NRadioGroup,\r\n NRadioButton,\r\n NSelect,\r\n NScrollbar,\r\n} from \"naive-ui\";\r\nimport type { SelectOption } from \"naive-ui\";\r\nimport provinceData from \"./province.json\";\r\n\r\ndefineOptions({ name: \"C_City\" });\r\n\r\ninterface CityItem {\r\n id: number;\r\n spell: string;\r\n name: string;\r\n}\r\n\r\n// 城市数据懒加载(83KB JSON 仅在组件挂载时加载)\r\nconst cityData = ref<{ cities: Record<string, CityItem[]> } | null>(null);\r\n\r\nonMounted(async () => {\r\n const mod = await import(\"./city.json\");\r\n cityData.value = mod.default ?? mod;\r\n});\r\n\r\ninterface ProvinceItem {\r\n id?: string;\r\n name: string;\r\n data: string[];\r\n}\r\n\r\ninterface Props {\r\n modelValue?: string;\r\n placeholder?: string;\r\n showLetters?: boolean;\r\n}\r\n\r\ninterface Emits {\r\n (e: \"update:modelValue\", value: string): void;\r\n (e: \"change\", value: string): void;\r\n}\r\n\r\nwithDefaults(defineProps<Props>(), {\r\n placeholder: \"请选择城市\",\r\n showLetters: true,\r\n});\r\n\r\nconst emit = defineEmits<Emits>();\r\n\r\nconst visible = ref(false);\r\nconst radioValue = ref<\"city\" | \"province\">(\"city\");\r\nconst searchValue = ref(\"\");\r\n\r\nconst allProvinces = computed(() => {\r\n const provinces: ProvinceItem[] = [];\r\n Object.values(provinceData).forEach((group) => {\r\n provinces.push(...(group as ProvinceItem[]));\r\n });\r\n return provinces;\r\n});\r\n\r\nconst cityDataByLetter = computed(() => {\r\n if (cityData.value?.cities) {\r\n return cityData.value.cities;\r\n }\r\n // 数据未加载时,从省份数据生成城市索引作为 fallback\r\n const cities: Record<string, CityItem[]> = {};\r\n let cityId = 1;\r\n const citySet = new Set<string>();\r\n allProvinces.value.forEach((province) => {\r\n province.data.forEach((cityName) => {\r\n citySet.add(cityName);\r\n });\r\n });\r\n Array.from(citySet).forEach((cityName) => {\r\n const letter = cityName[0].toUpperCase();\r\n if (!cities[letter]) cities[letter] = [];\r\n cities[letter].push({ id: cityId++, name: cityName, spell: \"\" });\r\n });\r\n const sortedCities: Record<string, CityItem[]> = {};\r\n Object.keys(cities)\r\n .sort()\r\n .forEach((letter) => {\r\n sortedCities[letter] = cities[letter].sort((a, b) =>\r\n a.name.localeCompare(b.name, \"zh-CN\"),\r\n );\r\n });\r\n return sortedCities;\r\n});\r\n\r\nconst letters = computed(() => {\r\n if (radioValue.value === \"city\") {\r\n return Object.keys(cityDataByLetter.value).sort();\r\n } else {\r\n const provinceLetters = new Set<string>();\r\n Object.keys(provinceData).forEach((key) => {\r\n if (key !== \"直辖市\" && key !== \"港澳\") {\r\n provinceLetters.add(key);\r\n }\r\n });\r\n const result = Array.from(provinceLetters).sort();\r\n result.push(\"直辖市\", \"港澳\");\r\n return result;\r\n }\r\n});\r\n\r\nconst searchOptions = computed((): SelectOption[] => {\r\n if (radioValue.value === \"city\") {\r\n const options: SelectOption[] = [];\r\n Object.values(cityDataByLetter.value).forEach((cities) => {\r\n (cities as CityItem[]).forEach((city) => {\r\n options.push({\r\n label: city.name,\r\n value: city.name,\r\n });\r\n });\r\n });\r\n return options;\r\n } else {\r\n return allProvinces.value.flatMap((province) =>\r\n province.data.map((city) => ({\r\n label: `${city} (${province.name})`,\r\n value: city,\r\n })),\r\n );\r\n }\r\n});\r\n\r\nconst handleCitySelect = (cityName: string): void => {\r\n emit(\"update:modelValue\", cityName);\r\n emit(\"change\", cityName);\r\n visible.value = false;\r\n};\r\n\r\nconst handleSearchSelect = (value: string): void => {\r\n if (value) {\r\n handleCitySelect(value);\r\n searchValue.value = \"\";\r\n }\r\n};\r\n\r\nconst scrollToLetter = (letter: string): void => {\r\n const element = document.getElementById(`letter-${letter}`);\r\n if (element) {\r\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\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_City2.js","names":["modelValue","placeholder","showLetters"],"sources":["../src/components/C_City/province.json","../src/components/C_City/index.vue","../src/components/C_City/index.vue","../src/components/C_City/index.vue"],"sourcesContent":["","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-05-30\r\n * @Description: 城市选择器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NPopover\r\n v-model:show=\"visible\"\r\n placement=\"bottom-start\"\r\n :width=\"430\"\r\n trigger=\"click\"\r\n :show-arrow=\"false\"\r\n >\r\n <template #trigger>\r\n <slot name=\"trigger\" :value=\"modelValue\" :visible=\"visible\">\r\n <div class=\"city-selector-trigger\">\r\n <span class=\"city-selector-trigger__text\">{{\r\n modelValue || placeholder\r\n }}</span>\r\n </div>\r\n </slot>\r\n </template>\r\n\r\n <div class=\"city-selector-content\">\r\n <div class=\"city-selector-header\">\r\n <NRadioGroup v-model:value=\"radioValue\" size=\"small\">\r\n <NRadioButton value=\"city\">按城市</NRadioButton>\r\n <NRadioButton value=\"province\">按省份</NRadioButton>\r\n </NRadioGroup>\r\n <NSelect\r\n v-model:value=\"searchValue\"\r\n class=\"city-selector-search\"\r\n :options=\"searchOptions\"\r\n filterable\r\n clearable\r\n placeholder=\"搜索城市\"\r\n @update:value=\"handleSearchSelect\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"showLetters\" class=\"city-selector-letters\">\r\n <span\r\n v-for=\"letter in letters\"\r\n :key=\"letter\"\r\n class=\"city-selector-letter\"\r\n @click=\"scrollToLetter(letter)\"\r\n >\r\n {{ letter }}\r\n </span>\r\n </div>\r\n\r\n <NScrollbar class=\"city-selector-body\">\r\n <div v-if=\"radioValue === 'city'\" class=\"city-list\">\r\n <div\r\n v-for=\"(cities, letter) in cityDataByLetter\"\r\n :key=\"letter\"\r\n :id=\"`letter-${letter}`\"\r\n class=\"city-group\"\r\n >\r\n <div class=\"city-group__letter\">{{ letter }}:</div>\r\n <div class=\"city-group__cities\">\r\n <span\r\n v-for=\"(city, index) in cities\"\r\n :key=\"`${letter}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city.name }\"\r\n @click=\"handleCitySelect(city.name)\"\r\n >\r\n {{ city.name }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div v-else class=\"province-list\">\r\n <div\r\n v-for=\"province in allProvinces\"\r\n :key=\"province.id\"\r\n :id=\"`letter-${province.id}`\"\r\n class=\"province-group\"\r\n >\r\n <div class=\"province-group__name\">{{ province.name }}:</div>\r\n <div class=\"province-group__cities\">\r\n <span\r\n v-for=\"(city, index) in province.data\"\r\n :key=\"`${province.id}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city }\"\r\n @click=\"handleCitySelect(city)\"\r\n >\r\n {{ city }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </NScrollbar>\r\n </div>\r\n </NPopover>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted } from \"vue\";\r\nimport {\r\n NPopover,\r\n NRadioGroup,\r\n NRadioButton,\r\n NSelect,\r\n NScrollbar,\r\n} from \"naive-ui\";\r\nimport type { SelectOption } from \"naive-ui\";\r\nimport provinceData from \"./province.json\";\r\n\r\ndefineOptions({ name: \"C_City\" });\r\n\r\ninterface CityItem {\r\n id: number;\r\n spell: string;\r\n name: string;\r\n}\r\n\r\n// 城市数据懒加载(83KB JSON 仅在组件挂载时加载)\r\nconst cityData = ref<{ cities: Record<string, CityItem[]> } | null>(null);\r\n\r\nonMounted(async () => {\r\n const mod = await import(\"./city.json\");\r\n cityData.value = mod.default ?? mod;\r\n});\r\n\r\ninterface ProvinceItem {\r\n id?: string;\r\n name: string;\r\n data: string[];\r\n}\r\n\r\ninterface Props {\r\n modelValue?: string;\r\n placeholder?: string;\r\n showLetters?: boolean;\r\n}\r\n\r\ninterface Emits {\r\n (e: \"update:modelValue\", value: string): void;\r\n (e: \"change\", value: string): void;\r\n}\r\n\r\nwithDefaults(defineProps<Props>(), {\r\n placeholder: \"请选择城市\",\r\n showLetters: true,\r\n});\r\n\r\nconst emit = defineEmits<Emits>();\r\n\r\nconst visible = ref(false);\r\nconst radioValue = ref<\"city\" | \"province\">(\"city\");\r\nconst searchValue = ref(\"\");\r\n\r\nconst allProvinces = computed(() => {\r\n const provinces: ProvinceItem[] = [];\r\n Object.values(provinceData).forEach((group) => {\r\n provinces.push(...(group as ProvinceItem[]));\r\n });\r\n return provinces;\r\n});\r\n\r\nconst cityDataByLetter = computed(() => {\r\n if (cityData.value?.cities) {\r\n return cityData.value.cities;\r\n }\r\n // 数据未加载时,从省份数据生成城市索引作为 fallback\r\n const cities: Record<string, CityItem[]> = {};\r\n let cityId = 1;\r\n const citySet = new Set<string>();\r\n allProvinces.value.forEach((province) => {\r\n province.data.forEach((cityName) => {\r\n citySet.add(cityName);\r\n });\r\n });\r\n Array.from(citySet).forEach((cityName) => {\r\n const letter = cityName[0].toUpperCase();\r\n if (!cities[letter]) cities[letter] = [];\r\n cities[letter].push({ id: cityId++, name: cityName, spell: \"\" });\r\n });\r\n const sortedCities: Record<string, CityItem[]> = {};\r\n Object.keys(cities)\r\n .sort()\r\n .forEach((letter) => {\r\n sortedCities[letter] = cities[letter].sort((a, b) =>\r\n a.name.localeCompare(b.name, \"zh-CN\"),\r\n );\r\n });\r\n return sortedCities;\r\n});\r\n\r\nconst letters = computed(() => {\r\n if (radioValue.value === \"city\") {\r\n return Object.keys(cityDataByLetter.value).sort();\r\n } else {\r\n const provinceLetters = new Set<string>();\r\n Object.keys(provinceData).forEach((key) => {\r\n if (key !== \"直辖市\" && key !== \"港澳\") {\r\n provinceLetters.add(key);\r\n }\r\n });\r\n const result = Array.from(provinceLetters).sort();\r\n result.push(\"直辖市\", \"港澳\");\r\n return result;\r\n }\r\n});\r\n\r\nconst searchOptions = computed((): SelectOption[] => {\r\n if (radioValue.value === \"city\") {\r\n const options: SelectOption[] = [];\r\n Object.values(cityDataByLetter.value).forEach((cities) => {\r\n (cities as CityItem[]).forEach((city) => {\r\n options.push({\r\n label: city.name,\r\n value: city.name,\r\n });\r\n });\r\n });\r\n return options;\r\n } else {\r\n return allProvinces.value.flatMap((province) =>\r\n province.data.map((city) => ({\r\n label: `${city} (${province.name})`,\r\n value: city,\r\n })),\r\n );\r\n }\r\n});\r\n\r\nconst handleCitySelect = (cityName: string): void => {\r\n emit(\"update:modelValue\", cityName);\r\n emit(\"change\", cityName);\r\n visible.value = false;\r\n};\r\n\r\nconst handleSearchSelect = (value: string): void => {\r\n if (value) {\r\n handleCitySelect(value);\r\n searchValue.value = \"\";\r\n }\r\n};\r\n\r\nconst scrollToLetter = (letter: string): void => {\r\n const element = document.getElementById(`letter-${letter}`);\r\n if (element) {\r\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\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: 2025-05-30\r\n * @Description: 城市选择器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NPopover\r\n v-model:show=\"visible\"\r\n placement=\"bottom-start\"\r\n :width=\"430\"\r\n trigger=\"click\"\r\n :show-arrow=\"false\"\r\n >\r\n <template #trigger>\r\n <slot name=\"trigger\" :value=\"modelValue\" :visible=\"visible\">\r\n <div class=\"city-selector-trigger\">\r\n <span class=\"city-selector-trigger__text\">{{\r\n modelValue || placeholder\r\n }}</span>\r\n </div>\r\n </slot>\r\n </template>\r\n\r\n <div class=\"city-selector-content\">\r\n <div class=\"city-selector-header\">\r\n <NRadioGroup v-model:value=\"radioValue\" size=\"small\">\r\n <NRadioButton value=\"city\">按城市</NRadioButton>\r\n <NRadioButton value=\"province\">按省份</NRadioButton>\r\n </NRadioGroup>\r\n <NSelect\r\n v-model:value=\"searchValue\"\r\n class=\"city-selector-search\"\r\n :options=\"searchOptions\"\r\n filterable\r\n clearable\r\n placeholder=\"搜索城市\"\r\n @update:value=\"handleSearchSelect\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"showLetters\" class=\"city-selector-letters\">\r\n <span\r\n v-for=\"letter in letters\"\r\n :key=\"letter\"\r\n class=\"city-selector-letter\"\r\n @click=\"scrollToLetter(letter)\"\r\n >\r\n {{ letter }}\r\n </span>\r\n </div>\r\n\r\n <NScrollbar class=\"city-selector-body\">\r\n <div v-if=\"radioValue === 'city'\" class=\"city-list\">\r\n <div\r\n v-for=\"(cities, letter) in cityDataByLetter\"\r\n :key=\"letter\"\r\n :id=\"`letter-${letter}`\"\r\n class=\"city-group\"\r\n >\r\n <div class=\"city-group__letter\">{{ letter }}:</div>\r\n <div class=\"city-group__cities\">\r\n <span\r\n v-for=\"(city, index) in cities\"\r\n :key=\"`${letter}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city.name }\"\r\n @click=\"handleCitySelect(city.name)\"\r\n >\r\n {{ city.name }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div v-else class=\"province-list\">\r\n <div\r\n v-for=\"province in allProvinces\"\r\n :key=\"province.id\"\r\n :id=\"`letter-${province.id}`\"\r\n class=\"province-group\"\r\n >\r\n <div class=\"province-group__name\">{{ province.name }}:</div>\r\n <div class=\"province-group__cities\">\r\n <span\r\n v-for=\"(city, index) in province.data\"\r\n :key=\"`${province.id}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city }\"\r\n @click=\"handleCitySelect(city)\"\r\n >\r\n {{ city }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </NScrollbar>\r\n </div>\r\n </NPopover>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted } from \"vue\";\r\nimport {\r\n NPopover,\r\n NRadioGroup,\r\n NRadioButton,\r\n NSelect,\r\n NScrollbar,\r\n} from \"naive-ui\";\r\nimport type { SelectOption } from \"naive-ui\";\r\nimport provinceData from \"./province.json\";\r\n\r\ndefineOptions({ name: \"C_City\" });\r\n\r\ninterface CityItem {\r\n id: number;\r\n spell: string;\r\n name: string;\r\n}\r\n\r\n// 城市数据懒加载(83KB JSON 仅在组件挂载时加载)\r\nconst cityData = ref<{ cities: Record<string, CityItem[]> } | null>(null);\r\n\r\nonMounted(async () => {\r\n const mod = await import(\"./city.json\");\r\n cityData.value = mod.default ?? mod;\r\n});\r\n\r\ninterface ProvinceItem {\r\n id?: string;\r\n name: string;\r\n data: string[];\r\n}\r\n\r\ninterface Props {\r\n modelValue?: string;\r\n placeholder?: string;\r\n showLetters?: boolean;\r\n}\r\n\r\ninterface Emits {\r\n (e: \"update:modelValue\", value: string): void;\r\n (e: \"change\", value: string): void;\r\n}\r\n\r\nwithDefaults(defineProps<Props>(), {\r\n placeholder: \"请选择城市\",\r\n showLetters: true,\r\n});\r\n\r\nconst emit = defineEmits<Emits>();\r\n\r\nconst visible = ref(false);\r\nconst radioValue = ref<\"city\" | \"province\">(\"city\");\r\nconst searchValue = ref(\"\");\r\n\r\nconst allProvinces = computed(() => {\r\n const provinces: ProvinceItem[] = [];\r\n Object.values(provinceData).forEach((group) => {\r\n provinces.push(...(group as ProvinceItem[]));\r\n });\r\n return provinces;\r\n});\r\n\r\nconst cityDataByLetter = computed(() => {\r\n if (cityData.value?.cities) {\r\n return cityData.value.cities;\r\n }\r\n // 数据未加载时,从省份数据生成城市索引作为 fallback\r\n const cities: Record<string, CityItem[]> = {};\r\n let cityId = 1;\r\n const citySet = new Set<string>();\r\n allProvinces.value.forEach((province) => {\r\n province.data.forEach((cityName) => {\r\n citySet.add(cityName);\r\n });\r\n });\r\n Array.from(citySet).forEach((cityName) => {\r\n const letter = cityName[0].toUpperCase();\r\n if (!cities[letter]) cities[letter] = [];\r\n cities[letter].push({ id: cityId++, name: cityName, spell: \"\" });\r\n });\r\n const sortedCities: Record<string, CityItem[]> = {};\r\n Object.keys(cities)\r\n .sort()\r\n .forEach((letter) => {\r\n sortedCities[letter] = cities[letter].sort((a, b) =>\r\n a.name.localeCompare(b.name, \"zh-CN\"),\r\n );\r\n });\r\n return sortedCities;\r\n});\r\n\r\nconst letters = computed(() => {\r\n if (radioValue.value === \"city\") {\r\n return Object.keys(cityDataByLetter.value).sort();\r\n } else {\r\n const provinceLetters = new Set<string>();\r\n Object.keys(provinceData).forEach((key) => {\r\n if (key !== \"直辖市\" && key !== \"港澳\") {\r\n provinceLetters.add(key);\r\n }\r\n });\r\n const result = Array.from(provinceLetters).sort();\r\n result.push(\"直辖市\", \"港澳\");\r\n return result;\r\n }\r\n});\r\n\r\nconst searchOptions = computed((): SelectOption[] => {\r\n if (radioValue.value === \"city\") {\r\n const options: SelectOption[] = [];\r\n Object.values(cityDataByLetter.value).forEach((cities) => {\r\n (cities as CityItem[]).forEach((city) => {\r\n options.push({\r\n label: city.name,\r\n value: city.name,\r\n });\r\n });\r\n });\r\n return options;\r\n } else {\r\n return allProvinces.value.flatMap((province) =>\r\n province.data.map((city) => ({\r\n label: `${city} (${province.name})`,\r\n value: city,\r\n })),\r\n );\r\n }\r\n});\r\n\r\nconst handleCitySelect = (cityName: string): void => {\r\n emit(\"update:modelValue\", cityName);\r\n emit(\"change\", cityName);\r\n visible.value = false;\r\n};\r\n\r\nconst handleSearchSelect = (value: string): void => {\r\n if (value) {\r\n handleCitySelect(value);\r\n searchValue.value = \"\";\r\n }\r\n};\r\n\r\nconst scrollToLetter = (letter: string): void => {\r\n const element = document.getElementById(`letter-${letter}`);\r\n if (element) {\r\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\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: 2025-05-30\r\n * @Description: 城市选择器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NPopover\r\n v-model:show=\"visible\"\r\n placement=\"bottom-start\"\r\n :width=\"430\"\r\n trigger=\"click\"\r\n :show-arrow=\"false\"\r\n >\r\n <template #trigger>\r\n <slot name=\"trigger\" :value=\"modelValue\" :visible=\"visible\">\r\n <div class=\"city-selector-trigger\">\r\n <span class=\"city-selector-trigger__text\">{{\r\n modelValue || placeholder\r\n }}</span>\r\n </div>\r\n </slot>\r\n </template>\r\n\r\n <div class=\"city-selector-content\">\r\n <div class=\"city-selector-header\">\r\n <NRadioGroup v-model:value=\"radioValue\" size=\"small\">\r\n <NRadioButton value=\"city\">按城市</NRadioButton>\r\n <NRadioButton value=\"province\">按省份</NRadioButton>\r\n </NRadioGroup>\r\n <NSelect\r\n v-model:value=\"searchValue\"\r\n class=\"city-selector-search\"\r\n :options=\"searchOptions\"\r\n filterable\r\n clearable\r\n placeholder=\"搜索城市\"\r\n @update:value=\"handleSearchSelect\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"showLetters\" class=\"city-selector-letters\">\r\n <span\r\n v-for=\"letter in letters\"\r\n :key=\"letter\"\r\n class=\"city-selector-letter\"\r\n @click=\"scrollToLetter(letter)\"\r\n >\r\n {{ letter }}\r\n </span>\r\n </div>\r\n\r\n <NScrollbar class=\"city-selector-body\">\r\n <div v-if=\"radioValue === 'city'\" class=\"city-list\">\r\n <div\r\n v-for=\"(cities, letter) in cityDataByLetter\"\r\n :key=\"letter\"\r\n :id=\"`letter-${letter}`\"\r\n class=\"city-group\"\r\n >\r\n <div class=\"city-group__letter\">{{ letter }}:</div>\r\n <div class=\"city-group__cities\">\r\n <span\r\n v-for=\"(city, index) in cities\"\r\n :key=\"`${letter}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city.name }\"\r\n @click=\"handleCitySelect(city.name)\"\r\n >\r\n {{ city.name }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div v-else class=\"province-list\">\r\n <div\r\n v-for=\"province in allProvinces\"\r\n :key=\"province.id\"\r\n :id=\"`letter-${province.id}`\"\r\n class=\"province-group\"\r\n >\r\n <div class=\"province-group__name\">{{ province.name }}:</div>\r\n <div class=\"province-group__cities\">\r\n <span\r\n v-for=\"(city, index) in province.data\"\r\n :key=\"`${province.id}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city }\"\r\n @click=\"handleCitySelect(city)\"\r\n >\r\n {{ city }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </NScrollbar>\r\n </div>\r\n </NPopover>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted } from \"vue\";\r\nimport {\r\n NPopover,\r\n NRadioGroup,\r\n NRadioButton,\r\n NSelect,\r\n NScrollbar,\r\n} from \"naive-ui\";\r\nimport type { SelectOption } from \"naive-ui\";\r\nimport provinceData from \"./province.json\";\r\n\r\ndefineOptions({ name: \"C_City\" });\r\n\r\ninterface CityItem {\r\n id: number;\r\n spell: string;\r\n name: string;\r\n}\r\n\r\n// 城市数据懒加载(83KB JSON 仅在组件挂载时加载)\r\nconst cityData = ref<{ cities: Record<string, CityItem[]> } | null>(null);\r\n\r\nonMounted(async () => {\r\n const mod = await import(\"./city.json\");\r\n cityData.value = mod.default ?? mod;\r\n});\r\n\r\ninterface ProvinceItem {\r\n id?: string;\r\n name: string;\r\n data: string[];\r\n}\r\n\r\ninterface Props {\r\n modelValue?: string;\r\n placeholder?: string;\r\n showLetters?: boolean;\r\n}\r\n\r\ninterface Emits {\r\n (e: \"update:modelValue\", value: string): void;\r\n (e: \"change\", value: string): void;\r\n}\r\n\r\nwithDefaults(defineProps<Props>(), {\r\n placeholder: \"请选择城市\",\r\n showLetters: true,\r\n});\r\n\r\nconst emit = defineEmits<Emits>();\r\n\r\nconst visible = ref(false);\r\nconst radioValue = ref<\"city\" | \"province\">(\"city\");\r\nconst searchValue = ref(\"\");\r\n\r\nconst allProvinces = computed(() => {\r\n const provinces: ProvinceItem[] = [];\r\n Object.values(provinceData).forEach((group) => {\r\n provinces.push(...(group as ProvinceItem[]));\r\n });\r\n return provinces;\r\n});\r\n\r\nconst cityDataByLetter = computed(() => {\r\n if (cityData.value?.cities) {\r\n return cityData.value.cities;\r\n }\r\n // 数据未加载时,从省份数据生成城市索引作为 fallback\r\n const cities: Record<string, CityItem[]> = {};\r\n let cityId = 1;\r\n const citySet = new Set<string>();\r\n allProvinces.value.forEach((province) => {\r\n province.data.forEach((cityName) => {\r\n citySet.add(cityName);\r\n });\r\n });\r\n Array.from(citySet).forEach((cityName) => {\r\n const letter = cityName[0].toUpperCase();\r\n if (!cities[letter]) cities[letter] = [];\r\n cities[letter].push({ id: cityId++, name: cityName, spell: \"\" });\r\n });\r\n const sortedCities: Record<string, CityItem[]> = {};\r\n Object.keys(cities)\r\n .sort()\r\n .forEach((letter) => {\r\n sortedCities[letter] = cities[letter].sort((a, b) =>\r\n a.name.localeCompare(b.name, \"zh-CN\"),\r\n );\r\n });\r\n return sortedCities;\r\n});\r\n\r\nconst letters = computed(() => {\r\n if (radioValue.value === \"city\") {\r\n return Object.keys(cityDataByLetter.value).sort();\r\n } else {\r\n const provinceLetters = new Set<string>();\r\n Object.keys(provinceData).forEach((key) => {\r\n if (key !== \"直辖市\" && key !== \"港澳\") {\r\n provinceLetters.add(key);\r\n }\r\n });\r\n const result = Array.from(provinceLetters).sort();\r\n result.push(\"直辖市\", \"港澳\");\r\n return result;\r\n }\r\n});\r\n\r\nconst searchOptions = computed((): SelectOption[] => {\r\n if (radioValue.value === \"city\") {\r\n const options: SelectOption[] = [];\r\n Object.values(cityDataByLetter.value).forEach((cities) => {\r\n (cities as CityItem[]).forEach((city) => {\r\n options.push({\r\n label: city.name,\r\n value: city.name,\r\n });\r\n });\r\n });\r\n return options;\r\n } else {\r\n return allProvinces.value.flatMap((province) =>\r\n province.data.map((city) => ({\r\n label: `${city} (${province.name})`,\r\n value: city,\r\n })),\r\n );\r\n }\r\n});\r\n\r\nconst handleCitySelect = (cityName: string): void => {\r\n emit(\"update:modelValue\", cityName);\r\n emit(\"change\", cityName);\r\n visible.value = false;\r\n};\r\n\r\nconst handleSearchSelect = (value: string): void => {\r\n if (value) {\r\n handleCitySelect(value);\r\n searchValue.value = \"\";\r\n }\r\n};\r\n\r\nconst scrollToLetter = (letter: string): void => {\r\n const element = document.getElementById(`letter-${letter}`);\r\n if (element) {\r\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\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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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"C_Code-DPZlNSxL.css","names":[],"sources":["../src/components/C_Code/index.vue?vue&type=style&index=0&scoped=2f676c83&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled */.mr-2[data-v-2f676c83] {\n margin-right: 0.5rem;\n}\n.ml-2[data-v-2f676c83] {\n margin-left: 0.5rem;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA"}
package/dist/C_Code2.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { t as C_Icon_default } from "./C_Icon2.js";
2
2
  import { t as export_helper_default } from "./export-helper.js";
3
- import { Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, nextTick, normalizeStyle, onMounted, onUnmounted, openBlock, ref, resolveComponent, toDisplayString, watch, withCtx } from "vue";
3
+ import { NButton, NCode, NModal, NSpin, NTooltip } from "naive-ui";
4
+ import { Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, nextTick, normalizeStyle, onMounted, onUnmounted, openBlock, ref, toDisplayString, watch, withCtx } from "vue";
4
5
 
5
6
  //#region src/components/C_Code/index.vue?vue&type=script&setup=true&lang.ts
6
7
  const _hoisted_1 = { class: "c-code-wrapper" };
@@ -193,11 +194,11 @@ var index_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCo
193
194
  toggleFullscreen
194
195
  });
195
196
  return (_ctx, _cache) => {
196
- const _component_NButton = resolveComponent("NButton");
197
- const _component_NTooltip = resolveComponent("NTooltip");
198
- const _component_NCode = resolveComponent("NCode");
199
- const _component_NSpin = resolveComponent("NSpin");
200
- const _component_NModal = resolveComponent("NModal");
197
+ const _component_NButton = NButton;
198
+ const _component_NTooltip = NTooltip;
199
+ const _component_NCode = NCode;
200
+ const _component_NSpin = NSpin;
201
+ const _component_NModal = NModal;
201
202
  return openBlock(), createElementBlock("div", _hoisted_1, [
202
203
  createCommentVNode(" 代码标题栏 "),
203
204
  _ctx.showHeader ? (openBlock(), createElementBlock("div", _hoisted_2, [createElementVNode("div", _hoisted_3, [languageIcon.value ? (openBlock(), createBlock(C_Icon_default, {
@@ -339,7 +340,7 @@ var index_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCo
339
340
 
340
341
  //#endregion
341
342
  //#region src/components/C_Code/index.vue
342
- var C_Code_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-c9fe4d76"]]);
343
+ var C_Code_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-2f676c83"]]);
343
344
 
344
345
  //#endregion
345
346
  export { C_Code_default as t };