create-young-proj 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +13 -2
  3. package/dist/index.mjs +18 -18
  4. package/index.mjs +3 -3
  5. package/package.json +10 -12
  6. package/template-admin-server/.editorconfig +11 -0
  7. package/template-admin-server/.nvmrc +1 -0
  8. package/template-admin-server/.vscode/extensions.json +6 -0
  9. package/template-admin-server/.vscode/settings.json +4 -0
  10. package/template-admin-server/README.md +73 -0
  11. package/template-admin-server/_gitignore +15 -0
  12. package/template-admin-server/boot.mjs +11 -0
  13. package/template-admin-server/package.json +60 -0
  14. package/template-admin-server/rome.json +22 -0
  15. package/template-admin-server/src/config/config.default.ts +56 -0
  16. package/template-admin-server/src/configuration.ts +47 -0
  17. package/template-admin-server/src/controller/admin.controller.ts +397 -0
  18. package/template-admin-server/src/controller/api.controller.ts +98 -0
  19. package/template-admin-server/src/controller/base.controller.ts +70 -0
  20. package/template-admin-server/src/controller/dto/api.ts +47 -0
  21. package/template-admin-server/src/controller/dto/index.ts +36 -0
  22. package/template-admin-server/src/controller/dto/menu.ts +41 -0
  23. package/template-admin-server/src/controller/dto/role.ts +41 -0
  24. package/template-admin-server/src/controller/dto/user.ts +52 -0
  25. package/template-admin-server/src/controller/menu.controller.ts +138 -0
  26. package/template-admin-server/src/controller/role.controller.ts +116 -0
  27. package/template-admin-server/src/controller/user.controller.ts +108 -0
  28. package/template-admin-server/src/entities/Api.ts +29 -0
  29. package/template-admin-server/src/entities/BaseCreate.ts +30 -0
  30. package/template-admin-server/src/entities/Menu.ts +39 -0
  31. package/template-admin-server/src/entities/Role.ts +36 -0
  32. package/template-admin-server/src/entities/User.ts +35 -0
  33. package/template-admin-server/src/entities/index.ts +10 -0
  34. package/template-admin-server/src/filter/default.filter.ts +22 -0
  35. package/template-admin-server/src/filter/notfound.filter.ts +23 -0
  36. package/template-admin-server/src/middleware/helper.middleware.ts +28 -0
  37. package/template-admin-server/src/middleware/index.ts +9 -0
  38. package/template-admin-server/src/middleware/jwt.middleware.ts +32 -0
  39. package/template-admin-server/src/middleware/report.middleware.ts +26 -0
  40. package/template-admin-server/src/service/api.service.ts +174 -0
  41. package/template-admin-server/src/service/basic.ts +118 -0
  42. package/template-admin-server/src/service/index.ts +10 -0
  43. package/template-admin-server/src/service/menu.service.ts +139 -0
  44. package/template-admin-server/src/service/role.service.ts +286 -0
  45. package/template-admin-server/src/service/user.service.ts +124 -0
  46. package/template-admin-server/src/strategy/jwt.strategy.ts +26 -0
  47. package/template-admin-server/src/types/index.ts +42 -0
  48. package/template-admin-server/src/types/types.d.ts +31 -0
  49. package/template-admin-server/tsconfig.json +24 -0
  50. package/template-vue-admin/.vscode/extensions.json +10 -0
  51. package/template-vue-admin/.vscode/list-add.code-snippets +108 -0
  52. package/template-vue-admin/.vscode/list-export.code-snippets +72 -0
  53. package/template-vue-admin/.vscode/list.code-snippets +61 -0
  54. package/template-vue-admin/.vscode/settings.json +7 -0
  55. package/template-vue-admin/Dockerfile +42 -0
  56. package/template-vue-admin/README.md +75 -0
  57. package/template-vue-admin/_env +8 -0
  58. package/template-vue-admin/_gitignore +30 -0
  59. package/template-vue-admin/boot.mjs +16 -0
  60. package/template-vue-admin/config/.devrc +2 -0
  61. package/template-vue-admin/config/.onlinerc +2 -0
  62. package/template-vue-admin/config/.testrc +2 -0
  63. package/template-vue-admin/index.html +21 -0
  64. package/template-vue-admin/nitro.config.ts +19 -0
  65. package/template-vue-admin/package.json +50 -0
  66. package/template-vue-admin/plugins/env.ts +26 -0
  67. package/template-vue-admin/public/vite.svg +1 -0
  68. package/template-vue-admin/rome.json +26 -0
  69. package/template-vue-admin/routes/api/[...all].ts +49 -0
  70. package/template-vue-admin/routes/get/env.ts +18 -0
  71. package/template-vue-admin/src/App.vue +14 -0
  72. package/template-vue-admin/src/apis/delete.ts +36 -0
  73. package/template-vue-admin/src/apis/get.ts +84 -0
  74. package/template-vue-admin/src/apis/index.ts +10 -0
  75. package/template-vue-admin/src/apis/patch.ts +79 -0
  76. package/template-vue-admin/src/apis/post.ts +77 -0
  77. package/template-vue-admin/src/assets/img/login_background.jpg +0 -0
  78. package/template-vue-admin/src/auto-components.d.ts +36 -0
  79. package/template-vue-admin/src/auto-imports.d.ts +282 -0
  80. package/template-vue-admin/src/layouts/blank.vue +9 -0
  81. package/template-vue-admin/src/layouts/default/components/Link.vue +23 -0
  82. package/template-vue-admin/src/layouts/default/components/Logo.vue +20 -0
  83. package/template-vue-admin/src/layouts/default/components/Menu.vue +54 -0
  84. package/template-vue-admin/src/layouts/default/components/NavSearch.vue +52 -0
  85. package/template-vue-admin/src/layouts/default/components/ScrollPane.vue +79 -0
  86. package/template-vue-admin/src/layouts/default/components/TagsView.vue +137 -0
  87. package/template-vue-admin/src/layouts/default/components/TopMenu.vue +21 -0
  88. package/template-vue-admin/src/layouts/default/components/UserCenter.vue +50 -0
  89. package/template-vue-admin/src/layouts/default/index.vue +95 -0
  90. package/template-vue-admin/src/main.ts +44 -0
  91. package/template-vue-admin/src/modules/1-router.ts +66 -0
  92. package/template-vue-admin/src/modules/2-pinia.ts +10 -0
  93. package/template-vue-admin/src/modules/3-net.ts +75 -0
  94. package/template-vue-admin/src/modules/4-auth.ts +122 -0
  95. package/template-vue-admin/src/stores/index.ts +9 -0
  96. package/template-vue-admin/src/stores/local/index.ts +23 -0
  97. package/template-vue-admin/src/stores/session/index.ts +63 -0
  98. package/template-vue-admin/src/stores/tags.ts +109 -0
  99. package/template-vue-admin/src/typings/global.d.ts +70 -0
  100. package/template-vue-admin/src/typings/index.ts +50 -0
  101. package/template-vue-admin/src/views/403.vue +32 -0
  102. package/template-vue-admin/src/views/[...all_404].vue +556 -0
  103. package/template-vue-admin/src/views/base/login.vue +193 -0
  104. package/template-vue-admin/src/views/dashboard/[name].vue +23 -0
  105. package/template-vue-admin/src/views/index.vue +19 -0
  106. package/template-vue-admin/src/views/system/api.vue +161 -0
  107. package/template-vue-admin/src/views/system/hooks/useRole.ts +286 -0
  108. package/template-vue-admin/src/views/system/menuList.vue +195 -0
  109. package/template-vue-admin/src/views/system/role.vue +132 -0
  110. package/template-vue-admin/src/views/system/user.vue +193 -0
  111. package/template-vue-admin/src/vite-env.d.ts +52 -0
  112. package/template-vue-admin/tsconfig.json +21 -0
  113. package/template-vue-admin/tsconfig.node.json +9 -0
  114. package/template-vue-admin/unocss.config.ts +47 -0
  115. package/template-vue-admin/vite.config.ts +77 -0
  116. package/template-vue-thin/package.json +14 -13
  117. package/template-vue-thin/vite.config.ts +1 -6
