@robot-admin/naive-ui-components 0.5.0 → 0.6.1

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 (115) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/C_Breadcrumb.cjs +1 -0
  3. package/dist/C_Breadcrumb.d.cts +2 -0
  4. package/dist/C_Breadcrumb.d.ts +3 -0
  5. package/dist/C_Breadcrumb.js +1 -0
  6. package/dist/C_Breadcrumb.js.map +1 -0
  7. package/dist/C_Breadcrumb2.js +2 -0
  8. package/dist/C_Breadcrumb2.js.map +1 -0
  9. package/dist/C_Captcha.d.cts +1 -1
  10. package/dist/C_Captcha.d.ts +1 -1
  11. package/dist/C_Cascade.d.cts +1 -1
  12. package/dist/C_Cascade.d.ts +1 -1
  13. package/dist/C_City.d.cts +1 -1
  14. package/dist/C_City.d.ts +1 -1
  15. package/dist/C_Code.d.cts +1 -1
  16. package/dist/C_Code.d.ts +1 -1
  17. package/dist/C_Date.d.cts +1 -1
  18. package/dist/C_Date.d.ts +1 -1
  19. package/dist/C_Editor.d.cts +1 -1
  20. package/dist/C_Editor.d.ts +1 -1
  21. package/dist/C_Guide.d.cts +1 -1
  22. package/dist/C_Guide.d.ts +1 -1
  23. package/dist/C_Icon.d.cts +1 -1
  24. package/dist/C_Icon.d.ts +1 -1
  25. package/dist/C_Language.d.cts +1 -1
  26. package/dist/C_Language.d.ts +1 -1
  27. package/dist/C_Markdown.d.cts +1 -1
  28. package/dist/C_Markdown.d.ts +1 -1
  29. package/dist/C_Menu.cjs +1 -0
  30. package/dist/C_Menu.d.cts +2 -0
  31. package/dist/C_Menu.d.ts +3 -0
  32. package/dist/C_Menu.js +1 -0
  33. package/dist/C_Menu.js.map +1 -0
  34. package/dist/C_Menu2.js +2 -0
  35. package/dist/C_Menu2.js.map +1 -0
  36. package/dist/C_Progress.d.cts +1 -1
  37. package/dist/C_Progress.d.ts +1 -1
  38. package/dist/C_Steps.d.cts +1 -1
  39. package/dist/C_Steps.d.ts +1 -1
  40. package/dist/{C_Table-Dcam_tRs.css.map → C_Table-vZlcgH6x.css.map} +1 -1
  41. package/dist/{C_Table-tbUx-R4H.css.map → C_Table-wzAO43l0.css.map} +1 -1
  42. package/dist/C_Table.css +69 -69
  43. package/dist/C_Table.js.map +1 -1
  44. package/dist/C_Table2.js +1 -1
  45. package/dist/C_Table2.js.map +1 -1
  46. package/dist/C_TagsView-DX3LecK1.css.map +1 -0
  47. package/dist/C_TagsView-DqOTa8bL.css.map +1 -0
  48. package/dist/C_TagsView.cjs +1 -0
  49. package/dist/C_TagsView.css +194 -0
  50. package/dist/C_TagsView.d.cts +2 -0
  51. package/dist/C_TagsView.d.ts +3 -0
  52. package/dist/C_TagsView.js +1 -0
  53. package/dist/C_TagsView.js.map +1 -0
  54. package/dist/C_TagsView2.js +2 -0
  55. package/dist/C_TagsView2.js.map +1 -0
  56. package/dist/C_Theme.d.cts +1 -1
  57. package/dist/C_Theme.d.ts +1 -1
  58. package/dist/C_VtableGantt.d.cts +1 -1
  59. package/dist/C_VtableGantt.d.ts +1 -1
  60. package/dist/_shared.cjs +1 -0
  61. package/dist/_shared.d.cts +2 -0
  62. package/dist/_shared.d.ts +2 -0
  63. package/dist/_shared.js +1 -0
  64. package/dist/constants.d.ts +1 -1
  65. package/dist/constants2.d.ts +2 -2
  66. package/dist/constants3.d.ts +1 -1
  67. package/dist/constants4.d.ts +3 -3
  68. package/dist/constants5.d.ts +2 -2
  69. package/dist/index.cjs +1 -1
  70. package/dist/index.cjs.map +1 -1
  71. package/dist/index.d.cts +40 -36
  72. package/dist/index.d.ts +44 -36
  73. package/dist/index.js +1 -1
  74. package/dist/index.js.map +1 -1
  75. package/dist/index10.vue.d.ts +23 -65
  76. package/dist/index11.vue.d.ts +64 -18
  77. package/dist/index12.vue.d.ts +17 -72
  78. package/dist/index13.vue.d.ts +72 -46
  79. package/dist/index14.vue.d.ts +57 -23
  80. package/dist/index15.vue.d.ts +48 -11
  81. package/dist/index16.vue.d.ts +23 -652
  82. package/dist/index17.vue.d.ts +88 -0
  83. package/dist/index18.vue.d.ts +18 -0
  84. package/dist/index19.vue.d.ts +662 -0
  85. package/dist/index3.vue.d.ts +20 -37
  86. package/dist/index4.vue.d.ts +37 -23
  87. package/dist/index5.vue.d.ts +22 -26
  88. package/dist/index6.vue.d.ts +24 -37
  89. package/dist/index7.vue.d.ts +36 -44
  90. package/dist/index8.vue.d.ts +40 -25
  91. package/dist/index9.vue.d.ts +34 -23
  92. package/dist/menuAdapter.d.ts +167 -0
  93. package/dist/menuAdapter.js +2 -0
  94. package/dist/menuAdapter.js.map +1 -0
  95. package/dist/resolver.cjs +1 -1
  96. package/dist/resolver.cjs.map +1 -1
  97. package/dist/resolver.d.cts +1 -1
  98. package/dist/resolver.d.ts +1 -1
  99. package/dist/resolver.js +1 -1
  100. package/dist/resolver.js.map +1 -1
  101. package/dist/style.css +267 -71
  102. package/dist/useCalendarEvents.d.ts +1 -1
  103. package/dist/useCollapsePanel.d.ts +1 -1
  104. package/dist/useCropperCore.d.ts +3 -3
  105. package/dist/useDraggableLayout.d.ts +3 -3
  106. package/dist/useDynamicFormState.d.ts +8 -8
  107. package/dist/useInfiniteScroll.d.ts +3 -3
  108. package/dist/useModalEdit.d.ts +4 -5
  109. package/dist/useQRCode.d.ts +2 -2
  110. package/dist/useSearchState.d.ts +3 -3
  111. package/dist/useSignatureHistory.d.ts +3 -3
  112. package/dist/useSplitResize.d.ts +2 -2
  113. package/dist/useTimeSelection.d.ts +1 -1
  114. package/dist/useTreeOperations.d.ts +3 -3
  115. package/package.json +3 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"C_TagsView-DX3LecK1.css","names":[],"sources":["../src/components/C_TagsView/index.vue?vue&type=style&index=0&scoped=66047096&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//* ===========================================\n * 标签组件样式 - 精简版\n * =========================================== */\n/* --------- 标签视图容器 --------- */\n.tags-view-container[data-v-66047096] {\n border-bottom: 1px solid var(--color-border);\n padding: 8px 16px 0;\n position: relative;\n width: 100%;\n}\n\n/* --------- 滚动轨道容器 --------- */\n.tags-track[data-v-66047096] {\n width: 100%;\n overflow: hidden;\n position: relative;\n}\n\n/* --------- 滚动容器 --------- */\n.tags-container[data-v-66047096] {\n display: flex;\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: none;\n -ms-overflow-style: none;\n padding: 0 20px;\n align-items: center;\n min-height: 40px;\n}\n.tags-container[data-v-66047096]::-webkit-scrollbar {\n display: none;\n}\n\n/* --------- 现代化标签样式 --------- */\n.n-tag[data-v-66047096] {\n position: relative;\n display: inline-flex;\n align-items: center;\n padding: 0 12px;\n height: 28px;\n margin-right: 4px;\n font-size: 12px;\n font-weight: 500;\n border-radius: 14px;\n border: 1px solid var(--color-border);\n cursor: pointer;\n transition: all 0.22s cubic-bezier(0.4, 0, 0.2, 1);\n flex-shrink: 0;\n white-space: nowrap;\n /* 内部高光效果 */\n /* --------- 悬停效果 --------- */\n /* --------- 激活状态 --------- */\n /* --------- 关闭按钮 --------- */\n}\n.n-tag[data-v-66047096]::before {\n content: \"\";\n position: absolute;\n top: 1px;\n left: 1px;\n right: 1px;\n height: 50%;\n border-radius: 13px 13px 6px 6px;\n background: linear-gradient(180deg, rgba(255, 255, 255, 0.3), transparent);\n opacity: 0.5;\n transition: opacity 0.22s ease;\n}\n.n-tag[data-v-66047096]:hover:not([type=primary]) {\n color: var(--color-primary) !important;\n border-color: var(--color-primary);\n transform: scale(1.02);\n}\n.n-tag[data-v-66047096]:hover:not([type=primary])::before {\n opacity: 0.8;\n}\n.n-tag[data-v-66047096]:hover:not([type=primary]) .c-icon,\n.n-tag[data-v-66047096]:hover:not([type=primary]) [class*=\"c-icon\"] {\n color: var(--color-primary) !important;\n}\n.n-tag:hover:not([type=primary]) i[data-v-66047096],\n.n-tag:hover:not([type=primary]) .icon[data-v-66047096] {\n color: var(--color-primary) !important;\n}\n.n-tag[data-v-66047096]:hover:not([type=primary]) .n-tag__close {\n color: var(--color-primary) !important;\n opacity: 0.8;\n transform: scale(1.05);\n}\n.n-tag[type=primary][data-v-66047096] {\n background: var(--tag-active-bg, rgba(32, 128, 240, 0.08)) !important;\n color: var(--color-primary) !important;\n border-color: var(--color-primary) !important;\n font-weight: 600;\n transform: scale(1.02);\n}\n.n-tag[type=primary][data-v-66047096]::before {\n opacity: 0.6;\n}\n.n-tag[type=primary][data-v-66047096] .n-tag__content,\n.n-tag[type=primary][data-v-66047096] *:not(.n-tag__close) {\n color: var(--color-primary) !important;\n}\n.n-tag[type=primary][data-v-66047096] .c-icon,\n.n-tag[type=primary][data-v-66047096] [class*=\"c-icon\"] {\n color: var(--color-primary) !important;\n}\n.n-tag[type=primary] i[data-v-66047096],\n.n-tag[type=primary] .icon[data-v-66047096] {\n color: var(--color-primary) !important;\n}\n.n-tag[type=primary][data-v-66047096]:hover {\n background: var(--tag-active-hover-bg, rgba(32, 128, 240, 0.12)) !important;\n transform: scale(1.03);\n}\n.n-tag[type=primary][data-v-66047096] .n-tag__close {\n color: var(--color-primary) !important;\n opacity: 0.8;\n}\n.n-tag[data-v-66047096] .n-tag__close {\n width: 16px !important;\n height: 16px !important;\n border-radius: 8px !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n margin-left: 6px !important;\n font-size: 12px !important;\n font-weight: 600 !important;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;\n opacity: 0.6;\n background: rgba(0, 0, 0, 0.02) !important;\n border: 1px solid transparent;\n}\n.n-tag[data-v-66047096] .n-tag__close:not(:hover) {\n transform: scale(0.9);\n}\n.n-tag[data-v-66047096] .n-tag__close:hover {\n background: linear-gradient(135deg, rgba(248, 113, 113, 0.1), rgba(239, 68, 68, 0.08)) !important;\n border-color: rgba(239, 68, 68, 0.15) !important;\n color: #ef4444 !important;\n opacity: 1 !important;\n transform: scale(0.6) !important;\n box-shadow: 0 2px 6px rgba(239, 68, 68, 0.2) !important;\n}\n.n-tag[data-v-66047096] .n-tag__close:active {\n transform: scale(0.95) !important;\n transition-duration: 0.1s !important;\n}\n\n/* --------- C_Icon --------- */\n[data-v-66047096] .c-icon {\n margin-right: 4px;\n font-size: 12px;\n transition: color 0.22s ease;\n display: inline-flex;\n align-items: center;\n}\n\n/* --------- 响应式 --------- */\n@media (max-width: 768px) {\n.tags-view-container[data-v-66047096] {\n padding: 6px 12px 0;\n}\n.n-tag[data-v-66047096] {\n height: 26px;\n padding: 0 10px;\n font-size: 11px;\n margin-right: 3px;\n border-radius: 13px;\n}\n.n-tag[data-v-66047096] .n-tag__close {\n width: 14px;\n height: 14px;\n font-size: 11px;\n margin-left: 4px;\n}\n.tags-container[data-v-66047096] {\n padding: 0 12px;\n min-height: 36px;\n}\n[data-v-66047096] .c-icon {\n font-size: 11px;\n margin-right: 3px;\n}\n}\n/* --------- 暗色主题 --------- */\n[data-theme=dark] .n-tag[data-v-66047096] .n-tag__close {\n background: rgba(255, 255, 255, 0.03) !important;\n}\n[data-theme=dark] .n-tag[data-v-66047096] .n-tag__close:hover {\n background: linear-gradient(135deg, rgba(248, 113, 113, 0.12), rgba(239, 68, 68, 0.1)) !important;\n box-shadow: 0 2px 6px rgba(239, 68, 68, 0.25) !important;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"C_TagsView-DqOTa8bL.css","names":[],"sources":["../src/components/C_TagsView/index.vue?vue&type=style&index=0&scoped=66047096&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//* ===========================================\n * 标签组件样式 - 精简版\n * =========================================== */\n/* --------- 标签视图容器 --------- */\n.tags-view-container[data-v-66047096] {\n border-bottom: 1px solid var(--color-border);\n padding: 8px 16px 0;\n position: relative;\n width: 100%;\n}\n\n/* --------- 滚动轨道容器 --------- */\n.tags-track[data-v-66047096] {\n width: 100%;\n overflow: hidden;\n position: relative;\n}\n\n/* --------- 滚动容器 --------- */\n.tags-container[data-v-66047096] {\n display: flex;\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: none;\n -ms-overflow-style: none;\n padding: 0 20px;\n align-items: center;\n min-height: 40px;\n}\n.tags-container[data-v-66047096]::-webkit-scrollbar {\n display: none;\n}\n\n/* --------- 现代化标签样式 --------- */\n.n-tag[data-v-66047096] {\n position: relative;\n display: inline-flex;\n align-items: center;\n padding: 0 12px;\n height: 28px;\n margin-right: 4px;\n font-size: 12px;\n font-weight: 500;\n border-radius: 14px;\n border: 1px solid var(--color-border);\n cursor: pointer;\n transition: all 0.22s cubic-bezier(0.4, 0, 0.2, 1);\n flex-shrink: 0;\n white-space: nowrap;\n /* 内部高光效果 */\n /* --------- 悬停效果 --------- */\n /* --------- 激活状态 --------- */\n /* --------- 关闭按钮 --------- */\n}\n.n-tag[data-v-66047096]::before {\n content: \"\";\n position: absolute;\n top: 1px;\n left: 1px;\n right: 1px;\n height: 50%;\n border-radius: 13px 13px 6px 6px;\n background: linear-gradient(180deg, rgba(255, 255, 255, 0.3), transparent);\n opacity: 0.5;\n transition: opacity 0.22s ease;\n}\n.n-tag[data-v-66047096]:hover:not([type=primary]) {\n color: var(--color-primary) !important;\n border-color: var(--color-primary);\n transform: scale(1.02);\n}\n.n-tag[data-v-66047096]:hover:not([type=primary])::before {\n opacity: 0.8;\n}\n.n-tag[data-v-66047096]:hover:not([type=primary]) .c-icon,\n.n-tag[data-v-66047096]:hover:not([type=primary]) [class*=\"c-icon\"] {\n color: var(--color-primary) !important;\n}\n.n-tag:hover:not([type=primary]) i[data-v-66047096],\n.n-tag:hover:not([type=primary]) .icon[data-v-66047096] {\n color: var(--color-primary) !important;\n}\n.n-tag[data-v-66047096]:hover:not([type=primary]) .n-tag__close {\n color: var(--color-primary) !important;\n opacity: 0.8;\n transform: scale(1.05);\n}\n.n-tag[type=primary][data-v-66047096] {\n background: var(--tag-active-bg, rgba(32, 128, 240, 0.08)) !important;\n color: var(--color-primary) !important;\n border-color: var(--color-primary) !important;\n font-weight: 600;\n transform: scale(1.02);\n}\n.n-tag[type=primary][data-v-66047096]::before {\n opacity: 0.6;\n}\n.n-tag[type=primary][data-v-66047096] .n-tag__content,\n.n-tag[type=primary][data-v-66047096] *:not(.n-tag__close) {\n color: var(--color-primary) !important;\n}\n.n-tag[type=primary][data-v-66047096] .c-icon,\n.n-tag[type=primary][data-v-66047096] [class*=\"c-icon\"] {\n color: var(--color-primary) !important;\n}\n.n-tag[type=primary] i[data-v-66047096],\n.n-tag[type=primary] .icon[data-v-66047096] {\n color: var(--color-primary) !important;\n}\n.n-tag[type=primary][data-v-66047096]:hover {\n background: var(--tag-active-hover-bg, rgba(32, 128, 240, 0.12)) !important;\n transform: scale(1.03);\n}\n.n-tag[type=primary][data-v-66047096] .n-tag__close {\n color: var(--color-primary) !important;\n opacity: 0.8;\n}\n.n-tag[data-v-66047096] .n-tag__close {\n width: 16px !important;\n height: 16px !important;\n border-radius: 8px !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n margin-left: 6px !important;\n font-size: 12px !important;\n font-weight: 600 !important;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;\n opacity: 0.6;\n background: rgba(0, 0, 0, 0.02) !important;\n border: 1px solid transparent;\n}\n.n-tag[data-v-66047096] .n-tag__close:not(:hover) {\n transform: scale(0.9);\n}\n.n-tag[data-v-66047096] .n-tag__close:hover {\n background: linear-gradient(135deg, rgba(248, 113, 113, 0.1), rgba(239, 68, 68, 0.08)) !important;\n border-color: rgba(239, 68, 68, 0.15) !important;\n color: #ef4444 !important;\n opacity: 1 !important;\n transform: scale(0.6) !important;\n box-shadow: 0 2px 6px rgba(239, 68, 68, 0.2) !important;\n}\n.n-tag[data-v-66047096] .n-tag__close:active {\n transform: scale(0.95) !important;\n transition-duration: 0.1s !important;\n}\n\n/* --------- C_Icon --------- */\n[data-v-66047096] .c-icon {\n margin-right: 4px;\n font-size: 12px;\n transition: color 0.22s ease;\n display: inline-flex;\n align-items: center;\n}\n\n/* --------- 响应式 --------- */\n@media (max-width: 768px) {\n.tags-view-container[data-v-66047096] {\n padding: 6px 12px 0;\n}\n.n-tag[data-v-66047096] {\n height: 26px;\n padding: 0 10px;\n font-size: 11px;\n margin-right: 3px;\n border-radius: 13px;\n}\n.n-tag[data-v-66047096] .n-tag__close {\n width: 14px;\n height: 14px;\n font-size: 11px;\n margin-left: 4px;\n}\n.tags-container[data-v-66047096] {\n padding: 0 12px;\n min-height: 36px;\n}\n[data-v-66047096] .c-icon {\n font-size: 11px;\n margin-right: 3px;\n}\n}\n/* --------- 暗色主题 --------- */\n[data-theme=dark] .n-tag[data-v-66047096] .n-tag__close {\n background: rgba(255, 255, 255, 0.03) !important;\n}\n[data-theme=dark] .n-tag[data-v-66047096] .n-tag__close:hover {\n background: linear-gradient(135deg, rgba(248, 113, 113, 0.12), rgba(239, 68, 68, 0.1)) !important;\n box-shadow: 0 2px 6px rgba(239, 68, 68, 0.25) !important;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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"}
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./C_Icon.js`);const e=require(`./C_TagsView.js`);exports.C_TagsView=e.t,exports.useTagsView=e.n;
@@ -0,0 +1,194 @@
1
+ /* unplugin-vue-components disabled *//* ===========================================
2
+ * 标签组件样式 - 精简版
3
+ * =========================================== */
4
+ /* --------- 标签视图容器 --------- */
5
+ .tags-view-container[data-v-66047096] {
6
+ border-bottom: 1px solid var(--color-border);
7
+ padding: 8px 16px 0;
8
+ position: relative;
9
+ width: 100%;
10
+ }
11
+
12
+ /* --------- 滚动轨道容器 --------- */
13
+ .tags-track[data-v-66047096] {
14
+ width: 100%;
15
+ overflow: hidden;
16
+ position: relative;
17
+ }
18
+
19
+ /* --------- 滚动容器 --------- */
20
+ .tags-container[data-v-66047096] {
21
+ display: flex;
22
+ overflow-x: auto;
23
+ overflow-y: hidden;
24
+ scrollbar-width: none;
25
+ -ms-overflow-style: none;
26
+ padding: 0 20px;
27
+ align-items: center;
28
+ min-height: 40px;
29
+ }
30
+ .tags-container[data-v-66047096]::-webkit-scrollbar {
31
+ display: none;
32
+ }
33
+
34
+ /* --------- 现代化标签样式 --------- */
35
+ .n-tag[data-v-66047096] {
36
+ position: relative;
37
+ display: inline-flex;
38
+ align-items: center;
39
+ padding: 0 12px;
40
+ height: 28px;
41
+ margin-right: 4px;
42
+ font-size: 12px;
43
+ font-weight: 500;
44
+ border-radius: 14px;
45
+ border: 1px solid var(--color-border);
46
+ cursor: pointer;
47
+ transition: all 0.22s cubic-bezier(0.4, 0, 0.2, 1);
48
+ flex-shrink: 0;
49
+ white-space: nowrap;
50
+ /* 内部高光效果 */
51
+ /* --------- 悬停效果 --------- */
52
+ /* --------- 激活状态 --------- */
53
+ /* --------- 关闭按钮 --------- */
54
+ }
55
+ .n-tag[data-v-66047096]::before {
56
+ content: "";
57
+ position: absolute;
58
+ top: 1px;
59
+ left: 1px;
60
+ right: 1px;
61
+ height: 50%;
62
+ border-radius: 13px 13px 6px 6px;
63
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.3), transparent);
64
+ opacity: 0.5;
65
+ transition: opacity 0.22s ease;
66
+ }
67
+ .n-tag[data-v-66047096]:hover:not([type=primary]) {
68
+ color: var(--color-primary) !important;
69
+ border-color: var(--color-primary);
70
+ transform: scale(1.02);
71
+ }
72
+ .n-tag[data-v-66047096]:hover:not([type=primary])::before {
73
+ opacity: 0.8;
74
+ }
75
+ .n-tag[data-v-66047096]:hover:not([type=primary]) .c-icon,
76
+ .n-tag[data-v-66047096]:hover:not([type=primary]) [class*="c-icon"] {
77
+ color: var(--color-primary) !important;
78
+ }
79
+ .n-tag:hover:not([type=primary]) i[data-v-66047096],
80
+ .n-tag:hover:not([type=primary]) .icon[data-v-66047096] {
81
+ color: var(--color-primary) !important;
82
+ }
83
+ .n-tag[data-v-66047096]:hover:not([type=primary]) .n-tag__close {
84
+ color: var(--color-primary) !important;
85
+ opacity: 0.8;
86
+ transform: scale(1.05);
87
+ }
88
+ .n-tag[type=primary][data-v-66047096] {
89
+ background: var(--tag-active-bg, rgba(32, 128, 240, 0.08)) !important;
90
+ color: var(--color-primary) !important;
91
+ border-color: var(--color-primary) !important;
92
+ font-weight: 600;
93
+ transform: scale(1.02);
94
+ }
95
+ .n-tag[type=primary][data-v-66047096]::before {
96
+ opacity: 0.6;
97
+ }
98
+ .n-tag[type=primary][data-v-66047096] .n-tag__content,
99
+ .n-tag[type=primary][data-v-66047096] *:not(.n-tag__close) {
100
+ color: var(--color-primary) !important;
101
+ }
102
+ .n-tag[type=primary][data-v-66047096] .c-icon,
103
+ .n-tag[type=primary][data-v-66047096] [class*="c-icon"] {
104
+ color: var(--color-primary) !important;
105
+ }
106
+ .n-tag[type=primary] i[data-v-66047096],
107
+ .n-tag[type=primary] .icon[data-v-66047096] {
108
+ color: var(--color-primary) !important;
109
+ }
110
+ .n-tag[type=primary][data-v-66047096]:hover {
111
+ background: var(--tag-active-hover-bg, rgba(32, 128, 240, 0.12)) !important;
112
+ transform: scale(1.03);
113
+ }
114
+ .n-tag[type=primary][data-v-66047096] .n-tag__close {
115
+ color: var(--color-primary) !important;
116
+ opacity: 0.8;
117
+ }
118
+ .n-tag[data-v-66047096] .n-tag__close {
119
+ width: 16px !important;
120
+ height: 16px !important;
121
+ border-radius: 8px !important;
122
+ display: flex !important;
123
+ align-items: center !important;
124
+ justify-content: center !important;
125
+ margin-left: 6px !important;
126
+ font-size: 12px !important;
127
+ font-weight: 600 !important;
128
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
129
+ opacity: 0.6;
130
+ background: rgba(0, 0, 0, 0.02) !important;
131
+ border: 1px solid transparent;
132
+ }
133
+ .n-tag[data-v-66047096] .n-tag__close:not(:hover) {
134
+ transform: scale(0.9);
135
+ }
136
+ .n-tag[data-v-66047096] .n-tag__close:hover {
137
+ background: linear-gradient(135deg, rgba(248, 113, 113, 0.1), rgba(239, 68, 68, 0.08)) !important;
138
+ border-color: rgba(239, 68, 68, 0.15) !important;
139
+ color: #ef4444 !important;
140
+ opacity: 1 !important;
141
+ transform: scale(0.6) !important;
142
+ box-shadow: 0 2px 6px rgba(239, 68, 68, 0.2) !important;
143
+ }
144
+ .n-tag[data-v-66047096] .n-tag__close:active {
145
+ transform: scale(0.95) !important;
146
+ transition-duration: 0.1s !important;
147
+ }
148
+
149
+ /* --------- C_Icon --------- */
150
+ [data-v-66047096] .c-icon {
151
+ margin-right: 4px;
152
+ font-size: 12px;
153
+ transition: color 0.22s ease;
154
+ display: inline-flex;
155
+ align-items: center;
156
+ }
157
+
158
+ /* --------- 响应式 --------- */
159
+ @media (max-width: 768px) {
160
+ .tags-view-container[data-v-66047096] {
161
+ padding: 6px 12px 0;
162
+ }
163
+ .n-tag[data-v-66047096] {
164
+ height: 26px;
165
+ padding: 0 10px;
166
+ font-size: 11px;
167
+ margin-right: 3px;
168
+ border-radius: 13px;
169
+ }
170
+ .n-tag[data-v-66047096] .n-tag__close {
171
+ width: 14px;
172
+ height: 14px;
173
+ font-size: 11px;
174
+ margin-left: 4px;
175
+ }
176
+ .tags-container[data-v-66047096] {
177
+ padding: 0 12px;
178
+ min-height: 36px;
179
+ }
180
+ [data-v-66047096] .c-icon {
181
+ font-size: 11px;
182
+ margin-right: 3px;
183
+ }
184
+ }
185
+ /* --------- 暗色主题 --------- */
186
+ [data-theme=dark] .n-tag[data-v-66047096] .n-tag__close {
187
+ background: rgba(255, 255, 255, 0.03) !important;
188
+ }
189
+ [data-theme=dark] .n-tag[data-v-66047096] .n-tag__close:hover {
190
+ background: linear-gradient(135deg, rgba(248, 113, 113, 0.12), rgba(239, 68, 68, 0.1)) !important;
191
+ box-shadow: 0 2px 6px rgba(239, 68, 68, 0.25) !important;
192
+ }
193
+
194
+ /*# sourceMappingURL=C_TagsView-DX3LecK1.css.map*/
@@ -0,0 +1,2 @@
1
+ import { i as useTagsView, n as _default, r as UseTagsViewOptions, t as ContextMenuLabels } from "./index17.vue.js";
2
+ export { _default as C_TagsView, type ContextMenuLabels, type UseTagsViewOptions, useTagsView };
@@ -0,0 +1,3 @@
1
+ import "./menuAdapter.js";
2
+ import { i as useTagsView, n as _default, r as UseTagsViewOptions, t as ContextMenuLabels } from "./index17.vue.js";
3
+ export { _default as C_TagsView, type ContextMenuLabels, type UseTagsViewOptions, useTagsView };
@@ -0,0 +1 @@
1
+ import"./C_Icon2.js";import{n as e,t}from"./C_TagsView2.js";export{t as C_TagsView,e as useTagsView};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"C_TagsView.js","names":[],"sources":["../src/components/C_TagsView/useTagsView.ts","../src/components/C_TagsView/index.vue","../src/components/C_TagsView/index.vue","../src/components/C_TagsView/index.vue"],"sourcesContent":["import { ref, type Ref } from 'vue'\nimport type { TagItem } from '../_shared'\n\nexport interface UseTagsViewOptions {\n /** localStorage 持久化 key,传空字符串则不持久化 */\n persistKey?: string\n /** 首页路径,用于 removeAll 后的回退 */\n homePath?: string\n}\n\nconst STORAGE_KEY_DEFAULT = '__tags_view_list__'\n\n/**\n * 标签页管理 composable\n *\n * 独立于组件使用 — 可在任何地方管理标签状态\n *\n * @example 独立使用\n * ```ts\n * const tags = useTagsView({ persistKey: 'my-tags' })\n * tags.addTag({ path: '/home', title: '首页', meta: { affix: true } })\n * ```\n */\nexport function useTagsView(options: UseTagsViewOptions = {}) {\n const { persistKey = STORAGE_KEY_DEFAULT, homePath = '/home' } = options\n\n // ====== 持久化 ======\n const loadPersistedTags = (): TagItem[] => {\n if (!persistKey) return []\n try {\n const raw = localStorage.getItem(persistKey)\n return raw ? JSON.parse(raw) : []\n } catch {\n return []\n }\n }\n\n const persistTags = (tags: TagItem[]) => {\n if (!persistKey) return\n try {\n localStorage.setItem(persistKey, JSON.stringify(tags))\n } catch {\n /* silently fail */\n }\n }\n\n // ====== State ======\n const tagsViewList: Ref<TagItem[]> = ref(loadPersistedTags())\n const activeTag = ref('')\n\n const syncPersist = () => persistTags(tagsViewList.value)\n\n // ====== Actions ======\n\n const initTags = (tags?: TagItem[]) => {\n if (tags) {\n tagsViewList.value = tags\n } else {\n // 去重\n tagsViewList.value = [\n ...new Map(tagsViewList.value.map(tag => [tag.path, tag])).values(),\n ]\n }\n syncPersist()\n }\n\n const setActiveTag = (path: string) => {\n activeTag.value = path\n }\n\n const addTag = (tag: TagItem) => {\n const existingIndex = tagsViewList.value.findIndex(\n item => item.path === tag.path\n )\n\n if (existingIndex === -1) {\n tagsViewList.value.push(tag)\n } else {\n const existing = tagsViewList.value[existingIndex]\n if (existing.title !== tag.title || !existing.originalTitle) {\n existing.title = tag.title\n existing.originalTitle = tag.originalTitle || existing.originalTitle\n }\n }\n\n setActiveTag(tag.path)\n syncPersist()\n }\n\n const removeTag = (index: number): string | null => {\n if (index >= 0 && index < tagsViewList.value.length) {\n const removed = tagsViewList.value.splice(index, 1)[0]?.path ?? null\n syncPersist()\n return removed\n }\n return null\n }\n\n const removeOtherTags = (index: number) => {\n if (index === 0) {\n tagsViewList.value = [tagsViewList.value[0]].filter(Boolean)\n } else {\n tagsViewList.value = [\n tagsViewList.value[0],\n tagsViewList.value[index],\n ].filter(Boolean)\n }\n syncPersist()\n }\n\n const removeLeftTags = (index: number) => {\n tagsViewList.value = [\n tagsViewList.value[0],\n ...tagsViewList.value.slice(index),\n ]\n syncPersist()\n }\n\n const removeRightTags = (index: number) => {\n tagsViewList.value = tagsViewList.value.slice(0, index + 1)\n syncPersist()\n }\n\n const removeAllTags = () => {\n tagsViewList.value = tagsViewList.value.filter(tag => tag.meta?.affix)\n syncPersist()\n }\n\n return {\n tagsViewList,\n activeTag,\n homePath,\n initTags,\n setActiveTag,\n addTag,\n removeTag,\n removeOtherTags,\n removeLeftTags,\n removeRightTags,\n removeAllTags,\n }\n}\n","/* unplugin-vue-components disabled */<!--\n * @Description: 通用标签页导航组件 — 路由感知的多标签管理\n *\n * 内置功能:\n * - 路由变化自动添加标签\n * - 持久化(localStorage,可关闭)\n * - 右键菜单(关闭/关闭其他/关闭左侧/关闭右侧/关闭所有)\n * - 水平滚轮滚动\n * - i18n 支持(labelFormatter)\n *\n * @example 基础用法\n * ```vue\n * <C_TagsView\n * :label-formatter=\"$t\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * @example 自定义首页 + 菜单文案\n * ```vue\n * <C_TagsView\n * home-path=\"/dashboard\"\n * home-title=\"Dashboard\"\n * :context-menu-labels=\"{ close: 'Close', closeAll: 'Close All', ... }\"\n * />\n * ```\n *\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"tags-view-container\">\n <div\n class=\"tags-track\"\n ref=\"tagsTrack\"\n @wheel=\"handleWheel\"\n >\n <div\n class=\"tags-container\"\n ref=\"tagsContainer\"\n >\n <NTag\n v-for=\"(tag, index) in tags.tagsViewList.value\"\n :key=\"tag.path\"\n :type=\"isActive(tag) ? 'primary' : 'default'\"\n :closable=\"!isAffix(tag)\"\n :data-path=\"tag.path\"\n @close.stop=\"handleClose(tag, index)\"\n @click=\"navigateToTag(tag)\"\n @contextmenu.prevent=\"\n (e: MouseEvent) => showContextMenu(e, tag, index)\n \"\n >\n <template #icon>\n <C_Icon\n :name=\"tag.icon\"\n :size=\"12\"\n />\n </template>\n {{ tag.title }}\n </NTag>\n </div>\n </div>\n <NDropdown\n v-if=\"contextMenuVisible\"\n :show=\"contextMenuVisible\"\n :options=\"contextMenuOptions\"\n :x=\"contextMenuX\"\n :y=\"contextMenuY\"\n @clickoutside=\"closeContextMenu\"\n @select=\"handleContextMenuSelect\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, nextTick, h } from 'vue'\n import { useRoute, useRouter } from 'vue-router'\n import { C_Icon } from '../C_Icon'\n import type { TagItem } from '../_shared'\n import { useTagsView, type UseTagsViewOptions } from './useTagsView'\n\n defineOptions({ name: 'C_TagsView' })\n\n export interface ContextMenuLabels {\n close?: string\n closeOthers?: string\n closeLeft?: string\n closeRight?: string\n closeAll?: string\n }\n\n const props = withDefaults(\n defineProps<{\n /**\n * 标签文本格式化函数(用于 i18n)\n */\n labelFormatter?: (label: string) => string\n /** 首页路径 */\n homePath?: string\n /** 首页标题(原始文本) */\n homeTitle?: string\n /** 首页图标 */\n homeIcon?: string\n /** 持久化 localStorage key,传空字符串禁用 */\n persistKey?: string\n /** 右键菜单文案(国际化适配) */\n contextMenuLabels?: ContextMenuLabels\n /** useTagsView 配置项(优先级最高) */\n tagsViewOptions?: UseTagsViewOptions\n }>(),\n {\n homePath: '/home',\n homeTitle: '首页',\n homeIcon: 'mdi:home',\n persistKey: '__tags_view_list__',\n contextMenuLabels: () => ({\n close: '关闭',\n closeOthers: '关闭其他',\n closeLeft: '关闭左侧',\n closeRight: '关闭右侧',\n closeAll: '关闭所有',\n }),\n }\n )\n\n const emit = defineEmits<{\n /** 标签被关闭后跳转 */\n close: [fallbackPath: string]\n /** 关闭全部后 */\n closeAll: []\n }>()\n\n const route = useRoute()\n const router = useRouter()\n\n // ====== Tags composable ======\n const tags = useTagsView(\n props.tagsViewOptions ?? {\n persistKey: props.persistKey,\n homePath: props.homePath,\n }\n )\n\n // ====== 首次渲染前重新翻译持久化标签 ======\n if (tags.tagsViewList.value.length > 0 && props.labelFormatter) {\n const allRoutes = router.getRoutes()\n const translatedTags = tags.tagsViewList.value.map(tag => {\n const matchedRoute = allRoutes.find(r => r.path === tag.path)\n const originalTitle =\n tag.originalTitle || (matchedRoute?.meta?.title as string) || tag.title\n return {\n ...tag,\n originalTitle,\n title: props.labelFormatter!(originalTitle),\n }\n })\n tags.initTags(translatedTags)\n }\n\n const formatLabel = (title: string): string =>\n props.labelFormatter ? props.labelFormatter(title) : title\n\n // ====== UI State ======\n\n const contextMenuVisible = ref(false)\n const contextMenuX = ref(0)\n const contextMenuY = ref(0)\n const selectedTag = ref<TagItem | null>(null)\n const selectedIndex = ref(-1)\n const tagsTrack = ref<HTMLElement>()\n const tagsContainer = ref<HTMLElement>()\n\n // ====== Helpers ======\n const isActive = (tag: TagItem): boolean => tag.path === route.path\n const isAffix = (tag: TagItem) => tag.meta?.affix\n\n const handleWheel = (e: WheelEvent) => {\n const container = tagsContainer.value\n if (!container) return\n e.preventDefault()\n container.scrollTo({\n left: container.scrollLeft + e.deltaY,\n behavior: 'smooth',\n })\n }\n\n const scrollToTag = (path: string) => {\n nextTick(() => {\n const targetTag = tagsContainer.value?.querySelector(\n `[data-path=\"${path}\"]`\n ) as HTMLElement\n if (targetTag) {\n targetTag.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'center',\n })\n }\n })\n }\n\n // ====== Actions ======\n\n const navigateToTag = (tag: TagItem) => {\n if (tag.path !== route.path) {\n router.push(tag.path)\n }\n scrollToTag(tag.path)\n }\n\n const handleClose = (tag: TagItem, index: number) => {\n if (isAffix(tag)) return\n\n const wasActive = isActive(tag)\n const tagsBeforeRemove = tags.tagsViewList.value.length\n tags.removeTag(index)\n\n if (wasActive) {\n const remaining = tags.tagsViewList.value\n const wasLastTag = index === tagsBeforeRemove - 1\n let fallbackPath: string\n\n if (wasLastTag) {\n fallbackPath = remaining[index - 1]?.path || props.homePath\n } else {\n fallbackPath = remaining[remaining.length - 1]?.path || props.homePath\n }\n\n router.push(fallbackPath)\n emit('close', fallbackPath)\n }\n }\n\n const showContextMenu = (event: MouseEvent, tag: TagItem, index: number) => {\n event.preventDefault()\n selectedTag.value = tag\n selectedIndex.value = index\n contextMenuVisible.value = true\n contextMenuX.value = event.clientX\n contextMenuY.value = event.clientY\n }\n\n const closeContextMenu = () => (contextMenuVisible.value = false)\n\n const contextMenuOptions = computed(() => {\n const labels = props.contextMenuLabels\n return [\n {\n type: 'option' as const,\n label: labels.close ?? '关闭',\n key: 'close',\n disabled: isAffix(selectedTag.value as TagItem),\n icon: () => h('span', { class: 'i-mdi:close' }),\n },\n {\n type: 'option' as const,\n label: labels.closeOthers ?? '关闭其他',\n key: 'closeOthers',\n icon: () => h('span', { class: 'i-mdi:arrow-left-right-bold' }),\n },\n {\n type: 'option' as const,\n label: labels.closeLeft ?? '关闭左侧',\n key: 'closeLeft',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-left' }),\n },\n {\n type: 'option' as const,\n label: labels.closeRight ?? '关闭右侧',\n key: 'closeRight',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-right' }),\n },\n {\n type: 'option' as const,\n label: labels.closeAll ?? '关闭所有',\n key: 'closeAll',\n icon: () => h('span', { class: 'i-mdi:tally-mark-5' }),\n },\n ]\n })\n\n const handleContextMenuSelect = (key: string) => {\n if (!selectedTag.value || selectedIndex.value === -1) return\n\n switch (key) {\n case 'close':\n handleClose(selectedTag.value, selectedIndex.value)\n break\n case 'closeOthers':\n tags.removeOtherTags(selectedIndex.value)\n break\n case 'closeLeft':\n tags.removeLeftTags(selectedIndex.value)\n break\n case 'closeRight':\n tags.removeRightTags(selectedIndex.value)\n break\n case 'closeAll':\n tags.removeAllTags()\n router.push(props.homePath)\n emit('closeAll')\n break\n }\n closeContextMenu()\n }\n\n // ====== 路由自动跟踪 ======\n watch(\n () => route.path,\n (newPath: string) => {\n const originalTitle =\n newPath === props.homePath\n ? props.homeTitle\n : (route.meta.title as string) || 'Unnamed Page'\n\n tags.addTag({\n path: newPath,\n originalTitle,\n title: formatLabel(originalTitle),\n icon:\n newPath === props.homePath\n ? props.homeIcon\n : (route.meta.icon as string),\n meta: { affix: route.meta.affix as boolean },\n })\n\n tags.setActiveTag(newPath)\n scrollToTag(newPath)\n },\n { immediate: true }\n )\n\n // ====== 暴露 ======\n defineExpose({\n /** useTagsView composable 实例 */\n tags,\n /** 滚动到指定标签 */\n scrollToTag,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","/* unplugin-vue-components disabled */<!--\n * @Description: 通用标签页导航组件 — 路由感知的多标签管理\n *\n * 内置功能:\n * - 路由变化自动添加标签\n * - 持久化(localStorage,可关闭)\n * - 右键菜单(关闭/关闭其他/关闭左侧/关闭右侧/关闭所有)\n * - 水平滚轮滚动\n * - i18n 支持(labelFormatter)\n *\n * @example 基础用法\n * ```vue\n * <C_TagsView\n * :label-formatter=\"$t\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * @example 自定义首页 + 菜单文案\n * ```vue\n * <C_TagsView\n * home-path=\"/dashboard\"\n * home-title=\"Dashboard\"\n * :context-menu-labels=\"{ close: 'Close', closeAll: 'Close All', ... }\"\n * />\n * ```\n *\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"tags-view-container\">\n <div\n class=\"tags-track\"\n ref=\"tagsTrack\"\n @wheel=\"handleWheel\"\n >\n <div\n class=\"tags-container\"\n ref=\"tagsContainer\"\n >\n <NTag\n v-for=\"(tag, index) in tags.tagsViewList.value\"\n :key=\"tag.path\"\n :type=\"isActive(tag) ? 'primary' : 'default'\"\n :closable=\"!isAffix(tag)\"\n :data-path=\"tag.path\"\n @close.stop=\"handleClose(tag, index)\"\n @click=\"navigateToTag(tag)\"\n @contextmenu.prevent=\"\n (e: MouseEvent) => showContextMenu(e, tag, index)\n \"\n >\n <template #icon>\n <C_Icon\n :name=\"tag.icon\"\n :size=\"12\"\n />\n </template>\n {{ tag.title }}\n </NTag>\n </div>\n </div>\n <NDropdown\n v-if=\"contextMenuVisible\"\n :show=\"contextMenuVisible\"\n :options=\"contextMenuOptions\"\n :x=\"contextMenuX\"\n :y=\"contextMenuY\"\n @clickoutside=\"closeContextMenu\"\n @select=\"handleContextMenuSelect\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, nextTick, h } from 'vue'\n import { useRoute, useRouter } from 'vue-router'\n import { C_Icon } from '../C_Icon'\n import type { TagItem } from '../_shared'\n import { useTagsView, type UseTagsViewOptions } from './useTagsView'\n\n defineOptions({ name: 'C_TagsView' })\n\n export interface ContextMenuLabels {\n close?: string\n closeOthers?: string\n closeLeft?: string\n closeRight?: string\n closeAll?: string\n }\n\n const props = withDefaults(\n defineProps<{\n /**\n * 标签文本格式化函数(用于 i18n)\n */\n labelFormatter?: (label: string) => string\n /** 首页路径 */\n homePath?: string\n /** 首页标题(原始文本) */\n homeTitle?: string\n /** 首页图标 */\n homeIcon?: string\n /** 持久化 localStorage key,传空字符串禁用 */\n persistKey?: string\n /** 右键菜单文案(国际化适配) */\n contextMenuLabels?: ContextMenuLabels\n /** useTagsView 配置项(优先级最高) */\n tagsViewOptions?: UseTagsViewOptions\n }>(),\n {\n homePath: '/home',\n homeTitle: '首页',\n homeIcon: 'mdi:home',\n persistKey: '__tags_view_list__',\n contextMenuLabels: () => ({\n close: '关闭',\n closeOthers: '关闭其他',\n closeLeft: '关闭左侧',\n closeRight: '关闭右侧',\n closeAll: '关闭所有',\n }),\n }\n )\n\n const emit = defineEmits<{\n /** 标签被关闭后跳转 */\n close: [fallbackPath: string]\n /** 关闭全部后 */\n closeAll: []\n }>()\n\n const route = useRoute()\n const router = useRouter()\n\n // ====== Tags composable ======\n const tags = useTagsView(\n props.tagsViewOptions ?? {\n persistKey: props.persistKey,\n homePath: props.homePath,\n }\n )\n\n // ====== 首次渲染前重新翻译持久化标签 ======\n if (tags.tagsViewList.value.length > 0 && props.labelFormatter) {\n const allRoutes = router.getRoutes()\n const translatedTags = tags.tagsViewList.value.map(tag => {\n const matchedRoute = allRoutes.find(r => r.path === tag.path)\n const originalTitle =\n tag.originalTitle || (matchedRoute?.meta?.title as string) || tag.title\n return {\n ...tag,\n originalTitle,\n title: props.labelFormatter!(originalTitle),\n }\n })\n tags.initTags(translatedTags)\n }\n\n const formatLabel = (title: string): string =>\n props.labelFormatter ? props.labelFormatter(title) : title\n\n // ====== UI State ======\n\n const contextMenuVisible = ref(false)\n const contextMenuX = ref(0)\n const contextMenuY = ref(0)\n const selectedTag = ref<TagItem | null>(null)\n const selectedIndex = ref(-1)\n const tagsTrack = ref<HTMLElement>()\n const tagsContainer = ref<HTMLElement>()\n\n // ====== Helpers ======\n const isActive = (tag: TagItem): boolean => tag.path === route.path\n const isAffix = (tag: TagItem) => tag.meta?.affix\n\n const handleWheel = (e: WheelEvent) => {\n const container = tagsContainer.value\n if (!container) return\n e.preventDefault()\n container.scrollTo({\n left: container.scrollLeft + e.deltaY,\n behavior: 'smooth',\n })\n }\n\n const scrollToTag = (path: string) => {\n nextTick(() => {\n const targetTag = tagsContainer.value?.querySelector(\n `[data-path=\"${path}\"]`\n ) as HTMLElement\n if (targetTag) {\n targetTag.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'center',\n })\n }\n })\n }\n\n // ====== Actions ======\n\n const navigateToTag = (tag: TagItem) => {\n if (tag.path !== route.path) {\n router.push(tag.path)\n }\n scrollToTag(tag.path)\n }\n\n const handleClose = (tag: TagItem, index: number) => {\n if (isAffix(tag)) return\n\n const wasActive = isActive(tag)\n const tagsBeforeRemove = tags.tagsViewList.value.length\n tags.removeTag(index)\n\n if (wasActive) {\n const remaining = tags.tagsViewList.value\n const wasLastTag = index === tagsBeforeRemove - 1\n let fallbackPath: string\n\n if (wasLastTag) {\n fallbackPath = remaining[index - 1]?.path || props.homePath\n } else {\n fallbackPath = remaining[remaining.length - 1]?.path || props.homePath\n }\n\n router.push(fallbackPath)\n emit('close', fallbackPath)\n }\n }\n\n const showContextMenu = (event: MouseEvent, tag: TagItem, index: number) => {\n event.preventDefault()\n selectedTag.value = tag\n selectedIndex.value = index\n contextMenuVisible.value = true\n contextMenuX.value = event.clientX\n contextMenuY.value = event.clientY\n }\n\n const closeContextMenu = () => (contextMenuVisible.value = false)\n\n const contextMenuOptions = computed(() => {\n const labels = props.contextMenuLabels\n return [\n {\n type: 'option' as const,\n label: labels.close ?? '关闭',\n key: 'close',\n disabled: isAffix(selectedTag.value as TagItem),\n icon: () => h('span', { class: 'i-mdi:close' }),\n },\n {\n type: 'option' as const,\n label: labels.closeOthers ?? '关闭其他',\n key: 'closeOthers',\n icon: () => h('span', { class: 'i-mdi:arrow-left-right-bold' }),\n },\n {\n type: 'option' as const,\n label: labels.closeLeft ?? '关闭左侧',\n key: 'closeLeft',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-left' }),\n },\n {\n type: 'option' as const,\n label: labels.closeRight ?? '关闭右侧',\n key: 'closeRight',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-right' }),\n },\n {\n type: 'option' as const,\n label: labels.closeAll ?? '关闭所有',\n key: 'closeAll',\n icon: () => h('span', { class: 'i-mdi:tally-mark-5' }),\n },\n ]\n })\n\n const handleContextMenuSelect = (key: string) => {\n if (!selectedTag.value || selectedIndex.value === -1) return\n\n switch (key) {\n case 'close':\n handleClose(selectedTag.value, selectedIndex.value)\n break\n case 'closeOthers':\n tags.removeOtherTags(selectedIndex.value)\n break\n case 'closeLeft':\n tags.removeLeftTags(selectedIndex.value)\n break\n case 'closeRight':\n tags.removeRightTags(selectedIndex.value)\n break\n case 'closeAll':\n tags.removeAllTags()\n router.push(props.homePath)\n emit('closeAll')\n break\n }\n closeContextMenu()\n }\n\n // ====== 路由自动跟踪 ======\n watch(\n () => route.path,\n (newPath: string) => {\n const originalTitle =\n newPath === props.homePath\n ? props.homeTitle\n : (route.meta.title as string) || 'Unnamed Page'\n\n tags.addTag({\n path: newPath,\n originalTitle,\n title: formatLabel(originalTitle),\n icon:\n newPath === props.homePath\n ? props.homeIcon\n : (route.meta.icon as string),\n meta: { affix: route.meta.affix as boolean },\n })\n\n tags.setActiveTag(newPath)\n scrollToTag(newPath)\n },\n { immediate: true }\n )\n\n // ====== 暴露 ======\n defineExpose({\n /** useTagsView composable 实例 */\n tags,\n /** 滚动到指定标签 */\n scrollToTag,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","<!--\n * @Description: 通用标签页导航组件 — 路由感知的多标签管理\n *\n * 内置功能:\n * - 路由变化自动添加标签\n * - 持久化(localStorage,可关闭)\n * - 右键菜单(关闭/关闭其他/关闭左侧/关闭右侧/关闭所有)\n * - 水平滚轮滚动\n * - i18n 支持(labelFormatter)\n *\n * @example 基础用法\n * ```vue\n * <C_TagsView\n * :label-formatter=\"$t\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * @example 自定义首页 + 菜单文案\n * ```vue\n * <C_TagsView\n * home-path=\"/dashboard\"\n * home-title=\"Dashboard\"\n * :context-menu-labels=\"{ close: 'Close', closeAll: 'Close All', ... }\"\n * />\n * ```\n *\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"tags-view-container\">\n <div\n class=\"tags-track\"\n ref=\"tagsTrack\"\n @wheel=\"handleWheel\"\n >\n <div\n class=\"tags-container\"\n ref=\"tagsContainer\"\n >\n <NTag\n v-for=\"(tag, index) in tags.tagsViewList.value\"\n :key=\"tag.path\"\n :type=\"isActive(tag) ? 'primary' : 'default'\"\n :closable=\"!isAffix(tag)\"\n :data-path=\"tag.path\"\n @close.stop=\"handleClose(tag, index)\"\n @click=\"navigateToTag(tag)\"\n @contextmenu.prevent=\"\n (e: MouseEvent) => showContextMenu(e, tag, index)\n \"\n >\n <template #icon>\n <C_Icon\n :name=\"tag.icon\"\n :size=\"12\"\n />\n </template>\n {{ tag.title }}\n </NTag>\n </div>\n </div>\n <NDropdown\n v-if=\"contextMenuVisible\"\n :show=\"contextMenuVisible\"\n :options=\"contextMenuOptions\"\n :x=\"contextMenuX\"\n :y=\"contextMenuY\"\n @clickoutside=\"closeContextMenu\"\n @select=\"handleContextMenuSelect\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, nextTick, h } from 'vue'\n import { useRoute, useRouter } from 'vue-router'\n import { C_Icon } from '../C_Icon'\n import type { TagItem } from '../_shared'\n import { useTagsView, type UseTagsViewOptions } from './useTagsView'\n\n defineOptions({ name: 'C_TagsView' })\n\n export interface ContextMenuLabels {\n close?: string\n closeOthers?: string\n closeLeft?: string\n closeRight?: string\n closeAll?: string\n }\n\n const props = withDefaults(\n defineProps<{\n /**\n * 标签文本格式化函数(用于 i18n)\n */\n labelFormatter?: (label: string) => string\n /** 首页路径 */\n homePath?: string\n /** 首页标题(原始文本) */\n homeTitle?: string\n /** 首页图标 */\n homeIcon?: string\n /** 持久化 localStorage key,传空字符串禁用 */\n persistKey?: string\n /** 右键菜单文案(国际化适配) */\n contextMenuLabels?: ContextMenuLabels\n /** useTagsView 配置项(优先级最高) */\n tagsViewOptions?: UseTagsViewOptions\n }>(),\n {\n homePath: '/home',\n homeTitle: '首页',\n homeIcon: 'mdi:home',\n persistKey: '__tags_view_list__',\n contextMenuLabels: () => ({\n close: '关闭',\n closeOthers: '关闭其他',\n closeLeft: '关闭左侧',\n closeRight: '关闭右侧',\n closeAll: '关闭所有',\n }),\n }\n )\n\n const emit = defineEmits<{\n /** 标签被关闭后跳转 */\n close: [fallbackPath: string]\n /** 关闭全部后 */\n closeAll: []\n }>()\n\n const route = useRoute()\n const router = useRouter()\n\n // ====== Tags composable ======\n const tags = useTagsView(\n props.tagsViewOptions ?? {\n persistKey: props.persistKey,\n homePath: props.homePath,\n }\n )\n\n // ====== 首次渲染前重新翻译持久化标签 ======\n if (tags.tagsViewList.value.length > 0 && props.labelFormatter) {\n const allRoutes = router.getRoutes()\n const translatedTags = tags.tagsViewList.value.map(tag => {\n const matchedRoute = allRoutes.find(r => r.path === tag.path)\n const originalTitle =\n tag.originalTitle || (matchedRoute?.meta?.title as string) || tag.title\n return {\n ...tag,\n originalTitle,\n title: props.labelFormatter!(originalTitle),\n }\n })\n tags.initTags(translatedTags)\n }\n\n const formatLabel = (title: string): string =>\n props.labelFormatter ? props.labelFormatter(title) : title\n\n // ====== UI State ======\n\n const contextMenuVisible = ref(false)\n const contextMenuX = ref(0)\n const contextMenuY = ref(0)\n const selectedTag = ref<TagItem | null>(null)\n const selectedIndex = ref(-1)\n const tagsTrack = ref<HTMLElement>()\n const tagsContainer = ref<HTMLElement>()\n\n // ====== Helpers ======\n const isActive = (tag: TagItem): boolean => tag.path === route.path\n const isAffix = (tag: TagItem) => tag.meta?.affix\n\n const handleWheel = (e: WheelEvent) => {\n const container = tagsContainer.value\n if (!container) return\n e.preventDefault()\n container.scrollTo({\n left: container.scrollLeft + e.deltaY,\n behavior: 'smooth',\n })\n }\n\n const scrollToTag = (path: string) => {\n nextTick(() => {\n const targetTag = tagsContainer.value?.querySelector(\n `[data-path=\"${path}\"]`\n ) as HTMLElement\n if (targetTag) {\n targetTag.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'center',\n })\n }\n })\n }\n\n // ====== Actions ======\n\n const navigateToTag = (tag: TagItem) => {\n if (tag.path !== route.path) {\n router.push(tag.path)\n }\n scrollToTag(tag.path)\n }\n\n const handleClose = (tag: TagItem, index: number) => {\n if (isAffix(tag)) return\n\n const wasActive = isActive(tag)\n const tagsBeforeRemove = tags.tagsViewList.value.length\n tags.removeTag(index)\n\n if (wasActive) {\n const remaining = tags.tagsViewList.value\n const wasLastTag = index === tagsBeforeRemove - 1\n let fallbackPath: string\n\n if (wasLastTag) {\n fallbackPath = remaining[index - 1]?.path || props.homePath\n } else {\n fallbackPath = remaining[remaining.length - 1]?.path || props.homePath\n }\n\n router.push(fallbackPath)\n emit('close', fallbackPath)\n }\n }\n\n const showContextMenu = (event: MouseEvent, tag: TagItem, index: number) => {\n event.preventDefault()\n selectedTag.value = tag\n selectedIndex.value = index\n contextMenuVisible.value = true\n contextMenuX.value = event.clientX\n contextMenuY.value = event.clientY\n }\n\n const closeContextMenu = () => (contextMenuVisible.value = false)\n\n const contextMenuOptions = computed(() => {\n const labels = props.contextMenuLabels\n return [\n {\n type: 'option' as const,\n label: labels.close ?? '关闭',\n key: 'close',\n disabled: isAffix(selectedTag.value as TagItem),\n icon: () => h('span', { class: 'i-mdi:close' }),\n },\n {\n type: 'option' as const,\n label: labels.closeOthers ?? '关闭其他',\n key: 'closeOthers',\n icon: () => h('span', { class: 'i-mdi:arrow-left-right-bold' }),\n },\n {\n type: 'option' as const,\n label: labels.closeLeft ?? '关闭左侧',\n key: 'closeLeft',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-left' }),\n },\n {\n type: 'option' as const,\n label: labels.closeRight ?? '关闭右侧',\n key: 'closeRight',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-right' }),\n },\n {\n type: 'option' as const,\n label: labels.closeAll ?? '关闭所有',\n key: 'closeAll',\n icon: () => h('span', { class: 'i-mdi:tally-mark-5' }),\n },\n ]\n })\n\n const handleContextMenuSelect = (key: string) => {\n if (!selectedTag.value || selectedIndex.value === -1) return\n\n switch (key) {\n case 'close':\n handleClose(selectedTag.value, selectedIndex.value)\n break\n case 'closeOthers':\n tags.removeOtherTags(selectedIndex.value)\n break\n case 'closeLeft':\n tags.removeLeftTags(selectedIndex.value)\n break\n case 'closeRight':\n tags.removeRightTags(selectedIndex.value)\n break\n case 'closeAll':\n tags.removeAllTags()\n router.push(props.homePath)\n emit('closeAll')\n break\n }\n closeContextMenu()\n }\n\n // ====== 路由自动跟踪 ======\n watch(\n () => route.path,\n (newPath: string) => {\n const originalTitle =\n newPath === props.homePath\n ? props.homeTitle\n : (route.meta.title as string) || 'Unnamed Page'\n\n tags.addTag({\n path: newPath,\n originalTitle,\n title: formatLabel(originalTitle),\n icon:\n newPath === props.homePath\n ? props.homeIcon\n : (route.meta.icon as string),\n meta: { affix: route.meta.affix as boolean },\n })\n\n tags.setActiveTag(newPath)\n scrollToTag(newPath)\n },\n { immediate: true }\n )\n\n // ====== 暴露 ======\n defineExpose({\n /** useTagsView composable 实例 */\n tags,\n /** 滚动到指定标签 */\n scrollToTag,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{t as e}from"./C_Icon2.js";import{t}from"./export-helper.js";import{NDropdown as n,NTag as r}from"naive-ui";import{Fragment as i,computed as a,createBlock as o,createCommentVNode as s,createElementBlock as c,createElementVNode as l,createTextVNode as u,createVNode as d,defineComponent as f,h as p,nextTick as m,openBlock as h,ref as g,renderList as _,toDisplayString as v,unref as y,watch as b,withCtx as x,withModifiers as S}from"vue";import{useRoute as C,useRouter as w}from"vue-router";function T(e={}){let{persistKey:t=`__tags_view_list__`,homePath:n=`/home`}=e,r=()=>{if(!t)return[];try{let e=localStorage.getItem(t);return e?JSON.parse(e):[]}catch{return[]}},i=e=>{if(t)try{localStorage.setItem(t,JSON.stringify(e))}catch{}},a=g(r()),o=g(``),s=()=>i(a.value),c=e=>{e?a.value=e:a.value=[...new Map(a.value.map(e=>[e.path,e])).values()],s()},l=e=>{o.value=e};return{tagsViewList:a,activeTag:o,homePath:n,initTags:c,setActiveTag:l,addTag:e=>{let t=a.value.findIndex(t=>t.path===e.path);if(t===-1)a.value.push(e);else{let n=a.value[t];(n.title!==e.title||!n.originalTitle)&&(n.title=e.title,n.originalTitle=e.originalTitle||n.originalTitle)}l(e.path),s()},removeTag:e=>{if(e>=0&&e<a.value.length){let t=a.value.splice(e,1)[0]?.path??null;return s(),t}return null},removeOtherTags:e=>{e===0?a.value=[a.value[0]].filter(Boolean):a.value=[a.value[0],a.value[e]].filter(Boolean),s()},removeLeftTags:e=>{a.value=[a.value[0],...a.value.slice(e)],s()},removeRightTags:e=>{a.value=a.value.slice(0,e+1),s()},removeAllTags:()=>{a.value=a.value.filter(e=>e.meta?.affix),s()}}}const E={class:`tags-view-container`};var D=t(f({name:`C_TagsView`,__name:`index`,props:{labelFormatter:{},homePath:{default:`/home`},homeTitle:{default:`首页`},homeIcon:{default:`mdi:home`},persistKey:{default:`__tags_view_list__`},contextMenuLabels:{default:()=>({close:`关闭`,closeOthers:`关闭其他`,closeLeft:`关闭左侧`,closeRight:`关闭右侧`,closeAll:`关闭所有`})},tagsViewOptions:{}},emits:[`close`,`closeAll`],setup(t,{expose:f,emit:D}){let O=t,k=D,A=C(),j=w(),M=T(O.tagsViewOptions??{persistKey:O.persistKey,homePath:O.homePath});if(M.tagsViewList.value.length>0&&O.labelFormatter){let e=j.getRoutes(),t=M.tagsViewList.value.map(t=>{let n=e.find(e=>e.path===t.path),r=t.originalTitle||n?.meta?.title||t.title;return{...t,originalTitle:r,title:O.labelFormatter(r)}});M.initTags(t)}let N=e=>O.labelFormatter?O.labelFormatter(e):e,P=g(!1),F=g(0),I=g(0),L=g(null),R=g(-1),z=g(),B=g(),V=e=>e.path===A.path,H=e=>e.meta?.affix,U=e=>{let t=B.value;t&&(e.preventDefault(),t.scrollTo({left:t.scrollLeft+e.deltaY,behavior:`smooth`}))},W=e=>{m(()=>{let t=B.value?.querySelector(`[data-path="${e}"]`);t&&t.scrollIntoView({behavior:`smooth`,block:`nearest`,inline:`center`})})},G=e=>{e.path!==A.path&&j.push(e.path),W(e.path)},K=(e,t)=>{if(H(e))return;let n=V(e),r=M.tagsViewList.value.length;if(M.removeTag(t),n){let e=M.tagsViewList.value,n=t===r-1,i;i=n?e[t-1]?.path||O.homePath:e[e.length-1]?.path||O.homePath,j.push(i),k(`close`,i)}},q=(e,t,n)=>{e.preventDefault(),L.value=t,R.value=n,P.value=!0,F.value=e.clientX,I.value=e.clientY},J=()=>P.value=!1,Y=a(()=>{let e=O.contextMenuLabels;return[{type:`option`,label:e.close??`关闭`,key:`close`,disabled:H(L.value),icon:()=>p(`span`,{class:`i-mdi:close`})},{type:`option`,label:e.closeOthers??`关闭其他`,key:`closeOthers`,icon:()=>p(`span`,{class:`i-mdi:arrow-left-right-bold`})},{type:`option`,label:e.closeLeft??`关闭左侧`,key:`closeLeft`,icon:()=>p(`span`,{class:`i-mdi:align-horizontal-left`})},{type:`option`,label:e.closeRight??`关闭右侧`,key:`closeRight`,icon:()=>p(`span`,{class:`i-mdi:align-horizontal-right`})},{type:`option`,label:e.closeAll??`关闭所有`,key:`closeAll`,icon:()=>p(`span`,{class:`i-mdi:tally-mark-5`})}]}),X=e=>{if(!(!L.value||R.value===-1)){switch(e){case`close`:K(L.value,R.value);break;case`closeOthers`:M.removeOtherTags(R.value);break;case`closeLeft`:M.removeLeftTags(R.value);break;case`closeRight`:M.removeRightTags(R.value);break;case`closeAll`:M.removeAllTags(),j.push(O.homePath),k(`closeAll`);break}J()}};return b(()=>A.path,e=>{let t=e===O.homePath?O.homeTitle:A.meta.title||`Unnamed Page`;M.addTag({path:e,originalTitle:t,title:N(t),icon:e===O.homePath?O.homeIcon:A.meta.icon,meta:{affix:A.meta.affix}}),M.setActiveTag(e),W(e)},{immediate:!0}),f({tags:M,scrollToTag:W}),(t,a)=>{let f=r,p=n;return h(),c(`div`,E,[l(`div`,{class:`tags-track`,ref_key:`tagsTrack`,ref:z,onWheel:U},[l(`div`,{class:`tags-container`,ref_key:`tagsContainer`,ref:B},[(h(!0),c(i,null,_(y(M).tagsViewList.value,(t,n)=>(h(),o(f,{key:t.path,type:V(t)?`primary`:`default`,closable:!H(t),"data-path":t.path,onClose:S(e=>K(t,n),[`stop`]),onClick:e=>G(t),onContextmenu:S(e=>q(e,t,n),[`prevent`])},{icon:x(()=>[d(y(e),{name:t.icon,size:12},null,8,[`name`])]),default:x(()=>[u(` `+v(t.title),1)]),_:2},1032,[`type`,`closable`,`data-path`,`onClose`,`onClick`,`onContextmenu`]))),128))],512)],544),P.value?(h(),o(p,{key:0,show:P.value,options:Y.value,x:F.value,y:I.value,onClickoutside:J,onSelect:X},null,8,[`show`,`options`,`x`,`y`])):s(`v-if`,!0)])}}}),[[`__scopeId`,`data-v-66047096`]]);export{T as n,D as t};
2
+ //# sourceMappingURL=C_TagsView2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"C_TagsView2.js","names":[],"sources":["../src/components/C_TagsView/useTagsView.ts","../src/components/C_TagsView/index.vue","../src/components/C_TagsView/index.vue","../src/components/C_TagsView/index.vue"],"sourcesContent":["import { ref, type Ref } from 'vue'\nimport type { TagItem } from '../_shared'\n\nexport interface UseTagsViewOptions {\n /** localStorage 持久化 key,传空字符串则不持久化 */\n persistKey?: string\n /** 首页路径,用于 removeAll 后的回退 */\n homePath?: string\n}\n\nconst STORAGE_KEY_DEFAULT = '__tags_view_list__'\n\n/**\n * 标签页管理 composable\n *\n * 独立于组件使用 — 可在任何地方管理标签状态\n *\n * @example 独立使用\n * ```ts\n * const tags = useTagsView({ persistKey: 'my-tags' })\n * tags.addTag({ path: '/home', title: '首页', meta: { affix: true } })\n * ```\n */\nexport function useTagsView(options: UseTagsViewOptions = {}) {\n const { persistKey = STORAGE_KEY_DEFAULT, homePath = '/home' } = options\n\n // ====== 持久化 ======\n const loadPersistedTags = (): TagItem[] => {\n if (!persistKey) return []\n try {\n const raw = localStorage.getItem(persistKey)\n return raw ? JSON.parse(raw) : []\n } catch {\n return []\n }\n }\n\n const persistTags = (tags: TagItem[]) => {\n if (!persistKey) return\n try {\n localStorage.setItem(persistKey, JSON.stringify(tags))\n } catch {\n /* silently fail */\n }\n }\n\n // ====== State ======\n const tagsViewList: Ref<TagItem[]> = ref(loadPersistedTags())\n const activeTag = ref('')\n\n const syncPersist = () => persistTags(tagsViewList.value)\n\n // ====== Actions ======\n\n const initTags = (tags?: TagItem[]) => {\n if (tags) {\n tagsViewList.value = tags\n } else {\n // 去重\n tagsViewList.value = [\n ...new Map(tagsViewList.value.map(tag => [tag.path, tag])).values(),\n ]\n }\n syncPersist()\n }\n\n const setActiveTag = (path: string) => {\n activeTag.value = path\n }\n\n const addTag = (tag: TagItem) => {\n const existingIndex = tagsViewList.value.findIndex(\n item => item.path === tag.path\n )\n\n if (existingIndex === -1) {\n tagsViewList.value.push(tag)\n } else {\n const existing = tagsViewList.value[existingIndex]\n if (existing.title !== tag.title || !existing.originalTitle) {\n existing.title = tag.title\n existing.originalTitle = tag.originalTitle || existing.originalTitle\n }\n }\n\n setActiveTag(tag.path)\n syncPersist()\n }\n\n const removeTag = (index: number): string | null => {\n if (index >= 0 && index < tagsViewList.value.length) {\n const removed = tagsViewList.value.splice(index, 1)[0]?.path ?? null\n syncPersist()\n return removed\n }\n return null\n }\n\n const removeOtherTags = (index: number) => {\n if (index === 0) {\n tagsViewList.value = [tagsViewList.value[0]].filter(Boolean)\n } else {\n tagsViewList.value = [\n tagsViewList.value[0],\n tagsViewList.value[index],\n ].filter(Boolean)\n }\n syncPersist()\n }\n\n const removeLeftTags = (index: number) => {\n tagsViewList.value = [\n tagsViewList.value[0],\n ...tagsViewList.value.slice(index),\n ]\n syncPersist()\n }\n\n const removeRightTags = (index: number) => {\n tagsViewList.value = tagsViewList.value.slice(0, index + 1)\n syncPersist()\n }\n\n const removeAllTags = () => {\n tagsViewList.value = tagsViewList.value.filter(tag => tag.meta?.affix)\n syncPersist()\n }\n\n return {\n tagsViewList,\n activeTag,\n homePath,\n initTags,\n setActiveTag,\n addTag,\n removeTag,\n removeOtherTags,\n removeLeftTags,\n removeRightTags,\n removeAllTags,\n }\n}\n","/* unplugin-vue-components disabled */<!--\n * @Description: 通用标签页导航组件 — 路由感知的多标签管理\n *\n * 内置功能:\n * - 路由变化自动添加标签\n * - 持久化(localStorage,可关闭)\n * - 右键菜单(关闭/关闭其他/关闭左侧/关闭右侧/关闭所有)\n * - 水平滚轮滚动\n * - i18n 支持(labelFormatter)\n *\n * @example 基础用法\n * ```vue\n * <C_TagsView\n * :label-formatter=\"$t\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * @example 自定义首页 + 菜单文案\n * ```vue\n * <C_TagsView\n * home-path=\"/dashboard\"\n * home-title=\"Dashboard\"\n * :context-menu-labels=\"{ close: 'Close', closeAll: 'Close All', ... }\"\n * />\n * ```\n *\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"tags-view-container\">\n <div\n class=\"tags-track\"\n ref=\"tagsTrack\"\n @wheel=\"handleWheel\"\n >\n <div\n class=\"tags-container\"\n ref=\"tagsContainer\"\n >\n <NTag\n v-for=\"(tag, index) in tags.tagsViewList.value\"\n :key=\"tag.path\"\n :type=\"isActive(tag) ? 'primary' : 'default'\"\n :closable=\"!isAffix(tag)\"\n :data-path=\"tag.path\"\n @close.stop=\"handleClose(tag, index)\"\n @click=\"navigateToTag(tag)\"\n @contextmenu.prevent=\"\n (e: MouseEvent) => showContextMenu(e, tag, index)\n \"\n >\n <template #icon>\n <C_Icon\n :name=\"tag.icon\"\n :size=\"12\"\n />\n </template>\n {{ tag.title }}\n </NTag>\n </div>\n </div>\n <NDropdown\n v-if=\"contextMenuVisible\"\n :show=\"contextMenuVisible\"\n :options=\"contextMenuOptions\"\n :x=\"contextMenuX\"\n :y=\"contextMenuY\"\n @clickoutside=\"closeContextMenu\"\n @select=\"handleContextMenuSelect\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, nextTick, h } from 'vue'\n import { useRoute, useRouter } from 'vue-router'\n import { C_Icon } from '../C_Icon'\n import type { TagItem } from '../_shared'\n import { useTagsView, type UseTagsViewOptions } from './useTagsView'\n\n defineOptions({ name: 'C_TagsView' })\n\n export interface ContextMenuLabels {\n close?: string\n closeOthers?: string\n closeLeft?: string\n closeRight?: string\n closeAll?: string\n }\n\n const props = withDefaults(\n defineProps<{\n /**\n * 标签文本格式化函数(用于 i18n)\n */\n labelFormatter?: (label: string) => string\n /** 首页路径 */\n homePath?: string\n /** 首页标题(原始文本) */\n homeTitle?: string\n /** 首页图标 */\n homeIcon?: string\n /** 持久化 localStorage key,传空字符串禁用 */\n persistKey?: string\n /** 右键菜单文案(国际化适配) */\n contextMenuLabels?: ContextMenuLabels\n /** useTagsView 配置项(优先级最高) */\n tagsViewOptions?: UseTagsViewOptions\n }>(),\n {\n homePath: '/home',\n homeTitle: '首页',\n homeIcon: 'mdi:home',\n persistKey: '__tags_view_list__',\n contextMenuLabels: () => ({\n close: '关闭',\n closeOthers: '关闭其他',\n closeLeft: '关闭左侧',\n closeRight: '关闭右侧',\n closeAll: '关闭所有',\n }),\n }\n )\n\n const emit = defineEmits<{\n /** 标签被关闭后跳转 */\n close: [fallbackPath: string]\n /** 关闭全部后 */\n closeAll: []\n }>()\n\n const route = useRoute()\n const router = useRouter()\n\n // ====== Tags composable ======\n const tags = useTagsView(\n props.tagsViewOptions ?? {\n persistKey: props.persistKey,\n homePath: props.homePath,\n }\n )\n\n // ====== 首次渲染前重新翻译持久化标签 ======\n if (tags.tagsViewList.value.length > 0 && props.labelFormatter) {\n const allRoutes = router.getRoutes()\n const translatedTags = tags.tagsViewList.value.map(tag => {\n const matchedRoute = allRoutes.find(r => r.path === tag.path)\n const originalTitle =\n tag.originalTitle || (matchedRoute?.meta?.title as string) || tag.title\n return {\n ...tag,\n originalTitle,\n title: props.labelFormatter!(originalTitle),\n }\n })\n tags.initTags(translatedTags)\n }\n\n const formatLabel = (title: string): string =>\n props.labelFormatter ? props.labelFormatter(title) : title\n\n // ====== UI State ======\n\n const contextMenuVisible = ref(false)\n const contextMenuX = ref(0)\n const contextMenuY = ref(0)\n const selectedTag = ref<TagItem | null>(null)\n const selectedIndex = ref(-1)\n const tagsTrack = ref<HTMLElement>()\n const tagsContainer = ref<HTMLElement>()\n\n // ====== Helpers ======\n const isActive = (tag: TagItem): boolean => tag.path === route.path\n const isAffix = (tag: TagItem) => tag.meta?.affix\n\n const handleWheel = (e: WheelEvent) => {\n const container = tagsContainer.value\n if (!container) return\n e.preventDefault()\n container.scrollTo({\n left: container.scrollLeft + e.deltaY,\n behavior: 'smooth',\n })\n }\n\n const scrollToTag = (path: string) => {\n nextTick(() => {\n const targetTag = tagsContainer.value?.querySelector(\n `[data-path=\"${path}\"]`\n ) as HTMLElement\n if (targetTag) {\n targetTag.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'center',\n })\n }\n })\n }\n\n // ====== Actions ======\n\n const navigateToTag = (tag: TagItem) => {\n if (tag.path !== route.path) {\n router.push(tag.path)\n }\n scrollToTag(tag.path)\n }\n\n const handleClose = (tag: TagItem, index: number) => {\n if (isAffix(tag)) return\n\n const wasActive = isActive(tag)\n const tagsBeforeRemove = tags.tagsViewList.value.length\n tags.removeTag(index)\n\n if (wasActive) {\n const remaining = tags.tagsViewList.value\n const wasLastTag = index === tagsBeforeRemove - 1\n let fallbackPath: string\n\n if (wasLastTag) {\n fallbackPath = remaining[index - 1]?.path || props.homePath\n } else {\n fallbackPath = remaining[remaining.length - 1]?.path || props.homePath\n }\n\n router.push(fallbackPath)\n emit('close', fallbackPath)\n }\n }\n\n const showContextMenu = (event: MouseEvent, tag: TagItem, index: number) => {\n event.preventDefault()\n selectedTag.value = tag\n selectedIndex.value = index\n contextMenuVisible.value = true\n contextMenuX.value = event.clientX\n contextMenuY.value = event.clientY\n }\n\n const closeContextMenu = () => (contextMenuVisible.value = false)\n\n const contextMenuOptions = computed(() => {\n const labels = props.contextMenuLabels\n return [\n {\n type: 'option' as const,\n label: labels.close ?? '关闭',\n key: 'close',\n disabled: isAffix(selectedTag.value as TagItem),\n icon: () => h('span', { class: 'i-mdi:close' }),\n },\n {\n type: 'option' as const,\n label: labels.closeOthers ?? '关闭其他',\n key: 'closeOthers',\n icon: () => h('span', { class: 'i-mdi:arrow-left-right-bold' }),\n },\n {\n type: 'option' as const,\n label: labels.closeLeft ?? '关闭左侧',\n key: 'closeLeft',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-left' }),\n },\n {\n type: 'option' as const,\n label: labels.closeRight ?? '关闭右侧',\n key: 'closeRight',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-right' }),\n },\n {\n type: 'option' as const,\n label: labels.closeAll ?? '关闭所有',\n key: 'closeAll',\n icon: () => h('span', { class: 'i-mdi:tally-mark-5' }),\n },\n ]\n })\n\n const handleContextMenuSelect = (key: string) => {\n if (!selectedTag.value || selectedIndex.value === -1) return\n\n switch (key) {\n case 'close':\n handleClose(selectedTag.value, selectedIndex.value)\n break\n case 'closeOthers':\n tags.removeOtherTags(selectedIndex.value)\n break\n case 'closeLeft':\n tags.removeLeftTags(selectedIndex.value)\n break\n case 'closeRight':\n tags.removeRightTags(selectedIndex.value)\n break\n case 'closeAll':\n tags.removeAllTags()\n router.push(props.homePath)\n emit('closeAll')\n break\n }\n closeContextMenu()\n }\n\n // ====== 路由自动跟踪 ======\n watch(\n () => route.path,\n (newPath: string) => {\n const originalTitle =\n newPath === props.homePath\n ? props.homeTitle\n : (route.meta.title as string) || 'Unnamed Page'\n\n tags.addTag({\n path: newPath,\n originalTitle,\n title: formatLabel(originalTitle),\n icon:\n newPath === props.homePath\n ? props.homeIcon\n : (route.meta.icon as string),\n meta: { affix: route.meta.affix as boolean },\n })\n\n tags.setActiveTag(newPath)\n scrollToTag(newPath)\n },\n { immediate: true }\n )\n\n // ====== 暴露 ======\n defineExpose({\n /** useTagsView composable 实例 */\n tags,\n /** 滚动到指定标签 */\n scrollToTag,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","/* unplugin-vue-components disabled */<!--\n * @Description: 通用标签页导航组件 — 路由感知的多标签管理\n *\n * 内置功能:\n * - 路由变化自动添加标签\n * - 持久化(localStorage,可关闭)\n * - 右键菜单(关闭/关闭其他/关闭左侧/关闭右侧/关闭所有)\n * - 水平滚轮滚动\n * - i18n 支持(labelFormatter)\n *\n * @example 基础用法\n * ```vue\n * <C_TagsView\n * :label-formatter=\"$t\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * @example 自定义首页 + 菜单文案\n * ```vue\n * <C_TagsView\n * home-path=\"/dashboard\"\n * home-title=\"Dashboard\"\n * :context-menu-labels=\"{ close: 'Close', closeAll: 'Close All', ... }\"\n * />\n * ```\n *\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"tags-view-container\">\n <div\n class=\"tags-track\"\n ref=\"tagsTrack\"\n @wheel=\"handleWheel\"\n >\n <div\n class=\"tags-container\"\n ref=\"tagsContainer\"\n >\n <NTag\n v-for=\"(tag, index) in tags.tagsViewList.value\"\n :key=\"tag.path\"\n :type=\"isActive(tag) ? 'primary' : 'default'\"\n :closable=\"!isAffix(tag)\"\n :data-path=\"tag.path\"\n @close.stop=\"handleClose(tag, index)\"\n @click=\"navigateToTag(tag)\"\n @contextmenu.prevent=\"\n (e: MouseEvent) => showContextMenu(e, tag, index)\n \"\n >\n <template #icon>\n <C_Icon\n :name=\"tag.icon\"\n :size=\"12\"\n />\n </template>\n {{ tag.title }}\n </NTag>\n </div>\n </div>\n <NDropdown\n v-if=\"contextMenuVisible\"\n :show=\"contextMenuVisible\"\n :options=\"contextMenuOptions\"\n :x=\"contextMenuX\"\n :y=\"contextMenuY\"\n @clickoutside=\"closeContextMenu\"\n @select=\"handleContextMenuSelect\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, nextTick, h } from 'vue'\n import { useRoute, useRouter } from 'vue-router'\n import { C_Icon } from '../C_Icon'\n import type { TagItem } from '../_shared'\n import { useTagsView, type UseTagsViewOptions } from './useTagsView'\n\n defineOptions({ name: 'C_TagsView' })\n\n export interface ContextMenuLabels {\n close?: string\n closeOthers?: string\n closeLeft?: string\n closeRight?: string\n closeAll?: string\n }\n\n const props = withDefaults(\n defineProps<{\n /**\n * 标签文本格式化函数(用于 i18n)\n */\n labelFormatter?: (label: string) => string\n /** 首页路径 */\n homePath?: string\n /** 首页标题(原始文本) */\n homeTitle?: string\n /** 首页图标 */\n homeIcon?: string\n /** 持久化 localStorage key,传空字符串禁用 */\n persistKey?: string\n /** 右键菜单文案(国际化适配) */\n contextMenuLabels?: ContextMenuLabels\n /** useTagsView 配置项(优先级最高) */\n tagsViewOptions?: UseTagsViewOptions\n }>(),\n {\n homePath: '/home',\n homeTitle: '首页',\n homeIcon: 'mdi:home',\n persistKey: '__tags_view_list__',\n contextMenuLabels: () => ({\n close: '关闭',\n closeOthers: '关闭其他',\n closeLeft: '关闭左侧',\n closeRight: '关闭右侧',\n closeAll: '关闭所有',\n }),\n }\n )\n\n const emit = defineEmits<{\n /** 标签被关闭后跳转 */\n close: [fallbackPath: string]\n /** 关闭全部后 */\n closeAll: []\n }>()\n\n const route = useRoute()\n const router = useRouter()\n\n // ====== Tags composable ======\n const tags = useTagsView(\n props.tagsViewOptions ?? {\n persistKey: props.persistKey,\n homePath: props.homePath,\n }\n )\n\n // ====== 首次渲染前重新翻译持久化标签 ======\n if (tags.tagsViewList.value.length > 0 && props.labelFormatter) {\n const allRoutes = router.getRoutes()\n const translatedTags = tags.tagsViewList.value.map(tag => {\n const matchedRoute = allRoutes.find(r => r.path === tag.path)\n const originalTitle =\n tag.originalTitle || (matchedRoute?.meta?.title as string) || tag.title\n return {\n ...tag,\n originalTitle,\n title: props.labelFormatter!(originalTitle),\n }\n })\n tags.initTags(translatedTags)\n }\n\n const formatLabel = (title: string): string =>\n props.labelFormatter ? props.labelFormatter(title) : title\n\n // ====== UI State ======\n\n const contextMenuVisible = ref(false)\n const contextMenuX = ref(0)\n const contextMenuY = ref(0)\n const selectedTag = ref<TagItem | null>(null)\n const selectedIndex = ref(-1)\n const tagsTrack = ref<HTMLElement>()\n const tagsContainer = ref<HTMLElement>()\n\n // ====== Helpers ======\n const isActive = (tag: TagItem): boolean => tag.path === route.path\n const isAffix = (tag: TagItem) => tag.meta?.affix\n\n const handleWheel = (e: WheelEvent) => {\n const container = tagsContainer.value\n if (!container) return\n e.preventDefault()\n container.scrollTo({\n left: container.scrollLeft + e.deltaY,\n behavior: 'smooth',\n })\n }\n\n const scrollToTag = (path: string) => {\n nextTick(() => {\n const targetTag = tagsContainer.value?.querySelector(\n `[data-path=\"${path}\"]`\n ) as HTMLElement\n if (targetTag) {\n targetTag.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'center',\n })\n }\n })\n }\n\n // ====== Actions ======\n\n const navigateToTag = (tag: TagItem) => {\n if (tag.path !== route.path) {\n router.push(tag.path)\n }\n scrollToTag(tag.path)\n }\n\n const handleClose = (tag: TagItem, index: number) => {\n if (isAffix(tag)) return\n\n const wasActive = isActive(tag)\n const tagsBeforeRemove = tags.tagsViewList.value.length\n tags.removeTag(index)\n\n if (wasActive) {\n const remaining = tags.tagsViewList.value\n const wasLastTag = index === tagsBeforeRemove - 1\n let fallbackPath: string\n\n if (wasLastTag) {\n fallbackPath = remaining[index - 1]?.path || props.homePath\n } else {\n fallbackPath = remaining[remaining.length - 1]?.path || props.homePath\n }\n\n router.push(fallbackPath)\n emit('close', fallbackPath)\n }\n }\n\n const showContextMenu = (event: MouseEvent, tag: TagItem, index: number) => {\n event.preventDefault()\n selectedTag.value = tag\n selectedIndex.value = index\n contextMenuVisible.value = true\n contextMenuX.value = event.clientX\n contextMenuY.value = event.clientY\n }\n\n const closeContextMenu = () => (contextMenuVisible.value = false)\n\n const contextMenuOptions = computed(() => {\n const labels = props.contextMenuLabels\n return [\n {\n type: 'option' as const,\n label: labels.close ?? '关闭',\n key: 'close',\n disabled: isAffix(selectedTag.value as TagItem),\n icon: () => h('span', { class: 'i-mdi:close' }),\n },\n {\n type: 'option' as const,\n label: labels.closeOthers ?? '关闭其他',\n key: 'closeOthers',\n icon: () => h('span', { class: 'i-mdi:arrow-left-right-bold' }),\n },\n {\n type: 'option' as const,\n label: labels.closeLeft ?? '关闭左侧',\n key: 'closeLeft',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-left' }),\n },\n {\n type: 'option' as const,\n label: labels.closeRight ?? '关闭右侧',\n key: 'closeRight',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-right' }),\n },\n {\n type: 'option' as const,\n label: labels.closeAll ?? '关闭所有',\n key: 'closeAll',\n icon: () => h('span', { class: 'i-mdi:tally-mark-5' }),\n },\n ]\n })\n\n const handleContextMenuSelect = (key: string) => {\n if (!selectedTag.value || selectedIndex.value === -1) return\n\n switch (key) {\n case 'close':\n handleClose(selectedTag.value, selectedIndex.value)\n break\n case 'closeOthers':\n tags.removeOtherTags(selectedIndex.value)\n break\n case 'closeLeft':\n tags.removeLeftTags(selectedIndex.value)\n break\n case 'closeRight':\n tags.removeRightTags(selectedIndex.value)\n break\n case 'closeAll':\n tags.removeAllTags()\n router.push(props.homePath)\n emit('closeAll')\n break\n }\n closeContextMenu()\n }\n\n // ====== 路由自动跟踪 ======\n watch(\n () => route.path,\n (newPath: string) => {\n const originalTitle =\n newPath === props.homePath\n ? props.homeTitle\n : (route.meta.title as string) || 'Unnamed Page'\n\n tags.addTag({\n path: newPath,\n originalTitle,\n title: formatLabel(originalTitle),\n icon:\n newPath === props.homePath\n ? props.homeIcon\n : (route.meta.icon as string),\n meta: { affix: route.meta.affix as boolean },\n })\n\n tags.setActiveTag(newPath)\n scrollToTag(newPath)\n },\n { immediate: true }\n )\n\n // ====== 暴露 ======\n defineExpose({\n /** useTagsView composable 实例 */\n tags,\n /** 滚动到指定标签 */\n scrollToTag,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","<!--\n * @Description: 通用标签页导航组件 — 路由感知的多标签管理\n *\n * 内置功能:\n * - 路由变化自动添加标签\n * - 持久化(localStorage,可关闭)\n * - 右键菜单(关闭/关闭其他/关闭左侧/关闭右侧/关闭所有)\n * - 水平滚轮滚动\n * - i18n 支持(labelFormatter)\n *\n * @example 基础用法\n * ```vue\n * <C_TagsView\n * :label-formatter=\"$t\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * @example 自定义首页 + 菜单文案\n * ```vue\n * <C_TagsView\n * home-path=\"/dashboard\"\n * home-title=\"Dashboard\"\n * :context-menu-labels=\"{ close: 'Close', closeAll: 'Close All', ... }\"\n * />\n * ```\n *\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"tags-view-container\">\n <div\n class=\"tags-track\"\n ref=\"tagsTrack\"\n @wheel=\"handleWheel\"\n >\n <div\n class=\"tags-container\"\n ref=\"tagsContainer\"\n >\n <NTag\n v-for=\"(tag, index) in tags.tagsViewList.value\"\n :key=\"tag.path\"\n :type=\"isActive(tag) ? 'primary' : 'default'\"\n :closable=\"!isAffix(tag)\"\n :data-path=\"tag.path\"\n @close.stop=\"handleClose(tag, index)\"\n @click=\"navigateToTag(tag)\"\n @contextmenu.prevent=\"\n (e: MouseEvent) => showContextMenu(e, tag, index)\n \"\n >\n <template #icon>\n <C_Icon\n :name=\"tag.icon\"\n :size=\"12\"\n />\n </template>\n {{ tag.title }}\n </NTag>\n </div>\n </div>\n <NDropdown\n v-if=\"contextMenuVisible\"\n :show=\"contextMenuVisible\"\n :options=\"contextMenuOptions\"\n :x=\"contextMenuX\"\n :y=\"contextMenuY\"\n @clickoutside=\"closeContextMenu\"\n @select=\"handleContextMenuSelect\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, nextTick, h } from 'vue'\n import { useRoute, useRouter } from 'vue-router'\n import { C_Icon } from '../C_Icon'\n import type { TagItem } from '../_shared'\n import { useTagsView, type UseTagsViewOptions } from './useTagsView'\n\n defineOptions({ name: 'C_TagsView' })\n\n export interface ContextMenuLabels {\n close?: string\n closeOthers?: string\n closeLeft?: string\n closeRight?: string\n closeAll?: string\n }\n\n const props = withDefaults(\n defineProps<{\n /**\n * 标签文本格式化函数(用于 i18n)\n */\n labelFormatter?: (label: string) => string\n /** 首页路径 */\n homePath?: string\n /** 首页标题(原始文本) */\n homeTitle?: string\n /** 首页图标 */\n homeIcon?: string\n /** 持久化 localStorage key,传空字符串禁用 */\n persistKey?: string\n /** 右键菜单文案(国际化适配) */\n contextMenuLabels?: ContextMenuLabels\n /** useTagsView 配置项(优先级最高) */\n tagsViewOptions?: UseTagsViewOptions\n }>(),\n {\n homePath: '/home',\n homeTitle: '首页',\n homeIcon: 'mdi:home',\n persistKey: '__tags_view_list__',\n contextMenuLabels: () => ({\n close: '关闭',\n closeOthers: '关闭其他',\n closeLeft: '关闭左侧',\n closeRight: '关闭右侧',\n closeAll: '关闭所有',\n }),\n }\n )\n\n const emit = defineEmits<{\n /** 标签被关闭后跳转 */\n close: [fallbackPath: string]\n /** 关闭全部后 */\n closeAll: []\n }>()\n\n const route = useRoute()\n const router = useRouter()\n\n // ====== Tags composable ======\n const tags = useTagsView(\n props.tagsViewOptions ?? {\n persistKey: props.persistKey,\n homePath: props.homePath,\n }\n )\n\n // ====== 首次渲染前重新翻译持久化标签 ======\n if (tags.tagsViewList.value.length > 0 && props.labelFormatter) {\n const allRoutes = router.getRoutes()\n const translatedTags = tags.tagsViewList.value.map(tag => {\n const matchedRoute = allRoutes.find(r => r.path === tag.path)\n const originalTitle =\n tag.originalTitle || (matchedRoute?.meta?.title as string) || tag.title\n return {\n ...tag,\n originalTitle,\n title: props.labelFormatter!(originalTitle),\n }\n })\n tags.initTags(translatedTags)\n }\n\n const formatLabel = (title: string): string =>\n props.labelFormatter ? props.labelFormatter(title) : title\n\n // ====== UI State ======\n\n const contextMenuVisible = ref(false)\n const contextMenuX = ref(0)\n const contextMenuY = ref(0)\n const selectedTag = ref<TagItem | null>(null)\n const selectedIndex = ref(-1)\n const tagsTrack = ref<HTMLElement>()\n const tagsContainer = ref<HTMLElement>()\n\n // ====== Helpers ======\n const isActive = (tag: TagItem): boolean => tag.path === route.path\n const isAffix = (tag: TagItem) => tag.meta?.affix\n\n const handleWheel = (e: WheelEvent) => {\n const container = tagsContainer.value\n if (!container) return\n e.preventDefault()\n container.scrollTo({\n left: container.scrollLeft + e.deltaY,\n behavior: 'smooth',\n })\n }\n\n const scrollToTag = (path: string) => {\n nextTick(() => {\n const targetTag = tagsContainer.value?.querySelector(\n `[data-path=\"${path}\"]`\n ) as HTMLElement\n if (targetTag) {\n targetTag.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'center',\n })\n }\n })\n }\n\n // ====== Actions ======\n\n const navigateToTag = (tag: TagItem) => {\n if (tag.path !== route.path) {\n router.push(tag.path)\n }\n scrollToTag(tag.path)\n }\n\n const handleClose = (tag: TagItem, index: number) => {\n if (isAffix(tag)) return\n\n const wasActive = isActive(tag)\n const tagsBeforeRemove = tags.tagsViewList.value.length\n tags.removeTag(index)\n\n if (wasActive) {\n const remaining = tags.tagsViewList.value\n const wasLastTag = index === tagsBeforeRemove - 1\n let fallbackPath: string\n\n if (wasLastTag) {\n fallbackPath = remaining[index - 1]?.path || props.homePath\n } else {\n fallbackPath = remaining[remaining.length - 1]?.path || props.homePath\n }\n\n router.push(fallbackPath)\n emit('close', fallbackPath)\n }\n }\n\n const showContextMenu = (event: MouseEvent, tag: TagItem, index: number) => {\n event.preventDefault()\n selectedTag.value = tag\n selectedIndex.value = index\n contextMenuVisible.value = true\n contextMenuX.value = event.clientX\n contextMenuY.value = event.clientY\n }\n\n const closeContextMenu = () => (contextMenuVisible.value = false)\n\n const contextMenuOptions = computed(() => {\n const labels = props.contextMenuLabels\n return [\n {\n type: 'option' as const,\n label: labels.close ?? '关闭',\n key: 'close',\n disabled: isAffix(selectedTag.value as TagItem),\n icon: () => h('span', { class: 'i-mdi:close' }),\n },\n {\n type: 'option' as const,\n label: labels.closeOthers ?? '关闭其他',\n key: 'closeOthers',\n icon: () => h('span', { class: 'i-mdi:arrow-left-right-bold' }),\n },\n {\n type: 'option' as const,\n label: labels.closeLeft ?? '关闭左侧',\n key: 'closeLeft',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-left' }),\n },\n {\n type: 'option' as const,\n label: labels.closeRight ?? '关闭右侧',\n key: 'closeRight',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-right' }),\n },\n {\n type: 'option' as const,\n label: labels.closeAll ?? '关闭所有',\n key: 'closeAll',\n icon: () => h('span', { class: 'i-mdi:tally-mark-5' }),\n },\n ]\n })\n\n const handleContextMenuSelect = (key: string) => {\n if (!selectedTag.value || selectedIndex.value === -1) return\n\n switch (key) {\n case 'close':\n handleClose(selectedTag.value, selectedIndex.value)\n break\n case 'closeOthers':\n tags.removeOtherTags(selectedIndex.value)\n break\n case 'closeLeft':\n tags.removeLeftTags(selectedIndex.value)\n break\n case 'closeRight':\n tags.removeRightTags(selectedIndex.value)\n break\n case 'closeAll':\n tags.removeAllTags()\n router.push(props.homePath)\n emit('closeAll')\n break\n }\n closeContextMenu()\n }\n\n // ====== 路由自动跟踪 ======\n watch(\n () => route.path,\n (newPath: string) => {\n const originalTitle =\n newPath === props.homePath\n ? props.homeTitle\n : (route.meta.title as string) || 'Unnamed Page'\n\n tags.addTag({\n path: newPath,\n originalTitle,\n title: formatLabel(originalTitle),\n icon:\n newPath === props.homePath\n ? props.homeIcon\n : (route.meta.icon as string),\n meta: { affix: route.meta.affix as boolean },\n })\n\n tags.setActiveTag(newPath)\n scrollToTag(newPath)\n },\n { immediate: true }\n )\n\n // ====== 暴露 ======\n defineExpose({\n /** useTagsView composable 实例 */\n tags,\n /** 滚动到指定标签 */\n scrollToTag,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n"],"mappings":"gfAuBA,SAAgB,EAAY,EAA8B,EAAE,CAAE,CAC5D,GAAM,CAAE,aAAa,qBAAqB,WAAW,SAAY,EAG3D,MAAqC,CACzC,GAAI,CAAC,EAAY,MAAO,EAAE,CAC1B,GAAI,CACF,IAAM,EAAM,aAAa,QAAQ,EAAW,CAC5C,OAAO,EAAM,KAAK,MAAM,EAAI,CAAG,EAAE,MAC3B,CACN,MAAO,EAAE,GAIP,EAAe,GAAoB,CAClC,KACL,GAAI,CACF,aAAa,QAAQ,EAAY,KAAK,UAAU,EAAK,CAAC,MAChD,IAMJ,EAA+B,EAAI,GAAmB,CAAC,CACvD,EAAY,EAAI,GAAG,CAEnB,MAAoB,EAAY,EAAa,MAAM,CAInD,EAAY,GAAqB,CACjC,EACF,EAAa,MAAQ,EAGrB,EAAa,MAAQ,CACnB,GAAG,IAAI,IAAI,EAAa,MAAM,IAAI,GAAO,CAAC,EAAI,KAAM,EAAI,CAAC,CAAC,CAAC,QAAQ,CACpE,CAEH,GAAa,EAGT,EAAgB,GAAiB,CACrC,EAAU,MAAQ,GA6DpB,MAAO,CACL,eACA,YACA,WACA,WACA,eACA,OAhEc,GAAiB,CAC/B,IAAM,EAAgB,EAAa,MAAM,UACvC,GAAQ,EAAK,OAAS,EAAI,KAC3B,CAED,GAAI,IAAkB,GACpB,EAAa,MAAM,KAAK,EAAI,KACvB,CACL,IAAM,EAAW,EAAa,MAAM,IAChC,EAAS,QAAU,EAAI,OAAS,CAAC,EAAS,iBAC5C,EAAS,MAAQ,EAAI,MACrB,EAAS,cAAgB,EAAI,eAAiB,EAAS,eAI3D,EAAa,EAAI,KAAK,CACtB,GAAa,EAiDb,UA9CiB,GAAiC,CAClD,GAAI,GAAS,GAAK,EAAQ,EAAa,MAAM,OAAQ,CACnD,IAAM,EAAU,EAAa,MAAM,OAAO,EAAO,EAAE,CAAC,IAAI,MAAQ,KAEhE,OADA,GAAa,CACN,EAET,OAAO,MAyCP,gBAtCuB,GAAkB,CACrC,IAAU,EACZ,EAAa,MAAQ,CAAC,EAAa,MAAM,GAAG,CAAC,OAAO,QAAQ,CAE5D,EAAa,MAAQ,CACnB,EAAa,MAAM,GACnB,EAAa,MAAM,GACpB,CAAC,OAAO,QAAQ,CAEnB,GAAa,EA8Bb,eA3BsB,GAAkB,CACxC,EAAa,MAAQ,CACnB,EAAa,MAAM,GACnB,GAAG,EAAa,MAAM,MAAM,EAAM,CACnC,CACD,GAAa,EAuBb,gBApBuB,GAAkB,CACzC,EAAa,MAAQ,EAAa,MAAM,MAAM,EAAG,EAAQ,EAAE,CAC3D,GAAa,EAmBb,kBAhB0B,CAC1B,EAAa,MAAQ,EAAa,MAAM,OAAO,GAAO,EAAI,MAAM,MAAM,CACtE,GAAa,EAed,uaGjDD,IAAM,EAAQ,EAkCR,EAAO,EAOP,EAAQ,GAAS,CACjB,EAAS,GAAU,CAGnB,EAAO,EACX,EAAM,iBAAmB,CACvB,WAAY,EAAM,WAClB,SAAU,EAAM,SAClB,CACF,CAGA,GAAI,EAAK,aAAa,MAAM,OAAS,GAAK,EAAM,eAAgB,CAC9D,IAAM,EAAY,EAAO,WAAU,CAC7B,EAAiB,EAAK,aAAa,MAAM,IAAI,GAAO,CACxD,IAAM,EAAe,EAAU,KAAK,GAAK,EAAE,OAAS,EAAI,KAAI,CACtD,EACJ,EAAI,eAAkB,GAAc,MAAM,OAAoB,EAAI,MACpE,MAAO,CACL,GAAG,EACH,gBACA,MAAO,EAAM,eAAgB,EAAc,CAC7C,EACD,CACD,EAAK,SAAS,EAAc,CAG9B,IAAM,EAAe,GACnB,EAAM,eAAiB,EAAM,eAAe,EAAM,CAAG,EAIjD,EAAqB,EAAI,GAAK,CAC9B,EAAe,EAAI,EAAC,CACpB,EAAe,EAAI,EAAC,CACpB,EAAc,EAAoB,KAAI,CACtC,EAAgB,EAAI,GAAE,CACtB,EAAY,GAAiB,CAC7B,EAAgB,GAAiB,CAGjC,EAAY,GAA0B,EAAI,OAAS,EAAM,KACzD,EAAW,GAAiB,EAAI,MAAM,MAEtC,EAAe,GAAkB,CACrC,IAAM,EAAY,EAAc,MAC3B,IACL,EAAE,gBAAe,CACjB,EAAU,SAAS,CACjB,KAAM,EAAU,WAAa,EAAE,OAC/B,SAAU,SACX,CAAA,GAGG,EAAe,GAAiB,CACpC,MAAe,CACb,IAAM,EAAY,EAAc,OAAO,cACrC,eAAe,EAAK,IACrB,CACG,GACF,EAAU,eAAe,CACvB,SAAU,SACV,MAAO,UACP,OAAQ,SACT,CAAA,EAEJ,EAKG,EAAiB,GAAiB,CAClC,EAAI,OAAS,EAAM,MACrB,EAAO,KAAK,EAAI,KAAI,CAEtB,EAAY,EAAI,KAAI,EAGhB,GAAe,EAAc,IAAkB,CACnD,GAAI,EAAQ,EAAI,CAAE,OAElB,IAAM,EAAY,EAAS,EAAG,CACxB,EAAmB,EAAK,aAAa,MAAM,OAGjD,GAFA,EAAK,UAAU,EAAK,CAEhB,EAAW,CACb,IAAM,EAAY,EAAK,aAAa,MAC9B,EAAa,IAAU,EAAmB,EAC5C,EAEJ,AAGE,EAHE,EACa,EAAU,EAAQ,IAAI,MAAQ,EAAM,SAEpC,EAAU,EAAU,OAAS,IAAI,MAAQ,EAAM,SAGhE,EAAO,KAAK,EAAY,CACxB,EAAK,QAAS,EAAY,GAIxB,GAAmB,EAAmB,EAAc,IAAkB,CAC1E,EAAM,gBAAe,CACrB,EAAY,MAAQ,EACpB,EAAc,MAAQ,EACtB,EAAmB,MAAQ,GAC3B,EAAa,MAAQ,EAAM,QAC3B,EAAa,MAAQ,EAAM,SAGvB,MAA0B,EAAmB,MAAQ,GAErD,EAAqB,MAAe,CACxC,IAAM,EAAS,EAAM,kBACrB,MAAO,CACL,CACE,KAAM,SACN,MAAO,EAAO,OAAS,KACvB,IAAK,QACL,SAAU,EAAQ,EAAY,MAAiB,CAC/C,SAAY,EAAE,OAAQ,CAAE,MAAO,cAAe,CAAC,CAChD,CACD,CACE,KAAM,SACN,MAAO,EAAO,aAAe,OAC7B,IAAK,cACL,SAAY,EAAE,OAAQ,CAAE,MAAO,8BAA+B,CAAC,CAChE,CACD,CACE,KAAM,SACN,MAAO,EAAO,WAAa,OAC3B,IAAK,YACL,SAAY,EAAE,OAAQ,CAAE,MAAO,8BAA+B,CAAC,CAChE,CACD,CACE,KAAM,SACN,MAAO,EAAO,YAAc,OAC5B,IAAK,aACL,SAAY,EAAE,OAAQ,CAAE,MAAO,+BAAgC,CAAC,CACjE,CACD,CACE,KAAM,SACN,MAAO,EAAO,UAAY,OAC1B,IAAK,WACL,SAAY,EAAE,OAAQ,CAAE,MAAO,qBAAsB,CAAC,CACvD,CACH,EACD,CAEK,EAA2B,GAAgB,CAC3C,MAAC,EAAY,OAAS,EAAc,QAAU,IAElD,QAAQ,EAAR,CACE,IAAK,QACH,EAAY,EAAY,MAAO,EAAc,MAAK,CAClD,MACF,IAAK,cACH,EAAK,gBAAgB,EAAc,MAAK,CACxC,MACF,IAAK,YACH,EAAK,eAAe,EAAc,MAAK,CACvC,MACF,IAAK,aACH,EAAK,gBAAgB,EAAc,MAAK,CACxC,MACF,IAAK,WACH,EAAK,eAAc,CACnB,EAAO,KAAK,EAAM,SAAQ,CAC1B,EAAK,WAAU,CACf,MAEJ,GAAiB,UAInB,MACQ,EAAM,KACX,GAAoB,CACnB,IAAM,EACJ,IAAY,EAAM,SACd,EAAM,UACL,EAAM,KAAK,OAAoB,eAEtC,EAAK,OAAO,CACV,KAAM,EACN,gBACA,MAAO,EAAY,EAAc,CACjC,KACE,IAAY,EAAM,SACd,EAAM,SACL,EAAM,KAAK,KAClB,KAAM,CAAE,MAAO,EAAM,KAAK,MAAkB,CAC7C,CAAA,CAED,EAAK,aAAa,EAAO,CACzB,EAAY,EAAO,EAErB,CAAE,UAAW,GAAK,CACpB,CAGA,EAAa,CAEX,OAEA,cACD,CAAA,gCApTD,EAyCM,MAzCN,EAyCM,CAxCJ,EA8BM,MAAA,CA7BJ,MAAM,qBACF,YAAJ,IAAI,EACH,QAAO,IAER,EAwBM,MAAA,CAvBJ,MAAM,yBACF,gBAAJ,IAAI,WAEJ,EAmBO,EAAA,KAAA,EAlBkB,EAAA,EAAI,CAAC,aAAa,OAAjC,EAAK,SADf,EAmBO,EAAA,CAjBJ,IAAK,EAAI,KACT,KAAM,EAAS,EAAG,CAAA,UAAA,UAClB,SAAQ,CAAG,EAAQ,EAAG,CACtB,YAAW,EAAI,KACf,QAAK,EAAA,GAAO,EAAY,EAAK,EAAK,CAAA,CAAA,OAAA,CAAA,CAClC,QAAK,GAAE,EAAc,EAAG,CACxB,cAAW,EAAwB,GAAkB,EAAgB,EAAG,EAAK,EAAK,CAAA,CAAA,UAAA,CAAA,GAIxE,KAAI,MAIX,CAHF,EAGE,EAAA,EAAA,CAAA,CAFC,KAAM,EAAI,KACV,KAAM,qCAGX,CAAA,EADW,IACX,EAAG,EAAI,MAAK,CAAA,EAAA,CAAA,CAAA,oGAKV,EAAA,OAAA,GAAA,CADR,EAQE,EAAA,OANC,KAAM,EAAA,MACN,QAAS,EAAA,MACT,EAAG,EAAA,MACH,EAAG,EAAA,MACH,eAAc,EACd,SAAQ"}
@@ -1,2 +1,2 @@
1
- import { n as _default, t as ThemeMode } from "./index15.vue.js";
1
+ import { n as _default, t as ThemeMode } from "./index18.vue.js";
2
2
  export { _default as C_Theme, type ThemeMode };
package/dist/C_Theme.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { n as _default, t as ThemeMode } from "./index15.vue.js";
1
+ import { n as _default, t as ThemeMode } from "./index18.vue.js";
2
2
  export { _default as C_Theme, type ThemeMode };
@@ -1,2 +1,2 @@
1
- import { a as presetConfigs, i as GanttTask, n as GanttOptions, r as GanttPreset, t as _default } from "./index16.vue.js";
1
+ import { a as presetConfigs, i as GanttTask, n as GanttOptions, r as GanttPreset, t as _default } from "./index19.vue.js";
2
2
  export { _default as C_VtableGantt, type GanttOptions, type GanttPreset, type GanttTask, presetConfigs as ganttPresetConfigs };
@@ -1,2 +1,2 @@
1
- import { a as presetConfigs, i as GanttTask, n as GanttOptions, r as GanttPreset, t as _default } from "./index16.vue.js";
1
+ import { a as presetConfigs, i as GanttTask, n as GanttOptions, r as GanttPreset, t as _default } from "./index19.vue.js";
2
2
  export { _default as C_VtableGantt, type GanttOptions, type GanttPreset, type GanttTask, presetConfigs as ganttPresetConfigs };
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./menuAdapter.js`);exports.createMenuOptions=e.t,exports.flattenRoutes=e.n;
@@ -0,0 +1,2 @@
1
+ import { a as RouteItem, i as BreadcrumbItem, n as createMenuOptions, o as RouteMeta, r as flattenRoutes, s as TagItem, t as MenuAdapterConfig } from "./menuAdapter.js";
2
+ export { type BreadcrumbItem, type MenuAdapterConfig, type RouteItem, type RouteMeta, type TagItem, createMenuOptions, flattenRoutes };
@@ -0,0 +1,2 @@
1
+ import { a as RouteItem, i as BreadcrumbItem, n as createMenuOptions, o as RouteMeta, r as flattenRoutes, s as TagItem, t as MenuAdapterConfig } from "./menuAdapter.js";
2
+ export { type BreadcrumbItem, type MenuAdapterConfig, type RouteItem, type RouteMeta, type TagItem, createMenuOptions, flattenRoutes };
@@ -0,0 +1 @@
1
+ import{n as e,t}from"./menuAdapter.js";export{t as createMenuOptions,e as flattenRoutes};
@@ -121,9 +121,9 @@ declare const __VLS_export: vue.DefineComponent<CronProps, {
121
121
  height: string | number;
122
122
  modelValue: string;
123
123
  disabled: boolean;
124
- showPreview: boolean;
125
124
  previewCount: number;
126
125
  showTemplates: boolean;
126
+ showPreview: boolean;
127
127
  showSecond: boolean;
128
128
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
129
129
  declare const _default: typeof __VLS_export;
@@ -122,12 +122,12 @@ declare const __VLS_export: vue.DefineComponent<FormulaEditorProps, FormulaEdito
122
122
  }>, {
123
123
  height: string | number;
124
124
  modelValue: string;
125
- placeholder: string;
126
125
  disabled: boolean;
126
+ placeholder: string;
127
+ showPreview: boolean;
127
128
  variables: FormulaVariable[];
128
129
  functions: FormulaFunction[];
129
130
  sampleData: Record<string, number | string | boolean>;
130
- showPreview: boolean;
131
131
  showKeyboard: boolean;
132
132
  showVariablePanel: boolean;
133
133
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
@@ -217,7 +217,7 @@ declare function useNotificationCore(props: NotificationCenterProps): {
217
217
  actionText?: string | undefined;
218
218
  extra?: Record<string, unknown> | undefined;
219
219
  }[]>;
220
- activeCategory: vue.Ref<"all" | NotificationCategory, "all" | NotificationCategory>;
220
+ activeCategory: vue.Ref<NotificationCategory | "all", NotificationCategory | "all">;
221
221
  loading: vue.Ref<boolean, boolean>;
222
222
  total: vue.Ref<number, number>;
223
223
  page: vue.Ref<number, number>;
@@ -212,15 +212,15 @@ declare const __VLS_base: vue.DefineComponent<UploadProps, UploadExpose, {}, {},
212
212
  onFinish?: ((fileList: UploadFileItem[]) => any) | undefined;
213
213
  onExceed?: ((files: File[], fileList: UploadFileItem[]) => any) | undefined;
214
214
  }>, {
215
- data: Record<string, any>;
216
215
  disabled: boolean;
217
- multiple: boolean;
216
+ data: Record<string, any>;
218
217
  draggable: boolean;
219
- maxSize: number;
220
218
  action: string;
221
219
  headers: Record<string, string>;
220
+ multiple: boolean;
222
221
  directory: boolean;
223
222
  accept: string;
223
+ maxSize: number;
224
224
  maxCount: number;
225
225
  pasteable: boolean;
226
226
  chunked: boolean;
@@ -261,9 +261,9 @@ type PlayerInstance = InstanceType<typeof xgplayer.default>;
261
261
  declare const __VLS_export: vue.DefineComponent<VideoPlayerProps, VideoPlayerExpose, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
262
262
  error: (error: Error) => any;
263
263
  ready: () => any;
264
- ended: () => any;
265
264
  stateChange: (state: PlayerState) => any;
266
265
  timeUpdate: (currentTime: number, duration: number) => any;
266
+ ended: () => any;
267
267
  qualityChange: (quality: QualityLevel) => any;
268
268
  rateChange: (rate: number) => any;
269
269
  fullscreenChange: (isFullscreen: boolean) => any;
@@ -274,9 +274,9 @@ declare const __VLS_export: vue.DefineComponent<VideoPlayerProps, VideoPlayerExp
274
274
  }, string, vue.PublicProps, Readonly<VideoPlayerProps> & Readonly<{
275
275
  onError?: ((error: Error) => any) | undefined;
276
276
  onReady?: (() => any) | undefined;
277
- onEnded?: (() => any) | undefined;
278
277
  onStateChange?: ((state: PlayerState) => any) | undefined;
279
278
  onTimeUpdate?: ((currentTime: number, duration: number) => any) | undefined;
279
+ onEnded?: (() => any) | undefined;
280
280
  onQualityChange?: ((quality: QualityLevel) => any) | undefined;
281
281
  onRateChange?: ((rate: number) => any) | undefined;
282
282
  onFullscreenChange?: ((isFullscreen: boolean) => any) | undefined;