vft 0.0.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 (321) hide show
  1. package/package.json +54 -0
  2. package/src/app/index.ts +3 -0
  3. package/src/app/page-loading/assets/spin.gif +0 -0
  4. package/src/app/page-loading/index.less +10 -0
  5. package/src/app/page-loading/index.ts +3 -0
  6. package/src/app/page-loading/index.vue +38 -0
  7. package/src/app/table/assets/sort_triangle.png +0 -0
  8. package/src/app/table/demos/basic.vue +117 -0
  9. package/src/app/table/demos/complex.vue +2543 -0
  10. package/src/app/table/demos/index.vue +453 -0
  11. package/src/app/table/demos/rightAngle.png +0 -0
  12. package/src/app/table/header.vue +203 -0
  13. package/src/app/table/index.less +119 -0
  14. package/src/app/table/index.ts +5 -0
  15. package/src/app/table/index.vue +478 -0
  16. package/src/app/table/md/api.md +23 -0
  17. package/src/app/table/md/demo.md +3 -0
  18. package/src/app/table/types.ts +45 -0
  19. package/src/common/badge/index.scss +78 -0
  20. package/src/common/badge/index.ts +4 -0
  21. package/src/common/badge/index.vue +111 -0
  22. package/src/common/badge/types.ts +1 -0
  23. package/src/common/clamp/clamp-toggle.vue +91 -0
  24. package/src/common/clamp/index.ts +4 -0
  25. package/src/common/clamp/index.vue +247 -0
  26. package/src/common/code/index.less +321 -0
  27. package/src/common/code/index.ts +3 -0
  28. package/src/common/code/index.vue +60 -0
  29. package/src/common/config-provider/index.ts +4 -0
  30. package/src/common/config-provider/index.vue +94 -0
  31. package/src/common/config-provider/types.ts +29 -0
  32. package/src/common/icon/iconfont/iconfont.css +334 -0
  33. package/src/common/icon/index.scss +31 -0
  34. package/src/common/icon/index.ts +4 -0
  35. package/src/common/icon/index.vue +74 -0
  36. package/src/common/icon/types.ts +16 -0
  37. package/src/common/index.ts +6 -0
  38. package/src/common/message/index.ts +5 -0
  39. package/src/common/message/instance.ts +29 -0
  40. package/src/common/message/message.scss +108 -0
  41. package/src/common/message/message.ts +80 -0
  42. package/src/common/message/message.vue +162 -0
  43. package/src/common/message/method.ts +172 -0
  44. package/src/common/overlay/index.scss +14 -0
  45. package/src/common/overlay/index.ts +3 -0
  46. package/src/common/overlay/index.vue +117 -0
  47. package/src/constants/comp.ts +1 -0
  48. package/src/constants/index.ts +1 -0
  49. package/src/index.ts +3 -0
  50. package/src/page/index.ts +1 -0
  51. package/src/page/page-wrapper/index.scss +31 -0
  52. package/src/page/page-wrapper/index.ts +5 -0
  53. package/src/page/page-wrapper/index.vue +31 -0
  54. package/src/styles/vars.scss +500 -0
  55. package/src/use/index.ts +14 -0
  56. package/src/use/onPopupReopen.ts +15 -0
  57. package/src/use/use-delayed-toggle/index.ts +30 -0
  58. package/src/use/use-floating/index.ts +121 -0
  59. package/src/use/use-forward-ref.ts +35 -0
  60. package/src/use/use-global-config/index.ts +81 -0
  61. package/src/use/use-id/index.ts +43 -0
  62. package/src/use/use-model-toggle/index.ts +151 -0
  63. package/src/use/use-namespace/index.ts +91 -0
  64. package/src/use/use-ordered-children/index.ts +43 -0
  65. package/src/use/use-popper-container/index.ts +43 -0
  66. package/src/use/use-timeout/index.ts +18 -0
  67. package/src/use/use-z-index/index.ts +20 -0
  68. package/src/use/useGlobalZIndex.ts +24 -0
  69. package/src/use/useLazyRender.ts +17 -0
  70. package/src/use/useLockScroll.ts +66 -0
  71. package/src/utils/aria.ts +126 -0
  72. package/src/utils/arrays.ts +13 -0
  73. package/src/utils/error.ts +23 -0
  74. package/src/utils/event.ts +15 -0
  75. package/src/utils/helper.ts +7 -0
  76. package/src/utils/index.ts +8 -0
  77. package/src/utils/interceptor.ts +39 -0
  78. package/src/utils/mount-component.ts +65 -0
  79. package/src/utils/popper.ts +6 -0
  80. package/src/utils/rand.ts +12 -0
  81. package/src/utils/scroll.ts +101 -0
  82. package/src/utils/vnode.ts +169 -0
  83. package/src/web/avatar/index.scss +50 -0
  84. package/src/web/avatar/index.ts +3 -0
  85. package/src/web/avatar/index.vue +83 -0
  86. package/src/web/back-top/index.scss +35 -0
  87. package/src/web/back-top/index.ts +3 -0
  88. package/src/web/back-top/index.vue +72 -0
  89. package/src/web/back-top/types.ts +14 -0
  90. package/src/web/back-top/use-back-top.ts +65 -0
  91. package/src/web/cascader/index.scss +214 -0
  92. package/src/web/cascader/index.ts +5 -0
  93. package/src/web/cascader/index.vue +767 -0
  94. package/src/web/cascader-panel/config.ts +44 -0
  95. package/src/web/cascader-panel/index.scss +134 -0
  96. package/src/web/cascader-panel/index.ts +5 -0
  97. package/src/web/cascader-panel/index.vue +319 -0
  98. package/src/web/cascader-panel/menu.vue +135 -0
  99. package/src/web/cascader-panel/node-content.ts +23 -0
  100. package/src/web/cascader-panel/node.ts +218 -0
  101. package/src/web/cascader-panel/node.vue +197 -0
  102. package/src/web/cascader-panel/store.ts +83 -0
  103. package/src/web/cascader-panel/types.ts +56 -0
  104. package/src/web/cascader-panel/utils.ts +40 -0
  105. package/src/web/cascader-select/README.md +31 -0
  106. package/src/web/cascader-select/index.scss +54 -0
  107. package/src/web/cascader-select/index.ts +5 -0
  108. package/src/web/cascader-select/index.vue +132 -0
  109. package/src/web/cascader-select/types.ts +9 -0
  110. package/src/web/context-menu/createContextMenu.ts +72 -0
  111. package/src/web/context-menu/index.ts +4 -0
  112. package/src/web/context-menu/index.vue +89 -0
  113. package/src/web/context-menu/types.ts +27 -0
  114. package/src/web/context-menu/useContextMenu.ts +14 -0
  115. package/src/web/descriptions/description-item.vue +34 -0
  116. package/src/web/descriptions/description.vue +124 -0
  117. package/src/web/descriptions/descriptions-cell.ts +95 -0
  118. package/src/web/descriptions/descriptions-item.scss +68 -0
  119. package/src/web/descriptions/descriptions-row.vue +49 -0
  120. package/src/web/descriptions/descriptions.scss +153 -0
  121. package/src/web/descriptions/descriptions.type.ts +19 -0
  122. package/src/web/descriptions/index.ts +4 -0
  123. package/src/web/descriptions/token.ts +4 -0
  124. package/src/web/divider/index.scss +53 -0
  125. package/src/web/divider/index.ts +5 -0
  126. package/src/web/divider/index.vue +60 -0
  127. package/src/web/divider/types.ts +2 -0
  128. package/src/web/empty/assets/no-collect.png +0 -0
  129. package/src/web/empty/assets/no-data.png +0 -0
  130. package/src/web/empty/assets/no-filter.png +0 -0
  131. package/src/web/empty/assets/no-page-data.png +0 -0
  132. package/src/web/empty/assets/no-search.png +0 -0
  133. package/src/web/empty/constants.ts +12 -0
  134. package/src/web/empty/index.scss +57 -0
  135. package/src/web/empty/index.ts +5 -0
  136. package/src/web/empty/index.vue +96 -0
  137. package/src/web/exception/exception.png +0 -0
  138. package/src/web/exception/index.ts +3 -0
  139. package/src/web/exception/index.vue +44 -0
  140. package/src/web/filter/README.md +25 -0
  141. package/src/web/filter/index.scss +14 -0
  142. package/src/web/filter/index.ts +5 -0
  143. package/src/web/filter/index.vue +60 -0
  144. package/src/web/filter/type.ts +13 -0
  145. package/src/web/focus-trap/index.ts +6 -0
  146. package/src/web/focus-trap/index.vue +328 -0
  147. package/src/web/focus-trap/tokens.ts +23 -0
  148. package/src/web/focus-trap/utils.ts +178 -0
  149. package/src/web/full-screen/index.scss +22 -0
  150. package/src/web/full-screen/index.ts +3 -0
  151. package/src/web/full-screen/index.vue +24 -0
  152. package/src/web/icon-text/index.ts +3 -0
  153. package/src/web/icon-text/index.vue +77 -0
  154. package/src/web/image/index.scss +46 -0
  155. package/src/web/image/index.ts +5 -0
  156. package/src/web/image/index.vue +251 -0
  157. package/src/web/image/types.ts +1 -0
  158. package/src/web/index.ts +33 -0
  159. package/src/web/input/index.scss +473 -0
  160. package/src/web/input/index.ts +3 -0
  161. package/src/web/input/index.vue +533 -0
  162. package/src/web/input/utils.ts +102 -0
  163. package/src/web/layouts/blank.vue +4 -0
  164. package/src/web/layouts/footer/index.scss +31 -0
  165. package/src/web/layouts/footer/index.ts +3 -0
  166. package/src/web/layouts/footer/index.vue +38 -0
  167. package/src/web/layouts/header/index.scss +35 -0
  168. package/src/web/layouts/header/index.ts +3 -0
  169. package/src/web/layouts/header/index.vue +47 -0
  170. package/src/web/layouts/iframe/index.scss +18 -0
  171. package/src/web/layouts/iframe/index.vue +36 -0
  172. package/src/web/layouts/iframe/page.vue +30 -0
  173. package/src/web/layouts/index.ts +8 -0
  174. package/src/web/layouts/router-view-content/index.vue +70 -0
  175. package/src/web/link/index.scss +95 -0
  176. package/src/web/link/index.ts +3 -0
  177. package/src/web/link/index.vue +68 -0
  178. package/src/web/loading/directive.ts +104 -0
  179. package/src/web/loading/index.ts +6 -0
  180. package/src/web/loading/loading.scss +108 -0
  181. package/src/web/loading/loading.ts +156 -0
  182. package/src/web/loading/service.ts +145 -0
  183. package/src/web/loading/types.ts +29 -0
  184. package/src/web/logo/index.scss +31 -0
  185. package/src/web/logo/index.ts +5 -0
  186. package/src/web/logo/index.vue +45 -0
  187. package/src/web/logo/types.ts +6 -0
  188. package/src/web/menu/index.scss +336 -0
  189. package/src/web/menu/index.ts +8 -0
  190. package/src/web/menu/menu-collapse-transition.vue +62 -0
  191. package/src/web/menu/menu-item-group.vue +27 -0
  192. package/src/web/menu/menu-item.vue +126 -0
  193. package/src/web/menu/menu.vue +459 -0
  194. package/src/web/menu/sub-menu.vue +440 -0
  195. package/src/web/menu/types.ts +66 -0
  196. package/src/web/menu/use-menu-css-var.ts +11 -0
  197. package/src/web/menu/use-menu.ts +60 -0
  198. package/src/web/menu/utils/menu-bar.ts +19 -0
  199. package/src/web/menu/utils/menu-item.ts +55 -0
  200. package/src/web/menu/utils/submenu.ts +66 -0
  201. package/src/web/multiple-select-flat/index.ts +5 -0
  202. package/src/web/multiple-select-flat/index.vue +53 -0
  203. package/src/web/multiple-select-flat/types.ts +5 -0
  204. package/src/web/multiple-tabs/index.scss +16 -0
  205. package/src/web/multiple-tabs/index.ts +5 -0
  206. package/src/web/multiple-tabs/index.vue +193 -0
  207. package/src/web/multiple-tabs/tab-content.vue +40 -0
  208. package/src/web/multiple-tabs/types.ts +3 -0
  209. package/src/web/multiple-tabs/use/index.ts +2 -0
  210. package/src/web/multiple-tabs/use/use-multiple-tabs.ts +86 -0
  211. package/src/web/multiple-tabs/use/use-tab-dropdown.ts +101 -0
  212. package/src/web/nodata/README.md +42 -0
  213. package/src/web/nodata/fail.vue +13 -0
  214. package/src/web/nodata/img/100.png +0 -0
  215. package/src/web/nodata/img/101.png +0 -0
  216. package/src/web/nodata/img/102.png +0 -0
  217. package/src/web/nodata/img/103.png +0 -0
  218. package/src/web/nodata/img/104.png +0 -0
  219. package/src/web/nodata/img/105.png +0 -0
  220. package/src/web/nodata/img/106.png +0 -0
  221. package/src/web/nodata/img/107.png +0 -0
  222. package/src/web/nodata/img/200.png +0 -0
  223. package/src/web/nodata/img/201.png +0 -0
  224. package/src/web/nodata/img/202.png +0 -0
  225. package/src/web/nodata/img/203.png +0 -0
  226. package/src/web/nodata/index.scss +37 -0
  227. package/src/web/nodata/index.ts +6 -0
  228. package/src/web/nodata/index.vue +46 -0
  229. package/src/web/nodata/types.ts +17 -0
  230. package/src/web/only-child/index.tsx +69 -0
  231. package/src/web/pagination/components/jumper.vue +49 -0
  232. package/src/web/pagination/components/next.vue +40 -0
  233. package/src/web/pagination/components/pager.vue +215 -0
  234. package/src/web/pagination/components/prev.vue +35 -0
  235. package/src/web/pagination/components/sizes.vue +76 -0
  236. package/src/web/pagination/components/total.vue +21 -0
  237. package/src/web/pagination/index.scss +231 -0
  238. package/src/web/pagination/index.ts +5 -0
  239. package/src/web/pagination/pagination.ts +363 -0
  240. package/src/web/pagination/usePagination.ts +13 -0
  241. package/src/web/popover/directive.ts +21 -0
  242. package/src/web/popover/index.scss +58 -0
  243. package/src/web/popover/index.ts +3 -0
  244. package/src/web/popover/index.vue +161 -0
  245. package/src/web/popover/types.ts +26 -0
  246. package/src/web/popper/arrow.vue +45 -0
  247. package/src/web/popper/content.vue +311 -0
  248. package/src/web/popper/index.scss +108 -0
  249. package/src/web/popper/index.ts +11 -0
  250. package/src/web/popper/popper.vue +57 -0
  251. package/src/web/popper/tokens.ts +28 -0
  252. package/src/web/popper/trigger.vue +166 -0
  253. package/src/web/popper/types.ts +49 -0
  254. package/src/web/popper/utils.ts +81 -0
  255. package/src/web/qrcode/drawCanvas.ts +32 -0
  256. package/src/web/qrcode/drawLogo.ts +82 -0
  257. package/src/web/qrcode/index.ts +5 -0
  258. package/src/web/qrcode/index.vue +107 -0
  259. package/src/web/qrcode/qrcodePlus.ts +4 -0
  260. package/src/web/qrcode/toCanvas.ts +11 -0
  261. package/src/web/qrcode/types.ts +38 -0
  262. package/src/web/result/index.scss +69 -0
  263. package/src/web/result/index.ts +3 -0
  264. package/src/web/result/index.vue +63 -0
  265. package/src/web/scrollbar/bar.vue +48 -0
  266. package/src/web/scrollbar/index.scss +91 -0
  267. package/src/web/scrollbar/index.ts +5 -0
  268. package/src/web/scrollbar/index.vue +236 -0
  269. package/src/web/scrollbar/thumb.vue +183 -0
  270. package/src/web/scrollbar/tokens.ts +10 -0
  271. package/src/web/scrollbar/types.ts +7 -0
  272. package/src/web/scrollbar/util.ts +38 -0
  273. package/src/web/select/constants.ts +13 -0
  274. package/src/web/select/index.ts +11 -0
  275. package/src/web/select/index.vue +555 -0
  276. package/src/web/select/option-group.scss +49 -0
  277. package/src/web/select/option-group.vue +97 -0
  278. package/src/web/select/option-item.scss +66 -0
  279. package/src/web/select/option.scss +32 -0
  280. package/src/web/select/option.vue +110 -0
  281. package/src/web/select/select-dropdown.scss +86 -0
  282. package/src/web/select/select-dropdown.vue +51 -0
  283. package/src/web/select/select.scss +213 -0
  284. package/src/web/select/token.ts +56 -0
  285. package/src/web/select/useOption.ts +146 -0
  286. package/src/web/select/useSelect.ts +942 -0
  287. package/src/web/select/utils.ts +5 -0
  288. package/src/web/side-menu/index.scss +66 -0
  289. package/src/web/side-menu/index.ts +4 -0
  290. package/src/web/side-menu/index.vue +228 -0
  291. package/src/web/side-menu/types.ts +20 -0
  292. package/src/web/single-select/index.scss +60 -0
  293. package/src/web/single-select/index.ts +5 -0
  294. package/src/web/single-select/index.vue +70 -0
  295. package/src/web/single-select/select@2x.png +0 -0
  296. package/src/web/single-select/types.ts +5 -0
  297. package/src/web/svg/index.ts +3 -0
  298. package/src/web/svg/index.vue +22 -0
  299. package/src/web/tabs/index.scss +579 -0
  300. package/src/web/tabs/index.ts +6 -0
  301. package/src/web/tabs/index.vue +236 -0
  302. package/src/web/tabs/tab-bar.vue +90 -0
  303. package/src/web/tabs/tab-nav.vue +403 -0
  304. package/src/web/tabs/tab-pane.vue +90 -0
  305. package/src/web/tabs/types.ts +66 -0
  306. package/src/web/tag/index.scss +182 -0
  307. package/src/web/tag/index.ts +5 -0
  308. package/src/web/tag/index.vue +78 -0
  309. package/src/web/tag/types.ts +2 -0
  310. package/src/web/tooltip/content.vue +239 -0
  311. package/src/web/tooltip/index.ts +4 -0
  312. package/src/web/tooltip/tokens.ts +21 -0
  313. package/src/web/tooltip/tooltip.vue +270 -0
  314. package/src/web/tooltip/trigger.vue +119 -0
  315. package/src/web/tooltip/types.ts +56 -0
  316. package/src/web/tooltip/utils.ts +20 -0
  317. package/src/web/transition/collapse-transition.vue +73 -0
  318. package/src/web/transition/index.ts +5 -0
  319. package/tsconfig.json +8 -0
  320. package/types/component.ts +1 -0
  321. package/types/index.d.ts +286 -0
