foucui 1.0.1 → 1.0.2

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 (234) hide show
  1. package/dist/components/QiuCanvasKit/QiuCanvasEditor.vue.d.ts +3 -1
  2. package/dist/components/QiuCanvasKit/components/DataModulesPanel.vue.d.ts +1 -0
  3. package/dist/components/QiuTable/index.vue.d.ts +12 -12
  4. package/dist/foucui.css +1 -1
  5. package/dist/foucui.js +7476 -7373
  6. package/dist/foucui.umd.cjs +19 -19
  7. package/package.json +23 -13
  8. package/components/QiuAffix/index.vue +0 -186
  9. package/components/QiuAlert/index.vue +0 -208
  10. package/components/QiuAnchor/context.ts +0 -18
  11. package/components/QiuAnchor/index.vue +0 -180
  12. package/components/QiuAnchorLink/index.vue +0 -67
  13. package/components/QiuApp/index.vue +0 -9
  14. package/components/QiuAutocomplete/index.vue +0 -408
  15. package/components/QiuAvatar/index.vue +0 -140
  16. package/components/QiuBacktop/index.vue +0 -121
  17. package/components/QiuBadge/api/index.ts +0 -389
  18. package/components/QiuBadge/components/BadgeImagePickerDialog.vue +0 -243
  19. package/components/QiuBadge/components/BadgeLibraryManagerDialog.vue +0 -30
  20. package/components/QiuBadge/components/BadgeLibraryPanel.vue +0 -182
  21. package/components/QiuBadge/composables/useTableHostHeight.ts +0 -53
  22. package/components/QiuBadge/index.ts +0 -18
  23. package/components/QiuBadge/shared/BadgeTemplateRenderer.vue +0 -32
  24. package/components/QiuBadge/shared/assetUrl.ts +0 -26
  25. package/components/QiuBadge/shared/badgeTemplate.ts +0 -309
  26. package/components/QiuBadge/utils/chinaAreaData.ts +0 -44
  27. package/components/QiuBadge/utils/hostRegion.ts +0 -22
  28. package/components/QiuBadge/utils/pca-code.json +0 -1
  29. package/components/QiuBadge/utils/pdfFromElement.ts +0 -348
  30. package/components/QiuBadge/views/BadgeLibraryView.vue +0 -32
  31. package/components/QiuBadge/views/BadgeManageView.vue +0 -1364
  32. package/components/QiuBadge/views/BadgeTemplateEditorView.vue +0 -10
  33. package/components/QiuBadge/views/BadgeTemplateListView.vue +0 -229
  34. package/components/QiuBadge/views/DeskLabelTemplateListView.vue +0 -227
  35. package/components/QiuBadge/views/DeskLabelView.vue +0 -683
  36. package/components/QiuBadgeDot/index.vue +0 -87
  37. package/components/QiuButton/index.vue +0 -247
  38. package/components/QiuButtonGroup/index.vue +0 -63
  39. package/components/QiuCanvasKit/QiuCanvasEditor.vue +0 -5503
  40. package/components/QiuCanvasKit/QiuCanvasRenderer.vue +0 -348
  41. package/components/QiuCanvasKit/assetUrl.ts +0 -11
  42. package/components/QiuCanvasKit/components/DataModulesPanel.vue +0 -352
  43. package/components/QiuCanvasKit/export/html.ts +0 -132
  44. package/components/QiuCanvasKit/export/pdf.ts +0 -48
  45. package/components/QiuCanvasKit/export/png.ts +0 -50
  46. package/components/QiuCanvasKit/index.ts +0 -20
  47. package/components/QiuCanvasKit/modules/badgeCompat.ts +0 -84
  48. package/components/QiuCanvasKit/modules/dataRegistry.ts +0 -207
  49. package/components/QiuCanvasKit/modules/merge.ts +0 -71
  50. package/components/QiuCanvasKit/presets/badge.ts +0 -67
  51. package/components/QiuCanvasKit/presets/banner.ts +0 -79
  52. package/components/QiuCanvasKit/types.ts +0 -138
  53. package/components/QiuCard/index.vue +0 -104
  54. package/components/QiuCarousel/context.ts +0 -16
  55. package/components/QiuCarousel/index.vue +0 -343
  56. package/components/QiuCarouselItem/index.vue +0 -47
  57. package/components/QiuCascader/index.vue +0 -879
  58. package/components/QiuCascader/types.ts +0 -48
  59. package/components/QiuCheckbox/QiuCheckboxGroup.vue +0 -78
  60. package/components/QiuCheckbox/index.vue +0 -231
  61. package/components/QiuCheckbox/types.ts +0 -8
  62. package/components/QiuCode/index.vue +0 -64
  63. package/components/QiuCol/col.scss +0 -55
  64. package/components/QiuCol/index.vue +0 -64
  65. package/components/QiuCollapse/context.ts +0 -10
  66. package/components/QiuCollapse/index.vue +0 -70
  67. package/components/QiuCollapseItem/index.vue +0 -167
  68. package/components/QiuColorField/index.vue +0 -296
  69. package/components/QiuColorPicker/README.md +0 -118
  70. package/components/QiuColorPicker/index.vue +0 -60
  71. package/components/QiuColorfulCard/index.vue +0 -101
  72. package/components/QiuCombobox/index.vue +0 -277
  73. package/components/QiuConfigProvider/index.vue +0 -31
  74. package/components/QiuContextMenu/index.vue +0 -209
  75. package/components/QiuDate/index.vue +0 -1134
  76. package/components/QiuDescriptions/context.ts +0 -20
  77. package/components/QiuDescriptions/index.vue +0 -115
  78. package/components/QiuDescriptionsItem/index.vue +0 -103
  79. package/components/QiuDialog/index.vue +0 -828
  80. package/components/QiuDigitalCard/index.vue +0 -159
  81. package/components/QiuDivider/index.vue +0 -185
  82. package/components/QiuDot/index.vue +0 -83
  83. package/components/QiuDrawer/index.vue +0 -350
  84. package/components/QiuDropdown/QiuDropdownItem.vue +0 -74
  85. package/components/QiuDropdown/QiuDropdownMenu.vue +0 -22
  86. package/components/QiuDropdown/context.ts +0 -9
  87. package/components/QiuDropdown/index.vue +0 -189
  88. package/components/QiuEmpty/index.vue +0 -73
  89. package/components/QiuForm/index.vue +0 -172
  90. package/components/QiuForm/types.ts +0 -39
  91. package/components/QiuFormItem/index.vue +0 -276
  92. package/components/QiuFullscreen/index.vue +0 -11
  93. package/components/QiuGrid/index.vue +0 -408
  94. package/components/QiuHoverCard/index.vue +0 -192
  95. package/components/QiuIcon/index.vue +0 -117
  96. package/components/QiuIconPicker/iconify.libraries.ts +0 -182
  97. package/components/QiuIconPicker/icons.catalog.ts +0 -3072
  98. package/components/QiuIconPicker/index.vue +0 -488
  99. package/components/QiuImage/index.vue +0 -177
  100. package/components/QiuInput/index.vue +0 -328
  101. package/components/QiuInputNumber/index.vue +0 -295
  102. package/components/QiuInputOtp/index.vue +0 -190
  103. package/components/QiuKbd/index.vue +0 -57
  104. package/components/QiuLayoutContainer/index.vue +0 -50
  105. package/components/QiuLinkPreview/index.vue +0 -224
  106. package/components/QiuLoading/index.ts +0 -176
  107. package/components/QiuLoading/spinner.vue +0 -820
  108. package/components/QiuLoading/types.ts +0 -44
  109. package/components/QiuMention/index.vue +0 -299
  110. package/components/QiuMenu/QiuMenuRoot.vue +0 -241
  111. package/components/QiuMenu/components/QiuMenuItem.vue +0 -340
  112. package/components/QiuMenu/components/QiuSubMenu.vue +0 -504
  113. package/components/QiuMenu/context.ts +0 -21
  114. package/components/QiuMenu/index.vue +0 -43
  115. package/components/QiuMenuNav/QiuMenuNavItem.vue +0 -100
  116. package/components/QiuMenuNav/QiuMenuNavSub.vue +0 -120
  117. package/components/QiuMenuNav/context.ts +0 -14
  118. package/components/QiuMenuNav/index.vue +0 -148
  119. package/components/QiuMsg/QiuMsgItem.vue +0 -180
  120. package/components/QiuMsg/index.ts +0 -158
  121. package/components/QiuMsg/types.ts +0 -23
  122. package/components/QiuMsgBox/index.ts +0 -147
  123. package/components/QiuNotification/QiuNotificationItem.vue +0 -168
  124. package/components/QiuNotification/index.ts +0 -155
  125. package/components/QiuNotification/types.ts +0 -14
  126. package/components/QiuPage/index.vue +0 -12
  127. package/components/QiuPageHeader/index.vue +0 -115
  128. package/components/QiuPageMain/index.vue +0 -78
  129. package/components/QiuPagination/index.vue +0 -421
  130. package/components/QiuPasswordStrength/index.vue +0 -101
  131. package/components/QiuPopconfirm/index.vue +0 -196
  132. package/components/QiuPopover/index.vue +0 -277
  133. package/components/QiuProgress/index.vue +0 -235
  134. package/components/QiuQrcode/index.vue +0 -302
  135. package/components/QiuQueryForm/components/QiuQueryFormBottomPanel.vue +0 -13
  136. package/components/QiuQueryForm/components/QiuQueryFormLeftPanel.vue +0 -37
  137. package/components/QiuQueryForm/components/QiuQueryFormRightPanel.vue +0 -37
  138. package/components/QiuQueryForm/components/QiuQueryFormTopPanel.vue +0 -13
  139. package/components/QiuQueryForm/index.vue +0 -117
  140. package/components/QiuRadio/QiuRadioGroup.vue +0 -75
  141. package/components/QiuRadio/index.vue +0 -191
  142. package/components/QiuRadio/types.ts +0 -9
  143. package/components/QiuRate/index.vue +0 -184
  144. package/components/QiuRefresh/index.vue +0 -32
  145. package/components/QiuResult/index.vue +0 -103
  146. package/components/QiuRow/index.vue +0 -60
  147. package/components/QiuRow/types.ts +0 -5
  148. package/components/QiuScrollbar/index.vue +0 -107
  149. package/components/QiuSearchBar/index.vue +0 -154
  150. package/components/QiuSegmented/index.vue +0 -120
  151. package/components/QiuSelect/QiuOption.vue +0 -93
  152. package/components/QiuSelect/index.vue +0 -452
  153. package/components/QiuSelect/types.ts +0 -15
  154. package/components/QiuSkeleton/index.vue +0 -78
  155. package/components/QiuSlider/index.vue +0 -266
  156. package/components/QiuSpace/index.vue +0 -95
  157. package/components/QiuSparkline/index.vue +0 -92
  158. package/components/QiuStatistic/index.vue +0 -4
  159. package/components/QiuStatistics/index.vue +0 -123
  160. package/components/QiuStep/index.vue +0 -220
  161. package/components/QiuSteps/context.ts +0 -25
  162. package/components/QiuSteps/index.vue +0 -84
  163. package/components/QiuSwitch/index.vue +0 -145
  164. package/components/QiuTabBar/index.vue +0 -218
  165. package/components/QiuTabBar/types.ts +0 -19
  166. package/components/QiuTabPane/index.vue +0 -82
  167. package/components/QiuTable/columns.ts +0 -16
  168. package/components/QiuTable/export.ts +0 -102
  169. package/components/QiuTable/index.ts +0 -24
  170. package/components/QiuTable/index.vue +0 -3503
  171. package/components/QiuTable/registry.ts +0 -75
  172. package/components/QiuTable/styles/table.scss +0 -1230
  173. package/components/QiuTable/types.ts +0 -413
  174. package/components/QiuTable/useArea.ts +0 -202
  175. package/components/QiuTable/useColumns.ts +0 -325
  176. package/components/QiuTable/useEdit.ts +0 -136
  177. package/components/QiuTable/useExtras.ts +0 -115
  178. package/components/QiuTable/useHistory.ts +0 -77
  179. package/components/QiuTable/useMerge.ts +0 -105
  180. package/components/QiuTable/useResize.ts +0 -86
  181. package/components/QiuTable/useScrollSync.ts +0 -152
  182. package/components/QiuTable/useVirtual.ts +0 -97
  183. package/components/QiuTable/utils.ts +0 -165
  184. package/components/QiuTableColumn/index.vue +0 -101
  185. package/components/QiuTag/index.vue +0 -143
  186. package/components/QiuText/index.vue +0 -99
  187. package/components/QiuTime/index.vue +0 -548
  188. package/components/QiuTimeAgo/index.vue +0 -103
  189. package/components/QiuTimeline/index.vue +0 -54
  190. package/components/QiuTimelineItem/index.vue +0 -140
  191. package/components/QiuTips/index.vue +0 -323
  192. package/components/QiuTooltip/index.vue +0 -237
  193. package/components/QiuTransfer/index.vue +0 -277
  194. package/components/QiuTree/QiuTreeNode.vue +0 -146
  195. package/components/QiuTree/index.vue +0 -143
  196. package/components/QiuTree/types.ts +0 -30
  197. package/components/QiuTreeSelect/index.vue +0 -259
  198. package/components/QiuTrend/index.vue +0 -92
  199. package/components/QiuUpload/index.vue +0 -628
  200. package/components/QiuUploadCrop/index.vue +0 -1267
  201. package/components/QiuWatermark/index.vue +0 -121
  202. package/components/useBodyScrollLock.ts +0 -28
  203. package/dist/components/QiuBadge/utils/pca-code.json.d.ts +0 -3
  204. package/plugins/qiu.ts +0 -83
  205. package/plugins/shortcuts.ts +0 -69
  206. package/src/bridge/@/api/media.ts +0 -8
  207. package/src/bridge/@/api/notice.ts +0 -5
  208. package/src/bridge/@/config/index.ts +0 -38
  209. package/src/bridge/@/config/media.config.ts +0 -37
  210. package/src/bridge/@/config/security.config.ts +0 -8
  211. package/src/bridge/@/i18n/index.ts +0 -6
  212. package/src/bridge/@/store/modules/bing.ts +0 -9
  213. package/src/bridge/@/store/modules/errorLog.ts +0 -9
  214. package/src/bridge/@/store/modules/media.ts +0 -10
  215. package/src/bridge/@/store/modules/routes.ts +0 -10
  216. package/src/bridge/@/store/modules/settings.ts +0 -9
  217. package/src/bridge/@/store/modules/tabs.ts +0 -9
  218. package/src/bridge/@/store/modules/user.ts +0 -9
  219. package/src/bridge/@/utils/convertToCamelCase.ts +0 -11
  220. package/src/bridge/@/utils/index.ts +0 -9
  221. package/src/bridge/@/utils/pageTitle.ts +0 -4
  222. package/src/bridge/@/utils/routes.ts +0 -14
  223. package/src/bridge/@/utils/validate.ts +0 -17
  224. package/src/bridge/@qiu/plugins/shortcuts.ts +0 -3
  225. package/src/i18n.ts +0 -8
  226. package/src/icons/qiu-logo.svg +0 -1
  227. package/styles/dark.scss +0 -194
  228. package/styles/normalize.css +0 -349
  229. package/styles/plain.scss +0 -423
  230. package/styles/qiu-tokens.scss +0 -40
  231. package/styles/qiu.scss +0 -1149
  232. package/styles/technology.scss +0 -452
  233. package/styles/var.scss +0 -382
  234. package/styles/variables.scss +0 -77
