@skyfox2000/webui 1.0.13 → 1.2.0

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 (162) hide show
  1. package/lib/assets/modules/file-upload-CBUcsUnR.js +170 -0
  2. package/lib/assets/modules/form-validate-CgX7aR7T.js +297 -0
  3. package/lib/assets/modules/index-Civhd8xG.js +112 -0
  4. package/lib/assets/modules/index-DQMdt51R.js +726 -0
  5. package/lib/assets/modules/{index-BEWJ_qAH.js → index-DmWrkTXX.js} +1 -1
  6. package/lib/assets/modules/{menuTabs-BXdbFZor.js → menuTabs-BRYvFWA-.js} +131 -121
  7. package/lib/assets/modules/settingInfo-BZakNKIN.js +999 -0
  8. package/lib/assets/modules/uploadList-B7XoxGOh.js +278 -0
  9. package/lib/components/common/icon/index.vue.d.ts +1 -1
  10. package/lib/components/content/dialog/index.vue.d.ts +1 -1
  11. package/lib/components/content/drawer/index.vue.d.ts +1 -1
  12. package/lib/components/content/form/index.vue.d.ts +1 -1
  13. package/lib/components/content/search/index.vue.d.ts +1 -1
  14. package/lib/components/content/table/index.vue.d.ts +1 -1
  15. package/lib/components/content/table/tableOperate.vue.d.ts +1 -1
  16. package/lib/components/content/toolbar/icontool.vue.d.ts +1 -1
  17. package/lib/components/content/toolbar/index.vue.d.ts +1 -1
  18. package/lib/components/content/tree/index.vue.d.ts +1 -1
  19. package/lib/components/form/transfer/transferTable.vue.d.ts +1 -1
  20. package/lib/components/form/treeSelect/index.vue.d.ts +1 -1
  21. package/lib/components/form/upload/uploadList.vue.d.ts +1 -1
  22. package/lib/const/options.d.ts +32 -0
  23. package/lib/directives/enter-submit.d.ts +4 -0
  24. package/lib/directives/index.d.ts +2 -0
  25. package/lib/directives/permission.d.ts +5 -0
  26. package/lib/es/AceEditor/index.js +9 -8
  27. package/lib/es/BasicLayout/index.js +28 -24
  28. package/lib/es/Error403/index.js +15 -10
  29. package/lib/es/Error404/index.js +15 -10
  30. package/lib/es/ExcelForm/index.js +380 -175
  31. package/lib/es/UploadForm/index.js +23 -20
  32. package/lib/index.d.ts +42 -2
  33. package/lib/router/index.d.ts +16 -0
  34. package/lib/stores/appInfo.d.ts +34 -0
  35. package/lib/stores/hostInfo.d.ts +9 -0
  36. package/lib/stores/pageInfo.d.ts +18 -0
  37. package/lib/stores/pinia.d.ts +3 -0
  38. package/lib/stores/settingInfo.d.ts +8 -0
  39. package/lib/stores/userInfo.d.ts +21 -0
  40. package/lib/typings/data.d.ts +80 -0
  41. package/lib/typings/form.d.ts +171 -0
  42. package/lib/typings/menu.d.ts +7 -0
  43. package/lib/typings/option.d.ts +175 -0
  44. package/lib/typings/page.d.ts +69 -0
  45. package/lib/typings/table.d.ts +181 -0
  46. package/lib/typings/tools.d.ts +130 -0
  47. package/lib/typings/tree.d.ts +72 -0
  48. package/lib/typings/upload.d.ts +161 -0
  49. package/lib/typings/urls.d.ts +69 -0
  50. package/lib/utils/cache.d.ts +23 -0
  51. package/lib/utils/data.d.ts +6 -0
  52. package/lib/utils/download.d.ts +4 -0
  53. package/lib/utils/eventbus.d.ts +16 -0
  54. package/lib/utils/export-table.d.ts +12 -0
  55. package/lib/utils/file-upload.d.ts +15 -0
  56. package/lib/utils/form-excel.d.ts +30 -0
  57. package/lib/utils/form-validate.d.ts +29 -0
  58. package/lib/utils/form.d.ts +9 -0
  59. package/lib/utils/icon-loader.d.ts +125 -0
  60. package/lib/utils/isEmpty.d.ts +1 -0
  61. package/lib/utils/main-openapis.d.ts +9 -0
  62. package/lib/utils/menu.d.ts +6 -0
  63. package/lib/utils/options.d.ts +10 -0
  64. package/lib/utils/page.d.ts +25 -0
  65. package/lib/utils/table.d.ts +21 -0
  66. package/lib/utils/tools.d.ts +18 -0
  67. package/lib/utils/tree.d.ts +3 -0
  68. package/lib/vite-env.d.ts +8 -0
  69. package/lib/webui.css +1 -1
  70. package/lib/webui.es.js +1020 -854
  71. package/package.json +7 -6
  72. package/src/components/common/icon/appicon.vue +1 -1
  73. package/src/components/common/icon/fullscreen.vue +2 -1
  74. package/src/components/common/icon/index.vue +1 -1
  75. package/src/components/common/icon/layoutIcon.vue +1 -1
  76. package/src/components/common/icon/projectIcon.vue +1 -1
  77. package/src/components/common/icon/toolIcon.vue +1 -1
  78. package/src/components/content/dialog/excelForm.vue +2 -2
  79. package/src/components/content/dialog/index.vue +1 -1
  80. package/src/components/content/dialog/uploadForm.vue +7 -6
  81. package/src/components/content/drawer/index.vue +43 -18
  82. package/src/components/content/form/formItem.vue +1 -1
  83. package/src/components/content/form/index.vue +1 -1
  84. package/src/components/content/search/index.vue +1 -1
  85. package/src/components/content/search/searchItem.vue +1 -1
  86. package/src/components/content/table/index.vue +8 -5
  87. package/src/components/content/table/tableOperate.vue +8 -4
  88. package/src/components/content/toolbar/icontool.vue +2 -2
  89. package/src/components/content/toolbar/index.vue +9 -5
  90. package/src/components/content/tree/index.vue +1 -1
  91. package/src/components/error/error403.vue +2 -2
  92. package/src/components/error/error404.vue +2 -2
  93. package/src/components/form/autoComplete/index.vue +1 -1
  94. package/src/components/form/cascader/index.vue +1 -2
  95. package/src/components/form/checkbox/index.vue +11 -5
  96. package/src/components/form/datePicker/index.vue +1 -1
  97. package/src/components/form/input/index.vue +1 -1
  98. package/src/components/form/input/inputNumber.vue +1 -1
  99. package/src/components/form/input/inputPassword.vue +1 -1
  100. package/src/components/form/radio/index.vue +1 -1
  101. package/src/components/form/radio/radioStatus.vue +1 -1
  102. package/src/components/form/rangePicker/index.vue +1 -1
  103. package/src/components/form/select/index.vue +1 -1
  104. package/src/components/form/switch/index.vue +7 -3
  105. package/src/components/form/textarea/index.vue +1 -1
  106. package/src/components/form/transfer/index.vue +1 -1
  107. package/src/components/form/transfer/transferTable.vue +42 -22
  108. package/src/components/form/treeSelect/index.vue +2 -3
  109. package/src/components/form/upload/uploadList.vue +1 -1
  110. package/src/components/layout/breadcrumb/index.vue +1 -1
  111. package/src/components/layout/header/headerExits.vue +1 -1
  112. package/src/components/layout/header/index.vue +1 -1
  113. package/src/components/layout/header/user.vue +2 -1
  114. package/src/components/layout/menu/index.vue +9 -3
  115. package/src/components/layout/menu/menuTabs.vue +10 -12
  116. package/src/components/layout/page/basicLayout.vue +1 -1
  117. package/src/const/options.ts +114 -0
  118. package/src/directives/enter-submit.ts +13 -0
  119. package/src/directives/index.ts +26 -0
  120. package/src/directives/permission.ts +144 -0
  121. package/src/index.ts +201 -0
  122. package/src/router/index.ts +196 -0
  123. package/src/stores/appInfo.ts +471 -0
  124. package/src/stores/hostInfo.ts +117 -0
  125. package/src/stores/pageInfo.ts +131 -0
  126. package/src/stores/pinia.ts +10 -0
  127. package/src/stores/settingInfo.ts +53 -0
  128. package/src/stores/userInfo.ts +392 -0
  129. package/src/typings/data.d.ts +81 -0
  130. package/src/typings/form.d.ts +172 -0
  131. package/src/typings/menu.d.ts +7 -0
  132. package/src/typings/option.d.ts +177 -0
  133. package/src/typings/page.d.ts +70 -0
  134. package/src/typings/table.d.ts +182 -0
  135. package/src/typings/tools.d.ts +131 -0
  136. package/src/typings/tree.d.ts +73 -0
  137. package/src/typings/upload.d.ts +162 -0
  138. package/src/typings/urls.d.ts +70 -0
  139. package/src/utils/cache.ts +175 -0
  140. package/src/utils/data.ts +189 -0
  141. package/src/utils/download.ts +80 -0
  142. package/src/utils/eventbus.ts +78 -0
  143. package/src/utils/export-table.ts +155 -0
  144. package/src/utils/file-upload.ts +304 -0
  145. package/src/utils/form-excel.ts +523 -0
  146. package/src/utils/form-validate.ts +368 -0
  147. package/src/utils/form.ts +188 -0
  148. package/src/utils/icon-loader.ts +412 -0
  149. package/src/utils/isEmpty.ts +18 -0
  150. package/src/utils/main-openapis.ts +72 -0
  151. package/src/utils/menu.ts +89 -0
  152. package/src/utils/options.ts +324 -0
  153. package/src/utils/page.ts +262 -0
  154. package/src/utils/table.ts +274 -0
  155. package/src/utils/tools.ts +362 -0
  156. package/src/utils/tree.ts +28 -0
  157. package/tsconfig.json +1 -8
  158. package/vite.config.ts +7 -4
  159. package/lib/assets/modules/index-BahGnrAq.js +0 -415
  160. package/lib/assets/modules/index-BoKIa2sr.js +0 -109
  161. package/lib/assets/modules/index-D47Ci-T3.js +0 -107
  162. package/lib/assets/modules/uploadList-Dzlg47V0.js +0 -182
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { ref, onMounted, onUnmounted } from 'vue';
3
- import { formValidate, useInputFactory, OptionItemProps, loadOption, unloadOption } from '@skyfox2000/webbase';
3
+ import { formValidate, useInputFactory, OptionItemProps, loadOption, unloadOption } from '@/index';
4
4
  import { Switch } from 'ant-design-vue';
