create-young-proj 0.0.1 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE +21 -21
- package/README.md +13 -2
- package/dist/index.mjs +18 -18
- package/index.mjs +3 -3
- package/package.json +10 -12
- package/template-admin-server/.editorconfig +11 -0
- package/template-admin-server/.nvmrc +1 -0
- package/template-admin-server/.vscode/extensions.json +6 -0
- package/template-admin-server/.vscode/settings.json +4 -0
- package/template-admin-server/README.md +73 -0
- package/template-admin-server/_gitignore +15 -0
- package/template-admin-server/boot.mjs +11 -0
- package/template-admin-server/package.json +60 -0
- package/template-admin-server/rome.json +22 -0
- package/template-admin-server/src/config/config.default.ts +56 -0
- package/template-admin-server/src/configuration.ts +47 -0
- package/template-admin-server/src/controller/admin.controller.ts +397 -0
- package/template-admin-server/src/controller/api.controller.ts +98 -0
- package/template-admin-server/src/controller/base.controller.ts +70 -0
- package/template-admin-server/src/controller/dto/api.ts +47 -0
- package/template-admin-server/src/controller/dto/index.ts +36 -0
- package/template-admin-server/src/controller/dto/menu.ts +41 -0
- package/template-admin-server/src/controller/dto/role.ts +41 -0
- package/template-admin-server/src/controller/dto/user.ts +52 -0
- package/template-admin-server/src/controller/menu.controller.ts +138 -0
- package/template-admin-server/src/controller/role.controller.ts +116 -0
- package/template-admin-server/src/controller/user.controller.ts +108 -0
- package/template-admin-server/src/entities/Api.ts +29 -0
- package/template-admin-server/src/entities/BaseCreate.ts +30 -0
- package/template-admin-server/src/entities/Menu.ts +39 -0
- package/template-admin-server/src/entities/Role.ts +36 -0
- package/template-admin-server/src/entities/User.ts +35 -0
- package/template-admin-server/src/entities/index.ts +10 -0
- package/template-admin-server/src/filter/default.filter.ts +22 -0
- package/template-admin-server/src/filter/notfound.filter.ts +23 -0
- package/template-admin-server/src/middleware/helper.middleware.ts +28 -0
- package/template-admin-server/src/middleware/index.ts +9 -0
- package/template-admin-server/src/middleware/jwt.middleware.ts +32 -0
- package/template-admin-server/src/middleware/report.middleware.ts +26 -0
- package/template-admin-server/src/service/api.service.ts +174 -0
- package/template-admin-server/src/service/basic.ts +118 -0
- package/template-admin-server/src/service/index.ts +10 -0
- package/template-admin-server/src/service/menu.service.ts +139 -0
- package/template-admin-server/src/service/role.service.ts +286 -0
- package/template-admin-server/src/service/user.service.ts +124 -0
- package/template-admin-server/src/strategy/jwt.strategy.ts +26 -0
- package/template-admin-server/src/types/index.ts +42 -0
- package/template-admin-server/src/types/types.d.ts +31 -0
- package/template-admin-server/tsconfig.json +24 -0
- package/template-vue-admin/.vscode/extensions.json +10 -0
- package/template-vue-admin/.vscode/list-add.code-snippets +108 -0
- package/template-vue-admin/.vscode/list-export.code-snippets +72 -0
- package/template-vue-admin/.vscode/list.code-snippets +61 -0
- package/template-vue-admin/.vscode/settings.json +7 -0
- package/template-vue-admin/Dockerfile +42 -0
- package/template-vue-admin/README.md +75 -0
- package/template-vue-admin/_env +8 -0
- package/template-vue-admin/_gitignore +30 -0
- package/template-vue-admin/boot.mjs +16 -0
- package/template-vue-admin/build/custom-plugin.ts +30 -0
- package/template-vue-admin/build/index.ts +7 -0
- package/template-vue-admin/build/plugins.ts +59 -0
- package/template-vue-admin/config/.devrc +2 -0
- package/template-vue-admin/config/.onlinerc +2 -0
- package/template-vue-admin/config/.testrc +2 -0
- package/template-vue-admin/index.html +21 -0
- package/template-vue-admin/nitro.config.ts +19 -0
- package/template-vue-admin/package.json +50 -0
- package/template-vue-admin/plugins/env.ts +26 -0
- package/template-vue-admin/public/vite.svg +1 -0
- package/template-vue-admin/rome.json +26 -0
- package/template-vue-admin/routes/api/[...all].ts +49 -0
- package/template-vue-admin/routes/get/env.ts +18 -0
- package/template-vue-admin/src/App.vue +14 -0
- package/template-vue-admin/src/apis/delete.ts +36 -0
- package/template-vue-admin/src/apis/get.ts +84 -0
- package/template-vue-admin/src/apis/index.ts +10 -0
- package/template-vue-admin/src/apis/patch.ts +79 -0
- package/template-vue-admin/src/apis/post.ts +77 -0
- package/template-vue-admin/src/assets/img/login_background.jpg +0 -0
- package/template-vue-admin/src/auto-components.d.ts +36 -0
- package/template-vue-admin/src/auto-imports.d.ts +282 -0
- package/template-vue-admin/src/layouts/blank.vue +9 -0
- package/template-vue-admin/src/layouts/default/components/Link.vue +23 -0
- package/template-vue-admin/src/layouts/default/components/Logo.vue +20 -0
- package/template-vue-admin/src/layouts/default/components/Menu.vue +54 -0
- package/template-vue-admin/src/layouts/default/components/NavSearch.vue +52 -0
- package/template-vue-admin/src/layouts/default/components/ScrollPane.vue +79 -0
- package/template-vue-admin/src/layouts/default/components/TagsView.vue +137 -0
- package/template-vue-admin/src/layouts/default/components/TopMenu.vue +21 -0
- package/template-vue-admin/src/layouts/default/components/UserCenter.vue +50 -0
- package/template-vue-admin/src/layouts/default/index.vue +95 -0
- package/template-vue-admin/src/main.ts +44 -0
- package/template-vue-admin/src/modules/1-router.ts +66 -0
- package/template-vue-admin/src/modules/2-pinia.ts +10 -0
- package/template-vue-admin/src/modules/3-net.ts +75 -0
- package/template-vue-admin/src/modules/4-auth.ts +126 -0
- package/template-vue-admin/src/shims.d.ts +12 -0
- package/template-vue-admin/src/stores/index.ts +9 -0
- package/template-vue-admin/src/stores/local/index.ts +23 -0
- package/template-vue-admin/src/stores/session/index.ts +63 -0
- package/template-vue-admin/src/stores/tags.ts +109 -0
- package/template-vue-admin/src/typings/global.d.ts +70 -0
- package/template-vue-admin/src/typings/index.ts +50 -0
- package/template-vue-admin/src/views/403.vue +32 -0
- package/template-vue-admin/src/views/[...all_404].vue +556 -0
- package/template-vue-admin/src/views/base/login.vue +193 -0
- package/template-vue-admin/src/views/dashboard/[name].vue +23 -0
- package/template-vue-admin/src/views/index.vue +19 -0
- package/template-vue-admin/src/views/system/api.vue +161 -0
- package/template-vue-admin/src/views/system/hooks/useRole.ts +286 -0
- package/template-vue-admin/src/views/system/menuList.vue +195 -0
- package/template-vue-admin/src/views/system/role.vue +132 -0
- package/template-vue-admin/src/views/system/user.vue +193 -0
- package/template-vue-admin/src/vite-env.d.ts +52 -0
- package/template-vue-admin/tsconfig.json +21 -0
- package/template-vue-admin/tsconfig.node.json +9 -0
- package/template-vue-admin/unocss.config.ts +47 -0
- package/template-vue-admin/vite.config.ts +32 -0
- package/template-vue-thin/package.json +14 -13
- package/template-vue-thin/vite.config.ts +1 -6
@@ -0,0 +1,195 @@
|
|
1
|
+
<!--
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2022-05-30 16:28:37
|
4
|
+
* @LastEditTime: 2023-01-06 11:35:16
|
5
|
+
* @Description: 菜单管理
|
6
|
+
-->
|
7
|
+
<route lang="yaml">
|
8
|
+
meta:
|
9
|
+
title: 菜单管理
|
10
|
+
authPath: /system/menuList
|
11
|
+
</route>
|
12
|
+
|
13
|
+
<script lang="ts" setup>
|
14
|
+
import { deepClone, isArray } from '@bluesyoung/utils';
|
15
|
+
import { useFormMode, YoungDialog } from '@bluesyoung/ui-vue3-element-plus';
|
16
|
+
import { apis } from '@/modules/3-net';
|
17
|
+
|
18
|
+
const FORM_TEMP: NavArrItem = {
|
19
|
+
breadcrumb: 0,
|
20
|
+
component: '',
|
21
|
+
createdAt: '',
|
22
|
+
creator: '',
|
23
|
+
icon: '',
|
24
|
+
id: 0,
|
25
|
+
name: '',
|
26
|
+
not_dev: 0,
|
27
|
+
parentId: 0,
|
28
|
+
path: '',
|
29
|
+
permission: '',
|
30
|
+
redirect: '',
|
31
|
+
sort: 0,
|
32
|
+
status: 1,
|
33
|
+
title: '',
|
34
|
+
updatedAt: '',
|
35
|
+
visible: 1
|
36
|
+
};
|
37
|
+
// key 的类型必须为 string 才会生效!!!
|
38
|
+
const expandKeys = ref<Set<string>>(new Set());
|
39
|
+
|
40
|
+
let tempArr: string[] = [];
|
41
|
+
const getFatherAndSon = (arr: NavArrItem[], num?: number): string[] => {
|
42
|
+
if (num === 1) {
|
43
|
+
tempArr = [];
|
44
|
+
}
|
45
|
+
for (const item of arr) {
|
46
|
+
tempArr.push(item.id + '');
|
47
|
+
if (item.children && isArray(item.children) && item.children.length > 0) {
|
48
|
+
getFatherAndSon(deepClone(item.children));
|
49
|
+
}
|
50
|
+
}
|
51
|
+
return tempArr;
|
52
|
+
};
|
53
|
+
const expandChange = (...args: any) => {
|
54
|
+
const [row, isOpen] = args as [NavArrItem, boolean];
|
55
|
+
const autoid = row.id;
|
56
|
+
if (isOpen) {
|
57
|
+
expandKeys.value.add(autoid + '');
|
58
|
+
} else {
|
59
|
+
const allSub = getFatherAndSon([row], 1);
|
60
|
+
allSub.forEach((v) => expandKeys.value.delete(v));
|
61
|
+
}
|
62
|
+
};
|
63
|
+
const tableData = ref<NavArrItem[]>([]);
|
64
|
+
|
65
|
+
const topMenuOption = ref<Partial<NavArrItem>[]>([]);
|
66
|
+
|
67
|
+
/**
|
68
|
+
* 获取节点列表
|
69
|
+
*/
|
70
|
+
const getList = async () => {
|
71
|
+
const list = Object.values(await apis.get.getMenuList());
|
72
|
+
|
73
|
+
tableData.value = list;
|
74
|
+
|
75
|
+
topMenuOption.value = [
|
76
|
+
{ title: '顶级目录', children: list, id: 0 }
|
77
|
+
];
|
78
|
+
};
|
79
|
+
|
80
|
+
const {
|
81
|
+
isAdd,
|
82
|
+
isEdit,
|
83
|
+
form,
|
84
|
+
edit,
|
85
|
+
del,
|
86
|
+
sure,
|
87
|
+
clear,
|
88
|
+
formRef,
|
89
|
+
validForm
|
90
|
+
} = useFormMode<NavArrItem>(FORM_TEMP, {
|
91
|
+
addCbk: async () => {
|
92
|
+
const res = await validForm() as boolean;
|
93
|
+
if (res) {
|
94
|
+
const v = deepClone(form.value);
|
95
|
+
await apis.post.addMenuItem(v);
|
96
|
+
ElMessage.success('菜单添加成功!');
|
97
|
+
}
|
98
|
+
return res;
|
99
|
+
},
|
100
|
+
modCbk: async () => {
|
101
|
+
const res = await validForm() as boolean;
|
102
|
+
if (res) {
|
103
|
+
const v = deepClone(form.value);
|
104
|
+
await apis.patch.changeMenuItem(v);
|
105
|
+
ElMessage.success('菜单修改成功!');
|
106
|
+
}
|
107
|
+
return res;
|
108
|
+
},
|
109
|
+
delCbk: async (nav: NavArrItem) => {
|
110
|
+
apis.delete.deleteMenu(nav.id.toString());
|
111
|
+
expandKeys.value.delete(nav.id.toString());
|
112
|
+
ElMessage.success('节点删除成功!');
|
113
|
+
// 框架有 bug,视图更新不及时
|
114
|
+
location.reload();
|
115
|
+
},
|
116
|
+
cgEffect: async () => {
|
117
|
+
await getList();
|
118
|
+
}
|
119
|
+
});
|
120
|
+
|
121
|
+
/**
|
122
|
+
* 添加节点
|
123
|
+
*/
|
124
|
+
const add = () => {
|
125
|
+
form.value.parentId = 0;
|
126
|
+
isAdd.value = true;
|
127
|
+
};
|
128
|
+
|
129
|
+
const changeVisiable = async (id: number, visible: number) => {
|
130
|
+
await apis.patch.changeMenuItem({ id, visible });
|
131
|
+
ElMessage.success('修改成功!');
|
132
|
+
getList();
|
133
|
+
};
|
134
|
+
|
135
|
+
getList()
|
136
|
+
</script>
|
137
|
+
|
138
|
+
<template>
|
139
|
+
<div class="index">
|
140
|
+
<div class="caozuoFat">
|
141
|
+
<ElButton type="primary" plain @click="add">新建菜单</ElButton>
|
142
|
+
</div>
|
143
|
+
<!-- 节点列表 -->
|
144
|
+
<ElTable :data="tableData" style="width: 100%; margin-bottom: 20px;" :tree-props="{ children: 'children' }"
|
145
|
+
row-key="id" :expand-row-keys="[...expandKeys]" @expand-change="expandChange">
|
146
|
+
<ElTableColumn prop="name" label="英文名称" width="320px" />
|
147
|
+
<ElTableColumn prop="title" label="标题" />
|
148
|
+
<ElTableColumn prop="sort" label="同级排序" />
|
149
|
+
<ElTableColumn prop="component" label="页面路径" />
|
150
|
+
<ElTableColumn prop="visible" label="隐藏/显示">
|
151
|
+
<template #default="scope">
|
152
|
+
<ElSwitch v-model="scope.row.visible" :active-value="1" :inactive-value="0" active-color="#409EFF"
|
153
|
+
inactive-color="#909399" @change="(e) => changeVisiable(scope.row.id, e as number)" />
|
154
|
+
</template>
|
155
|
+
</ElTableColumn>
|
156
|
+
<ElTableColumn prop="creator" label="创建人" />
|
157
|
+
<ElTableColumn label="操作" width="300" fixed="right">
|
158
|
+
<template #default="scope">
|
159
|
+
<ElButton @click="edit(scope.row)">编辑</ElButton>
|
160
|
+
<ElButton type="danger" @click="del(scope.row)">删除</ElButton>
|
161
|
+
</template>
|
162
|
+
</ElTableColumn>
|
163
|
+
</ElTable>
|
164
|
+
<!-- 添加 / 编辑 -->
|
165
|
+
<YoungDialog width="370px" :is-add="isAdd" :is-edit="isEdit" @sure="sure" @clear="clear">
|
166
|
+
<template #body>
|
167
|
+
<ElForm ref="formRef" :model="form" label-width="80px">
|
168
|
+
<ElFormItem label="上级目录">
|
169
|
+
<ElCascader :model-value="form.parentId" :props="{
|
170
|
+
label: 'title',
|
171
|
+
value: 'id',
|
172
|
+
checkStrictly: true,
|
173
|
+
multiple: false
|
174
|
+
}" :options="topMenuOption" :show-all-levels="false"
|
175
|
+
@update:model-value="(e: any) => form.parentId = e[e.length - 1]" />
|
176
|
+
</ElFormItem>
|
177
|
+
<ElFormItem label="英文名称" prop="name" :rules="{ required: true, message: '请输入英文名', trigger: 'blur' }">
|
178
|
+
<ElInput v-model="form.name" placeholder="请输入英文名" />
|
179
|
+
</ElFormItem>
|
180
|
+
<ElFormItem label="标题" prop="title" :rules="{ required: true, message: '请输入页面标题', trigger: 'blur' }">
|
181
|
+
<ElInput v-model="form.title" placeholder="请输入页面标题" />
|
182
|
+
</ElFormItem>
|
183
|
+
<ElFormItem label="排序">
|
184
|
+
<ElInput v-model.number="form.sort" />
|
185
|
+
</ElFormItem>
|
186
|
+
<ElFormItem label="路径" prop="component" :rules="form.parentId === 0 ? {} :
|
187
|
+
{ message: '请输入合法的路径, eg: /path/page', trigger: 'blur', validator: (_: any, v: string) => v.trim() === '' || /\/(.*)\/(.*)/.test(v) }
|
188
|
+
">
|
189
|
+
<ElInput v-model="form.component" />
|
190
|
+
</ElFormItem>
|
191
|
+
</ElForm>
|
192
|
+
</template>
|
193
|
+
</YoungDialog>
|
194
|
+
</div>
|
195
|
+
</template>
|
@@ -0,0 +1,132 @@
|
|
1
|
+
<!--
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2022-03-01 20:04:26
|
4
|
+
* @LastEditTime: 2023-01-09 10:32:11
|
5
|
+
* @Description: 角色列表
|
6
|
+
-->
|
7
|
+
<route lang="yaml">
|
8
|
+
meta:
|
9
|
+
title: 角色列表
|
10
|
+
authPath: /system/role
|
11
|
+
</route>
|
12
|
+
|
13
|
+
<script lang="ts" setup>
|
14
|
+
import { YoungTable, YoungDialog, YoungPagination } from '@bluesyoung/ui-vue3-element-plus';
|
15
|
+
import { useRoleApi, useRoleBase, useRoleMenu } from './hooks/useRole';
|
16
|
+
|
17
|
+
const {
|
18
|
+
query,
|
19
|
+
getList,
|
20
|
+
tableHead,
|
21
|
+
tableData,
|
22
|
+
baseFormRef,
|
23
|
+
changeStatus,
|
24
|
+
base
|
25
|
+
} = useRoleBase();
|
26
|
+
|
27
|
+
const { showPriority, menu } = useRoleMenu();
|
28
|
+
|
29
|
+
const { showApi, api } = useRoleApi();
|
30
|
+
|
31
|
+
getList();
|
32
|
+
</script>
|
33
|
+
|
34
|
+
<template>
|
35
|
+
<div class="flex">
|
36
|
+
<div class="m-2">
|
37
|
+
<ElInput v-model="query.name" placeholder="请输入角色名称(中文)" />
|
38
|
+
</div>
|
39
|
+
<div class="m-2">
|
40
|
+
<ElInput v-model="query.keyword" placeholder="请输入角色关键字(英文)" />
|
41
|
+
</div>
|
42
|
+
<div class="m-2 w-50">
|
43
|
+
<ElSelect v-model="query.status" placeholder="请选择状态" clearable>
|
44
|
+
<ElOption :value="1" label="1-启用" />
|
45
|
+
<ElOption :value="0" label="0-禁用" />
|
46
|
+
</ElSelect>
|
47
|
+
</div>
|
48
|
+
<div class="m-2">
|
49
|
+
<ElButton type="primary" @click="getList">搜索</ElButton>
|
50
|
+
</div>
|
51
|
+
<div class="m-2">
|
52
|
+
<ElButton type="success" @click="base.isAdd = true">添加角色</ElButton>
|
53
|
+
</div>
|
54
|
+
</div>
|
55
|
+
<div class="m-2">
|
56
|
+
<YoungTable :table-data="tableData" :table-head="tableHead" :table-height="680">
|
57
|
+
<template #switch>
|
58
|
+
<ElTableColumn label="禁用/启用">
|
59
|
+
<template #default="scope">
|
60
|
+
<ElSwitch v-model="scope.row.status" :active-value="1" :inactive-value="0" active-color="#409EFF"
|
61
|
+
inactive-color="#909399" @change="(e) => changeStatus(scope.row.id, e as number)" />
|
62
|
+
</template>
|
63
|
+
</ElTableColumn>
|
64
|
+
</template>
|
65
|
+
<template #operate>
|
66
|
+
<ElTableColumn label="操作" width="300px" fixed="right">
|
67
|
+
<template #default="scope">
|
68
|
+
<ElButton type="primary" link @click="base.edit(scope.row)">信息编辑</ElButton>
|
69
|
+
<ElButton type="primary" link @click="menu.edit(scope.row)">菜单编辑</ElButton>
|
70
|
+
<ElButton type="primary" link @click="api.edit(scope.row)">接口编辑</ElButton>
|
71
|
+
<ElButton type="danger" link @click="base.del(scope.row)">删除</ElButton>
|
72
|
+
</template>
|
73
|
+
</ElTableColumn>
|
74
|
+
</template>
|
75
|
+
</YoungTable>
|
76
|
+
<YoungPagination v-model:page="query.pageNum" v-model:limit="query.pageSize" :total="query.total"
|
77
|
+
@page-change="getList" />
|
78
|
+
</div>
|
79
|
+
<!-- 基础信息编辑 -->
|
80
|
+
<YoungDialog :is-add="base.isAdd" :is-edit="base.isEdit" width="520px" @sure="base.sure" @clear="base.clear">
|
81
|
+
<template #body>
|
82
|
+
<ElForm ref="baseFormRef" :model="base.form" label-width="120px">
|
83
|
+
<ElFormItem label="角色名称(中文)" prop="name" :rules="[{ required: true, message: '请填写角色名称', trigger: 'blur' }]">
|
84
|
+
<ElInput v-model="base.form.name" class="!w-300px" />
|
85
|
+
</ElFormItem>
|
86
|
+
<ElFormItem label="关键字(英文)" prop="keyword" :rules="[{ required: true, message: '请填写关键字', trigger: 'blur' }]">
|
87
|
+
<ElInput v-model="base.form.keyword" class="!w-300px" />
|
88
|
+
</ElFormItem>
|
89
|
+
<ElFormItem label="角色描述">
|
90
|
+
<ElInput v-model="base.form.desc" class="!w-300px" />
|
91
|
+
</ElFormItem>
|
92
|
+
</ElForm>
|
93
|
+
</template>
|
94
|
+
</YoungDialog>
|
95
|
+
<!-- 菜单编辑 -->
|
96
|
+
<YoungDialog real-title="菜单编辑" :is-edit="showPriority" top="5vh" width="1200px" @sure="menu.sure" @clear="menu.clear">
|
97
|
+
<template #body>
|
98
|
+
<ElTable :data="menu.tableData" row-key="id" :default-expand-all="false" class="max-h-600px !overflow-y-auto">
|
99
|
+
<ElTableColumn prop="name" label="节点名称" width="320px">
|
100
|
+
<template #default="scope">
|
101
|
+
<ElCheckbox v-model="menu.checkMap[scope.row.id]" @change="menu.selectChange(scope.row)">{{
|
102
|
+
scope.row.title
|
103
|
+
}}</ElCheckbox>
|
104
|
+
</template>
|
105
|
+
</ElTableColumn>
|
106
|
+
<ElTableColumn v-for="(item, index) in menu.tableHead" v-bind="item" :key="index + 'fsdjhfaer'" />
|
107
|
+
<ElTableColumn prop="name" label="隐藏/显示">
|
108
|
+
<template #default="scope">
|
109
|
+
<ElSwitch v-model="scope.row.visible" :active-value="1" :inactive-value="0" active-color="#409EFF"
|
110
|
+
inactive-color="#909399" disabled />
|
111
|
+
</template>
|
112
|
+
</ElTableColumn>
|
113
|
+
</ElTable>
|
114
|
+
</template>
|
115
|
+
</YoungDialog>
|
116
|
+
<!-- 接口编辑 -->
|
117
|
+
<YoungDialog real-title="接口编辑" :is-edit="showApi" top="5vh" width="1200px" @sure="api.sure" @clear="api.clear">
|
118
|
+
<template #body>
|
119
|
+
<ElTable :data="api.tableData" row-key="id" :default-expand-all="false" class="max-h-600px !overflow-y-auto">
|
120
|
+
<ElTableColumn prop="name" width="100px">
|
121
|
+
<template #header>
|
122
|
+
<ElCheckbox v-model="api.isAll" @change="api.changeAll">全选</ElCheckbox>
|
123
|
+
</template>
|
124
|
+
<template #default="scope">
|
125
|
+
<ElCheckbox v-model="api.checkMap[scope.row.id]">{{ scope.row.title }}</ElCheckbox>
|
126
|
+
</template>
|
127
|
+
</ElTableColumn>
|
128
|
+
<ElTableColumn v-for="(item, index) in api.tableHead" v-bind="item" :key="index + 'fsdjhfaer'" />
|
129
|
+
</ElTable>
|
130
|
+
</template>
|
131
|
+
</YoungDialog>
|
132
|
+
</template>
|
@@ -0,0 +1,193 @@
|
|
1
|
+
<!--
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2022-10-27 11:28:27
|
4
|
+
* @LastEditTime: 2023-01-09 10:32:20
|
5
|
+
* @Description:
|
6
|
+
-->
|
7
|
+
<route lang="yaml">
|
8
|
+
meta:
|
9
|
+
title: 用户管理
|
10
|
+
authPath: /system/user
|
11
|
+
</route>
|
12
|
+
|
13
|
+
<script lang="ts" setup>
|
14
|
+
import { useFormMode, YoungDialog, YoungPagination, YoungTable, YoungSelect } from '@bluesyoung/ui-vue3-element-plus';
|
15
|
+
import type { TableHeadItem, TableDataItem, SelectOptionItem } from '@bluesyoung/ui-vue3-element-plus';
|
16
|
+
import { deepClone } from '@bluesyoung/utils';
|
17
|
+
import { RoleItem, UserItem } from '@/typings';
|
18
|
+
import { apis } from '@/modules/3-net';
|
19
|
+
|
20
|
+
interface Form extends UserItem { };
|
21
|
+
const FORM_TEMP: Form = {
|
22
|
+
id: 0,
|
23
|
+
username: '',
|
24
|
+
nickname: '',
|
25
|
+
mobile: '',
|
26
|
+
roleId: 1,
|
27
|
+
status: 1,
|
28
|
+
initPassword: ''
|
29
|
+
};
|
30
|
+
const {
|
31
|
+
isAdd,
|
32
|
+
isEdit,
|
33
|
+
edit,
|
34
|
+
del,
|
35
|
+
sure,
|
36
|
+
clear,
|
37
|
+
form,
|
38
|
+
formRef,
|
39
|
+
validForm
|
40
|
+
} = useFormMode<Form>(FORM_TEMP, {
|
41
|
+
addCbk: async () => {
|
42
|
+
const res = await validForm() as boolean;
|
43
|
+
if (res) {
|
44
|
+
const v = deepClone(form.value);
|
45
|
+
await apis.post.addUserItem(v);
|
46
|
+
ElMessage.success('新增成功!');
|
47
|
+
}
|
48
|
+
return res;
|
49
|
+
},
|
50
|
+
modCbk: async () => {
|
51
|
+
const res = await validForm() as boolean;
|
52
|
+
if (res) {
|
53
|
+
const v = deepClone(form.value);
|
54
|
+
await apis.patch.changeUserItem(v);
|
55
|
+
ElMessage.success('修改成功!');
|
56
|
+
}
|
57
|
+
return res;
|
58
|
+
},
|
59
|
+
delCbk: async (row) => {
|
60
|
+
await apis.delete.deleteUser(row.id.toString());
|
61
|
+
ElMessage.success('删除成功!');
|
62
|
+
query.pageNum = 1;
|
63
|
+
},
|
64
|
+
cgEffect: () => getList()
|
65
|
+
});
|
66
|
+
const tableHead: TableHeadItem<Form>[] = [
|
67
|
+
{ prop: 'id', label: '用户ID' },
|
68
|
+
{ prop: 'username', label: '用户名' },
|
69
|
+
{ prop: 'mobile', label: '手机号' },
|
70
|
+
{ prop: 'role_name', label: '角色名称' },
|
71
|
+
{ prop: 'creator', label: '创建信息' },
|
72
|
+
];
|
73
|
+
interface Query extends BaseQuery {
|
74
|
+
username: string;
|
75
|
+
mobile: string;
|
76
|
+
status: 0 | 1;
|
77
|
+
};
|
78
|
+
const query = reactive<Query>({
|
79
|
+
pageNum: 1,
|
80
|
+
pageSize: 50,
|
81
|
+
total: 0,
|
82
|
+
username: '',
|
83
|
+
mobile: '',
|
84
|
+
status: 1
|
85
|
+
});
|
86
|
+
|
87
|
+
const tableData = ref<TableDataItem<Form>[]>([]);
|
88
|
+
const roleList = ref<SelectOptionItem<number>[]>([]);
|
89
|
+
const getList = async () => {
|
90
|
+
const { list: role_list } = await apis.get.getRoleList({ noPagination: true });
|
91
|
+
roleList.value = (role_list || []).map((item: RoleItem) => {
|
92
|
+
return {
|
93
|
+
label: item.name,
|
94
|
+
value: item.id
|
95
|
+
};
|
96
|
+
});
|
97
|
+
|
98
|
+
const { list, pageNum, pageSize, total } = await apis.get.getUserList(query);
|
99
|
+
tableData.value = deepClone(list || []);
|
100
|
+
query.pageNum = +pageNum || 1;
|
101
|
+
query.pageSize = +pageSize || 50;
|
102
|
+
query.total = +total || 0;
|
103
|
+
};
|
104
|
+
/**
|
105
|
+
* @param id userId
|
106
|
+
* @param status 0 | 1
|
107
|
+
*/
|
108
|
+
const changeStatus = async (id: number, status: number) => {
|
109
|
+
await apis.patch.changeUserItem({ id, status });
|
110
|
+
ElMessage.success('修改成功!');
|
111
|
+
getList();
|
112
|
+
};
|
113
|
+
|
114
|
+
const changePwd = (e: UserItem) => {
|
115
|
+
ElMessageBox.prompt('请输入新密码').then(async ({ value }) => {
|
116
|
+
value = value.trim()
|
117
|
+
if (value) {
|
118
|
+
await apis.patch.changeUserItem({ id: e.id, newPassword: value });
|
119
|
+
ElMessage.success('修改成功!');
|
120
|
+
}
|
121
|
+
}).catch(() => null);
|
122
|
+
};
|
123
|
+
|
124
|
+
getList();
|
125
|
+
</script>
|
126
|
+
|
127
|
+
<template>
|
128
|
+
<div class="flex">
|
129
|
+
<div class="m-2">
|
130
|
+
<ElInput v-model="query.username" placeholder="请输入用户名" />
|
131
|
+
</div>
|
132
|
+
<div class="m-2">
|
133
|
+
<ElInput v-model="query.mobile" placeholder="请输入手机号" :maxlength="11" />
|
134
|
+
</div>
|
135
|
+
<div class="m-2 w-50">
|
136
|
+
<ElSelect v-model="query.status" placeholder="请选择状态" clearable>
|
137
|
+
<ElOption :value="1" label="1-启用" />
|
138
|
+
<ElOption :value="0" label="0-禁用" />
|
139
|
+
</ElSelect>
|
140
|
+
</div>
|
141
|
+
<div class="m-2">
|
142
|
+
<ElButton type="primary" @click="getList">搜索</ElButton>
|
143
|
+
</div>
|
144
|
+
<div class="m-2">
|
145
|
+
<ElButton type="success" @click="isAdd = true">添加用户</ElButton>
|
146
|
+
</div>
|
147
|
+
</div>
|
148
|
+
<div class="m-2">
|
149
|
+
<YoungTable :table-data="tableData" :table-head="tableHead" :table-height="680">
|
150
|
+
<template #switch>
|
151
|
+
<ElTableColumn label="禁用/启用">
|
152
|
+
<template #default="scope">
|
153
|
+
<ElSwitch v-model="scope.row.status" :active-value="1" :inactive-value="0" active-color="#409EFF"
|
154
|
+
inactive-color="#909399" @change="(e) => changeStatus(scope.row.id, e as number)" />
|
155
|
+
</template>
|
156
|
+
</ElTableColumn>
|
157
|
+
</template>
|
158
|
+
<template #operate>
|
159
|
+
<ElTableColumn label="操作" width="300px" fixed="right">
|
160
|
+
<template #default="scope">
|
161
|
+
<ElButton type="primary" link @click="edit(scope.row)">编辑</ElButton>
|
162
|
+
<ElButton type="warning" link @click="changePwd(scope.row)">修改密码</ElButton>
|
163
|
+
<ElButton type="danger" link @click="del(scope.row)">删除</ElButton>
|
164
|
+
</template>
|
165
|
+
</ElTableColumn>
|
166
|
+
</template>
|
167
|
+
</YoungTable>
|
168
|
+
<YoungPagination v-show="query.total > 0" v-model:page="query.pageNum" v-model:limit="query.pageSize"
|
169
|
+
:total="query.total" @page-change="getList" />
|
170
|
+
</div>
|
171
|
+
<YoungDialog :is-add="isAdd" :is-edit="isEdit" width="520px" @sure="sure" @clear="clear">
|
172
|
+
<template #body>
|
173
|
+
<ElForm ref="formRef" :model="form" label-width="100px">
|
174
|
+
<ElFormItem label="用户名" prop="username" :rules="{ required: true, message: '请输用户名', trigger: 'blur' }">
|
175
|
+
<ElInput v-model="form.username" class="!w-300px" />
|
176
|
+
</ElFormItem>
|
177
|
+
<ElFormItem label="昵称" prop="nickname" :rules="{ required: true, message: '请输昵称(用于右上角展示)', trigger: 'blur' }">
|
178
|
+
<ElInput v-model="form.nickname" class="!w-300px" />
|
179
|
+
</ElFormItem>
|
180
|
+
<ElFormItem label="手机号" prop="mobile" :rules="{ required: true, message: '请输手机号', trigger: 'blur' }">
|
181
|
+
<ElInput v-model="form.mobile" :maxlength="11" class="!w-300px" />
|
182
|
+
</ElFormItem>
|
183
|
+
<ElFormItem label="角色">
|
184
|
+
<YoungSelect v-model="form.roleId" placeholder="请选择角色" :options="roleList" />
|
185
|
+
</ElFormItem>
|
186
|
+
<ElFormItem v-if="isAdd" label="初始密码" prop="initPassword"
|
187
|
+
:rules="{ required: true, message: '请输初始密码', trigger: 'blur' }">
|
188
|
+
<ElInput v-model="form.initPassword" class="!w-300px" />
|
189
|
+
</ElFormItem>
|
190
|
+
</ElForm>
|
191
|
+
</template>
|
192
|
+
</YoungDialog>
|
193
|
+
</template>
|
@@ -0,0 +1,52 @@
|
|
1
|
+
/*
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2022-12-03 15:57:40
|
4
|
+
* @LastEditTime: 2023-01-05 09:16:16
|
5
|
+
* @Description:
|
6
|
+
*/
|
7
|
+
/// <reference types="vite/client" />
|
8
|
+
/// <reference types="vite-plugin-pages/client" />
|
9
|
+
/// <reference types="vite-plugin-vue-layouts/client" />
|
10
|
+
|
11
|
+
declare module '*.vue' {
|
12
|
+
import type { DefineComponent } from 'vue'
|
13
|
+
const component: DefineComponent<{}, {}, any>
|
14
|
+
export default component
|
15
|
+
}
|
16
|
+
|
17
|
+
/**
|
18
|
+
* import.meta.env 类型提示
|
19
|
+
*/
|
20
|
+
declare interface ImportMetaEnv {
|
21
|
+
/**
|
22
|
+
* 标题
|
23
|
+
*/
|
24
|
+
VITE_TITLE?: string;
|
25
|
+
|
26
|
+
/**
|
27
|
+
* 基础接口请求地址
|
28
|
+
*/
|
29
|
+
VITE_BASE_HTTP: string;
|
30
|
+
|
31
|
+
|
32
|
+
/**
|
33
|
+
* 是否启用 Casdoor
|
34
|
+
*/
|
35
|
+
// VITE_ENABLE_CASDOOR?: string;
|
36
|
+
/**
|
37
|
+
* Casdoor 相关
|
38
|
+
*/
|
39
|
+
// VITE_CAS_SERVER?: string;
|
40
|
+
// VITE_CAS_ID?: string;
|
41
|
+
// VITE_CAS_ORG?: string;
|
42
|
+
// VITE_CAS_APP?: string;
|
43
|
+
|
44
|
+
/**
|
45
|
+
* 是否静态部署
|
46
|
+
*/
|
47
|
+
VITE_USE_DEFAULT_DEPLOY_METHOD?: boolean;
|
48
|
+
}
|
49
|
+
|
50
|
+
declare interface Window {
|
51
|
+
__YOUNG_VITE_ENV__: ImportMetaEnv;
|
52
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
{
|
2
|
+
"compilerOptions": {
|
3
|
+
"target": "ESNext",
|
4
|
+
"useDefineForClassFields": true,
|
5
|
+
"module": "ESNext",
|
6
|
+
"moduleResolution": "Node",
|
7
|
+
"strict": true,
|
8
|
+
"jsx": "preserve",
|
9
|
+
"resolveJsonModule": true,
|
10
|
+
"isolatedModules": true,
|
11
|
+
"esModuleInterop": true,
|
12
|
+
"lib": ["ESNext", "DOM"],
|
13
|
+
"skipLibCheck": true,
|
14
|
+
"noEmit": true,
|
15
|
+
"paths": {
|
16
|
+
"@/*": ["./src/*"]
|
17
|
+
}
|
18
|
+
},
|
19
|
+
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", ".nitro/**/*"],
|
20
|
+
"references": [{ "path": "./tsconfig.node.json" }]
|
21
|
+
}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
/*
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2022-03-01 19:11:11
|
4
|
+
* @LastEditTime: 2022-05-21 18:32:05
|
5
|
+
* @Description:
|
6
|
+
*/
|
7
|
+
import {
|
8
|
+
defineConfig,
|
9
|
+
presetAttributify,
|
10
|
+
presetIcons,
|
11
|
+
presetTypography,
|
12
|
+
presetUno,
|
13
|
+
presetWebFonts,
|
14
|
+
transformerDirectives,
|
15
|
+
transformerVariantGroup,
|
16
|
+
} from 'unocss';
|
17
|
+
|
18
|
+
export default defineConfig({
|
19
|
+
shortcuts: [
|
20
|
+
[
|
21
|
+
'btn',
|
22
|
+
'px-4 py-1 rounded inline-block bg-teal-700 text-white cursor-pointer hover:bg-teal-800 disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50',
|
23
|
+
],
|
24
|
+
[
|
25
|
+
'icon-btn',
|
26
|
+
'inline-block cursor-pointer select-none opacity-75 transition duration-200 ease-in-out hover:opacity-100 hover:text-teal-600',
|
27
|
+
],
|
28
|
+
],
|
29
|
+
presets: [
|
30
|
+
presetUno(),
|
31
|
+
presetAttributify(),
|
32
|
+
presetIcons({
|
33
|
+
scale: 1.2,
|
34
|
+
warn: true,
|
35
|
+
}),
|
36
|
+
presetTypography(),
|
37
|
+
presetWebFonts({
|
38
|
+
fonts: {
|
39
|
+
sans: 'DM Sans',
|
40
|
+
serif: 'DM Serif Display',
|
41
|
+
mono: 'DM Mono',
|
42
|
+
},
|
43
|
+
}),
|
44
|
+
],
|
45
|
+
transformers: [transformerDirectives(), transformerVariantGroup()],
|
46
|
+
safelist: 'prose prose-sm m-auto text-left'.split(' '),
|
47
|
+
});
|
@@ -0,0 +1,32 @@
|
|
1
|
+
/*
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2022-12-03 15:57:40
|
4
|
+
* @LastEditTime: 2023-01-10 15:12:20
|
5
|
+
* @Description:
|
6
|
+
*/
|
7
|
+
import { fileURLToPath, URL } from 'node:url';
|
8
|
+
import { defineConfig, loadEnv } from 'vite';
|
9
|
+
import type { ConfigEnv, UserConfigExport } from 'vite';
|
10
|
+
import { usePlugins, localServer } from './build';
|
11
|
+
|
12
|
+
// https://vitejs.dev/config/
|
13
|
+
export default ({ command, mode }: ConfigEnv): UserConfigExport => {
|
14
|
+
const root = process.cwd();
|
15
|
+
const viteEnv = loadEnv(mode, root);
|
16
|
+
console.log('🚀 ~ file: vite.config.ts ~ line 36 ~ viteEnv', viteEnv);
|
17
|
+
return defineConfig({
|
18
|
+
base: './',
|
19
|
+
plugins: usePlugins(),
|
20
|
+
resolve: {
|
21
|
+
alias: {
|
22
|
+
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
23
|
+
},
|
24
|
+
},
|
25
|
+
server: {
|
26
|
+
host: true,
|
27
|
+
proxy: {
|
28
|
+
'/api': localServer,
|
29
|
+
},
|
30
|
+
},
|
31
|
+
});
|
32
|
+
};
|