@@ -1,504 +0,0 @@
1
- <template>
2
- <template v-if="itemOrMenu.meta && itemOrMenu.meta.levelHidden">
3
- <template v-for="route in itemOrMenu.children" :key="route.path">
4
- <qiu-menu :item="route" :layout="layout" />
5
- </template>
6
- </template>
7
- <li
8
- v-else
9
- ref="subRef"
10
- class="qiu-route-menu-sub"
11
- :class="{
12
- 'is-open': isOpen,
13
- 'is-active': isSubActive,
14
- 'is-popup': isPopupMode,
15
- }"
16
- role="none"
17
- @mouseenter="onEnter"
18
- @mouseleave="onLeave"
19
- >
20
- <div ref="titleRef" class="qiu-route-menu-sub__title" @click="onTitleClick">
21
- <span class="qiu-route-menu-sub__icon-wrap">
22
- <qiu-icon
23
- :icon="itemOrMenu.meta?.icon || 'folder-line'"
24
- :is-custom-svg="itemOrMenu.meta?.isCustomSvg"
25
- :title="menuTitle"
26
- />
27
- <qiu-dot
28
- v-if="itemOrMenu.meta?.dot"
29
- class="qiu-route-menu-sub__dot"
30
- :type="dotType"
31
- />
32
- </span>
33
- <span class="qiu-route-menu-sub__text" :title="menuTitle">
34
- {{ menuTitle }}
35
- </span>
36
- <qiu-tag
37
- v-if="itemOrMenu.meta?.badge"
38
- class="qiu-route-menu-sub__badge"
39
- :class="[`qiu-menu-tag--${badgeEffect}`]"
40
- size="small"
41
- :type="badgeType"
42
- :effect="badgeEffect"
43
- >
44
- {{ translate(itemOrMenu.meta.badge) }}
45
- </qiu-tag>
46
- <span v-if="!isPopupMode" class="qiu-route-menu-sub__arrow" :class="{ 'is-open': isOpen }">
47
- <qiu-icon icon="arrow-down-s-line" />
48
- </span>
49
- <span v-else class="qiu-route-menu-sub__more">
50
- <qiu-icon icon="arrow-right-s-line" />
51
- </span>
52
- </div>
53
-
54
- <!-- 展开态:内联子菜单;收起/弹出态:Teleport + fixed 级联 tips -->
55
- <Teleport to="body" :disabled="!isFlyout">
56
- <ul
57
- v-show="showChildList"
58
- ref="listRef"
59
- class="qiu-route-menu-sub__list"
60
- :class="{
61
- 'is-flyout': isFlyout,
62
- 'qiu-menu-flyout-panel': isFlyout,
63
- [`is-placement-${flyoutPlacement}`]: isFlyout,
64
- }"
65
- :style="isFlyout ? flyoutStyle : undefined"
66
- @mouseenter="onEnter"
67
- @mouseleave="onLeave"
68
- >
69
- <i v-if="isFlyout" class="qiu-menu-flyout-panel__arrow" aria-hidden="true" />
70
- <div v-if="isFlyout" class="qiu-menu-flyout-panel__head">{{ menuTitle }}</div>
71
- <slot />
72
- </ul>
73
- </Teleport>
74
- </li>
75
- </template>
76
-
77
- <script lang="ts" setup>
78
- import type { QiuRouteMenuContext } from '../context'
79
- import { QIU_ROUTE_MENU_KEY } from '../context'
80
- import { translate } from '../../../src/i18n'
81
-
82
- defineOptions({
83
- name: 'QiuSubMenu',
84
- })
85
-
86
- const props = defineProps({
87
- itemOrMenu: {
88
- type: Object,
89
- default: () => ({}),
90
- },
91
- layout: {
92
- type: String,
93
- default: '',
94
- },
95
- })
96
-
97
- const menuCtx = inject<QiuRouteMenuContext>(QIU_ROUTE_MENU_KEY, null)
98
- const subRef = ref<HTMLLIElement | null>(null)
99
- const titleRef = ref<HTMLElement | null>(null)
100
- const listRef = ref<HTMLElement | null>(null)
101
- const flyoutStyle = ref<Record<string, string>>({})
102
- const flyoutPlacement = ref<'bottom' | 'right' | 'left'>('right')
103
- let leaveTimer: ReturnType<typeof setTimeout> | null = null
104
-
105
- const index = computed(() => props.itemOrMenu.path as string)
106
- const menuTitle = computed(() => translate(props.itemOrMenu.meta?.title || ''))
107
- const isHorizontal = computed(() => menuCtx?.mode.value === 'horizontal')
108
- const isCollapse = computed(() => menuCtx?.collapse.value ?? false)
109
- const isPopupMode = computed(() => isHorizontal.value || isCollapse.value)
110
- const isFlyout = computed(() => isPopupMode.value)
111
- const isOpen = computed(() => menuCtx?.isSubOpen(index.value) ?? false)
112
- const isSubActive = computed(() => menuCtx?.isActive(index.value) ?? false)
113
- const badgeType = computed(() => props.itemOrMenu.meta?.badgeType || 'info')
114
- const badgeEffect = computed(() => props.itemOrMenu.meta?.badgeEffect || 'dark')
115
- const dotType = computed(() => {
116
- const d = props.itemOrMenu.meta?.dot
117
- if (d === true) return 'danger'
118
- if (typeof d === 'string') return d
119
- return 'danger'
120
- })
121
- const showChildList = computed(() => isOpen.value)
122
-
123
- const updateFlyoutPos = () => {
124
- const el = titleRef.value
125
- if (!el || !isFlyout.value) return
126
- const rect = el.getBoundingClientRect()
127
- const panelW = 200
128
- const depth = index.value.split('/').filter(Boolean).length
129
- // 已在 flyout 内的子级:向右级联;横向顶栏一级:向下展开
130
- const inFlyoutPanel = !!el.closest('.qiu-menu-flyout-panel')
131
- let left = 0
132
- let top = 0
133
- let placement: 'bottom' | 'right' | 'left' = 'right'
134
- const triggerCX = rect.left + rect.width / 2
135
- const triggerCY = rect.top + rect.height / 2
136
-
137
- if (isHorizontal.value && !inFlyoutPanel) {
138
- placement = 'bottom'
139
- const gap = 6
140
- // 尽量让触发项落在面板上方中部,三角对准菜单名
141
- left = Math.round(triggerCX - panelW / 2)
142
- top = Math.round(rect.bottom + gap)
143
- left = Math.min(Math.max(8, left), window.innerWidth - panelW - 8)
144
- } else {
145
- const gap = 10
146
- left = Math.round(rect.right + gap)
147
- top = Math.round(rect.top)
148
- if (left + panelW > window.innerWidth - 8) {
149
- left = Math.round(rect.left - panelW - gap)
150
- placement = 'left'
151
- } else {
152
- placement = 'right'
153
- }
154
- }
155
-
156
- const maxTop = window.innerHeight - 16
157
- if (top > maxTop - 80) top = Math.max(8, maxTop - 240)
158
- if (top < 8) top = 8
159
-
160
- // tips 三角对准触发项中心(指向上级菜单名)
161
- const arrowHalf = 5
162
- let arrowX = Math.round(triggerCX - left - arrowHalf)
163
- let arrowY = Math.round(triggerCY - top - arrowHalf)
164
- arrowX = Math.min(Math.max(12, arrowX), panelW - 22)
165
- arrowY = Math.min(Math.max(12, arrowY), 220)
166
-
167
- flyoutPlacement.value = placement
168
- flyoutStyle.value = {
169
- position: 'fixed',
170
- top: `${top}px`,
171
- left: `${left}px`,
172
- zIndex: String(5200 + depth),
173
- '--qiu-flyout-arrow-x': `${arrowX}px`,
174
- '--qiu-flyout-arrow-y': `${arrowY}px`,
175
- }
176
- }
177
-
178
- const openFlyout = () => {
179
- if (isPopupMode.value) menuCtx?.enterFlyout(index.value)
180
- else menuCtx?.openSub(index.value)
181
- nextTick(() => {
182
- updateFlyoutPos()
183
- requestAnimationFrame(() => updateFlyoutPos())
184
- })
185
- }
186
-
187
- const onTitleClick = () => {
188
- if (!menuCtx) return
189
- if (isPopupMode.value) {
190
- if (isOpen.value) menuCtx.leaveFlyout()
191
- else openFlyout()
192
- return
193
- }
194
- menuCtx.toggleSub(index.value)
195
- }
196
-
197
- const onEnter = () => {
198
- if (leaveTimer) {
199
- clearTimeout(leaveTimer)
200
- leaveTimer = null
201
- }
202
- if (!menuCtx) return
203
- if (menuCtx.menuTrigger.value === 'hover' || isPopupMode.value) {
204
- openFlyout()
205
- }
206
- }
207
-
208
- const onLeave = (e: MouseEvent) => {
209
- const related = e.relatedTarget as Node | null
210
- if (related && (subRef.value?.contains(related) || listRef.value?.contains(related))) return
211
-
212
- if (!isPopupMode.value) {
213
- if (menuCtx?.menuTrigger.value !== 'hover') return
214
- if (leaveTimer) clearTimeout(leaveTimer)
215
- leaveTimer = setTimeout(() => {
216
- menuCtx?.closeSub(index.value)
217
- leaveTimer = null
218
- }, 120)
219
- return
220
- }
221
- // 弹出/收起:交给根级统一延迟关闭,避免移入下一级 Teleport 面板时被关掉
222
- menuCtx?.leaveFlyout()
223
- }
224
-
225
- watch(isOpen, (v) => {
226
- if (v && isFlyout.value) nextTick(() => updateFlyoutPos())
227
- })
228
-
229
- onBeforeUnmount(() => {
230
- if (leaveTimer) clearTimeout(leaveTimer)
231
- })
232
- </script>
233
-
234
- <style lang="scss" scoped>
235
- .qiu-route-menu-sub {
236
- position: relative;
237
- list-style: none;
238
-
239
- &__title {
240
- position: relative;
241
- box-sizing: border-box;
242
- display: flex;
243
- gap: 8px;
244
- align-items: center;
245
- width: 100%;
246
- height: var(--qiu-menu-item-height);
247
- padding: 0 12px;
248
- overflow: hidden;
249
- line-height: 1.2;
250
- color: var(--qiu-menu-color-text, var(--qiu-menu-text-color, #fff));
251
- cursor: pointer;
252
- border-radius: var(--qiu-border-radius-base);
253
- transition: background 0.2s ease, color 0.2s ease;
254
-
255
- &:hover {
256
- color: #fff !important;
257
- background-color: var(--qiu-color-primary);
258
-
259
- .qiu-icon,
260
- [class*='ri-'],
261
- .qiu-route-menu-sub__text,
262
- .qiu-route-menu-sub__arrow,
263
- .qiu-route-menu-sub__more {
264
- color: #fff !important;
265
- }
266
- }
267
-
268
- .qiu-icon,
269
- [class*='ri-'] {
270
- flex-shrink: 0;
271
- font-size: 16px;
272
- line-height: 1;
273
- color: inherit;
274
- }
275
- }
276
-
277
- &.is-active > &__title {
278
- color: #fff !important;
279
- background-color: var(--qiu-color-primary);
280
-
281
- .qiu-icon,
282
- [class*='ri-'],
283
- .qiu-route-menu-sub__text,
284
- .qiu-route-menu-sub__arrow,
285
- .qiu-route-menu-sub__more {
286
- color: #fff !important;
287
- }
288
- }
289
-
290
- &__text {
291
- flex: 1;
292
- min-width: 0;
293
- overflow: hidden;
294
- text-overflow: ellipsis;
295
- white-space: nowrap;
296
- }
297
-
298
- &__icon-wrap {
299
- position: relative;
300
- display: inline-flex;
301
- flex-shrink: 0;
302
- align-items: center;
303
- justify-content: center;
304
- width: 16px;
305
- height: 16px;
306
- min-width: 16px;
307
- min-height: 16px;
308
- overflow: hidden;
309
- }
310
-
311
- &__badge {
312
- flex-shrink: 0;
313
- border-radius: 999px !important;
314
- }
315
-
316
- &__dot {
317
- position: absolute !important;
318
- top: 0;
319
- right: 0;
320
- z-index: 1;
321
- margin: 0 !important;
322
- }
323
-
324
- &__arrow,
325
- &__more {
326
- flex-shrink: 0;
327
- font-size: 12px;
328
- line-height: 1;
329
- transition: transform 0.2s ease;
330
- backface-visibility: hidden;
331
- transform: translateZ(0);
332
- }
333
-
334
- &__arrow.is-open {
335
- transform: translateZ(0) rotate(180deg);
336
- }
337
-
338
- &__list {
339
- padding: 4px 0;
340
- margin: 0;
341
- list-style: none;
342
-
343
- :deep(.qiu-route-menu-item__inner) {
344
- padding-left: 28px;
345
- }
346
- }
347
-
348
- .qiu-route-menu--horizontal > .qiu-route-menu__list > & {
349
- > .qiu-route-menu-sub__title {
350
- height: 40px;
351
- padding: 0 16px;
352
- }
353
- }
354
- }
355
-
356
- :deep(.qiu-menu-tag--dark.qiu-tag--info) {
357
- color: #fff;
358
- background: #1f1f1f;
359
- border-color: #1f1f1f;
360
- }
361
-
362
- :deep(.qiu-menu-tag--plain.qiu-tag--info) {
363
- color: #1f1f1f;
364
- background: transparent;
365
- border-color: #1f1f1f;
366
- }
367
-
368
- .qiu-route-menu-sub.is-active > .qiu-route-menu-sub__title,
369
- .qiu-route-menu-sub__title:hover {
370
- :deep(.qiu-menu-tag--dark.qiu-tag--info) {
371
- color: #1f1f1f;
372
- background: #fff;
373
- border-color: #fff;
374
- }
375
-
376
- :deep(.qiu-menu-tag--plain.qiu-tag--info) {
377
- color: #fff;
378
- background: transparent;
379
- border-color: #fff;
380
- }
381
- }
382
- </style>
383
-
384
- <style lang="scss">
385
- /* Teleport 级联 tips 面板(多级菜单) */
386
- .qiu-menu-flyout-panel.qiu-route-menu-sub__list.is-flyout {
387
- position: relative;
388
- box-sizing: border-box;
389
- min-width: 180px;
390
- max-width: 260px;
391
- max-height: calc(100vh - 24px);
392
- padding: 6px 0 8px;
393
- overflow-x: visible;
394
- overflow-y: auto;
395
- pointer-events: auto;
396
- background: var(--qiu-bg-color-overlay, #fff);
397
- border: 1px solid var(--qiu-border-color, #dcdfe6);
398
- border-radius: var(--qiu-border-radius-base, 6px);
399
- box-shadow: var(--qiu-box-shadow-light, 0 6px 16px rgba(0, 0, 0, 0.12));
400
- }
401
-
402
- /* 横向向下展开:上方透明桥接,避免移入时菜单被关掉 */
403
- .qiu-menu-flyout-panel.is-placement-bottom::before {
404
- position: absolute;
405
- top: -10px;
406
- right: 0;
407
- left: 0;
408
- height: 10px;
409
- content: '';
410
- }
411
-
412
- .qiu-menu-flyout-panel__arrow {
413
- position: absolute;
414
- z-index: 2;
415
- width: 10px;
416
- height: 10px;
417
- pointer-events: none;
418
- background: var(--qiu-bg-color-overlay, #fff);
419
- border-top: 1px solid var(--qiu-border-color, #dcdfe6);
420
- border-left: 1px solid var(--qiu-border-color, #dcdfe6);
421
- }
422
-
423
- /* 向右展开:三角指向左侧上级菜单名 */
424
- .qiu-menu-flyout-panel.is-placement-right .qiu-menu-flyout-panel__arrow {
425
- top: var(--qiu-flyout-arrow-y, 14px);
426
- left: -5px;
427
- transform: rotate(-45deg);
428
- }
429
-
430
- /* 向下展开:三角指向上方一级菜单名 */
431
- .qiu-menu-flyout-panel.is-placement-bottom .qiu-menu-flyout-panel__arrow {
432
- top: -5px;
433
- left: var(--qiu-flyout-arrow-x, 18px);
434
- transform: rotate(45deg);
435
- }
436
-
437
- /* 向左展开:三角指向右侧上级菜单名 */
438
- .qiu-menu-flyout-panel.is-placement-left .qiu-menu-flyout-panel__arrow {
439
- top: var(--qiu-flyout-arrow-y, 14px);
440
- right: -5px;
441
- left: auto;
442
- transform: rotate(135deg);
443
- }
444
-
445
- .qiu-menu-flyout-panel__head {
446
- padding: 4px 14px 8px;
447
- margin-bottom: 4px;
448
- overflow: hidden;
449
- font-size: 12px;
450
- font-weight: 600;
451
- color: var(--qiu-text-color-secondary, #909399);
452
- text-overflow: ellipsis;
453
- white-space: nowrap;
454
- border-bottom: 1px solid var(--qiu-border-color-lighter, #ebeef5);
455
- }
456
-
457
- .qiu-menu-flyout-panel {
458
- .qiu-route-menu-item__inner,
459
- .qiu-route-menu-sub__title {
460
- box-sizing: border-box;
461
- display: flex !important;
462
- gap: 8px;
463
- align-items: center;
464
- width: calc(100% - 16px) !important;
465
- height: 36px !important;
466
- padding: 0 12px !important;
467
- margin: 0 8px 2px !important;
468
- color: var(--qiu-text-color-primary, #303133) !important;
469
- background: transparent !important;
470
- border-radius: 6px;
471
-
472
- .qiu-route-menu-item__text,
473
- .qiu-route-menu-sub__text,
474
- .qiu-route-menu-item__badge,
475
- .qiu-route-menu-sub__badge,
476
- .qiu-route-menu-sub__more,
477
- .qiu-icon,
478
- [class*='ri-'] {
479
- display: inline-flex !important;
480
- color: inherit !important;
481
- }
482
-
483
- .qiu-route-menu-sub__arrow {
484
- display: none !important;
485
- }
486
-
487
- &:hover {
488
- color: #fff !important;
489
- background-color: var(--qiu-color-primary) !important;
490
- }
491
- }
492
-
493
- .qiu-route-menu-item.is-active > .qiu-route-menu-item__inner,
494
- .qiu-route-menu-sub.is-active > .qiu-route-menu-sub__title {
495
- color: #fff !important;
496
- background-color: var(--qiu-color-primary) !important;
497
- }
498
-
499
- /* 面板内叶子不再叠一层仅名称 tip */
500
- .qiu-route-menu-item__tip {
501
- display: none !important;
502
- }
503
- }
504
- </style>
@@ -1,21 +0,0 @@
1
- import type { InjectionKey, Ref } from 'vue'
2
-
3
- export interface QiuRouteMenuContext {
4
- mode: Ref<'vertical' | 'horizontal'>
5
- collapse: Ref<boolean>
6
- activeIndex: Ref<string>
7
- uniqueOpened: Ref<boolean>
8
- menuTrigger: Ref<'click' | 'hover'>
9
- isSubOpen: (index: string) => boolean
10
- toggleSub: (index: string) => void
11
- openSub: (index: string) => void
12
- closeSub: (index: string) => void
13
- /** 弹出/收起态:进入 flyout 链(取消延迟关闭) */
14
- enterFlyout: (index: string) => void
15
- /** 弹出/收起态:离开后延迟关闭整条 flyout 链 */
16
- leaveFlyout: () => void
17
- selectItem: (index: string) => void
18
- isActive: (index: string) => boolean
19
- }
20
-
21
- export const QIU_ROUTE_MENU_KEY: InjectionKey<QiuRouteMenuContext> = Symbol('QiuRouteMenu')
@@ -1,43 +0,0 @@
1
- <template>
2
- <component :is="menuComponent" :item-or-menu="item" :layout="layout">
3
- <template v-if="item.children && item.children.length > 0">
4
- <qiu-menu v-for="route in item.children" :key="route.path" :item="route" :layout="layout" />
5
- </template>
6
- </component>
7
- </template>
8
-
9
- <script lang="ts" setup>
10
- defineOptions({
11
- name: 'QiuMenu',
12
- })
13
-
14
- interface ComponentType {
15
- default: Component
16
- }
17
-
18
- const imports = import.meta.glob<ComponentType>('./components/**/*.vue', { eager: true })
19
- const Components: Record<string, Component> = {}
20
- Object.getOwnPropertyNames(imports).forEach((key) => {
21
- Components[key.replaceAll(/(\/|components|\.|vue)/g, '')] = imports[key].default
22
- })
23
-
24
- const props = defineProps({
25
- item: {
26
- type: Object,
27
- required: true,
28
- },
29
- layout: {
30
- type: String,
31
- default: '',
32
- },
33
- })
34
-
35
- const menuComponent = computed(() =>
36
- props.item.children &&
37
- props.item.children.some((route: any) => {
38
- return route.meta && route.meta.hidden !== true
39
- })
40
- ? Components['QiuSubMenu']
41
- : Components['QiuMenuItem']
42
- )
43
- </script>
@@ -1,100 +0,0 @@
1
- <template>
2
- <li
3
- class="qiu-menu-nav-item"
4
- :class="{
5
- 'is-active': isActive,
6
- 'is-disabled': disabled,
7
- }"
8
- role="menuitem"
9
- @click="handleClick"
10
- >
11
- <div class="qiu-menu-nav-item__inner">
12
- <slot name="icon" />
13
- <span class="qiu-menu-nav-item__title">
14
- <slot>{{ title }}</slot>
15
- </span>
16
- </div>
17
- </li>
18
- </template>
19
-
20
- <script lang="ts" setup>
21
- import type { QiuMenuNavContext } from './context'
22
- import { QIU_MENU_NAV_KEY } from './context'
23
-
24
- defineOptions({ name: 'QiuMenuNavItem' })
25
-
26
- const props = withDefaults(
27
- defineProps<{
28
- index: string
29
- title?: string
30
- disabled?: boolean
31
- }>(),
32
- {
33
- title: '',
34
- disabled: false,
35
- }
36
- )
37
-
38
- const menuCtx = inject<QiuMenuNavContext>(QIU_MENU_NAV_KEY, null)
39
-
40
- let router: ReturnType<typeof useRouter> | null = null
41
- try {
42
- router = useRouter()
43
- } catch {
44
- router = null
45
- }
46
-
47
- const isActive = computed(() => menuCtx?.activeIndex.value === props.index)
48
-
49
- const handleClick = () => {
50
- if (props.disabled || !menuCtx) return
51
- menuCtx.selectItem(props.index)
52
- if (menuCtx.router.value && router) {
53
- router.push(props.index).catch(() => {})
54
- }
55
- }
56
- </script>
57
-
58
- <style lang="scss" scoped>
59
- .qiu-menu-nav-item {
60
- list-style: none;
61
- cursor: pointer;
62
-
63
- &__inner {
64
- display: flex;
65
- gap: 8px;
66
- align-items: center;
67
- height: var(--qiu-menu-item-height, var(--qiu-menu-item-height, 56px));
68
- padding: 0 20px;
69
- overflow: hidden;
70
- color: var(--qiu-menu-text-color, var(--qiu-menu-text-color, #303133));
71
- text-overflow: ellipsis;
72
- white-space: nowrap;
73
- transition: background 0.2s ease, color 0.2s ease;
74
-
75
- &:hover {
76
- background: var(--qiu-menu-hover-bg-color, var(--qiu-menu-hover-bg-color, #ecf5ff));
77
- }
78
- }
79
-
80
- &.is-active > .qiu-menu-nav-item__inner {
81
- color: var(--qiu-menu-active-color, var(--qiu-menu-active-color, var(--qiu-color-primary, var(--qiu-color-primary))));
82
- background: var(--qiu-menu-hover-bg-color, var(--qiu-menu-hover-bg-color, #ecf5ff));
83
- }
84
-
85
- &.is-disabled {
86
- cursor: not-allowed;
87
- opacity: 0.5;
88
-
89
- .qiu-menu-nav-item__inner:hover {
90
- background: transparent;
91
- }
92
- }
93
-
94
- &__title {
95
- flex: 1;
96
- overflow: hidden;
97
- text-overflow: ellipsis;
98
- }
99
- }
100
- </style>