create-young-proj 0.6.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +5 -3
- package/dist/index.mjs +9 -9
- package/package.json +3 -6
- package/template-nuxt-admin/Dockerfile +41 -0
- package/template-nuxt-admin/README.md +57 -0
- package/template-nuxt-admin/_gitignore +23 -0
- package/template-nuxt-admin/_npmrc +2 -0
- package/template-nuxt-admin/app.vue +41 -0
- package/template-nuxt-admin/boot.mjs +16 -0
- package/template-nuxt-admin/components/ScreenFull.vue +18 -0
- package/template-nuxt-admin/components/TopSearch.vue +73 -0
- package/template-nuxt-admin/components/TopUser.vue +69 -0
- package/template-nuxt-admin/components/YoungChangePassword.vue +87 -0
- package/template-nuxt-admin/components/YoungCodeInput.vue +60 -0
- package/template-nuxt-admin/components/YoungLink.vue +23 -0
- package/template-nuxt-admin/components/YoungLoading.vue +39 -0
- package/template-nuxt-admin/components/layout/Footer.vue +29 -0
- package/template-nuxt-admin/components/layout/Logo.vue +52 -0
- package/template-nuxt-admin/components/layout/Main.vue +26 -0
- package/template-nuxt-admin/components/layout/NavBar.vue +77 -0
- package/template-nuxt-admin/components/layout/SideBar.vue +89 -0
- package/template-nuxt-admin/components/layout/SubMenu.vue +46 -0
- package/template-nuxt-admin/components/layout/TabsBar.vue +183 -0
- package/template-nuxt-admin/composables/api.ts +104 -0
- package/template-nuxt-admin/composables/apis/delete.ts +37 -0
- package/template-nuxt-admin/composables/apis/get.ts +83 -0
- package/template-nuxt-admin/composables/apis/index.ts +10 -0
- package/template-nuxt-admin/composables/apis/patch.ts +74 -0
- package/template-nuxt-admin/composables/apis/post.ts +85 -0
- package/template-nuxt-admin/composables/config.ts +13 -0
- package/template-nuxt-admin/composables/icon.ts +27 -0
- package/template-nuxt-admin/composables/nav.ts +60 -0
- package/template-nuxt-admin/composables/tags.ts +114 -0
- package/template-nuxt-admin/composables/user.ts +29 -0
- package/template-nuxt-admin/config/.devrc +1 -0
- package/template-nuxt-admin/config/.onlinerc +1 -0
- package/template-nuxt-admin/config/.testrc +1 -0
- package/template-nuxt-admin/env.d.ts +47 -0
- package/template-nuxt-admin/error.vue +53 -0
- package/template-nuxt-admin/layouts/blank.vue +9 -0
- package/template-nuxt-admin/layouts/default.vue +124 -0
- package/template-nuxt-admin/middleware/auth.global.ts +50 -0
- package/template-nuxt-admin/nuxt.config.ts +101 -0
- package/template-nuxt-admin/package.json +44 -0
- package/template-nuxt-admin/pages/home/[id].vue +28 -0
- package/template-nuxt-admin/pages/index.vue +20 -0
- package/template-nuxt-admin/pages/login.vue +179 -0
- package/template-nuxt-admin/pages/system/api.vue +166 -0
- package/template-nuxt-admin/pages/system/hooks/useRole.ts +336 -0
- package/template-nuxt-admin/pages/system/menuList.vue +329 -0
- package/template-nuxt-admin/pages/system/role.vue +117 -0
- package/template-nuxt-admin/pages/system/user.vue +214 -0
- package/template-nuxt-admin/plugins/directive.ts +26 -0
- package/template-nuxt-admin/public/default_avatar.svg +1 -0
- package/template-nuxt-admin/public/favicon.ico +0 -0
- package/template-nuxt-admin/public/image_placeholder.svg +15 -0
- package/template-nuxt-admin/public/tabbar_bg.png +0 -0
- package/template-nuxt-admin/rome.json +26 -0
- package/template-nuxt-admin/server/api/[...all].ts +10 -0
- package/template-nuxt-admin/server/plugins/env.ts +89 -0
- package/template-nuxt-admin/server/routes/get/env.ts +13 -0
- package/template-nuxt-admin/server/tsconfig.json +3 -0
- package/template-nuxt-admin/server/utils/index.ts +35 -0
- package/template-nuxt-admin/styles/element.scss +30 -0
- package/template-nuxt-admin/styles/index.scss +59 -0
- package/template-nuxt-admin/styles/variable.scss +103 -0
- package/template-nuxt-admin/tsconfig.json +7 -0
- package/template-nuxt-admin/typings/global.d.ts +16 -0
- package/template-nuxt-admin/typings/system.d.ts +66 -0
- package/template-nuxt-admin/typings/user.d.ts +19 -0
- package/template-nuxt-admin/uno.config.ts +40 -0
- package/template-nuxt-admin/utils/tool.ts +207 -0
- package/template-nuxt-admin/yarn.lock +7103 -0
- package/template-uni-app/README.md +20 -0
- package/template-uni-app/_env +1 -1
- package/template-uni-app/_env.development +2 -2
- package/template-uni-app/_env.production +0 -3
- package/template-uni-app/_env.test +0 -3
- package/template-uni-app/_npmrc +2 -0
- package/template-uni-app/auto-imports.d.ts +3 -0
- package/template-uni-app/dist/dev/mp-weixin/apis/index.js +44 -0
- package/template-uni-app/dist/dev/mp-weixin/apis/lib/index.js +90 -0
- package/template-uni-app/dist/dev/mp-weixin/apis/requests/get.js +10 -0
- package/template-uni-app/dist/dev/mp-weixin/apis/requests/index.js +1 -0
- package/template-uni-app/dist/dev/mp-weixin/apis/requests/post.js +15 -0
- package/template-uni-app/dist/dev/mp-weixin/app.js +93 -0
- package/template-uni-app/dist/dev/mp-weixin/app.json +51 -0
- package/template-uni-app/dist/dev/mp-weixin/app.wxss +2378 -0
- package/template-uni-app/dist/dev/mp-weixin/common/assets.js +13 -0
- package/template-uni-app/dist/dev/mp-weixin/common/vendor.js +10189 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-loading/young-loading.js +22 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-loading/young-loading.json +4 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-loading/young-loading.wxml +1 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-loading/young-loading.wxss +0 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-loading-mini/young-loading-mini.js +22 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-loading-mini/young-loading-mini.json +4 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-loading-mini/young-loading-mini.wxml +1 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-loading-mini/young-loading-mini.wxss +0 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-navbar/young-navbar.js +82 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-navbar/young-navbar.json +4 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-navbar/young-navbar.wxml +1 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-navbar/young-navbar.wxss +108 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-tabbar/young-tabbar.js +56 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-tabbar/young-tabbar.json +4 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-tabbar/young-tabbar.wxml +1 -0
- package/template-uni-app/dist/dev/mp-weixin/components/young-tabbar/young-tabbar.wxss +88 -0
- package/template-uni-app/dist/dev/mp-weixin/config/enum.js +21 -0
- package/template-uni-app/dist/dev/mp-weixin/config/index.js +1 -0
- package/template-uni-app/dist/dev/mp-weixin/config/map.js +1 -0
- package/template-uni-app/dist/dev/mp-weixin/layouts/default.js +30 -0
- package/template-uni-app/dist/dev/mp-weixin/layouts/default.json +6 -0
- package/template-uni-app/dist/dev/mp-weixin/layouts/default.wxml +1 -0
- package/template-uni-app/dist/dev/mp-weixin/layouts/default.wxss +0 -0
- package/template-uni-app/dist/dev/mp-weixin/layouts/tabbar.js +56 -0
- package/template-uni-app/dist/dev/mp-weixin/layouts/tabbar.json +9 -0
- package/template-uni-app/dist/dev/mp-weixin/layouts/tabbar.wxml +1 -0
- package/template-uni-app/dist/dev/mp-weixin/layouts/tabbar.wxss +0 -0
- package/template-uni-app/dist/dev/mp-weixin/node-modules/@dcloudio/uni-ui/lib/uni-card/uni-card.js +98 -0
- package/template-uni-app/dist/dev/mp-weixin/node-modules/@dcloudio/uni-ui/lib/uni-card/uni-card.json +4 -0
- package/template-uni-app/dist/dev/mp-weixin/node-modules/@dcloudio/uni-ui/lib/uni-card/uni-card.wxml +1 -0
- package/template-uni-app/dist/dev/mp-weixin/node-modules/@dcloudio/uni-ui/lib/uni-card/uni-card.wxss +125 -0
- package/template-uni-app/dist/dev/mp-weixin/pages/demo/index.js +38 -0
- package/template-uni-app/dist/dev/mp-weixin/pages/demo/index.json +5 -0
- package/template-uni-app/dist/dev/mp-weixin/pages/demo/index.wxml +1 -0
- package/template-uni-app/dist/dev/mp-weixin/pages/demo/index.wxss +0 -0
- package/template-uni-app/dist/dev/mp-weixin/pages/index.js +51 -0
- package/template-uni-app/dist/dev/mp-weixin/pages/index.json +5 -0
- package/template-uni-app/dist/dev/mp-weixin/pages/index.wxml +1 -0
- package/template-uni-app/dist/dev/mp-weixin/pages/index.wxss +0 -0
- package/template-uni-app/dist/dev/mp-weixin/pages/my.js +22 -0
- package/template-uni-app/dist/dev/mp-weixin/pages/my.json +3 -0
- package/template-uni-app/dist/dev/mp-weixin/pages/my.wxml +1 -0
- package/template-uni-app/dist/dev/mp-weixin/pages/my.wxss +0 -0
- package/template-uni-app/dist/dev/mp-weixin/project.config.json +56 -0
- package/template-uni-app/dist/dev/mp-weixin/static/back.png +0 -0
- package/template-uni-app/dist/dev/mp-weixin/static/h.png +0 -0
- package/template-uni-app/dist/dev/mp-weixin/static/home.png +0 -0
- package/template-uni-app/dist/dev/mp-weixin/static/home_active.png +0 -0
- package/template-uni-app/dist/dev/mp-weixin/static/more.png +0 -0
- package/template-uni-app/dist/dev/mp-weixin/static/my.png +0 -0
- package/template-uni-app/dist/dev/mp-weixin/static/my_active.png +0 -0
- package/template-uni-app/dist/dev/mp-weixin/static/network.png +0 -0
- package/template-uni-app/dist/dev/mp-weixin/store/index.js +8 -0
- package/template-uni-app/dist/dev/mp-weixin/store/local/index.js +11 -0
- package/template-uni-app/dist/dev/mp-weixin/store/system.js +14 -0
- package/template-uni-app/dist/dev/mp-weixin/utils/modal.js +82 -0
- package/template-uni-app/dist/dev/mp-weixin/utils/route.js +85 -0
- package/template-uni-app/dist/dev/mp-weixin/utils/system.js +27 -0
- package/template-uni-app/src/apis/index.ts +17 -14
- package/template-uni-app/src/components/young-loading/young-loading.vue +6 -13
- package/template-uni-app/src/components/young-loading-mini/young-loading-mini.vue +3 -10
- package/template-uni-app/src/layouts/default.vue +2 -3
- package/template-uni-app/src/layouts/tabbar.vue +22 -15
- package/template-uni-app/src/pages/index.vue +12 -3
- package/template-uni-app/src/pages/my.vue +15 -12
- package/template-uni-app/src/pages.json +8 -2
- package/template-uni-app/src/store/system.ts +4 -3
- package/template-uni-app/src/typings/global.d.ts +7 -0
- package/template-uni-app/src/utils/auth.ts +71 -1
- package/template-uni-app/src/utils/modal.ts +30 -7
- package/template-vue-admin/src/views/system/menuList.vue +3 -3
@@ -0,0 +1,329 @@
|
|
1
|
+
<!--
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2023-07-25 16:45:17
|
4
|
+
* @LastEditTime: 2023-08-25 16:55:00
|
5
|
+
* @Description:
|
6
|
+
-->
|
7
|
+
<script lang="ts" setup>
|
8
|
+
import { YoungTablePro, useFormMode, YoungDialog, YoungSelect } from '@bluesyoung/ui-vue3-element-plus';
|
9
|
+
import type { TableHeadItem } from '@bluesyoung/ui-vue3-element-plus';
|
10
|
+
import { deepClone, isArray } from '@bluesyoung/utils';
|
11
|
+
import { ElButton } from 'element-plus';
|
12
|
+
|
13
|
+
definePageMeta({
|
14
|
+
title: '菜单管理'
|
15
|
+
});
|
16
|
+
|
17
|
+
const FORM_TEMP: NavArrItem = {
|
18
|
+
breadcrumb: 0,
|
19
|
+
component: '',
|
20
|
+
createdAt: '',
|
21
|
+
creator: '',
|
22
|
+
icon: '',
|
23
|
+
id: 0,
|
24
|
+
name: '',
|
25
|
+
not_dev: 0,
|
26
|
+
parentId: 0,
|
27
|
+
path: '',
|
28
|
+
permission: '',
|
29
|
+
redirect: '',
|
30
|
+
sort: 0,
|
31
|
+
status: 1,
|
32
|
+
title: '',
|
33
|
+
updatedAt: '',
|
34
|
+
visible: 1
|
35
|
+
};
|
36
|
+
// key 的类型必须为 string 才会生效!!!
|
37
|
+
const expandKeys = ref<Set<string>>(new Set());
|
38
|
+
|
39
|
+
let tempArr: string[] = [];
|
40
|
+
const getFatherAndSon = (arr: NavArrItem[], num?: number): string[] => {
|
41
|
+
if (num === 1) {
|
42
|
+
tempArr = [];
|
43
|
+
}
|
44
|
+
for (const item of arr) {
|
45
|
+
tempArr.push(item.id + '');
|
46
|
+
if (item.children && isArray(item.children) && item.children.length > 0) {
|
47
|
+
getFatherAndSon(deepClone(item.children));
|
48
|
+
}
|
49
|
+
}
|
50
|
+
return tempArr;
|
51
|
+
};
|
52
|
+
const expandChange = (...args: any) => {
|
53
|
+
const [row, isOpen] = args as [NavArrItem, boolean];
|
54
|
+
const autoid = row.id;
|
55
|
+
if (isOpen) {
|
56
|
+
expandKeys.value.add(autoid + '');
|
57
|
+
} else {
|
58
|
+
const allSub = getFatherAndSon([row], 1);
|
59
|
+
allSub.forEach((v) => expandKeys.value.delete(v));
|
60
|
+
}
|
61
|
+
};
|
62
|
+
const tableData = ref<NavArrItem[]>([]);
|
63
|
+
|
64
|
+
const topMenuOption = ref<Partial<NavArrItem>[]>([]);
|
65
|
+
|
66
|
+
/**
|
67
|
+
* 生成节点映射
|
68
|
+
*/
|
69
|
+
const nodeMap = new Map<string, NavArrItem>();
|
70
|
+
const generateNodeMap = (list: NavArrItem[]) => {
|
71
|
+
for (const node of list) {
|
72
|
+
nodeMap.set(node.id.toString(), node);
|
73
|
+
if (node.children && node.children?.length > 0) {
|
74
|
+
generateNodeMap(node.children);
|
75
|
+
}
|
76
|
+
}
|
77
|
+
};
|
78
|
+
|
79
|
+
/**
|
80
|
+
* 获取节点列表
|
81
|
+
*/
|
82
|
+
const getList = async () => {
|
83
|
+
const list = Object.values(await apis.get.getMenuList());
|
84
|
+
generateNodeMap(list);
|
85
|
+
|
86
|
+
tableData.value = list;
|
87
|
+
|
88
|
+
topMenuOption.value = [
|
89
|
+
{ title: '顶级目录', children: list, id: 0 }
|
90
|
+
];
|
91
|
+
};
|
92
|
+
|
93
|
+
const {
|
94
|
+
isAdd,
|
95
|
+
isEdit,
|
96
|
+
form,
|
97
|
+
edit,
|
98
|
+
del,
|
99
|
+
sure,
|
100
|
+
clear,
|
101
|
+
formRef,
|
102
|
+
validForm
|
103
|
+
} = useFormMode<NavArrItem>(FORM_TEMP, {
|
104
|
+
addCbk: async () => {
|
105
|
+
const res = await validForm() as boolean;
|
106
|
+
if (res) {
|
107
|
+
const v = deepClone(form.value);
|
108
|
+
await apis.post.addMenuItem(v);
|
109
|
+
ElMessage.success('菜单添加成功!');
|
110
|
+
}
|
111
|
+
return res;
|
112
|
+
},
|
113
|
+
modCbk: async () => {
|
114
|
+
const res = await validForm() as boolean;
|
115
|
+
if (res) {
|
116
|
+
const v = deepClone(form.value);
|
117
|
+
await apis.patch.changeMenuItem(v);
|
118
|
+
ElMessage.success('菜单修改成功!');
|
119
|
+
}
|
120
|
+
return res;
|
121
|
+
},
|
122
|
+
delCbk: async (nav: NavArrItem) => {
|
123
|
+
apis.delete.deleteMenu(nav.id.toString());
|
124
|
+
expandKeys.value.delete(nav.id.toString());
|
125
|
+
ElMessage.success('节点删除成功!');
|
126
|
+
// 框架有 bug,视图更新不及时
|
127
|
+
location.reload();
|
128
|
+
},
|
129
|
+
cgEffect: async () => {
|
130
|
+
await getList();
|
131
|
+
}
|
132
|
+
});
|
133
|
+
|
134
|
+
/**
|
135
|
+
* 添加节点
|
136
|
+
*/
|
137
|
+
const add = () => {
|
138
|
+
form.value.parentId = 0;
|
139
|
+
isAdd.value = true;
|
140
|
+
};
|
141
|
+
|
142
|
+
const tableHead: TableHeadItem<NavArrItem>[] = [
|
143
|
+
{
|
144
|
+
prop: 'title', label: '标题', render: (row) => h('div', { class: 'inline-flex items-center justify-center' }, [
|
145
|
+
h('div', { class: row.icon }),
|
146
|
+
h('div', row.title)
|
147
|
+
])
|
148
|
+
},
|
149
|
+
{
|
150
|
+
prop: 'sort', label: '同级排序', aligin: 'center', render: (row, i) => h('div', {
|
151
|
+
class: 'flex text-2xl justify-center'
|
152
|
+
}, [
|
153
|
+
h('div', {
|
154
|
+
class: 'i-ic-round-keyboard-arrow-up cursor-pointer',
|
155
|
+
title: '向上',
|
156
|
+
onClick: async () => {
|
157
|
+
const arr = nodeMap.get(row.parentId.toString())?.children || [];
|
158
|
+
const index = arr.findIndex((m) => m.id === row.id);
|
159
|
+
if (index <= 0) {
|
160
|
+
return ElMessage.warning('已经到最前面啦!');
|
161
|
+
} else {
|
162
|
+
const pre = arr[index - 1];
|
163
|
+
|
164
|
+
const num = row.sort;
|
165
|
+
const preNum = pre.sort;
|
166
|
+
|
167
|
+
if (num !== preNum) {
|
168
|
+
row.sort = preNum;
|
169
|
+
pre.sort = num;
|
170
|
+
} else {
|
171
|
+
row.sort = num - 1;
|
172
|
+
}
|
173
|
+
await Promise.all([
|
174
|
+
apis.patch.changeMenuItem(row),
|
175
|
+
apis.patch.changeMenuItem(pre),
|
176
|
+
]);
|
177
|
+
ElMessage.success('顺序修改成功!');
|
178
|
+
getList();
|
179
|
+
}
|
180
|
+
}
|
181
|
+
}),
|
182
|
+
h('div', {
|
183
|
+
class: 'i-ic-round-keyboard-arrow-down cursor-pointer',
|
184
|
+
title: '向下',
|
185
|
+
onClick: async () => {
|
186
|
+
const arr = nodeMap.get(row.parentId.toString())?.children || [];
|
187
|
+
const index = arr.findIndex((m) => m.id === row.id);
|
188
|
+
if (index === arr.length - 1) {
|
189
|
+
return ElMessage.warning('已经到最后面啦!');
|
190
|
+
} else {
|
191
|
+
const next = arr[index + 1];
|
192
|
+
|
193
|
+
const num = row.sort;
|
194
|
+
const nextNum = next.sort;
|
195
|
+
|
196
|
+
if (num !== nextNum) {
|
197
|
+
row.sort = nextNum;
|
198
|
+
next.sort = num;
|
199
|
+
} else {
|
200
|
+
row.sort = num + 1;
|
201
|
+
}
|
202
|
+
await Promise.all([
|
203
|
+
apis.patch.changeMenuItem(row),
|
204
|
+
apis.patch.changeMenuItem(next),
|
205
|
+
]);
|
206
|
+
ElMessage.success('顺序修改成功!');
|
207
|
+
getList();
|
208
|
+
}
|
209
|
+
}
|
210
|
+
}),
|
211
|
+
])
|
212
|
+
},
|
213
|
+
{ prop: 'component', label: '页面路径' },
|
214
|
+
{
|
215
|
+
prop: 'visible', label: '隐藏/显示', render: (row) => h(YoungSelect, {
|
216
|
+
modelValue: row.visible,
|
217
|
+
options: [{ label: '显示', value: 1 }, { label: '隐藏', value: 0 }],
|
218
|
+
'onUpdate:modelValue': async (e: number) => {
|
219
|
+
// 状态未修改
|
220
|
+
if (e === row.visible) {
|
221
|
+
return;
|
222
|
+
}
|
223
|
+
|
224
|
+
row.visible = e;
|
225
|
+
await apis.patch.changeMenuItem({ ...row, visible: e });
|
226
|
+
ElMessage.success('菜单修改成功!');
|
227
|
+
}
|
228
|
+
})
|
229
|
+
},
|
230
|
+
{ prop: 'creator', label: '创建时间' },
|
231
|
+
{
|
232
|
+
prop: 'id', label: '操作', fixed: 'right', width: '180', render: (row) => h('div', [
|
233
|
+
h(ElButton, {
|
234
|
+
text: true,
|
235
|
+
class: '!p-0',
|
236
|
+
type: 'primary',
|
237
|
+
onClick: () => edit(row),
|
238
|
+
}, {
|
239
|
+
default: () => h('div', '编辑')
|
240
|
+
}),
|
241
|
+
h(ElButton, {
|
242
|
+
type: 'primary',
|
243
|
+
class: '!p-0',
|
244
|
+
text: true,
|
245
|
+
onClick: () => {
|
246
|
+
form.value.parentId = row.id;
|
247
|
+
isAdd.value = true;
|
248
|
+
},
|
249
|
+
}, {
|
250
|
+
default: () => h('div', '添加子节点')
|
251
|
+
}),
|
252
|
+
h(ElButton, {
|
253
|
+
text: true,
|
254
|
+
class: '!p-0',
|
255
|
+
type: 'danger',
|
256
|
+
onClick: () => del(row),
|
257
|
+
}, {
|
258
|
+
default: () => h('div', '删除')
|
259
|
+
})
|
260
|
+
])
|
261
|
+
}
|
262
|
+
];
|
263
|
+
|
264
|
+
useTabReOpen(getList);
|
265
|
+
</script>
|
266
|
+
|
267
|
+
<template>
|
268
|
+
<ElCard>
|
269
|
+
<div>
|
270
|
+
<ElButton type="primary" plain @click="add">新建菜单</ElButton>
|
271
|
+
</div>
|
272
|
+
<br />
|
273
|
+
<!-- 节点列表 -->
|
274
|
+
<YoungTablePro :table-data="tableData" :table-head="tableHead" :tree-props="{ children: 'children' }" row-key="id"
|
275
|
+
:expand-row-keys="[...expandKeys]" @expand-change="expandChange" />
|
276
|
+
<!-- 添加 / 编辑 -->
|
277
|
+
<YoungDialog width="370px" :is-add="isAdd" :diff-form="form" :is-edit="isEdit" @sure="sure" @clear="clear">
|
278
|
+
<template #body>
|
279
|
+
<ElForm ref="formRef" :model="form" label-width="80px" :label-position="WindowSize['lt-lg'] ? 'top' : 'left'">
|
280
|
+
<ElFormItem label="上级目录">
|
281
|
+
<ElCascader :model-value="form.parentId" :props="{
|
282
|
+
label: 'title',
|
283
|
+
value: 'id',
|
284
|
+
checkStrictly: true,
|
285
|
+
multiple: false
|
286
|
+
}" :options="topMenuOption" :show-all-levels="false"
|
287
|
+
@update:model-value="(e: any) => form.parentId = e[e.length - 1]" />
|
288
|
+
</ElFormItem>
|
289
|
+
<ElFormItem label="英文名称" prop="name" :rules="{ required: true, message: '请输入英文名', trigger: 'blur' }">
|
290
|
+
<ElInput v-model.trim="form.name" placeholder="请输入英文名" />
|
291
|
+
</ElFormItem>
|
292
|
+
<ElFormItem label="标题" prop="title" :rules="{ required: true, message: '请输入页面标题', trigger: 'blur' }">
|
293
|
+
<ElInput v-model.trim="form.title" placeholder="请输入页面标题" />
|
294
|
+
</ElFormItem>
|
295
|
+
<ElFormItem label="图标">
|
296
|
+
<ElSelect v-model="form.icon" class="select_icon" placeholder="请选择图标">
|
297
|
+
<template #prefix>
|
298
|
+
<div :class="form.icon" />
|
299
|
+
</template>
|
300
|
+
<ElOption v-for="(item, index) in MenuIconList" :key="index + 'sfjhaeoir'" :value="item.label">
|
301
|
+
<div :class="item.label" />
|
302
|
+
</ElOption>
|
303
|
+
</ElSelect>
|
304
|
+
</ElFormItem>
|
305
|
+
<ElFormItem label="排序">
|
306
|
+
<ElInputNumber v-model.number="form.sort" />
|
307
|
+
</ElFormItem>
|
308
|
+
<ElFormItem label="是否显示">
|
309
|
+
<ElRadioGroup v-model="form.visible">
|
310
|
+
<ElRadio :label="1">显示</ElRadio>
|
311
|
+
<ElRadio :label="0">隐藏</ElRadio>
|
312
|
+
</ElRadioGroup>
|
313
|
+
</ElFormItem>
|
314
|
+
<ElFormItem label="路径" prop="component" :rules="form.parentId === 0 ? {} :
|
315
|
+
{ message: '请输入合法的路径, eg: /path/page', trigger: 'blur', validator: (_: any, v: string) => v.trim() === '' || /\/(.*)\/(.*)/.test(v) }
|
316
|
+
">
|
317
|
+
<ElInput v-model.trim="form.component" />
|
318
|
+
</ElFormItem>
|
319
|
+
</ElForm>
|
320
|
+
</template>
|
321
|
+
</YoungDialog>
|
322
|
+
</ElCard>
|
323
|
+
</template>
|
324
|
+
|
325
|
+
<style lang="scss" scoped>
|
326
|
+
:deep(.select_icon .el-input__inner) {
|
327
|
+
opacity: 0 !important;
|
328
|
+
}
|
329
|
+
</style>
|
@@ -0,0 +1,117 @@
|
|
1
|
+
<!--
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2023-07-25 16:45:39
|
4
|
+
* @LastEditTime: 2023-08-25 16:55:10
|
5
|
+
* @Description:
|
6
|
+
-->
|
7
|
+
<script lang="ts" setup>
|
8
|
+
import { YoungTablePro, YoungDialog, YoungPagination, YoungSearchForm } from '@bluesyoung/ui-vue3-element-plus';
|
9
|
+
import { useRoleApi, useRoleBase, useRoleMenu } from './hooks/useRole';
|
10
|
+
|
11
|
+
definePageMeta({
|
12
|
+
title: '角色管理'
|
13
|
+
});
|
14
|
+
|
15
|
+
const {
|
16
|
+
query,
|
17
|
+
queryScheme,
|
18
|
+
reset,
|
19
|
+
getList,
|
20
|
+
tableHead,
|
21
|
+
tableData,
|
22
|
+
baseFormRef,
|
23
|
+
base
|
24
|
+
} = useRoleBase();
|
25
|
+
|
26
|
+
const { showPriority, menu } = useRoleMenu();
|
27
|
+
|
28
|
+
const { showApi, api } = useRoleApi();
|
29
|
+
|
30
|
+
useTabReOpen(getList);
|
31
|
+
</script>
|
32
|
+
|
33
|
+
<template>
|
34
|
+
<ElCard>
|
35
|
+
<YoungSearchForm v-model="query" :search-scheme="queryScheme" :on-search="getList" :on-reset="reset">
|
36
|
+
<template #btns>
|
37
|
+
<ElButton type="success" @click="base.isAdd = true">添加角色</ElButton>
|
38
|
+
</template>
|
39
|
+
</YoungSearchForm>
|
40
|
+
</ElCard>
|
41
|
+
|
42
|
+
<br />
|
43
|
+
|
44
|
+
<ElCard>
|
45
|
+
<YoungTablePro :table-data="tableData" :table-head="tableHead">
|
46
|
+
<template #operate>
|
47
|
+
<ElTableColumn label="操作" width="300px" fixed="right">
|
48
|
+
<template #default="scope">
|
49
|
+
<ElButton type="primary" link @click="base.edit(scope.row)">信息编辑</ElButton>
|
50
|
+
<ElButton type="primary" link @click="menu.edit(scope.row)">菜单编辑</ElButton>
|
51
|
+
<ElButton type="primary" link @click="api.edit(scope.row)">接口编辑</ElButton>
|
52
|
+
<ElButton type="danger" link @click="base.del(scope.row)">删除</ElButton>
|
53
|
+
</template>
|
54
|
+
</ElTableColumn>
|
55
|
+
</template>
|
56
|
+
</YoungTablePro>
|
57
|
+
<YoungPagination v-model:page="query.pageNum" v-model:limit="query.pageSize" :total="query.total"
|
58
|
+
@page-change="getList" />
|
59
|
+
</ElCard>
|
60
|
+
<!-- 基础信息编辑 -->
|
61
|
+
<YoungDialog :is-add="base.isAdd" :diff-form="base.form" :is-edit="base.isEdit" width="520px" @sure="base.sure"
|
62
|
+
@clear="base.clear">
|
63
|
+
<template #body>
|
64
|
+
<ElForm ref="baseFormRef" :model="base.form" label-width="120px"
|
65
|
+
:label-position="WindowSize['lt-lg'] ? 'top' : 'left'">
|
66
|
+
<ElFormItem label="角色名称(中文)" prop="name" :rules="[{ required: true, message: '请填写角色名称', trigger: 'blur' }]">
|
67
|
+
<ElInput v-model.trim="base.form.name" class="!w-300px" />
|
68
|
+
</ElFormItem>
|
69
|
+
<ElFormItem label="关键字(英文)" prop="keyword" :rules="[{ required: true, message: '请填写关键字', trigger: 'blur' }]">
|
70
|
+
<ElInput v-model.trim="base.form.keyword" class="!w-300px" />
|
71
|
+
</ElFormItem>
|
72
|
+
<ElFormItem label="角色描述">
|
73
|
+
<ElInput v-model.trim="base.form.desc" class="!w-300px" />
|
74
|
+
</ElFormItem>
|
75
|
+
</ElForm>
|
76
|
+
</template>
|
77
|
+
</YoungDialog>
|
78
|
+
<!-- 菜单编辑 -->
|
79
|
+
<YoungDialog real-title="菜单编辑" :diff-form="menu.checkMap" :is-edit="showPriority" top="5vh" width="1200px"
|
80
|
+
@sure="menu.sure" @clear="menu.clear">
|
81
|
+
<template #body>
|
82
|
+
<ElTable :data="menu.tableData" row-key="id" :default-expand-all="false" class="max-h-600px !overflow-y-auto">
|
83
|
+
<ElTableColumn prop="name" label="节点名称" width="320px">
|
84
|
+
<template #default="scope">
|
85
|
+
<ElCheckbox v-model="menu.checkMap[scope.row.id]" @change="menu.selectChange(scope.row)">{{
|
86
|
+
scope.row.title
|
87
|
+
}}</ElCheckbox>
|
88
|
+
</template>
|
89
|
+
</ElTableColumn>
|
90
|
+
<ElTableColumn v-for="(item, index) in menu.tableHead" v-bind="item" :key="index + 'fsdjhfaer'" />
|
91
|
+
<ElTableColumn prop="name" label="隐藏/显示">
|
92
|
+
<template #default="scope">
|
93
|
+
<ElSwitch v-model="scope.row.visible" :active-value="1" :inactive-value="0" active-color="#409EFF"
|
94
|
+
inactive-color="#909399" disabled />
|
95
|
+
</template>
|
96
|
+
</ElTableColumn>
|
97
|
+
</ElTable>
|
98
|
+
</template>
|
99
|
+
</YoungDialog>
|
100
|
+
<!-- 接口编辑 -->
|
101
|
+
<YoungDialog real-title="接口编辑" :diff-form="api.checkMap" :is-edit="showApi" top="5vh" width="1200px" @sure="api.sure"
|
102
|
+
@clear="api.clear">
|
103
|
+
<template #body>
|
104
|
+
<ElTable :data="api.tableData" row-key="id" :default-expand-all="false" class="max-h-600px !overflow-y-auto">
|
105
|
+
<ElTableColumn prop="name" width="100px">
|
106
|
+
<template #header>
|
107
|
+
<ElCheckbox v-model="api.isAll" @change="api.changeAll">全选</ElCheckbox>
|
108
|
+
</template>
|
109
|
+
<template #default="scope">
|
110
|
+
<ElCheckbox v-model="api.checkMap[scope.row.id]">{{ scope.row.title }}</ElCheckbox>
|
111
|
+
</template>
|
112
|
+
</ElTableColumn>
|
113
|
+
<ElTableColumn v-for="(item, index) in api.tableHead" v-bind="item" :key="index + 'fsdjhfaer'" />
|
114
|
+
</ElTable>
|
115
|
+
</template>
|
116
|
+
</YoungDialog>
|
117
|
+
</template>
|
@@ -0,0 +1,214 @@
|
|
1
|
+
<!--
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2023-07-25 16:46:00
|
4
|
+
* @LastEditTime: 2023-08-25 16:55:17
|
5
|
+
* @Description:
|
6
|
+
-->
|
7
|
+
<script lang="ts" setup>
|
8
|
+
import { useFormMode, YoungDialog, YoungTablePro, YoungPagination, YoungSelect, useQuery, YoungSearchForm } from '@bluesyoung/ui-vue3-element-plus';
|
9
|
+
import type { TableDataItem, TableHeadItem, SelectOptionItem, YoungSearchScheme } from '@bluesyoung/ui-vue3-element-plus';
|
10
|
+
import { deepClone } from '@bluesyoung/utils';
|
11
|
+
import { ElButton } from 'element-plus';
|
12
|
+
|
13
|
+
definePageMeta({
|
14
|
+
title: '用户管理'
|
15
|
+
});
|
16
|
+
|
17
|
+
interface Form extends UserItem { op?: any; };
|
18
|
+
const FORM_TEMP: Form = {
|
19
|
+
id: 0,
|
20
|
+
username: '',
|
21
|
+
nickname: '',
|
22
|
+
mobile: '',
|
23
|
+
roleId: 1,
|
24
|
+
status: 1,
|
25
|
+
initPassword: ''
|
26
|
+
};
|
27
|
+
const {
|
28
|
+
isAdd,
|
29
|
+
isEdit,
|
30
|
+
edit,
|
31
|
+
del,
|
32
|
+
sure,
|
33
|
+
clear,
|
34
|
+
form,
|
35
|
+
formRef,
|
36
|
+
validForm
|
37
|
+
} = useFormMode<Form>(FORM_TEMP, {
|
38
|
+
addCbk: async () => {
|
39
|
+
const res = await validForm() as boolean;
|
40
|
+
if (res) {
|
41
|
+
const v = deepClone(form.value);
|
42
|
+
await apis.post.addUserItem(v);
|
43
|
+
ElMessage.success('新增成功!');
|
44
|
+
}
|
45
|
+
return res;
|
46
|
+
},
|
47
|
+
modCbk: async () => {
|
48
|
+
const res = await validForm() as boolean;
|
49
|
+
if (res) {
|
50
|
+
const v = deepClone(form.value);
|
51
|
+
await apis.patch.changeUserItem(v);
|
52
|
+
ElMessage.success('修改成功!');
|
53
|
+
}
|
54
|
+
return res;
|
55
|
+
},
|
56
|
+
delCbk: async (row) => {
|
57
|
+
await apis.delete.deleteUser(row.id.toString());
|
58
|
+
ElMessage.success('删除成功!');
|
59
|
+
query.value.pageNum = 1;
|
60
|
+
},
|
61
|
+
cgEffect: () => getList(),
|
62
|
+
});
|
63
|
+
|
64
|
+
const tableHead: TableHeadItem<Form>[] = [
|
65
|
+
{ prop: 'id', label: '用户ID' },
|
66
|
+
{ prop: 'username', label: '用户名' },
|
67
|
+
{ prop: 'mobile', label: '手机号' },
|
68
|
+
{ prop: 'role_name', label: '角色名称' },
|
69
|
+
{ prop: 'creator', label: '创建信息' },
|
70
|
+
{
|
71
|
+
prop: 'op', label: '操作', width: '300px', fixed: 'right', render: (row) => h('div', [
|
72
|
+
hasPermission('/access/system/update/user') && h(ElButton, {
|
73
|
+
type: 'primary',
|
74
|
+
text: true,
|
75
|
+
class: '!p-0',
|
76
|
+
onClick: () => edit(row)
|
77
|
+
}, {
|
78
|
+
default: () => '编辑'
|
79
|
+
}),
|
80
|
+
hasPermission('/access/system/update/user') && h(ElButton, {
|
81
|
+
type: 'warning',
|
82
|
+
text: true,
|
83
|
+
class: '!p-0',
|
84
|
+
onClick: () => changePwd(row)
|
85
|
+
}, {
|
86
|
+
default: () => '修改密码'
|
87
|
+
}),
|
88
|
+
hasPermission('/access/system/del/user') && h(ElButton, {
|
89
|
+
type: 'danger',
|
90
|
+
text: true,
|
91
|
+
class: '!p-0',
|
92
|
+
onClick: () => del(row)
|
93
|
+
}, {
|
94
|
+
default: () => '删除'
|
95
|
+
})
|
96
|
+
])
|
97
|
+
}
|
98
|
+
];
|
99
|
+
const tableData = ref<TableDataItem<Form>[]>([]);
|
100
|
+
|
101
|
+
const getList = async () => {
|
102
|
+
const { list: role_list } = await apis.get.getRoleList({ noPagination: true });
|
103
|
+
roleList.value = (role_list || []).map((item: RoleItem) => {
|
104
|
+
return {
|
105
|
+
label: item.name,
|
106
|
+
value: item.id
|
107
|
+
};
|
108
|
+
});
|
109
|
+
|
110
|
+
const { list, pageNum, pageSize, total } = await apis.get.getUserList(query.value);
|
111
|
+
tableData.value = deepClone(list || []);
|
112
|
+
|
113
|
+
query.value.pageNum = +pageNum || 1;
|
114
|
+
query.value.pageSize = +pageSize || 50;
|
115
|
+
query.value.total = +total || 0;
|
116
|
+
};
|
117
|
+
|
118
|
+
const changePwd = (e: UserItem) => {
|
119
|
+
ElMessageBox.prompt('请输入新密码').then(async ({ value }) => {
|
120
|
+
value = value.trim()
|
121
|
+
if (value) {
|
122
|
+
await apis.patch.changeUserItem({ id: e.id, newPassword: value });
|
123
|
+
ElMessage.success('修改成功!');
|
124
|
+
}
|
125
|
+
}).catch(() => null);
|
126
|
+
};
|
127
|
+
|
128
|
+
interface Query extends BaseQuery {
|
129
|
+
username: string;
|
130
|
+
mobile: string;
|
131
|
+
status: 0 | 1;
|
132
|
+
}
|
133
|
+
|
134
|
+
const { query, reset } = useQuery<Query>(
|
135
|
+
{
|
136
|
+
pageNum: 1,
|
137
|
+
pageSize: 10,
|
138
|
+
total: 0,
|
139
|
+
username: '',
|
140
|
+
mobile: '',
|
141
|
+
status: 1
|
142
|
+
},
|
143
|
+
getList,
|
144
|
+
);
|
145
|
+
const queryScheme: YoungSearchScheme<Query> = {
|
146
|
+
username: {
|
147
|
+
type: 'input',
|
148
|
+
tip: '用户名',
|
149
|
+
attrs: {
|
150
|
+
placeholder: '请输入用户名',
|
151
|
+
},
|
152
|
+
},
|
153
|
+
mobile: {
|
154
|
+
type: 'input',
|
155
|
+
tip: '手机号',
|
156
|
+
attrs: {
|
157
|
+
placeholder: '请输入手机号',
|
158
|
+
maxlength: 11
|
159
|
+
}
|
160
|
+
},
|
161
|
+
status: {
|
162
|
+
type: 'select',
|
163
|
+
tip: '状态',
|
164
|
+
attrs: {
|
165
|
+
placeholder: '用户状态',
|
166
|
+
},
|
167
|
+
options: [{ label: '禁用', value: 0 }, { label: '启用', value: 1 }],
|
168
|
+
}
|
169
|
+
};
|
170
|
+
|
171
|
+
const roleList = ref<SelectOptionItem<number>[]>([]);
|
172
|
+
|
173
|
+
useTabReOpen(getList);
|
174
|
+
</script>
|
175
|
+
<template>
|
176
|
+
<ElCard>
|
177
|
+
<YoungSearchForm v-model="query" :search-scheme="queryScheme" :on-search="getList" :on-reset="reset">
|
178
|
+
<template #btns>
|
179
|
+
<ElButton v-permission="'/access/system/create/user'" type="success" @click="isAdd = true">添加用户</ElButton>
|
180
|
+
</template>
|
181
|
+
</YoungSearchForm>
|
182
|
+
</ElCard>
|
183
|
+
|
184
|
+
<br />
|
185
|
+
|
186
|
+
<ElCard>
|
187
|
+
<YoungTablePro :table-data="tableData" :table-head="tableHead" />
|
188
|
+
<YoungPagination v-model:page="query.pageNum" v-model:limit="query.pageSize" :total="query.total"
|
189
|
+
@page-change="getList" />
|
190
|
+
</ElCard>
|
191
|
+
|
192
|
+
<YoungDialog :is-add="isAdd" :diff-form="form" :is-edit="isEdit" width="520px" @sure="sure" @clear="clear">
|
193
|
+
<template #body>
|
194
|
+
<ElForm ref="formRef" :model="form" label-width="100px" :label-position="WindowSize['lt-lg'] ? 'top' : 'left'">
|
195
|
+
<ElFormItem label="用户名" prop="username" :rules="{ required: true, message: '请输用户名', trigger: 'blur' }">
|
196
|
+
<ElInput v-model.trim="form.username" class="!w-300px" />
|
197
|
+
</ElFormItem>
|
198
|
+
<ElFormItem label="昵称" prop="nickname" :rules="{ required: true, message: '请输昵称(用于右上角展示)', trigger: 'blur' }">
|
199
|
+
<ElInput v-model.trim="form.nickname" class="!w-300px" />
|
200
|
+
</ElFormItem>
|
201
|
+
<ElFormItem label="手机号" prop="mobile" :rules="{ required: true, message: '请输手机号', trigger: 'blur' }">
|
202
|
+
<ElInput v-model.trim="form.mobile" :maxlength="11" class="!w-300px" />
|
203
|
+
</ElFormItem>
|
204
|
+
<ElFormItem label="角色">
|
205
|
+
<YoungSelect v-model="form.roleId" placeholder="请选择角色" :options="roleList" />
|
206
|
+
</ElFormItem>
|
207
|
+
<ElFormItem v-if="isAdd" label="初始密码" prop="initPassword"
|
208
|
+
:rules="{ required: true, message: '请输初始密码', trigger: 'blur' }">
|
209
|
+
<ElInput v-model.trim="form.initPassword" class="!w-300px" />
|
210
|
+
</ElFormItem>
|
211
|
+
</ElForm>
|
212
|
+
</template>
|
213
|
+
</YoungDialog>
|
214
|
+
</template>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
/*
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2023-07-31 14:04:44
|
4
|
+
* @LastEditTime: 2023-07-31 14:33:10
|
5
|
+
* @Description:
|
6
|
+
*/
|
7
|
+
import { isString } from '@bluesyoung/utils';
|
8
|
+
|
9
|
+
export default defineNuxtPlugin((nuxtApp) => {
|
10
|
+
/**
|
11
|
+
* 鉴自指令定义的zdy
|
12
|
+
*/
|
13
|
+
nuxtApp.vueApp.directive('permission', {
|
14
|
+
mounted(el, binding) {
|
15
|
+
const { value } = binding;
|
16
|
+
|
17
|
+
if (isString(value) && value) {
|
18
|
+
if (!hasPermission(value as unknown as string)) {
|
19
|
+
el.parentNode && el.parentNode.removeChild(el);
|
20
|
+
}
|
21
|
+
} else {
|
22
|
+
throw new Error(`need value! Like v-permission="'/access/get/list'"`);
|
23
|
+
}
|
24
|
+
},
|
25
|
+
});
|
26
|
+
});
|
@@ -0,0 +1 @@
|
|
1
|
+
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="200px" height="200.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M28.717511 509.428622c0.068267 263.850667 213.8112 477.684622 477.411556 477.639111 263.600356-0.045511 477.275022-213.970489 477.229511-477.843911 0-263.850667-213.720178-477.752889-477.320534-477.752889-126.611911 0-248.035556 50.3808-337.555911 140.014934a478.094222 478.094222 0 0 0-139.764622 337.92z" fill="#FFFFFF" /><path d="M856.814933 833.9456c-12.811378-67.1744-130.753422-131.390578-236.612266-166.479644-5.165511-1.729422-37.387378-16.201956-17.2032-77.459912 52.747378-54.0672 92.728889-141.175467 92.728889-226.941155 0-131.754667-87.699911-200.886044-189.622045-200.886045-101.944889 0-189.394489 69.063111-189.394489 200.886045 0 86.038756 40.004267 173.488356 92.842667 227.487289 20.593778 53.976178-16.224711 74.092089-23.984356 76.777244-100.693333 36.340622-217.679644 100.784356-230.559289 166.479645a478.685867 478.685867 0 0 1-55.591822-574.350223 477.639111 477.639111 0 0 1 536.9856-209.942755C842.183111 107.633778 984.314311 295.5264 984.450844 509.5424a475.363556 475.363556 0 0 1-127.635911 324.4032" fill="#B8D4FF" /></svg>
|
Binary file
|