5
5
  import message from 'vue-m-message';
6
6
 
@@ -47,7 +47,11 @@ onUnmounted(() => {
47
47
  <template>
48
48
  <Switch
49
49
  v-if="switchOptions.length === 2"
50
- :class="[errInfo?.errClass === 'error' ? 'error !border-red-300 shadow-[0_0_3px_0px_#ff4d4f]' : '', 'bg-blue-300', 'w-[58px]']"
50
+ :class="[
51
+ errInfo?.errClass === 'error' ? 'error !border-red-300 shadow-[0_0_3px_0px_#ff4d4f]' : '',
52
+ 'bg-blue-300',
53
+ 'w-[58px]',
54
+ ]"
51
55
  :checkedChildren="switchOptions[0].label"
52
56
  :checkedValue="switchOptions[0].value"
53
57
  :unCheckedChildren="switchOptions[1].label"
@@ -55,4 +59,4 @@ onUnmounted(() => {
55
59
  @change="onChange"
56
60
  v-bind="$attrs"
57
61
  />
58
- </template>
62
+ </template>
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { formValidate, useInputFactory } from '@skyfox2000/webbase';
2
+ import { formValidate, useInputFactory } from '@/index';
3
3
  import { Textarea } from 'ant-design-vue';
4
4
 
5
5
  const { editorCtrl, labelText, errInfo } = useInputFactory();
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { ref, onMounted, watch } from 'vue';
3
- import { AnyControl, doQuery, formValidate, OptionItemProps, useInputFactory } from '@skyfox2000/webbase';
3
+ import { AnyControl, doQuery, formValidate, OptionItemProps, useInputFactory } from '@/index';
4
4
  import { Transfer } from 'ant-design-vue';
5
5
  import { IUrlInfo, ReqParams } from '@skyfox2000/fapi';
6
6
  const props = defineProps<{
@@ -2,7 +2,7 @@
2
2
  import Transfer from './index.vue';
3
3
  import { Table } from 'ant-design-vue';
4
4
  import { AnyData } from '@skyfox2000/fapi';
5
- import { doQuery, GridControl, PrimaryKey } from '@skyfox2000/webbase';
5
+ import { doQuery, GridControl, PrimaryKey } from '@/index';
6
6
  import { onMounted, PropType, ref, watch } from 'vue';
7
7
  const props = defineProps({
8
8
  /**
@@ -92,33 +92,53 @@ onMounted(async () => {
92
92
  });
93
93
  </script>
94
94
  <template>
95
- <Transfer :data-source="transferData" :row-key="(record: AnyData) => record[primaryKey]" v-model:value="targetKeys"
95
+ <Transfer
96
+ :data-source="transferData"
97
+ :row-key="(record: AnyData) => record[primaryKey]"
98
+ v-model:value="targetKeys"
96
99
  :list-style="{
97
100
  width: '300px',
98
101
  height: '500px',
99
- }" :show-select-all="false" :show-search="true" :filter-option="(inputValue: string, item: AnyData) => {
100
- for (const column of props.gridCtrl.columns.value) {
101
- if (item[column.dataIndex].toString().indexOf(inputValue) !== -1) {
102
- return true;
102
+ }"
103
+ :show-select-all="false"
104
+ :show-search="true"
105
+ :filter-option="
106
+ (inputValue: string, item: AnyData) => {
107
+ for (const column of props.gridCtrl.columns.value) {
108
+ if (item[column.dataIndex].toString().indexOf(inputValue) !== -1) {
109
+ return true;
110
+ }
103
111
  }
112
+ return false;
104
113
  }
105
- return false;
106
- }
107
- " v-bind="$attrs">
114
+ "
115
+ v-bind="$attrs"
116
+ >
108
117
  <template #children="{ filteredItems, onItemSelectAll, onItemSelect, selectedKeys }">
109
- <Table :columns="gridCtrl.columns.value" :row-key="primaryKey" :row-selection="getRowSelection({
110
- disabled: false,
111
- selectedKeys,
112
- onItemSelectAll,
113
- onItemSelect,
114
- })
115
- " :bordered="false" size="small" :data-source="filteredItems" :scroll="{ x: 300 }" :custom-row="(record) => ({
116
- onClick: () => {
117
- const key = record[primaryKey];
118
- onItemSelect(key, !selectedKeys.includes(key));
119
- },
120
- })
121
- " />
118
+ <Table
119
+ :columns="gridCtrl.columns.value"
120
+ :row-key="primaryKey"
121
+ :row-selection="
122
+ getRowSelection({
123
+ disabled: false,
124
+ selectedKeys,
125
+ onItemSelectAll,
126
+ onItemSelect,
127
+ })
128
+ "
129
+ :bordered="false"
130
+ size="small"
131
+ :data-source="filteredItems"
132
+ :scroll="{ x: 300 }"
133
+ :custom-row="
134
+ (record) => ({
135
+ onClick: () => {
136
+ const key = record[primaryKey];
137
+ onItemSelect(key, !selectedKeys.includes(key));
138
+ },
139
+ })
140
+ "
141
+ />
122
142
  </template>
123
143
  </Transfer>
124
144
  </template>
@@ -1,9 +1,8 @@
1
1
  <script lang="ts" setup>
2
2
  import { ref, watch, onMounted, PropType } from 'vue';
3
3
  import { TreeSelect } from 'ant-design-vue';
4
- import { queryTree } from '@skyfox2000/webbase';
5
- import type { SelectValue, TreeControl, TreeNode } from '@skyfox2000/webbase';
6
- import { useInputFactory } from '@skyfox2000/webbase';
4
+ import type { SelectValue, TreeControl, TreeNode } from '@/index';
5
+ import { queryTree, useInputFactory } from '@/index';
7
6
  import { fieldMapping } from '@skyfox2000/fapi';
8
7
 
9
8
  const props = defineProps({
@@ -4,7 +4,7 @@ import { computed, ref, watch } from 'vue';
4
4
  import message from 'vue-m-message';
5
5
  import type { UploadProps } from 'ant-design-vue';
6
6
  import { Upload, Progress, Tag } from 'ant-design-vue';
7
- import { UploadFile, UploadStatus, donwloadFromMinio, path } from '@skyfox2000/webbase';
7
+ import { UploadFile, UploadStatus, donwloadFromMinio, path } from '@/index';
8
8
  import { IUrlInfo } from '@skyfox2000/fapi';
9
9
 
10
10
  export interface UploadListProps {
@@ -2,7 +2,7 @@
2
2
  import { onMounted, watch } from 'vue';
3
3
  import { Breadcrumb, theme } from 'ant-design-vue';
4
4
  import { ToolIcon } from '../../common';
5
- import { BreadcrumbRoute, showBreadcrumb, crumbs, usePageInfo } from '@skyfox2000/webbase';
5
+ import { BreadcrumbRoute, showBreadcrumb, crumbs, usePageInfo } from '@/index';
6
6
 
7
7
  const { useToken } = theme;
8
8
  const { token } = useToken();
@@ -1,9 +1,9 @@
1
1
  <script setup lang="ts">
2
2
  import { ref } from 'vue';
3
3
  import { Modal, Flex } from 'ant-design-vue';
4
- import { useUserInfo } from '@skyfox2000/webbase';
5
4
  import { mainAppApis } from '@skyfox2000/microbase';
6
5
  import { ToolIcon } from '../../common';
6
+ import { useUserInfo } from '@/index';
7
7
 
8
8
  const userInfoStore = useUserInfo();
9
9
 
@@ -1,6 +1,6 @@
1
1
  <script lang="ts" setup>
2
2
  import { LayoutHeader, theme, Space } from 'ant-design-vue';
3
- import { useSettingInfo } from '@skyfox2000/webbase';
3
+ import { useSettingInfo } from '@/index';
4
4
  import { ToolIcon } from '../../common';
5
5
  import Breadcrumb from '../breadcrumb/index.vue';
6
6
  import HeaderExits from './headerExits.vue';
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
+ import { useUserInfo } from '@/index';
2
3
  import { Tooltip, AppIcon } from '../../common';
3
- import { useUserInfo } from '@skyfox2000/webbase';
4
+
4
5
  const userInfo = useUserInfo().userInfo;
5
6
  </script>
6
7
  <template>
@@ -2,7 +2,7 @@
2
2
  import { nextTick, onMounted, reactive, ref, watch } from 'vue';
3
3
  import { ItemType, Menu } from 'ant-design-vue';
4
4
  import type { MenuProps } from 'ant-design-vue';
5
- import { AppRouter, initMenu, useSettingInfo, useAppInfo, usePageInfo } from '@skyfox2000/webbase';
5
+ import { AppRouter, initMenu, useSettingInfo, useAppInfo, usePageInfo } from '@/index';
6
6
 
7
7
  import { ProjectIcon } from '../../common';
8
8
 
@@ -58,7 +58,13 @@ onMounted(() => {
58
58
  });
59
59
  </script>
60
60
  <template>
61
- <Menu v-model:openKeys="showOpenKeys" v-model:selectedKeys="selectedKeys" mode="inline" theme="dark"
62
- :items="menuData" @click="onMenuClick">
61
+ <Menu
62
+ v-model:openKeys="showOpenKeys"
63
+ v-model:selectedKeys="selectedKeys"
64
+ mode="inline"
65
+ theme="dark"
66
+ :items="menuData"
67
+ @click="onMenuClick"
68
+ >
63
69
  </Menu>
64
70
  </template>
@@ -1,26 +1,24 @@
1
1
  <script setup lang="ts">
2
2
  import { Tabs, TabPane, theme } from 'ant-design-vue';
3
- import { useAppInfo, usePageInfo } from '@skyfox2000/webbase';
4
- // import { useRouter } from 'vue-router';
3
+ import { useAppInfo, usePageInfo, AppRouter } from '@/index';
5
4
  import { ToolIcon, Tooltip } from '../../common';
6
- // import { watch } from 'vue';
5
+ import { watch } from 'vue';
7
6
 
8
7
  const { useToken } = theme;
9
8
  const { token } = useToken();
10
9
 
11
10
  const pageInfoStore = usePageInfo();
12
- // const router = useRouter();
13
11
 
14
12
  // 通过路由设置当前激活页签
15
13
  // 避免通过浏览器后退按钮,导致页签不更新
16
- // watch(
17
- // () => router.currentRoute.value.path,
18
- // (newVal) => {
19
- // if (newVal !== pageInfoStore.TabActive) {
20
- // pageInfoStore.setTabActive(newVal);
21
- // }
22
- // },
23
- // );
14
+ watch(
15
+ () => AppRouter.currentRoute.value.path,
16
+ (newVal) => {
17
+ if (newVal !== pageInfoStore.TabActive) {
18
+ pageInfoStore.setTabActive(newVal);
19
+ }
20
+ },
21
+ );
24
22
 
25
23
  const onTabClicked = (tabKey: any) => {
26
24
  useAppInfo().push(tabKey as string);
@@ -7,7 +7,7 @@ import Menu from '../menu/index.vue';
7
7
  import Header from '../header/index.vue';
8
8
  import MenuTabs from '../menu/menuTabs.vue';
9
9
  import AppIcon from '../../common/icon/appicon.vue';
10
- import { useAppInfo, usePageInfo, useSettingInfo } from '@skyfox2000/webbase';
10
+ import { useAppInfo, usePageInfo, useSettingInfo } from '@/index';
11
11
  import message from 'vue-m-message';
12
12
 
13
13
  const props = defineProps<{ routes: any }>();
@@ -0,0 +1,114 @@
1
+ /**
2
+ * 静态选项
3
+ */
4
+ export class OPTIONS {
5
+ private static dict: Record<string, Record<string, any>[]> = {};
6
+ static Keys = {
7
+ EnableDisable: 'EnableDisable',
8
+ SuccessResult: 'SuccessResult',
9
+ YesNo: 'YesNo',
10
+ MaleFemale: 'MaleFemale',
11
+ };
12
+
13
+ /**
14
+ * 静态选择项列表
15
+ * @param key 名称
16
+ * @returns
17
+ */
18
+ static getOptions = (key: string) => {
19
+ return OPTIONS.dict[key];
20
+ };
21
+ /**
22
+ * 静态选择项对象
23
+ * @param key 名称
24
+ * @param value 值
25
+ * @returns
26
+ */
27
+ static getOptionItem = (key: string, value: string | number) => {
28
+ return OPTIONS.dict[key].find((item) => item.value === value);
29
+ };
30
+ /**
31
+ * 设置静态选择项
32
+ * @param key 名称
33
+ * @param list 列表
34
+ */
35
+ static setOptions = (key: string, list: Record<string, any>[]) => {
36
+ OPTIONS.dict[key] = list;
37
+ };
38
+ /**
39
+ * 启用/停用选项
40
+ * - 启用 1
41
+ * - 停用 0
42
+ */
43
+ static EnableDisable = [
44
+ {
45
+ label: '启用',
46
+ text: '✅ 启用',
47
+ value: 1,
48
+ },
49
+ {
50
+ label: '停用',
51
+ text: '🚫 停用',
52
+ value: 0,
53
+ },
54
+ ];
55
+
56
+ /**
57
+ * 成功/失败选项
58
+ * - 成功 1
59
+ * - 失败 0
60
+ */
61
+ static SuccessResult = [
62
+ {
63
+ label: '成功',
64
+ text: '✅ 成功',
65
+ value: 1,
66
+ },
67
+ {
68
+ label: '失败',
69
+ text: '🚫 失败',
70
+ value: 0,
71
+ },
72
+ ];
73
+
74
+ /**
75
+ * 是/否选项
76
+ * - 是 1
77
+ * - 否 0
78
+ */
79
+ static YesNo = [
80
+ {
81
+ label: '是',
82
+ text: '✅ 是',
83
+ value: 1,
84
+ },
85
+ {
86
+ label: '否',
87
+ text: '❎ 否',
88
+ value: 0,
89
+ },
90
+ ];
91
+
92
+ /**
93
+ * 男/女选项
94
+ * - 男 M
95
+ * - 女 F
96
+ */
97
+ static MaleFemale = [
98
+ {
99
+ label: '男',
100
+ text: '男 👨',
101
+ value: 'M',
102
+ },
103
+ {
104
+ label: '女',
105
+ text: '女 👩',
106
+ value: 'F',
107
+ },
108
+ ];
109
+ }
110
+
111
+ OPTIONS.setOptions('EnableDisable', OPTIONS.EnableDisable);
112
+ OPTIONS.setOptions('SuccessResult', OPTIONS.SuccessResult);
113
+ OPTIONS.setOptions('YesNo', OPTIONS.YesNo);
114
+ OPTIONS.setOptions('MaleFemale', OPTIONS.MaleFemale);
@@ -0,0 +1,13 @@
1
+ // 创建自定义指令监听回车键
2
+ export const enterSubmit = {
3
+ mounted: (el: HTMLElement, binding: any) => {
4
+ el.addEventListener('keydown', (e) => {
5
+ if (e.key === 'Enter') {
6
+ binding.value();
7
+ }
8
+ });
9
+ },
10
+ unmounted: (el: HTMLElement) => {
11
+ el.removeEventListener('keydown', () => {});
12
+ },
13
+ };
@@ -0,0 +1,26 @@
1
+ import { App } from 'vue';
2
+ import { vAuth } from './permission';
3
+ import { enterSubmit } from './enter-submit';
4
+
5
+ // 定义指令映射表,方便管理
6
+ const directives = {
7
+ auth: vAuth,
8
+ submit: enterSubmit,
9
+ };
10
+
11
+ /**
12
+ * 初始化所有自定义指令
13
+ * @param app Vue 应用实例
14
+ * @param customs 自定义需要注册的指令,不传则注册全部
15
+ */
16
+ export const initDirective = (app: App<Element>, customs?: string[]) => {
17
+ const directivesToRegister = customs || Object.keys(directives);
18
+
19
+ directivesToRegister.forEach((name) => {
20
+ if (name in directives) {
21
+ app.directive(name, directives[name as keyof typeof directives]);
22
+ }
23
+ });
24
+
25
+ return app;
26
+ };
@@ -0,0 +1,144 @@
1
+ import { useUserInfo } from '@/index';
2
+ import { isEmpty } from '@/utils/isEmpty';
3
+ import { EnvConfig } from '@skyfox2000/microbase';
4
+ import { DirectiveBinding, VNode } from 'vue';
5
+
6
+ /**
7
+ * 组件行为类型
8
+ */
9
+ type BehaviorType = 'remove' | 'disable';
10
+
11
+ /**
12
+ * 权限参数类型
13
+ */
14
+ interface PermissionParams {
15
+ url: string;
16
+ role?: string | string[];
17
+ permit?: string;
18
+ behavior?: BehaviorType;
19
+ }
20
+
21
+ /**
22
+ * 处理组件显示行为
23
+ * @param el 组件元素
24
+ * @param vnode Vue虚拟节点
25
+ * @param hasPermission 是否有权限
26
+ * @param behavior 权限控制行为
27
+ */
28
+ const handleElementVisibility = (
29
+ el: HTMLElement,
30
+ vnode: VNode,
31
+ hasPermission: boolean,
32
+ behavior: BehaviorType = 'remove',
33
+ ) => {
34
+ if (!hasPermission) {
35
+ if (behavior === 'disable') {
36
+ // 获取组件实例
37
+ const component = vnode.component;
38
+ if (component) {
39
+ // 设置组件的 disabled 属性
40
+ component.props.disabled = true;
41
+ } else if (vnode.el) {
42
+ // 处理原生元素
43
+ el.setAttribute('disabled', 'disabled');
44
+ (el as HTMLButtonElement).disabled = true;
45
+ } else {
46
+ // 原生HTML元素
47
+ // 处理原生元素
48
+ el.setAttribute('disabled', 'disabled');
49
+ (el as HTMLButtonElement).disabled = true;
50
+ }
51
+ // 添加禁用样式
52
+ el.classList.add('disabled');
53
+ } else {
54
+ // 处理移除逻辑
55
+ const comment = document.createComment('No Permission');
56
+ const parent = el.parentNode;
57
+ if (parent) {
58
+ // 如果是组件,需要处理组件的显示状态
59
+ const component = vnode.component;
60
+ if (component) {
61
+ // 通过 v-show 来控制组件的显示
62
+ component.props.style = { display: 'none' };
63
+ } else {
64
+ parent.replaceChild(comment, el);
65
+ }
66
+ }
67
+ }
68
+ }
69
+ };
70
+
71
+ /**
72
+ * 检查权限
73
+ * @param params 权限参数
74
+ * @returns 是否有权限
75
+ */
76
+ const checkPermission = (params: PermissionParams): boolean => {
77
+ const userInfoStore = useUserInfo();
78
+ const { url, role, permit } = params;
79
+
80
+ // 获取当前URL,优先使用传入的url,否则使用当前路由路径
81
+ const currentUrl = url;
82
+
83
+ if (EnvConfig.VITE_PERMISSION_MODE === 'role') {
84
+ // 仅判断角色权限
85
+ if (!isEmpty(role) && role !== undefined) {
86
+ return userInfoStore.hasRole(role);
87
+ }
88
+ // 如果没有配置角色,默认允许访问
89
+ return true;
90
+ } else if (EnvConfig.VITE_PERMISSION_MODE === 'permit') {
91
+ // 角色和权限任意一个有效即可
92
+ let hasRolePermission = false;
93
+ let hasPermitPermission = false;
94
+
95
+ // 检查角色权限
96
+ if (!isEmpty(role) && role !== undefined) {
97
+ hasRolePermission = userInfoStore.hasRole(role);
98
+ }
99
+
100
+ // 检查功能权限
101
+ if (!isEmpty(permit) && typeof permit === 'string') {
102
+ hasPermitPermission = userInfoStore.hasPermit(currentUrl, permit);
103
+ }
104
+
105
+ // 如果都没有配置,默认允许访问
106
+ if (isEmpty(role) && isEmpty(permit)) {
107
+ return true;
108
+ }
109
+
110
+ // 任意一个有权限即可
111
+ return hasRolePermission || hasPermitPermission;
112
+ }
113
+
114
+ // 默认不允许访问
115
+ return false;
116
+ };
117
+
118
+ /**
119
+ * 统一权限控制指令
120
+ * 使用方式:
121
+ * v-auth="{ url: '/path', role: 'admin', permit: ':edit' }"
122
+ * v-auth:disable="{ role: 'admin', permit: ':edit' }"
123
+ * v-auth="{ role: 'admin', permit: ':edit', behavior: 'disable' }"
124
+ */
125
+ export const vAuth = {
126
+ mounted(el: HTMLElement, binding: DirectiveBinding, vnode: VNode) {
127
+ const params = binding.value || {};
128
+ const argBehavior = (binding.arg as BehaviorType) || 'remove';
129
+ // 参数中的behavior优先级更高,没有的话使用指令参数中的behavior
130
+ const behavior = params.behavior || argBehavior;
131
+
132
+ const hasPermission = checkPermission(params);
133
+ handleElementVisibility(el, vnode, hasPermission, behavior);
134
+ },
135
+ updated(el: HTMLElement, binding: DirectiveBinding, vnode: VNode) {
136
+ const params = binding.value || {};
137
+ const argBehavior = (binding.arg as BehaviorType) || 'remove';
138
+ // 参数中的behavior优先级更高,没有的话使用指令参数中的behavior
139
+ const behavior = params.behavior || argBehavior;
140
+
141
+ const hasPermission = checkPermission(params);
142
+ handleElementVisibility(el, vnode, hasPermission, behavior);
143
+ },
144
+ };