@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.
- package/lib/assets/modules/file-upload-CBUcsUnR.js +170 -0
- package/lib/assets/modules/form-validate-CgX7aR7T.js +297 -0
- package/lib/assets/modules/index-Civhd8xG.js +112 -0
- package/lib/assets/modules/index-DQMdt51R.js +726 -0
- package/lib/assets/modules/{index-BEWJ_qAH.js → index-DmWrkTXX.js} +1 -1
- package/lib/assets/modules/{menuTabs-BXdbFZor.js → menuTabs-BRYvFWA-.js} +131 -121
- package/lib/assets/modules/settingInfo-BZakNKIN.js +999 -0
- package/lib/assets/modules/uploadList-B7XoxGOh.js +278 -0
- package/lib/components/common/icon/index.vue.d.ts +1 -1
- package/lib/components/content/dialog/index.vue.d.ts +1 -1
- package/lib/components/content/drawer/index.vue.d.ts +1 -1
- package/lib/components/content/form/index.vue.d.ts +1 -1
- package/lib/components/content/search/index.vue.d.ts +1 -1
- package/lib/components/content/table/index.vue.d.ts +1 -1
- package/lib/components/content/table/tableOperate.vue.d.ts +1 -1
- package/lib/components/content/toolbar/icontool.vue.d.ts +1 -1
- package/lib/components/content/toolbar/index.vue.d.ts +1 -1
- package/lib/components/content/tree/index.vue.d.ts +1 -1
- package/lib/components/form/transfer/transferTable.vue.d.ts +1 -1
- package/lib/components/form/treeSelect/index.vue.d.ts +1 -1
- package/lib/components/form/upload/uploadList.vue.d.ts +1 -1
- package/lib/const/options.d.ts +32 -0
- package/lib/directives/enter-submit.d.ts +4 -0
- package/lib/directives/index.d.ts +2 -0
- package/lib/directives/permission.d.ts +5 -0
- package/lib/es/AceEditor/index.js +9 -8
- package/lib/es/BasicLayout/index.js +28 -24
- package/lib/es/Error403/index.js +15 -10
- package/lib/es/Error404/index.js +15 -10
- package/lib/es/ExcelForm/index.js +380 -175
- package/lib/es/UploadForm/index.js +23 -20
- package/lib/index.d.ts +42 -2
- package/lib/router/index.d.ts +16 -0
- package/lib/stores/appInfo.d.ts +34 -0
- package/lib/stores/hostInfo.d.ts +9 -0
- package/lib/stores/pageInfo.d.ts +18 -0
- package/lib/stores/pinia.d.ts +3 -0
- package/lib/stores/settingInfo.d.ts +8 -0
- package/lib/stores/userInfo.d.ts +21 -0
- package/lib/typings/data.d.ts +80 -0
- package/lib/typings/form.d.ts +171 -0
- package/lib/typings/menu.d.ts +7 -0
- package/lib/typings/option.d.ts +175 -0
- package/lib/typings/page.d.ts +69 -0
- package/lib/typings/table.d.ts +181 -0
- package/lib/typings/tools.d.ts +130 -0
- package/lib/typings/tree.d.ts +72 -0
- package/lib/typings/upload.d.ts +161 -0
- package/lib/typings/urls.d.ts +69 -0
- package/lib/utils/cache.d.ts +23 -0
- package/lib/utils/data.d.ts +6 -0
- package/lib/utils/download.d.ts +4 -0
- package/lib/utils/eventbus.d.ts +16 -0
- package/lib/utils/export-table.d.ts +12 -0
- package/lib/utils/file-upload.d.ts +15 -0
- package/lib/utils/form-excel.d.ts +30 -0
- package/lib/utils/form-validate.d.ts +29 -0
- package/lib/utils/form.d.ts +9 -0
- package/lib/utils/icon-loader.d.ts +125 -0
- package/lib/utils/isEmpty.d.ts +1 -0
- package/lib/utils/main-openapis.d.ts +9 -0
- package/lib/utils/menu.d.ts +6 -0
- package/lib/utils/options.d.ts +10 -0
- package/lib/utils/page.d.ts +25 -0
- package/lib/utils/table.d.ts +21 -0
- package/lib/utils/tools.d.ts +18 -0
- package/lib/utils/tree.d.ts +3 -0
- package/lib/vite-env.d.ts +8 -0
- package/lib/webui.css +1 -1
- package/lib/webui.es.js +1020 -854
- package/package.json +7 -6
- package/src/components/common/icon/appicon.vue +1 -1
- package/src/components/common/icon/fullscreen.vue +2 -1
- package/src/components/common/icon/index.vue +1 -1
- package/src/components/common/icon/layoutIcon.vue +1 -1
- package/src/components/common/icon/projectIcon.vue +1 -1
- package/src/components/common/icon/toolIcon.vue +1 -1
- package/src/components/content/dialog/excelForm.vue +2 -2
- package/src/components/content/dialog/index.vue +1 -1
- package/src/components/content/dialog/uploadForm.vue +7 -6
- package/src/components/content/drawer/index.vue +43 -18
- package/src/components/content/form/formItem.vue +1 -1
- package/src/components/content/form/index.vue +1 -1
- package/src/components/content/search/index.vue +1 -1
- package/src/components/content/search/searchItem.vue +1 -1
- package/src/components/content/table/index.vue +8 -5
- package/src/components/content/table/tableOperate.vue +8 -4
- package/src/components/content/toolbar/icontool.vue +2 -2
- package/src/components/content/toolbar/index.vue +9 -5
- package/src/components/content/tree/index.vue +1 -1
- package/src/components/error/error403.vue +2 -2
- package/src/components/error/error404.vue +2 -2
- package/src/components/form/autoComplete/index.vue +1 -1
- package/src/components/form/cascader/index.vue +1 -2
- package/src/components/form/checkbox/index.vue +11 -5
- package/src/components/form/datePicker/index.vue +1 -1
- package/src/components/form/input/index.vue +1 -1
- package/src/components/form/input/inputNumber.vue +1 -1
- package/src/components/form/input/inputPassword.vue +1 -1
- package/src/components/form/radio/index.vue +1 -1
- package/src/components/form/radio/radioStatus.vue +1 -1
- package/src/components/form/rangePicker/index.vue +1 -1
- package/src/components/form/select/index.vue +1 -1
- package/src/components/form/switch/index.vue +7 -3
- package/src/components/form/textarea/index.vue +1 -1
- package/src/components/form/transfer/index.vue +1 -1
- package/src/components/form/transfer/transferTable.vue +42 -22
- package/src/components/form/treeSelect/index.vue +2 -3
- package/src/components/form/upload/uploadList.vue +1 -1
- package/src/components/layout/breadcrumb/index.vue +1 -1
- package/src/components/layout/header/headerExits.vue +1 -1
- package/src/components/layout/header/index.vue +1 -1
- package/src/components/layout/header/user.vue +2 -1
- package/src/components/layout/menu/index.vue +9 -3
- package/src/components/layout/menu/menuTabs.vue +10 -12
- package/src/components/layout/page/basicLayout.vue +1 -1
- package/src/const/options.ts +114 -0
- package/src/directives/enter-submit.ts +13 -0
- package/src/directives/index.ts +26 -0
- package/src/directives/permission.ts +144 -0
- package/src/index.ts +201 -0
- package/src/router/index.ts +196 -0
- package/src/stores/appInfo.ts +471 -0
- package/src/stores/hostInfo.ts +117 -0
- package/src/stores/pageInfo.ts +131 -0
- package/src/stores/pinia.ts +10 -0
- package/src/stores/settingInfo.ts +53 -0
- package/src/stores/userInfo.ts +392 -0
- package/src/typings/data.d.ts +81 -0
- package/src/typings/form.d.ts +172 -0
- package/src/typings/menu.d.ts +7 -0
- package/src/typings/option.d.ts +177 -0
- package/src/typings/page.d.ts +70 -0
- package/src/typings/table.d.ts +182 -0
- package/src/typings/tools.d.ts +131 -0
- package/src/typings/tree.d.ts +73 -0
- package/src/typings/upload.d.ts +162 -0
- package/src/typings/urls.d.ts +70 -0
- package/src/utils/cache.ts +175 -0
- package/src/utils/data.ts +189 -0
- package/src/utils/download.ts +80 -0
- package/src/utils/eventbus.ts +78 -0
- package/src/utils/export-table.ts +155 -0
- package/src/utils/file-upload.ts +304 -0
- package/src/utils/form-excel.ts +523 -0
- package/src/utils/form-validate.ts +368 -0
- package/src/utils/form.ts +188 -0
- package/src/utils/icon-loader.ts +412 -0
- package/src/utils/isEmpty.ts +18 -0
- package/src/utils/main-openapis.ts +72 -0
- package/src/utils/menu.ts +89 -0
- package/src/utils/options.ts +324 -0
- package/src/utils/page.ts +262 -0
- package/src/utils/table.ts +274 -0
- package/src/utils/tools.ts +362 -0
- package/src/utils/tree.ts +28 -0
- package/tsconfig.json +1 -8
- package/vite.config.ts +7 -4
- package/lib/assets/modules/index-BahGnrAq.js +0 -415
- package/lib/assets/modules/index-BoKIa2sr.js +0 -109
- package/lib/assets/modules/index-D47Ci-T3.js +0 -107
- 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 '
|
|
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="[
|
|
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,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 '
|
|
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 '
|
|
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
|
|
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
|
-
}"
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
|
|
114
|
+
"
|
|
115
|
+
v-bind="$attrs"
|
|
116
|
+
>
|
|
108
117
|
<template #children="{ filteredItems, onItemSelectAll, onItemSelect, selectedKeys }">
|
|
109
|
-
<Table
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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 {
|
|
5
|
-
import
|
|
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 '
|
|
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 '
|
|
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 '
|
|
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';
|
|
@@ -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 '
|
|
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
|
|
62
|
-
:
|
|
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 '
|
|
4
|
-
// import { useRouter } from 'vue-router';
|
|
3
|
+
import { useAppInfo, usePageInfo, AppRouter } from '@/index';
|
|
5
4
|
import { ToolIcon, Tooltip } from '../../common';
|
|
6
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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 '
|
|
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
|
+
};
|