@@ -0,0 +1,66 @@
1
+ // @ts-nocheck
2
+ import { triggerEvent } from '@vri/utils';
3
+ import { EVENT_CODE } from '@vri/constants';
4
+ import type MenuItem from './menu-item';
5
+
6
+ class SubMenu {
7
+ public subMenuItems: NodeList;
8
+ public subIndex = 0;
9
+ constructor(public parent: MenuItem, public domNode: ParentNode) {
10
+ this.subIndex = 0;
11
+ this.init();
12
+ }
13
+
14
+ init(): void {
15
+ this.subMenuItems = this.domNode.querySelectorAll('li');
16
+ this.addListeners();
17
+ }
18
+
19
+ gotoSubIndex(idx: number): void {
20
+ if (idx === this.subMenuItems.length) {
21
+ idx = 0;
22
+ } else if (idx < 0) {
23
+ idx = this.subMenuItems.length - 1;
24
+ }
25
+ (this.subMenuItems[idx] as HTMLElement).focus();
26
+ this.subIndex = idx;
27
+ }
28
+
29
+ addListeners(): void {
30
+ const parentNode = this.parent.domNode;
31
+ Array.prototype.forEach.call(this.subMenuItems, (el: Element) => {
32
+ el.addEventListener('keydown', (event: KeyboardEvent) => {
33
+ let prevDef = false;
34
+ switch (event.code) {
35
+ case EVENT_CODE.down: {
36
+ this.gotoSubIndex(this.subIndex + 1);
37
+ prevDef = true;
38
+ break;
39
+ }
40
+ case EVENT_CODE.up: {
41
+ this.gotoSubIndex(this.subIndex - 1);
42
+ prevDef = true;
43
+ break;
44
+ }
45
+ case EVENT_CODE.tab: {
46
+ triggerEvent(parentNode as HTMLElement, 'mouseleave');
47
+ break;
48
+ }
49
+ case EVENT_CODE.enter:
50
+ case EVENT_CODE.space: {
51
+ prevDef = true;
52
+ (event.currentTarget as HTMLElement).click();
53
+ break;
54
+ }
55
+ }
56
+ if (prevDef) {
57
+ event.preventDefault();
58
+ event.stopPropagation();
59
+ }
60
+ return false;
61
+ });
62
+ });
63
+ }
64
+ }
65
+
66
+ export default SubMenu;
@@ -0,0 +1,5 @@
1
+ import MultipleSelectFlat from './index.vue';
2
+
3
+ export * from './types';
4
+
5
+ export { MultipleSelectFlat };
@@ -0,0 +1,53 @@
1
+ <template>
2
+ <div :class="ns.b()">
3
+ <el-checkbox :class="ns.e('check-all')" v-model="checkAll" @change="handleCheckAllChange">全部</el-checkbox>
4
+ <el-checkbox-group v-model="checkList" @change="handleCheckedChange">
5
+ <el-checkbox v-for="item in options" :key="item.code" :label="item.code">{{ item.name }}</el-checkbox>
6
+ </el-checkbox-group>
7
+ </div>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import { useNamespace } from '../../use';
12
+ import { ref } from 'vue';
13
+ import { type MultipleSelectFlatOptions } from './types';
14
+
15
+ const ns = /* hoist-static*/ useNamespace('multiple-select-flat');
16
+ defineOptions({ name: ns.b() });
17
+
18
+ interface MultipleSelcetFlatProps {
19
+ /** 选择项列表 */
20
+ options: Array<MultipleSelectFlatOptions>;
21
+ }
22
+ const { options } = defineProps<MultipleSelcetFlatProps>();
23
+
24
+ const emit = defineEmits<{
25
+ (e: 'submit', val: string): void;
26
+ }>();
27
+
28
+ const checkAll = ref(false);
29
+ const handleCheckAllChange = (val: boolean) => {
30
+ checkList.value = val ? options.map((o) => o.code) : [];
31
+ emit('submit', checkList.value.join());
32
+ };
33
+
34
+ const checkList = ref<string[]>([]);
35
+ const handleCheckedChange = (val: string[]) => {
36
+ checkAll.value = val.length === options.length;
37
+ emit('submit', checkList.value.join());
38
+ };
39
+ </script>
40
+
41
+ <style lang="scss" scoped>
42
+ $name: 'multiple-select-flat';
43
+
44
+ @include b($name) {
45
+ @include e(check-all) {
46
+ margin-right: 30px;
47
+ }
48
+
49
+ :deep(.el-checkbox-group) {
50
+ display: inline;
51
+ }
52
+ }
53
+ </style>
@@ -0,0 +1,5 @@
1
+ export interface MultipleSelectFlatOptions {
2
+ name: string;
3
+ code: string;
4
+ [key: string]: any;
5
+ }
@@ -0,0 +1,16 @@
1
+ $name: multiple-tabs;
2
+
3
+ @include set-root-css-vars($name, $multiple-tabs);
4
+
5
+ @function getCompCssVar($value) {
6
+ @return getCssVar($name, $value);
7
+ }
8
+
9
+ @include b($name) {
10
+ background-color: getCompCssVar('bg-color');
11
+ height: getCompCssVar('height');
12
+
13
+ @include e(title) {
14
+ @include line-clamp(1);
15
+ }
16
+ }
@@ -0,0 +1,5 @@
1
+ import MultipleTabs from './index.vue';
2
+
3
+ export * from './use';
4
+
5
+ export { MultipleTabs };
@@ -0,0 +1,193 @@
1
+ <script lang="ts" setup>
2
+ import { getRouterKeyPath, listenerRouteChange, useRouterHelper } from '@vri/router';
3
+ import { useMultipleTabStore, useTabs } from '@vri/store';
4
+ import { useRefs } from '@vri/use';
5
+ import { generateCssVars } from '@vri/utils';
6
+ import hotkeys from 'hotkeys-js';
7
+ import { computed, ref, unref } from 'vue';
8
+ import type { RouteLocationNormalized, RouteMeta } from 'vue-router';
9
+ import { useRouter } from 'vue-router';
10
+ import { useNamespace } from '../../use';
11
+ import type { TabsPaneContext } from '../tabs/types';
12
+ import Tabs from './../tabs/index.vue';
13
+ import TabPane from './../tabs/tab-pane.vue';
14
+ import TabContent from './tab-content.vue';
15
+ import type { TabContentExpose } from './types';
16
+ import { initAffixTabs, useTabsDrag } from './use';
17
+
18
+ interface MultipleTabsProps {
19
+ tabsStyle?: Record<string, Numberish>;
20
+ contextMenuStyle?: Record<string, Numberish>;
21
+ canDrag?: boolean;
22
+ }
23
+
24
+ const {
25
+ tabsStyle,
26
+ contextMenuStyle,
27
+ canDrag
28
+ } = defineProps<MultipleTabsProps>();
29
+
30
+ const ns = /* hoist-static*/ useNamespace('multiple-tabs');
31
+
32
+ defineOptions({
33
+ name: ns.b()
34
+ });
35
+
36
+ const affixList = initAffixTabs();
37
+
38
+ if (canDrag) {
39
+ useTabsDrag(affixList);
40
+ }
41
+
42
+ const tabStore = useMultipleTabStore();
43
+
44
+ // active path for tab
45
+ const activePathRef = ref('');
46
+ const activeIndex = ref(0);
47
+ const fromRoute = ref();
48
+
49
+ const router = useRouter();
50
+ const { go } = useRouterHelper();
51
+
52
+ // get current tab list
53
+ const getTabsState = computed(() => {
54
+ return tabStore.getTabList.filter((item) => {
55
+ return !item.meta?.hideTab;
56
+ });
57
+ });
58
+
59
+
60
+ watchEffect(() => {
61
+ if (activePathRef.value) {
62
+ const _activeIndex = getTabsState.value.findIndex(item => {
63
+ return getRouterKeyPath(item) === activePathRef.value;
64
+ });
65
+ if (_activeIndex === -1) {
66
+ activeIndex.value = getTabsState.value?.length - 1;
67
+ } else {
68
+ activeIndex.value = _activeIndex;
69
+ }
70
+ activeIndex.value = activeIndex.value < affixList?.length ? affixList?.length - 1 : activeIndex.value;
71
+ }
72
+ });
73
+
74
+ onBeforeRouteLeave(() => {
75
+ fromRoute.value = unref(router.currentRoute);
76
+ });
77
+
78
+ listenerRouteChange((route) => {
79
+ if (!route) {
80
+ return;
81
+ }
82
+
83
+ const { meta = {} } = route;
84
+ const { currentActivePath, hideTab } = meta as RouteMeta;
85
+
86
+ const isHide = !hideTab ? null : currentActivePath;
87
+
88
+ // set current active tab value
89
+ const activePath = getRouterKeyPath(route);
90
+
91
+ if (activePathRef.value !== activePath) {
92
+ activePathRef.value = activePath;
93
+ }
94
+
95
+ if (isHide) {
96
+ // 如果当前 tab 是隐藏的,则从路由中根据 currentActivePath 寻找到此路由的信息,然后在 tabStore 添加此路由
97
+ let findParentRoute = router.getRoutes().find((item) => item.path === currentActivePath);
98
+ findParentRoute && tabStore.addTab(findParentRoute as unknown as RouteLocationNormalized, unref(fromRoute), activeIndex.value, route);
99
+ } else {
100
+ tabStore.addTab(unref(route), unref(fromRoute), activeIndex.value);
101
+ }
102
+ });
103
+
104
+ // 点击 tab 根据 tab 传入的 path 路径,跳转到对应页面
105
+ function handleClick (pane: TabsPaneContext) {
106
+ if (activePathRef.value === pane.paneName) {
107
+ return;
108
+ }
109
+ const clickTab = getTabsState.value[pane.attrs.index];
110
+ activePathRef.value = pane.paneName as string;
111
+ const hideActiveRoutePath = (clickTab?.meta?.hideActiveRoute as RouteLocationNormalized)?.fullPath;
112
+ if (hideActiveRoutePath) {
113
+ go(hideActiveRoutePath);
114
+ } else {
115
+ go(clickTab.fullPath || clickTab.path);
116
+ }
117
+ }
118
+
119
+ // click x close tab
120
+ function handleRemove (targetPath: string) {
121
+ tabStore.closeTabByKey(targetPath, router);
122
+ }
123
+
124
+ const [refs, setRefs] = useRefs<TabContentExpose>();
125
+
126
+ function handleContextMenu (data: {pane: {attrs: {index: number;};}; event: any;}) {
127
+ const _index = data.pane.attrs.index;
128
+ const _event = data.event;
129
+ refs.value[_index].handleContext(_event);
130
+ }
131
+
132
+ const _tabsStyle = computed(() => {
133
+ let initTabStyle: Record<string, Numberish> = {
134
+ padding: '4px 0 0',
135
+ 'header-height': '26px',
136
+ 'item-color': '#5C5C5C',
137
+ 'item-bg-color': '#f8f8f8',
138
+ 'font-size': '13px',
139
+ 'item-padding': '0 10px',
140
+ 'close-icon-left': '8px',
141
+ 'item-distance': '10px',
142
+ 'item-max-width': '348px',
143
+ 'header-margin': '0 0 0 8px'
144
+ };
145
+
146
+ return { ...generateCssVars(initTabStyle, 'tabs'), ...tabsStyle };
147
+ });
148
+
149
+ const { closeCurrent } = useTabs();
150
+
151
+ hotkeys('command+e, ctrl+e', function () {
152
+ closeCurrent();
153
+ return false;
154
+ });
155
+
156
+ const _contextMenuStyle = computed(() => {
157
+ return {
158
+ ...generateCssVars({
159
+ border: '1px solid #dcdfe6',
160
+ 'sub-item-height': '40px',
161
+ 'item-min-width': '150px'
162
+ }, 'menu'),
163
+ ...contextMenuStyle
164
+ };
165
+ });
166
+ </script>
167
+
168
+ <template>
169
+ <div :class="ns.b()" :style="_tabsStyle">
170
+ <tabs
171
+ v-model:model-value="activePathRef"
172
+ type="card"
173
+ @tabClick="handleClick"
174
+ @tabRemove="handleRemove"
175
+ @tabContextMenu="handleContextMenu"
176
+ :closeIconCfg="{ color: 'white'}"
177
+ >
178
+ <!--why key add index:key not update after sort -->
179
+ <template v-for="(item, index) in getTabsState" :key="getRouterKeyPath(item) + index">
180
+ <tab-pane :closable="!(item.meta?.affix)" :index="index" :name="getRouterKeyPath(item)">
181
+ <template #label>
182
+ <tab-content :contextMenuStyle="_contextMenuStyle" :affixNum="affixList?.length"
183
+ :ref="setRefs(index)" :tabItem="item" />
184
+ </template>
185
+ </tab-pane>
186
+ </template>
187
+ </tabs>
188
+ </div>
189
+ </template>
190
+
191
+ <style lang="scss">
192
+ @import './index.scss';
193
+ </style>
@@ -0,0 +1,40 @@
1
+ <script lang="ts" setup>
2
+ import { computed } from 'vue';
3
+ import { type RouteLocationNormalized } from 'vue-router';
4
+ import { useContextMenu } from '../context-menu/useContextMenu';
5
+ import type { TabContentExpose } from './types';
6
+ import { useTabDropdown } from './use';
7
+
8
+ interface Props {
9
+ tabItem: RouteLocationNormalized;
10
+ affixNum: number;
11
+ contextMenuStyle?: Record<string, Numberish>;
12
+ }
13
+
14
+ const { tabItem, affixNum, contextMenuStyle } = defineProps<Props>();
15
+
16
+ const [createContextMenu] = useContextMenu();
17
+
18
+ const getTitle = computed(() => {
19
+ return tabItem.meta && (tabItem.meta.title as string);
20
+ });
21
+
22
+ const { getDropMenuList, handleContextMenu } = useTabDropdown(tabItem, affixNum);
23
+
24
+ function handleContext(e: MouseEvent) {
25
+ handleContextMenu(tabItem)(e);
26
+ createContextMenu({
27
+ event: e,
28
+ styles: contextMenuStyle,
29
+ items: getDropMenuList.value
30
+ });
31
+ }
32
+
33
+ defineExpose<TabContentExpose>({
34
+ handleContext
35
+ });
36
+ </script>
37
+
38
+ <template>
39
+ <span :title="getTitle" class="vri-multiple-tabs__title" @contextmenu.stop="handleContext">{{ getTitle }}</span>
40
+ </template>
@@ -0,0 +1,3 @@
1
+ export type TabContentExpose = {
2
+ handleContext: (e: MouseEvent) => void;
3
+ };
@@ -0,0 +1,2 @@
1
+ export * from './use-tab-dropdown';
2
+ export * from './use-multiple-tabs';
@@ -0,0 +1,86 @@
1
+ import { useSortable } from '@vri/use';
2
+ import { arrSort, isNullOrUndefined } from '@vri/utils';
3
+ import type { SortableEvent } from 'sortablejs';
4
+ import { nextTick, ref, toRaw } from 'vue';
5
+ import type { RouteLocationNormalized } from 'vue-router';
6
+ import { useRouter } from 'vue-router';
7
+ import { useMultipleTabStore } from '@vri/store';
8
+
9
+ /**
10
+ * @description 初始化需要固定的 tab 标签
11
+ * @author wfd
12
+ * @date 2022/10/15 19:03
13
+ * @example
14
+ * @returns {string[]}
15
+ */
16
+ export function initAffixTabs(): string[] {
17
+ const affixList = ref<RouteLocationNormalized[]>([]);
18
+
19
+ const tabStore = useMultipleTabStore();
20
+ const router = useRouter();
21
+
22
+ // 过滤需要固定的标签
23
+ function filterAffixTabs(routes: RouteLocationNormalized[]) {
24
+ const tabs: RouteLocationNormalized[] = [];
25
+ routes &&
26
+ routes.forEach((route) => {
27
+ if (route.meta?.affix) {
28
+ // console.log(route, 777, toRaw(route));
29
+ tabs.push(toRaw(route));
30
+ }
31
+ });
32
+ return tabs;
33
+ }
34
+
35
+ function addAffixTabs() {
36
+ const affixTabs = filterAffixTabs(router.getRoutes() as unknown as RouteLocationNormalized[]);
37
+
38
+ arrSort(affixTabs, ['meta', 'order']);
39
+
40
+ affixList.value = affixTabs;
41
+
42
+ for (const tab of affixTabs) {
43
+ tabStore.addTab({
44
+ meta: tab.meta,
45
+ name: tab.name,
46
+ path: tab.path
47
+ } as RouteLocationNormalized);
48
+ }
49
+ }
50
+
51
+ let isAddAffix = false;
52
+
53
+ // 开始执行固定标签
54
+ if (!isAddAffix) {
55
+ addAffixTabs();
56
+ isAddAffix = true;
57
+ }
58
+ return affixList.value.map((item) => item.meta?.title).filter(Boolean) as string[];
59
+ }
60
+
61
+ export function useTabsDrag(affixTextList: string[]) {
62
+ const tabStore = useMultipleTabStore();
63
+ nextTick(() => {
64
+ const el = document.querySelectorAll('.vri-tabs__nav')?.[0] as HTMLElement;
65
+
66
+ const { initSortable } = useSortable(el, {
67
+ draggable: '.is-closable',
68
+ filter: (e) => {
69
+ const text = (e?.target as HTMLElement)?.innerText;
70
+ if (!text) return false;
71
+ return affixTextList.includes(text);
72
+ },
73
+
74
+ onEnd: (evt: SortableEvent) => {
75
+ const { oldIndex, newIndex } = evt;
76
+
77
+ if (isNullOrUndefined(oldIndex) || isNullOrUndefined(newIndex) || oldIndex === newIndex) {
78
+ return;
79
+ }
80
+
81
+ tabStore.sortTabs(oldIndex, newIndex);
82
+ }
83
+ });
84
+ initSortable();
85
+ });
86
+ }
@@ -0,0 +1,101 @@
1
+ import { getRouterKeyPath } from '@vri/router';
2
+ import { computed, reactive, unref } from 'vue';
3
+ import { type RouteLocationNormalized } from 'vue-router';
4
+ import { type ContextMenuItem } from '../../context-menu/types';
5
+ import { useMultipleTabStore, useTabs } from '@vri/store';
6
+
7
+ export function useTabDropdown(tabItem: RouteLocationNormalized, affixNum: number) {
8
+ // 记录当前点击多 tab 的索引与 tab 的信息
9
+ const state = reactive({
10
+ current: null as Nullable<RouteLocationNormalized>,
11
+ currentIndex: 0
12
+ });
13
+
14
+ const tabStore = useMultipleTabStore();
15
+ const { refreshPage, closeAll, close, closeLeft, closeOther, closeRight, newWinTab } = useTabs();
16
+
17
+ /**
18
+ * @description 多 tab 菜单列表
19
+ */
20
+ const getDropMenuList = computed(() => {
21
+ if (!tabItem) {
22
+ return;
23
+ }
24
+ const { meta } = tabItem;
25
+
26
+ const index = state.currentIndex;
27
+
28
+ // 关闭左侧标签页
29
+ const closeLeftDisabled = index === 0 || index <= affixNum;
30
+ // 关闭右侧标签页
31
+ const closeRightDisabled = tabStore.getTabList.length <= affixNum || (index === tabStore.getTabList.length - 1 && tabStore.getLastDragEndIndex >= 0);
32
+ // 关闭其他
33
+ const closeOtherDisabled = tabStore.getTabList.length === affixNum || (tabStore.getTabList.length === affixNum + 1 && index === affixNum);
34
+ // 关闭所有
35
+ const disabled = tabStore.getTabList.length === affixNum;
36
+
37
+ const dropMenuList: ContextMenuItem[] = [
38
+ {
39
+ iconCfg: { icon: 'vi-refresh' },
40
+ text: '刷新',
41
+ handler: () => refreshPage(tabItem)
42
+ },
43
+ {
44
+ iconCfg: { icon: 'vi-new-page' },
45
+ text: '新页面打开',
46
+ handler: () => newWinTab(tabItem),
47
+ divider: true
48
+ },
49
+ {
50
+ iconCfg: { icon: 'vi-close' },
51
+ text: '关闭标签页',
52
+ disabled: !!meta?.affix || disabled,
53
+ handler: () => close(tabItem)
54
+ },
55
+ {
56
+ iconCfg: { icon: 'vi-close-left' },
57
+ text: '关闭左侧标签页',
58
+ disabled: closeLeftDisabled,
59
+ handler: () => closeLeft(tabItem)
60
+ },
61
+ {
62
+ iconCfg: { icon: 'vi-close-right' },
63
+ text: '关闭右侧标签页',
64
+ disabled: closeRightDisabled,
65
+ divider: true,
66
+ handler: () => closeRight(tabItem)
67
+ },
68
+ {
69
+ iconCfg: { icon: 'vi-close-other' },
70
+ text: '关闭其它标签页',
71
+ disabled: closeOtherDisabled,
72
+ handler: () => closeOther(tabItem)
73
+ },
74
+ {
75
+ iconCfg: { icon: 'vi-close-all' },
76
+ text: '关闭所有标签页',
77
+ disabled,
78
+ handler: () => closeAll()
79
+ }
80
+ ];
81
+
82
+ return dropMenuList;
83
+ });
84
+
85
+ // 点击 tab 右侧菜单事件
86
+ function handleContextMenu(tabItem: RouteLocationNormalized) {
87
+ return (e: Event) => {
88
+ if (!tabItem) {
89
+ return;
90
+ }
91
+ e?.preventDefault();
92
+
93
+ // 获取当前点击的 tab 在多 tab 列表中的位置
94
+ const index = tabStore.getTabList.findIndex((tab) => getRouterKeyPath(tab) === getRouterKeyPath(tabItem));
95
+ state.current = tabItem;
96
+ state.currentIndex = index;
97
+ };
98
+ }
99
+
100
+ return { getDropMenuList, handleContextMenu };
101
+ }
@@ -0,0 +1,42 @@
1
+ # nodata 无数据组件
2
+
3
+ ## Usage
4
+
5
+ ```html
6
+ <vri-nodata :type="100"></vri-nodata>
7
+
8
+ <vri-nodata :type="104">
9
+ 加载失败,请
10
+ <span style="color: #0171f6; cursor: pointer" @click="refreshPage()">点击</span>
11
+ 重试
12
+ </vri-nodata>
13
+ ```
14
+
15
+ ## Props
16
+
17
+ | 属性名 | 说明 | 类型 | 是否必传 |
18
+ | ------ | ---------- | ------------- | -------- |
19
+ | type | 无数据类型 | string/number | 是 |
20
+
21
+ ### type enum
22
+
23
+ | type | 说明 | 级别 |
24
+ | ---- | ------------------------------ | ------ |
25
+ | 100 | 暂无数据 | 页面级 |
26
+ | 101 | 暂无相关数据 | 页面级 |
27
+ | 102 | 没有搜索结果?换个关键词试试 | 页面级 |
28
+ | 103 | 此筛选条件下无结果 | 页面级 |
29
+ | 104 | 加载失败,请刷新重试 | 页面级 |
30
+ | 105 | 页面打不开?刷新下试试 | 全局级 |
31
+ | 106 | 抱歉,您访问的页面报错了 | 全局级 |
32
+ | 107 | 网络错误,请检查网络连接后重试 | 页面级 |
33
+ | 200 | 暂无数据 | 局部级 |
34
+ | 201 | 暂无相关数据 | 局部级 |
35
+ | 202 | 没有搜索结果?换个关键词试试 | 局部级 |
36
+ | 203 | 此筛选条件下无结果 | 局部级 |
37
+
38
+ ## Slot
39
+
40
+ | 插槽名 | 说明 |
41
+ | ------ | --------------------- |
42
+ | - | 图片下方文字/内容插槽 |
@@ -0,0 +1,13 @@
1
+ <script setup lang="ts">
2
+ import NoData from './index.vue';
3
+
4
+ const emit = defineEmits(['click']);
5
+ </script>
6
+
7
+ <template>
8
+ <no-data type="104">
9
+ 加载失败,请
10
+ <span style="color: #0171f6;cursor: pointer" @click="emit('click');">点击</span>
11
+ 重试
12
+ </no-data>
13
+ </template>
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file