@@ -0,0 +1,193 @@
1
+ <!--
2
+ * @Author: zhangyang
3
+ * @Date: 2023-01-04 12:08:08
4
+ * @LastEditTime: 2023-01-09 09:38:39
5
+ * @Description:
6
+ -->
7
+ <route lang="yaml">
8
+ meta:
9
+ layout: blank
10
+ </route>
11
+
12
+ <script lang="ts" setup>
13
+ import { setToken } from '@/stores';
14
+ import { generateNavData } from '@/modules/4-auth';
15
+ import { apis } from '@/modules/3-net';
16
+
17
+ const title = window.__YOUNG_VITE_ENV__.VITE_TITLE || '管理后台';
18
+
19
+ type LoginType = 'code' | 'scan';
20
+ const loginType = ref<LoginType>('code');
21
+ const changeType = () => {
22
+ if (loginType.value === 'code') {
23
+ loginType.value = 'scan';
24
+ } else {
25
+ loginType.value = 'code';
26
+ }
27
+ };
28
+
29
+ const formRef = ref();
30
+ const form = reactive({
31
+ username: '',
32
+ password: ''
33
+ });
34
+ const rules = {
35
+ username: [{ required: true, trigger: 'blur', message: '请输入帐户名' }],
36
+ password: [{ required: true, trigger: 'blur', message: '请输入密码' }]
37
+ };
38
+
39
+ /**
40
+ * 路由器实例,负责改变路由
41
+ */
42
+ const router = useRouter();
43
+ const loginHandler = () => {
44
+ formRef.value?.validate(async (valid: boolean) => {
45
+ try {
46
+ if (valid) {
47
+ const data = await apis.post.login(form);
48
+ if (data) {
49
+ setToken(data);
50
+ await generateNavData();
51
+ router.push('/');
52
+ }
53
+ } else {
54
+ ElMessage.error('请仔细检查表单内容');
55
+ return;
56
+ }
57
+ } catch (error) {
58
+ console.error(error);
59
+ }
60
+ });
61
+ };
62
+
63
+ const start = () => {
64
+ ElMessage.success('敬请期待!');
65
+ };
66
+ </script>
67
+ <template>
68
+ <div class="login-main">
69
+ <div class="logo flex justify-center items-center pl-12 pt-4">
70
+ </div>
71
+ <div class="mx-auto flex justify-center flex-col items-center">
72
+ <div class="text-3xl mb-7">{{ title }}</div>
73
+ <div class="form">
74
+ <ElCard>
75
+ <template #header>
76
+ <span v-show="loginType === 'scan'">{{ '扫码登录' }}</span>
77
+ <span v-show="loginType === 'code'">{{ '密码登录' }}</span>
78
+ <div class="icon-container" @click="changeType">
79
+ <svg v-show="loginType === 'scan'" title="账号密码登录" t="1646619966567" class="icon" viewBox="0 0 1076 1024"
80
+ version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2882" width="200" height="200">
81
+ <path
82
+ d="M986.22796 0H90.275175A90.275175 90.275175 0 0 0 0 90.086315v634.570269a90.275175 90.275175 0 0 0 90.275175 90.275175h291.411288l-51.369975 152.410181H226.632239a28.32903 28.32903 0 0 0 0 56.65806h623.238657a28.32903 28.32903 0 0 0 0-56.65806h-103.495389l-51.369974-152.410181h291.222427A90.275175 90.275175 0 0 0 1076.503135 724.845444V90.086315A90.275175 90.275175 0 0 0 986.22796 0z m0 56.65806A33.617115 33.617115 0 0 1 1019.845076 90.086315V623.238657H56.65806V90.086315A33.617115 33.617115 0 0 1 90.275175 56.65806zM389.996311 967.34194l51.369975-152.410181h193.770564l51.369974 152.410181z m287.822944-209.06824H90.275175A33.617115 33.617115 0 0 1 56.65806 724.845444V679.896717h963.187016v45.704168a33.617115 33.617115 0 0 1-33.428256 33.617116z"
83
+ p-id="2883"></path>
84
+ </svg>
85
+ <svg v-show="loginType === 'code'" t="1646619725486" viewBox="0 0 1024 1024" version="1.1" class="icon"
86
+ xmlns="http://www.w3.org/2000/svg" p-id="2043" width="200" height="200">
87
+ <path
88
+ d="M384 554.666667a85.333333 85.333333 0 0 1 85.333333 85.333333v234.666667a85.333333 85.333333 0 0 1-85.333333 85.333333H149.333333a85.333333 85.333333 0 0 1-85.333333-85.333333V640a85.333333 85.333333 0 0 1 85.333333-85.333333h234.666667z m226.133333 277.333333c4.693333 0 8.533333 3.84 8.533334 8.533333V896h183.466666c4.693333 0 8.533333 3.84 8.533334 8.533333v46.933334a8.533333 8.533333 0 0 1-8.533334 8.533333H563.2a8.533333 8.533333 0 0 1-8.533333-8.533333v-110.933334c0-4.693333 3.84-8.533333 8.533333-8.533333h46.933333z m341.333334 0c4.693333 0 8.533333 3.84 8.533333 8.533333v110.933334a8.533333 8.533333 0 0 1-8.533333 8.533333h-46.933334a8.533333 8.533333 0 0 1-8.533333-8.533333v-110.933334c0-4.693333 3.84-8.533333 8.533333-8.533333h46.933334zM384 618.666667H149.333333a21.333333 21.333333 0 0 0-21.184 18.837333L128 640v234.666667a21.333333 21.333333 0 0 0 18.837333 21.184L149.333333 896h234.666667a21.333333 21.333333 0 0 0 21.184-18.837333L405.333333 874.666667V640a21.333333 21.333333 0 0 0-18.837333-21.184L384 618.666667z m418.133333 149.333333c4.693333 0 8.533333 3.84 8.533334 8.533333v46.933334a8.533333 8.533333 0 0 1-8.533334 8.533333h-46.933333a8.533333 8.533333 0 0 1-8.533333-8.533333v-46.933334c0-4.693333 3.84-8.533333 8.533333-8.533333h46.933333zM298.666667 704a21.333333 21.333333 0 0 1 21.333333 21.333333v64a21.333333 21.333333 0 0 1-21.333333 21.333334h-64a21.333333 21.333333 0 0 1-21.333334-21.333334v-64a21.333333 21.333333 0 0 1 21.333334-21.333333h64z m503.466666-149.333333c4.693333 0 8.533333 3.84 8.533334 8.533333v46.933333a8.533333 8.533333 0 0 1-8.533334 8.533334H618.666667v64h119.466666c4.693333 0 8.533333 3.84 8.533334 8.533333v46.933333a8.533333 8.533333 0 0 1-8.533334 8.533334h-174.933333a8.533333 8.533333 0 0 1-8.533333-8.533334v-174.933333c0-4.693333 3.84-8.533333 8.533333-8.533333h238.933333z m149.333334 128c4.693333 0 8.533333 3.84 8.533333 8.533333v46.933333a8.533333 8.533333 0 0 1-8.533333 8.533334h-132.266667a8.533333 8.533333 0 0 1-8.533333-8.533334v-46.933333c0-4.693333 3.84-8.533333 8.533333-8.533333h132.266667z m0-128c4.693333 0 8.533333 3.84 8.533333 8.533333v46.933333a8.533333 8.533333 0 0 1-8.533333 8.533334h-46.933334a8.533333 8.533333 0 0 1-8.533333-8.533334v-46.933333c0-4.693333 3.84-8.533333 8.533333-8.533333h46.933334zM384 64a85.333333 85.333333 0 0 1 85.333333 85.333333v234.666667a85.333333 85.333333 0 0 1-85.333333 85.333333H149.333333a85.333333 85.333333 0 0 1-85.333333-85.333333V149.333333a85.333333 85.333333 0 0 1 85.333333-85.333333h234.666667z m490.666667 0a85.333333 85.333333 0 0 1 85.333333 85.333333v234.666667a85.333333 85.333333 0 0 1-85.333333 85.333333H640a85.333333 85.333333 0 0 1-85.333333-85.333333V149.333333a85.333333 85.333333 0 0 1 85.333333-85.333333h234.666667zM384 128H149.333333a21.333333 21.333333 0 0 0-21.184 18.837333L128 149.333333v234.666667a21.333333 21.333333 0 0 0 18.837333 21.184L149.333333 405.333333h234.666667a21.333333 21.333333 0 0 0 21.184-18.837333L405.333333 384V149.333333a21.333333 21.333333 0 0 0-18.837333-21.184L384 128z m490.666667 0H640a21.333333 21.333333 0 0 0-21.184 18.837333L618.666667 149.333333v234.666667a21.333333 21.333333 0 0 0 18.837333 21.184L640 405.333333h234.666667a21.333333 21.333333 0 0 0 21.184-18.837333L896 384V149.333333a21.333333 21.333333 0 0 0-18.837333-21.184L874.666667 128z m-576 85.333333a21.333333 21.333333 0 0 1 21.333333 21.333334v64a21.333333 21.333333 0 0 1-21.333333 21.333333h-64a21.333333 21.333333 0 0 1-21.333334-21.333333v-64a21.333333 21.333333 0 0 1 21.333334-21.333334h64z m490.666666 0a21.333333 21.333333 0 0 1 21.333334 21.333334v64a21.333333 21.333333 0 0 1-21.333334 21.333333h-64a21.333333 21.333333 0 0 1-21.333333-21.333333v-64a21.333333 21.333333 0 0 1 21.333333-21.333334h64z"
89
+ fill="#333333" p-id="2044"></path>
90
+ </svg>
91
+ </div>
92
+ </template>
93
+ <div v-show="loginType === 'scan'">
94
+ <div class="text-center m-20px">
95
+ <ElButton type="primary" size="large" class="len" @click="start">钉钉扫码登录</ElButton>
96
+ </div>
97
+ <div class="w-384px text-center text-[#f56c6c]">首次登录请联系系统管理员开通权限</div>
98
+ </div>
99
+ <div class="code" v-show="loginType === 'code'">
100
+ <ElForm ref="formRef" :model="form" :rules="rules" @keyup.enter="loginHandler">
101
+ <ElFormItem prop="username">
102
+ <ElInput v-model.trim="form.username" size="large" placeholder="请输入用户名" tabindex="1" auto-complete="on"
103
+ clearable class="len" />
104
+ </ElFormItem>
105
+ <ElFormItem prop="password">
106
+ <ElInput v-model.trim="form.password" size="large" placeholder="请输入密码" tabindex="2" auto-complete="on"
107
+ type="password" clearable show-password class="len" />
108
+ </ElFormItem>
109
+ </ElForm>
110
+ <ElButton type="primary" size="large" class="len" @click="loginHandler">登 录</ElButton>
111
+ </div>
112
+ </ElCard>
113
+ </div>
114
+ </div>
115
+ </div>
116
+ </template>
117
+
118
+ <style lang="scss" scoped>
119
+ .login-main {
120
+ width: 100vw;
121
+ height: 100vh;
122
+ margin: 0;
123
+ padding: 0;
124
+ background-image: url('@/assets/img/login_background.jpg');
125
+ background-repeat: norepeat;
126
+ background-size: cover;
127
+ position: relative;
128
+ display: flex;
129
+ justify-content: space-evenly;
130
+ align-items: center;
131
+
132
+ .logo {
133
+ position: absolute;
134
+ left: 0;
135
+ top: 0;
136
+ }
137
+
138
+ .title {
139
+ font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
140
+ font-size: 2.1rem;
141
+ text-align: center;
142
+ }
143
+
144
+ .form {
145
+ $iw: 1.5rem;
146
+ position: relative;
147
+ display: flex;
148
+ justify-content: center;
149
+ align-items: center;
150
+
151
+ .icon {
152
+ width: $iw;
153
+ height: $iw;
154
+ position: absolute;
155
+ right: 0;
156
+ top: 0;
157
+ margin: 0.5rem;
158
+
159
+ &:hover {
160
+ cursor: pointer;
161
+ }
162
+
163
+ }
164
+
165
+
166
+ .code {
167
+ padding: 4rem 1rem;
168
+
169
+ .len {
170
+ width: 20rem;
171
+ margin-bottom: 0.3rem;
172
+ }
173
+ }
174
+
175
+ .img-btn {
176
+ width: 168px;
177
+ height: 28px;
178
+ display: flex;
179
+ justify-content: center;
180
+ align-items: center;
181
+
182
+ #img-zx {
183
+ height: 5rem;
184
+ margin-top: 0.5rem;
185
+ }
186
+
187
+ #img-zc {
188
+ height: 2rem;
189
+ }
190
+ }
191
+ }
192
+ }
193
+ </style>
@@ -0,0 +1,23 @@
1
+ <!--
2
+ * @Author: zhangyang
3
+ * @Date: 2022-10-26 09:55:45
4
+ * @LastEditTime: 2023-01-04 19:44:05
5
+ * @Description:
6
+ -->
7
+ <route lang="yaml">
8
+ meta:
9
+ title: 欢迎页
10
+ authPath: /dashboard/index
11
+ </route>
12
+
13
+ <script lang="ts" setup>
14
+ const title = window.__YOUNG_VITE_ENV__.VITE_TITLE || '管理后台';
15
+ </script>
16
+
17
+ <template>
18
+ <div>
19
+ <div class="text-4xl my-20 text-center font-bold">
20
+ 欢迎使用{{ title }}
21
+ </div>
22
+ </div>
23
+ </template>
@@ -0,0 +1,19 @@
1
+ <!--
2
+ * @Author: zhangyang
3
+ * @Date: 2022-10-25 11:54:36
4
+ * @LastEditTime: 2022-12-07 15:33:23
5
+ * @Description:
6
+ -->
7
+ <script lang="ts" setup>
8
+ const router = useRouter();
9
+ onMounted(() => {
10
+ router.replace('/dashboard/index');
11
+ });
12
+ onUpdated(() => {
13
+ router.replace('/dashboard/index');
14
+ });
15
+ </script>
16
+
17
+ <template>
18
+ <div></div>
19
+ </template>
@@ -0,0 +1,161 @@
1
+ <!--
2
+ * @Author: zhangyang
3
+ * @Date: 2022-10-27 14:24:32
4
+ * @LastEditTime: 2023-01-09 11:51:07
5
+ * @Description:
6
+ -->
7
+ <route lang="yaml">
8
+ meta:
9
+ title: 接口管理
10
+ authPath: /system/api
11
+ </route>
12
+
13
+ <script lang="ts" setup>
14
+ import { useFormMode, YoungDialog, YoungTable, YoungPagination, YoungSelect } from '@bluesyoung/ui-vue3-element-plus';
15
+ import type { TableDataItem, TableHeadItem, SelectOptionItem } from '@bluesyoung/ui-vue3-element-plus';
16
+ import { deepClone } from '@bluesyoung/utils';
17
+ import type { ApiItem, RoleItem } from '@/typings';
18
+ import { MethodObj } from '@/typings';
19
+ import { apis } from '@/modules/3-net';
20
+ import { ElButton, ElTag } from 'element-plus';
21
+
22
+ interface Form extends ApiItem { };
23
+ const FORM_TEMP: Form = {
24
+ id: 0,
25
+ path: '',
26
+ desc: '',
27
+ method: 'POST',
28
+ category: '',
29
+ roleIds: []
30
+ };
31
+ const {
32
+ isAdd,
33
+ isEdit,
34
+ edit,
35
+ del,
36
+ sure,
37
+ clear,
38
+ form,
39
+ formRef,
40
+ validForm
41
+ } = useFormMode<Form>(FORM_TEMP, {
42
+ addCbk: async () => {
43
+ const res = await validForm() as boolean;
44
+ if (res) {
45
+ const v = deepClone(form.value);
46
+ await apis.post.addApiItem(v);
47
+ ElMessage.success('新增成功!');
48
+ }
49
+ return res;
50
+ },
51
+ modCbk: async () => {
52
+ const res = await validForm() as boolean;
53
+ if (res) {
54
+ const v = deepClone(form.value);
55
+ await apis.patch.changeApiItem(v);
56
+ ElMessage.success('修改成功!');
57
+ }
58
+ return res;
59
+ },
60
+ delCbk: async (row) => {
61
+ await apis.delete.deleteApi(row.id.toString());
62
+ ElMessage.success('删除成功!');
63
+ query.pageNum = 1;
64
+ },
65
+ cgEffect: () => getList(),
66
+ });
67
+ const tableHead: TableHeadItem<Form>[] = [
68
+ { prop: 'id', label: '接口ID' },
69
+ { prop: 'desc', label: '接口描述' },
70
+ { prop: 'category', label: '接口分组' },
71
+ { prop: 'path', label: '接口路径' },
72
+ { prop: 'creator', label: '创建信息' },
73
+ {
74
+ prop: 'method', label: '接口方法', render: (row) => h(ElTag, {
75
+ effect: 'dark',
76
+ type: MethodObj[row.method]
77
+ },
78
+ {
79
+ default: () => row.method
80
+ }
81
+ )
82
+ },
83
+ {
84
+ prop: 'id', label: '操作', render: (row) => h('div', [
85
+ h(ElButton, { type: 'primary', link: true, onClick: () => edit(row) }, { default: () => '编辑' }),
86
+ h(ElButton, { type: 'danger', link: true, onClick: () => del(row) }, { default: () => '删除' })
87
+ ])
88
+ }
89
+ ];
90
+ const tableData = ref<TableDataItem<Form>[]>([]);
91
+
92
+ type Query = BaseQuery & Partial<Form>;
93
+ const query = reactive<Query>({
94
+ pageNum: 1,
95
+ pageSize: 10,
96
+ total: 0,
97
+ path: '',
98
+ });
99
+
100
+ const roleList = ref<SelectOptionItem<number>[]>([]);
101
+
102
+ const getList = async () => {
103
+ const { list: role_list } = await apis.get.getRoleList({ noPagination: true });
104
+ roleList.value = (role_list || []).map((item: RoleItem) => {
105
+ return {
106
+ label: item.name,
107
+ value: item.id
108
+ };
109
+ });
110
+
111
+ const { list, pageNum, pageSize, total } = await apis.get.getApiList(query);
112
+ tableData.value = deepClone(list || []);
113
+ query.pageNum = +pageNum || 1;
114
+ query.pageSize = +pageSize || 50;
115
+ query.total = +total || 0;
116
+ };
117
+
118
+ getList();
119
+ </script>
120
+
121
+ <template>
122
+ <div class="flex">
123
+ <div class="m-2">
124
+ <ElInput v-model="query.path" placeholder="请输入接口路径" />
125
+ </div>
126
+ <div class="m-2">
127
+ <ElButton type="primary" @click="getList">搜索</ElButton>
128
+ </div>
129
+ <div class="m-2">
130
+ <ElButton type="success" @click="isAdd = true">添加接口</ElButton>
131
+ </div>
132
+ </div>
133
+ <div class="m-2">
134
+ <YoungTable :table-data="tableData" :table-head="tableHead" :table-height="680" />
135
+ <YoungPagination v-model:page="query.pageNum" v-model:limit="query.pageSize" :total="query.total"
136
+ @page-change="getList" />
137
+ </div>
138
+ <YoungDialog :is-add="isAdd" :is-edit="isEdit" width="520px" @sure="sure" @clear="clear">
139
+ <template #body>
140
+ <ElForm ref="formRef" :model="form" label-width="100px">
141
+ <ElFormItem label="分组名称" prop="category" :rules="{ required: true, message: '请填写分组名称', trigger: 'blur' }">
142
+ <ElInput v-model="form.category" class="!w-300px" />
143
+ </ElFormItem>
144
+ <ElFormItem label="接口描述" prop="desc" :rules="{ required: true, message: '请填写接口描述', trigger: 'blur' }">
145
+ <ElInput v-model="form.desc" class="!w-300px" />
146
+ </ElFormItem>
147
+ <ElFormItem label="请求方法">
148
+ <YoungSelect v-model="form.method" class="!w-300px"
149
+ :options="Object.keys(MethodObj).map((item) => ({ label: item, value: item }))" />
150
+ </ElFormItem>
151
+ <ElFormItem label="接口路径" prop="path"
152
+ :rules="{ message: '请填写合法的接口路径, eg: /user/list', trigger: 'blur', validator: (_: any, v: string) => /\/(.*)\/(.*)/.test(v) }">
153
+ <ElInput v-model="form.path" class="!w-300px" />
154
+ </ElFormItem>
155
+ <ElFormItem label="关联角色">
156
+ <YoungSelect v-model="form.roleIds" multiple placeholder="请选择角色" class="!w-300px" :options="roleList" />
157
+ </ElFormItem>
158
+ </ElForm>
159
+ </template>
160
+ </YoungDialog>
161
+ </template>
@@ -0,0 +1,286 @@
1
+ /*
2
+ * @Author: zhangyang
3
+ * @Date: 2022-10-27 09:25:09
4
+ * @LastEditTime: 2023-01-09 14:20:07
5
+ * @Description:
6
+ */
7
+ import type { RoleItem, ApiItem } from '@/typings';
8
+ import type { TableDataItem, TableHeadItem } from '@bluesyoung/ui-vue3-element-plus';
9
+ import { useFormMode } from '@bluesyoung/ui-vue3-element-plus';
10
+ import { deepClone } from '@bluesyoung/utils';
11
+ import { apis } from '@/modules/3-net';
12
+ export const useRoleBase = () => {
13
+ const FORM_TEMP: RoleItem = {
14
+ id: 0,
15
+ name: '',
16
+ keyword: '',
17
+ desc: '',
18
+ status: 1,
19
+ sort: 0,
20
+ };
21
+ interface Query extends BaseQuery {
22
+ name: string;
23
+ keyword: string;
24
+ status: 0 | 1;
25
+ }
26
+ const query = reactive<Query>({
27
+ pageNum: 1,
28
+ pageSize: 50,
29
+ total: 0,
30
+ name: '',
31
+ keyword: '',
32
+ status: 1,
33
+ });
34
+
35
+ const { isAdd, isEdit, edit, del, sure, clear, form, formRef, validForm } = useFormMode(
36
+ FORM_TEMP,
37
+ {
38
+ addCbk: async () => {
39
+ const res = (await validForm()) as boolean;
40
+ if (res) {
41
+ const v = deepClone(form.value);
42
+ await apis.post.addRoleItem(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.changeRoleItem(v);
52
+ ElMessage.success('修改成功!');
53
+ }
54
+ return res;
55
+ },
56
+ delCbk: async (row) => {
57
+ await apis.delete.deleteRole(row.id.toString());
58
+ ElMessage.success('删除成功!');
59
+ query.pageNum = 1;
60
+ },
61
+ cgEffect: () => getList(),
62
+ },
63
+ );
64
+
65
+ /**
66
+ * @param status 0 | 1
67
+ */
68
+ const changeStatus = async (id: number, status: number) => {
69
+ await apis.patch.changeRoleItem({ id, status });
70
+ ElMessage.success('修改成功!');
71
+ getList();
72
+ };
73
+
74
+ const tableHead: TableHeadItem<RoleItem>[] = [
75
+ { label: '角色ID', prop: 'id' },
76
+ { label: '角色关键字', prop: 'keyword' },
77
+ { label: '角色名称', prop: 'name' },
78
+ { label: '角色描述', prop: 'desc' },
79
+ { label: '创建信息', prop: 'creator' },
80
+ ];
81
+ const tableData = ref<TableDataItem<RoleItem>[]>([]);
82
+ const getList = async () => {
83
+ const { list, pageNum, pageSize, total } = await apis.get.getRoleList(query);
84
+ tableData.value = deepClone(list || []);
85
+ query.pageNum = +pageNum || 1;
86
+ query.pageSize = +pageSize || 50;
87
+ query.total = +total || 0;
88
+ };
89
+
90
+ return {
91
+ query,
92
+ getList,
93
+ tableHead,
94
+ tableData,
95
+ baseFormRef: formRef,
96
+ changeStatus,
97
+ base: reactive({
98
+ form,
99
+ isAdd,
100
+ isEdit,
101
+ edit,
102
+ del,
103
+ sure,
104
+ clear,
105
+ }),
106
+ };
107
+ };
108
+
109
+ export const useRoleMenu = () => {
110
+ const showPriority = ref(false);
111
+ const currRole = ref(0);
112
+ const access = ref<number[]>([]);
113
+ const origin = ref<number[]>([]);
114
+
115
+ const tableHead = ref<TableHeadItem<NavArrItem>[]>([
116
+ { label: '菜单名称', prop: 'title' },
117
+ { label: '菜单id', prop: 'id' },
118
+ { label: '父节点', prop: 'parentId' },
119
+ { label: '页面路径', prop: 'component' },
120
+ ]);
121
+ const tableData = ref<TableDataItem<NavArrItem>[]>([]);
122
+
123
+ const checkMap = ref<Record<number, boolean>>({});
124
+
125
+ /**
126
+ * 生成节点映射
127
+ */
128
+ const nodeMap = new Map<number, NavArrItem>();
129
+ const generateNodeMap = (list: NavArrItem[]) => {
130
+ for (const node of list) {
131
+ nodeMap.set(node.id, node);
132
+ if (node.children && node.children?.length > 0) {
133
+ generateNodeMap(node.children);
134
+ }
135
+ }
136
+ };
137
+
138
+ /**
139
+ * 多级联动选择
140
+ */
141
+ const selectChange = (item: NavArrItem) => {
142
+ if (item.children && item.children?.length !== 0) {
143
+ item.children.forEach((v) => {
144
+ checkMap.value[v.id] = checkMap.value[item.id];
145
+ selectChange(v);
146
+ });
147
+ }
148
+ if (checkMap.value[item.id]) {
149
+ while (item.parentId) {
150
+ const tp = nodeMap.get(item.parentId);
151
+ if (tp) {
152
+ item = tp;
153
+ checkMap.value[item.id] = true;
154
+ } else {
155
+ break;
156
+ }
157
+ }
158
+ }
159
+ };
160
+
161
+ const edit = async (row: TableDataItem<RoleItem>) => {
162
+ currRole.value = row.id;
163
+ checkMap.value = {};
164
+ nodeMap.clear();
165
+
166
+ const { list, accessIds } = await apis.get.getRoleMenuTree(row.id);
167
+ generateNodeMap(list);
168
+ (Array.from(accessIds) as number[]).forEach((v) => {
169
+ checkMap.value[v] = true;
170
+ });
171
+
172
+ tableData.value = deepClone(list);
173
+ access.value = accessIds;
174
+ origin.value = accessIds;
175
+ showPriority.value = true;
176
+ };
177
+ const clear = () => {
178
+ showPriority.value = false;
179
+ currRole.value = 0;
180
+ tableData.value.length = 0;
181
+ };
182
+
183
+ const sure = async () => {
184
+ const before = origin.value.slice();
185
+ const now = Object.entries(checkMap.value)
186
+ .filter(([k, v]) => v)
187
+ .map(([k, v]) => +k);
188
+
189
+ const add = now.filter((v) => !before.includes(v));
190
+ const del = before.filter((v) => !now.includes(v));
191
+ await apis.patch.changeRoleMenu(currRole.value, add, del);
192
+ ElMessage.success('修改成功!');
193
+ clear();
194
+ };
195
+
196
+ return {
197
+ showPriority,
198
+ menu: reactive({
199
+ checkMap,
200
+ tableHead,
201
+ tableData,
202
+ edit,
203
+ clear,
204
+ sure,
205
+ selectChange,
206
+ }),
207
+ };
208
+ };
209
+
210
+ export const useRoleApi = () => {
211
+ const showApi = ref(false);
212
+ const currRole = ref(0);
213
+ const access = ref<number[]>([]);
214
+ const origin = ref<number[]>([]);
215
+
216
+ const tableHead = ref<TableHeadItem<ApiItem>[]>([
217
+ { prop: 'desc', label: '接口描述' },
218
+ { prop: 'id', label: '接口ID' },
219
+ { prop: 'method', label: '接口方法' },
220
+ { prop: 'path', label: '请求地址' },
221
+ ]);
222
+ const tableData = ref<TableDataItem<ApiItem>[]>([]);
223
+
224
+ const checkMap = ref<Record<number, boolean>>({});
225
+
226
+ const edit = async (row: TableDataItem<RoleItem>) => {
227
+ currRole.value = row.id;
228
+ checkMap.value = {};
229
+
230
+ const { list, accessIds } = await apis.get.getRoleApis(row.id);
231
+ (Array.from(accessIds) as number[]).forEach((v) => {
232
+ checkMap.value[v] = true;
233
+ });
234
+
235
+ tableData.value = deepClone(
236
+ Array.from(list)
237
+ .map((item: any) => item.children)
238
+ .flat(),
239
+ );
240
+
241
+ access.value = accessIds;
242
+ origin.value = accessIds;
243
+ showApi.value = true;
244
+
245
+ isAll.value = tableData.value.length === access.value.length;
246
+ };
247
+ const clear = () => {
248
+ showApi.value = false;
249
+ currRole.value = 0;
250
+ tableData.value.length = 0;
251
+ };
252
+
253
+ const sure = async () => {
254
+ const before = origin.value.slice();
255
+ const now = Object.entries(checkMap.value)
256
+ .filter(([k, v]) => v)
257
+ .map(([k, v]) => +k);
258
+
259
+ const add = now.filter((v) => !before.includes(v));
260
+ const del = before.filter((v) => !now.includes(v));
261
+ await apis.patch.changeRoleApi(currRole.value, add, del);
262
+ ElMessage.success('修改成功!');
263
+ clear();
264
+ };
265
+
266
+ const isAll = ref(false);
267
+ const changeAll = () => {
268
+ tableData.value.forEach((i) => {
269
+ checkMap.value[i.id] = isAll.value;
270
+ });
271
+ };
272
+
273
+ return {
274
+ showApi,
275
+ api: reactive({
276
+ checkMap,
277
+ tableHead,
278
+ tableData,
279
+ edit,
280
+ clear,
281
+ sure,
282
+ isAll,
283
+ changeAll,
284
+ }),
285
+ };
286
+ };