befly-admin 3.2.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/layouts/0.vue +2 -3
- package/src/layouts/2.vue +7 -4
- package/src/plugins/http.ts +2 -8
- package/src/plugins/router.ts +2 -1
- package/src/plugins/storage.ts +146 -0
- package/src/views/403/403.vue +39 -6
- package/src/views/admin/components/edit.vue +3 -3
- package/src/views/admin/components/role.vue +3 -3
- package/src/views/admin/index.vue +2 -2
- package/src/views/dict/components/edit.vue +3 -3
- package/src/views/dict/index.vue +2 -2
- package/src/views/index/components/{AddonList.vue → addonList.vue} +2 -2
- package/src/views/index/components/{EnvironmentInfo.vue → environmentInfo.vue} +1 -1
- package/src/views/index/components/{OperationLogs.vue → operationLogs.vue} +2 -2
- package/src/views/index/components/{PerformanceMetrics.vue → performanceMetrics.vue} +1 -1
- package/src/views/index/components/{QuickActions.vue → quickActions.vue} +3 -3
- package/src/views/index/components/{ServiceStatus.vue → serviceStatus.vue} +1 -1
- package/src/views/index/components/{SystemNotifications.vue → systemNotifications.vue} +1 -1
- package/src/views/index/components/{SystemOverview.vue → systemOverview.vue} +5 -5
- package/src/views/index/components/{SystemResources.vue → systemResources.vue} +4 -4
- package/src/views/index/components/{UserInfo.vue → userInfo.vue} +1 -1
- package/src/views/index/index.vue +7 -7
- package/src/views/login/components/emailLoginForm.vue +163 -0
- package/src/views/login/components/registerForm.vue +168 -0
- package/src/views/login/components/welcomePanel.vue +61 -0
- package/src/views/login/index_1.vue +16 -521
- package/src/views/menu/components/edit.vue +3 -3
- package/src/views/menu/index.vue +2 -2
- package/src/views/role/components/api.vue +3 -3
- package/src/views/role/components/menu.vue +10 -10
- package/src/views/role/index.vue +2 -2
- package/src/views/user/user.vue +8 -8
- package/src/api/auth.ts +0 -60
- package/temp/router.js +0 -71
|
@@ -2,16 +2,7 @@
|
|
|
2
2
|
<div class="auth-container" :class="{ 'sign-up-mode': $Data.isSignUp }">
|
|
3
3
|
<!-- 左侧欢迎区域 -->
|
|
4
4
|
<div class="left-panel">
|
|
5
|
-
<
|
|
6
|
-
<h2>你好,朋友!</h2>
|
|
7
|
-
<p>填写个人信息,开始使用</p>
|
|
8
|
-
<button class="toggle-btn" @click="$Method.toggleMode">注册账号</button>
|
|
9
|
-
</div>
|
|
10
|
-
<div class="panel-content" v-else>
|
|
11
|
-
<h2>欢迎回来!</h2>
|
|
12
|
-
<p>使用您的账号登录</p>
|
|
13
|
-
<button class="toggle-btn" @click="$Method.toggleMode">立即登录</button>
|
|
14
|
-
</div>
|
|
5
|
+
<WelcomePanel :is-sign-up="$Data.isSignUp" @toggle="$Method.toggleMode" />
|
|
15
6
|
</div>
|
|
16
7
|
|
|
17
8
|
<!-- 右侧表单区域 -->
|
|
@@ -20,159 +11,28 @@
|
|
|
20
11
|
<div class="form-container sign-in-form" :class="{ active: !$Data.isSignUp }">
|
|
21
12
|
<h2 class="form-title">登录到 Befly</h2>
|
|
22
13
|
|
|
23
|
-
<!-- 登录方式切换 -->
|
|
24
|
-
<div class="login-type-tabs">
|
|
25
|
-
<button type="button" class="tab-btn" :class="{ active: $Data.loginType === 'email' }" @click="$Method.switchLoginType('email')">邮箱登录</button>
|
|
26
|
-
<button type="button" class="tab-btn" :class="{ active: $Data.loginType === 'phone' }" @click="$Method.switchLoginType('phone')">手机登录</button>
|
|
27
|
-
<button type="button" class="tab-btn" :class="{ active: $Data.loginType === 'qrcode' }" @click="$Method.switchLoginType('qrcode')">扫码登录</button>
|
|
28
|
-
</div>
|
|
29
|
-
|
|
30
14
|
<!-- 邮箱登录 -->
|
|
31
|
-
<
|
|
32
|
-
<t-form-item name="email" label="邮箱">
|
|
33
|
-
<t-input v-model="$Data.loginForm.email.email" placeholder="请输入邮箱" size="large" clearable>
|
|
34
|
-
<template #prefix-icon>
|
|
35
|
-
<mail-icon />
|
|
36
|
-
</template>
|
|
37
|
-
</t-input>
|
|
38
|
-
</t-form-item>
|
|
39
|
-
|
|
40
|
-
<t-form-item name="password" label="密码">
|
|
41
|
-
<t-input v-model="$Data.loginForm.email.password" type="password" placeholder="请输入密码" size="large" clearable>
|
|
42
|
-
<template #prefix-icon>
|
|
43
|
-
<lock-on-icon />
|
|
44
|
-
</template>
|
|
45
|
-
</t-input>
|
|
46
|
-
</t-form-item>
|
|
47
|
-
|
|
48
|
-
<div class="form-footer">
|
|
49
|
-
<a href="#" class="forgot-password">忘记密码?</a>
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
<t-button theme="primary" type="submit" class="auth-btn" size="large" :loading="$Data.loginLoading"> 登录 </t-button>
|
|
53
|
-
</t-form>
|
|
54
|
-
|
|
55
|
-
<!-- 手机登录 -->
|
|
56
|
-
<t-form v-if="$Data.loginType === 'phone'" :data="$Data.loginForm.phone" :rules="$Data.loginRules.phone" :ref="(el) => ($Form.phoneForm = el)" @submit="$Method.handleLogin" class="login-form" :required-mark="false" show-error-message label-align="left" label-width="70px">
|
|
57
|
-
<t-form-item name="phone" label="手机号">
|
|
58
|
-
<t-input v-model="$Data.loginForm.phone.phone" placeholder="请输入手机号" size="large" clearable>
|
|
59
|
-
<template #prefix-icon>
|
|
60
|
-
<mobile-icon />
|
|
61
|
-
</template>
|
|
62
|
-
</t-input>
|
|
63
|
-
</t-form-item>
|
|
64
|
-
|
|
65
|
-
<t-form-item name="code" label="验证码">
|
|
66
|
-
<t-input v-model="$Data.loginForm.phone.code" placeholder="请输入验证码" size="large" clearable>
|
|
67
|
-
<template #prefix-icon>
|
|
68
|
-
<secured-icon />
|
|
69
|
-
</template>
|
|
70
|
-
<template #suffix>
|
|
71
|
-
<t-button variant="text" :disabled="$Data.codeCountdown > 0" @click="$Method.sendCode">
|
|
72
|
-
{{ $Data.codeCountdown > 0 ? `${$Data.codeCountdown}秒后重试` : '发送验证码' }}
|
|
73
|
-
</t-button>
|
|
74
|
-
</template>
|
|
75
|
-
</t-input>
|
|
76
|
-
</t-form-item>
|
|
77
|
-
|
|
78
|
-
<t-button theme="primary" type="submit" class="auth-btn" size="large" :loading="$Data.loginLoading"> 登录 </t-button>
|
|
79
|
-
</t-form>
|
|
80
|
-
|
|
81
|
-
<!-- 扫码登录 -->
|
|
82
|
-
<div v-if="$Data.loginType === 'qrcode'" class="qrcode-container">
|
|
83
|
-
<div class="qrcode-box">
|
|
84
|
-
<t-qrcode :value="$Data.qrcodeValue" :size="200" :status="$Data.qrcodeStatus" @refresh="$Method.refreshQrcode" />
|
|
85
|
-
<p class="qrcode-tip">{{ $Data.qrcodeTip }}</p>
|
|
86
|
-
</div>
|
|
87
|
-
</div>
|
|
15
|
+
<EmailLoginForm />
|
|
88
16
|
</div>
|
|
89
17
|
|
|
90
18
|
<!-- 注册表单 -->
|
|
91
19
|
<div class="form-container sign-up-form" :class="{ active: $Data.isSignUp }">
|
|
92
20
|
<h2 class="form-title">注册账号</h2>
|
|
93
21
|
|
|
94
|
-
<
|
|
95
|
-
<t-form-item name="name" label="姓名">
|
|
96
|
-
<t-input v-model="$Data.registerForm.name" placeholder="请输入姓名" size="large" clearable>
|
|
97
|
-
<template #prefix-icon>
|
|
98
|
-
<user-icon />
|
|
99
|
-
</template>
|
|
100
|
-
</t-input>
|
|
101
|
-
</t-form-item>
|
|
102
|
-
|
|
103
|
-
<t-form-item name="email" label="邮箱">
|
|
104
|
-
<t-input v-model="$Data.registerForm.email" placeholder="请输入邮箱" size="large" clearable>
|
|
105
|
-
<template #prefix-icon>
|
|
106
|
-
<mail-icon />
|
|
107
|
-
</template>
|
|
108
|
-
</t-input>
|
|
109
|
-
</t-form-item>
|
|
110
|
-
|
|
111
|
-
<t-form-item name="password" label="密码">
|
|
112
|
-
<t-input v-model="$Data.registerForm.password" type="password" placeholder="请输入密码" size="large" clearable>
|
|
113
|
-
<template #prefix-icon>
|
|
114
|
-
<lock-on-icon />
|
|
115
|
-
</template>
|
|
116
|
-
</t-input>
|
|
117
|
-
</t-form-item>
|
|
118
|
-
|
|
119
|
-
<t-button theme="primary" type="submit" class="auth-btn" size="large" :loading="$Data.registerLoading"> 注册 </t-button>
|
|
120
|
-
</t-form>
|
|
22
|
+
<RegisterForm @success="$Method.handleRegisterSuccess" />
|
|
121
23
|
</div>
|
|
122
24
|
</div>
|
|
123
25
|
</div>
|
|
124
26
|
</template>
|
|
125
27
|
|
|
126
28
|
<script setup>
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const $Form = $ref({
|
|
131
|
-
emailForm: null,
|
|
132
|
-
phoneForm: null,
|
|
133
|
-
registerForm: null
|
|
134
|
-
});
|
|
29
|
+
import WelcomePanel from './components/welcomePanel.vue';
|
|
30
|
+
import EmailLoginForm from './components/emailLoginForm.vue';
|
|
31
|
+
import RegisterForm from './components/registerForm.vue';
|
|
135
32
|
|
|
136
33
|
// 数据定义
|
|
137
34
|
const $Data = $ref({
|
|
138
|
-
|
|
139
|
-
registerLoading: false,
|
|
140
|
-
isSignUp: false,
|
|
141
|
-
loginType: 'email',
|
|
142
|
-
codeCountdown: 0,
|
|
143
|
-
qrcodeValue: '',
|
|
144
|
-
qrcodeStatus: 'loading',
|
|
145
|
-
qrcodeTip: '二维码加载中...',
|
|
146
|
-
loginForm: {
|
|
147
|
-
email: {
|
|
148
|
-
email: '',
|
|
149
|
-
password: ''
|
|
150
|
-
},
|
|
151
|
-
phone: {
|
|
152
|
-
phone: '',
|
|
153
|
-
code: ''
|
|
154
|
-
}
|
|
155
|
-
},
|
|
156
|
-
loginRules: {
|
|
157
|
-
email: {
|
|
158
|
-
email: [{ required: true, message: '请输入邮箱', type: 'error' }],
|
|
159
|
-
password: [{ required: true, message: '请输入密码', type: 'error' }]
|
|
160
|
-
},
|
|
161
|
-
phone: {
|
|
162
|
-
phone: [{ required: true, message: '请输入手机号', type: 'error' }],
|
|
163
|
-
code: [{ required: true, message: '请输入验证码', type: 'error' }]
|
|
164
|
-
}
|
|
165
|
-
},
|
|
166
|
-
registerForm: {
|
|
167
|
-
name: '',
|
|
168
|
-
email: '',
|
|
169
|
-
password: ''
|
|
170
|
-
},
|
|
171
|
-
registerRules: {
|
|
172
|
-
name: [{ required: true, message: '请输入姓名', type: 'error' }],
|
|
173
|
-
email: [{ required: true, message: '请输入邮箱', type: 'error' }],
|
|
174
|
-
password: [{ required: true, message: '请输入密码', type: 'error' }]
|
|
175
|
-
}
|
|
35
|
+
isSignUp: false
|
|
176
36
|
});
|
|
177
37
|
|
|
178
38
|
// 方法定义
|
|
@@ -182,150 +42,9 @@ const $Method = {
|
|
|
182
42
|
$Data.isSignUp = !$Data.isSignUp;
|
|
183
43
|
},
|
|
184
44
|
|
|
185
|
-
//
|
|
186
|
-
|
|
187
|
-
$Data.
|
|
188
|
-
// 如果切换到二维码登录,生成二维码
|
|
189
|
-
if (type === 'qrcode') {
|
|
190
|
-
$Method.generateQrcode();
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
|
|
194
|
-
// 生成二维码
|
|
195
|
-
generateQrcode() {
|
|
196
|
-
$Data.qrcodeStatus = 'loading';
|
|
197
|
-
$Data.qrcodeTip = '二维码加载中...';
|
|
198
|
-
|
|
199
|
-
// TODO: 调用生成二维码接口
|
|
200
|
-
// const res = await generateQrcodeApi();
|
|
201
|
-
|
|
202
|
-
// 模拟生成二维码
|
|
203
|
-
setTimeout(() => {
|
|
204
|
-
// 生成一个唯一的二维码标识
|
|
205
|
-
const qrcodeId = `qrcode_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
206
|
-
$Data.qrcodeValue = `https://befly.com/qrcode/scan?id=${qrcodeId}`;
|
|
207
|
-
$Data.qrcodeStatus = 'active';
|
|
208
|
-
$Data.qrcodeTip = '请使用手机扫描二维码登录';
|
|
209
|
-
|
|
210
|
-
// 开始轮询检查扫码状态
|
|
211
|
-
$Method.checkQrcodeStatus();
|
|
212
|
-
}, 1000);
|
|
213
|
-
},
|
|
214
|
-
|
|
215
|
-
// 刷新二维码
|
|
216
|
-
refreshQrcode() {
|
|
217
|
-
$Method.generateQrcode();
|
|
218
|
-
},
|
|
219
|
-
|
|
220
|
-
// 检查二维码状态
|
|
221
|
-
checkQrcodeStatus() {
|
|
222
|
-
// TODO: 实现轮询检查二维码扫描状态
|
|
223
|
-
// 这里模拟扫码状态变化
|
|
224
|
-
setTimeout(() => {
|
|
225
|
-
// 模拟扫码成功
|
|
226
|
-
// $Data.qrcodeStatus = 'scanned';
|
|
227
|
-
// $Data.qrcodeTip = '扫描成功,请在手机上确认登录';
|
|
228
|
-
// 模拟登录成功
|
|
229
|
-
// setTimeout(() => {
|
|
230
|
-
// localStorage.setItem('token', 'mock-token');
|
|
231
|
-
// MessagePlugin.success('登录成功');
|
|
232
|
-
// router.push('/dashboard');
|
|
233
|
-
// }, 2000);
|
|
234
|
-
}, 5000);
|
|
235
|
-
|
|
236
|
-
// 模拟二维码过期
|
|
237
|
-
setTimeout(() => {
|
|
238
|
-
if ($Data.qrcodeStatus === 'active') {
|
|
239
|
-
$Data.qrcodeStatus = 'expired';
|
|
240
|
-
$Data.qrcodeTip = '二维码已过期,请点击刷新';
|
|
241
|
-
}
|
|
242
|
-
}, 30000); // 30秒后过期
|
|
243
|
-
},
|
|
244
|
-
|
|
245
|
-
// 发送验证码
|
|
246
|
-
async sendCode() {
|
|
247
|
-
if (!$Data.loginForm.phone.phone) {
|
|
248
|
-
MessagePlugin.warning('请先输入手机号');
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
try {
|
|
253
|
-
await $Http('/addon/admin/sendSmsCode', { phone: $Data.loginForm.phone.phone });
|
|
254
|
-
|
|
255
|
-
MessagePlugin.success('验证码已发送');
|
|
256
|
-
$Data.codeCountdown = 60;
|
|
257
|
-
|
|
258
|
-
const timer = setInterval(() => {
|
|
259
|
-
$Data.codeCountdown--;
|
|
260
|
-
if ($Data.codeCountdown <= 0) {
|
|
261
|
-
clearInterval(timer);
|
|
262
|
-
}
|
|
263
|
-
}, 1000);
|
|
264
|
-
} catch (error) {
|
|
265
|
-
// 错误已经在 request 拦截器中处理
|
|
266
|
-
}
|
|
267
|
-
},
|
|
268
|
-
|
|
269
|
-
// 处理登录
|
|
270
|
-
async handleLogin() {
|
|
271
|
-
let valid = false;
|
|
272
|
-
let formData = null;
|
|
273
|
-
|
|
274
|
-
if ($Data.loginType === 'email') {
|
|
275
|
-
valid = await $Form.emailForm.validate();
|
|
276
|
-
formData = $Data.loginForm.email;
|
|
277
|
-
} else if ($Data.loginType === 'phone') {
|
|
278
|
-
valid = await $Form.phoneForm.validate();
|
|
279
|
-
formData = $Data.loginForm.phone;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
if (!valid) return;
|
|
283
|
-
|
|
284
|
-
$Data.loginLoading = true;
|
|
285
|
-
|
|
286
|
-
try {
|
|
287
|
-
const res = await $Http('/addon/admin/login', formData);
|
|
288
|
-
|
|
289
|
-
// 先保存 token
|
|
290
|
-
localStorage.setItem('token', res.data.token);
|
|
291
|
-
|
|
292
|
-
// 如果返回用户信息,也可以存储
|
|
293
|
-
if (res.data.userInfo) {
|
|
294
|
-
localStorage.setItem('userInfo', JSON.stringify(res.data.userInfo));
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
MessagePlugin.success('登录成功');
|
|
298
|
-
|
|
299
|
-
// 跳转到首页,路由守卫会自动加载菜单
|
|
300
|
-
await router.push('/');
|
|
301
|
-
} catch (error) {
|
|
302
|
-
// 错误已经在 request 拦截器中处理
|
|
303
|
-
} finally {
|
|
304
|
-
$Data.loginLoading = false;
|
|
305
|
-
}
|
|
306
|
-
},
|
|
307
|
-
|
|
308
|
-
// 处理注册
|
|
309
|
-
async handleRegister() {
|
|
310
|
-
const valid = await $Form.registerForm.validate();
|
|
311
|
-
if (!valid) return;
|
|
312
|
-
|
|
313
|
-
$Data.registerLoading = true;
|
|
314
|
-
|
|
315
|
-
try {
|
|
316
|
-
await $Http('/addon/admin/register', $Data.registerForm);
|
|
317
|
-
MessagePlugin.success('注册成功,请登录');
|
|
318
|
-
$Data.isSignUp = false;
|
|
319
|
-
|
|
320
|
-
// 清空注册表单
|
|
321
|
-
$Data.registerForm.name = '';
|
|
322
|
-
$Data.registerForm.email = '';
|
|
323
|
-
$Data.registerForm.password = '';
|
|
324
|
-
} catch (error) {
|
|
325
|
-
// 错误已经在 request 拦截器中处理
|
|
326
|
-
} finally {
|
|
327
|
-
$Data.registerLoading = false;
|
|
328
|
-
}
|
|
45
|
+
// 注册成功后切换到登录模式
|
|
46
|
+
handleRegisterSuccess() {
|
|
47
|
+
$Data.isSignUp = false;
|
|
329
48
|
}
|
|
330
49
|
};
|
|
331
50
|
</script>
|
|
@@ -354,54 +73,6 @@ const $Method = {
|
|
|
354
73
|
color: #fff;
|
|
355
74
|
z-index: 5;
|
|
356
75
|
transition: transform 0.5s ease-in-out;
|
|
357
|
-
|
|
358
|
-
.panel-content {
|
|
359
|
-
text-align: center;
|
|
360
|
-
padding: 2rem;
|
|
361
|
-
max-width: 400px;
|
|
362
|
-
|
|
363
|
-
h2 {
|
|
364
|
-
font-size: 2rem;
|
|
365
|
-
font-weight: 600;
|
|
366
|
-
margin-bottom: 1rem;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
p {
|
|
370
|
-
font-size: 1rem;
|
|
371
|
-
line-height: 1.6;
|
|
372
|
-
margin-bottom: 2rem;
|
|
373
|
-
opacity: 0.9;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
.toggle-btn {
|
|
377
|
-
padding: 0.8rem 3rem;
|
|
378
|
-
border: 2px solid #fff;
|
|
379
|
-
background: transparent;
|
|
380
|
-
color: #fff;
|
|
381
|
-
border-radius: 25px;
|
|
382
|
-
font-size: 0.9rem;
|
|
383
|
-
font-weight: 600;
|
|
384
|
-
cursor: pointer;
|
|
385
|
-
transition: all 0.3s;
|
|
386
|
-
|
|
387
|
-
&:hover {
|
|
388
|
-
background: #fff;
|
|
389
|
-
color: #48b19f;
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// 淡入动画
|
|
396
|
-
@keyframes fadeInUp {
|
|
397
|
-
from {
|
|
398
|
-
opacity: 0;
|
|
399
|
-
transform: translateY(20px);
|
|
400
|
-
}
|
|
401
|
-
to {
|
|
402
|
-
opacity: 1;
|
|
403
|
-
transform: translateY(0);
|
|
404
|
-
}
|
|
405
76
|
}
|
|
406
77
|
|
|
407
78
|
// 表单区域容器(全屏背景)
|
|
@@ -473,157 +144,6 @@ const $Method = {
|
|
|
473
144
|
width: 100%;
|
|
474
145
|
}
|
|
475
146
|
|
|
476
|
-
// 登录方式切换标签
|
|
477
|
-
.login-type-tabs {
|
|
478
|
-
display: flex;
|
|
479
|
-
justify-content: center;
|
|
480
|
-
gap: 0;
|
|
481
|
-
margin-bottom: 2rem;
|
|
482
|
-
border-bottom: 2px solid #f0f0f0;
|
|
483
|
-
width: 100%;
|
|
484
|
-
max-width: 450px;
|
|
485
|
-
|
|
486
|
-
.tab-btn {
|
|
487
|
-
padding: 0.75rem 1.2rem;
|
|
488
|
-
border: none;
|
|
489
|
-
background: transparent;
|
|
490
|
-
color: #666;
|
|
491
|
-
font-size: 0.875rem;
|
|
492
|
-
cursor: pointer;
|
|
493
|
-
position: relative;
|
|
494
|
-
transition: all 0.3s;
|
|
495
|
-
|
|
496
|
-
&::after {
|
|
497
|
-
content: '';
|
|
498
|
-
position: absolute;
|
|
499
|
-
bottom: -2px;
|
|
500
|
-
left: 0;
|
|
501
|
-
width: 100%;
|
|
502
|
-
height: 2px;
|
|
503
|
-
background: #48b19f;
|
|
504
|
-
transform: scaleX(0);
|
|
505
|
-
transition: transform 0.3s;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
&.active {
|
|
509
|
-
color: #48b19f;
|
|
510
|
-
font-weight: 600;
|
|
511
|
-
|
|
512
|
-
&::after {
|
|
513
|
-
transform: scaleX(1);
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
&:hover {
|
|
518
|
-
color: #48b19f;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
.login-form {
|
|
524
|
-
width: 100%;
|
|
525
|
-
max-width: 450px;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
.t-form-item {
|
|
529
|
-
width: 100%;
|
|
530
|
-
margin-bottom: 1.2rem;
|
|
531
|
-
|
|
532
|
-
:deep(.t-form__controls) {
|
|
533
|
-
width: 100%;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
:deep(.t-input) {
|
|
537
|
-
width: 100%;
|
|
538
|
-
background: #f8f9fa;
|
|
539
|
-
border: 1px solid #e0e0e0;
|
|
540
|
-
border-radius: 6px;
|
|
541
|
-
transition: all 0.3s;
|
|
542
|
-
|
|
543
|
-
&:hover {
|
|
544
|
-
border-color: #48b19f;
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
&:focus-within {
|
|
548
|
-
border-color: #48b19f;
|
|
549
|
-
background: #fff;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
input {
|
|
553
|
-
padding: 0.75rem 1rem;
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
.form-footer {
|
|
559
|
-
width: 100%;
|
|
560
|
-
display: flex;
|
|
561
|
-
justify-content: flex-end;
|
|
562
|
-
margin-bottom: 1rem;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
.forgot-password {
|
|
566
|
-
font-size: 0.8rem;
|
|
567
|
-
color: #888;
|
|
568
|
-
text-decoration: none;
|
|
569
|
-
|
|
570
|
-
&:hover {
|
|
571
|
-
color: #48b19f;
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
.auth-btn {
|
|
576
|
-
width: 100% !important;
|
|
577
|
-
max-width: 100%;
|
|
578
|
-
height: 44px;
|
|
579
|
-
border-radius: 6px;
|
|
580
|
-
background: #48b19f;
|
|
581
|
-
border: none;
|
|
582
|
-
font-size: 0.95rem;
|
|
583
|
-
font-weight: 600;
|
|
584
|
-
margin-top: 0.5rem;
|
|
585
|
-
transition: all 0.3s;
|
|
586
|
-
|
|
587
|
-
&:hover {
|
|
588
|
-
background: #3a9d8f;
|
|
589
|
-
transform: translateY(-1px);
|
|
590
|
-
box-shadow: 0 3px 10px rgba(72, 177, 159, 0.3);
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
:deep(.t-button__text) {
|
|
594
|
-
color: #fff;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
// 二维码容器
|
|
599
|
-
.qrcode-container {
|
|
600
|
-
display: flex;
|
|
601
|
-
align-items: center;
|
|
602
|
-
justify-content: center;
|
|
603
|
-
min-height: 350px;
|
|
604
|
-
padding: 2rem 0;
|
|
605
|
-
width: 100%;
|
|
606
|
-
max-width: 450px;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
.qrcode-box {
|
|
610
|
-
text-align: center;
|
|
611
|
-
display: flex;
|
|
612
|
-
flex-direction: column;
|
|
613
|
-
align-items: center;
|
|
614
|
-
gap: 1.5rem;
|
|
615
|
-
|
|
616
|
-
:deep(.t-qrcode) {
|
|
617
|
-
margin: 0 auto;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
.qrcode-tip {
|
|
621
|
-
font-size: 0.9rem;
|
|
622
|
-
color: #666;
|
|
623
|
-
margin-top: 0.5rem;
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
|
|
627
147
|
// 响应式设计
|
|
628
148
|
@media (max-width: 968px) {
|
|
629
149
|
.auth-container {
|
|
@@ -638,17 +158,8 @@ const $Method = {
|
|
|
638
158
|
|
|
639
159
|
.left-panel {
|
|
640
160
|
order: 1 !important;
|
|
161
|
+
position: relative;
|
|
641
162
|
min-height: 200px;
|
|
642
|
-
|
|
643
|
-
.panel-content {
|
|
644
|
-
h2 {
|
|
645
|
-
font-size: 1.5rem;
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
p {
|
|
649
|
-
font-size: 0.9rem;
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
163
|
}
|
|
653
164
|
|
|
654
165
|
.right-panel {
|
|
@@ -661,34 +172,18 @@ const $Method = {
|
|
|
661
172
|
padding: 2rem 1rem;
|
|
662
173
|
position: static;
|
|
663
174
|
}
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
@media (max-width: 576px) {
|
|
667
|
-
.left-panel .panel-content {
|
|
668
|
-
padding: 1.5rem;
|
|
669
|
-
|
|
670
|
-
h2 {
|
|
671
|
-
font-size: 1.3rem;
|
|
672
|
-
}
|
|
673
175
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
176
|
+
.auth-container.sign-up-mode {
|
|
177
|
+
.left-panel {
|
|
178
|
+
transform: none;
|
|
677
179
|
}
|
|
678
180
|
}
|
|
181
|
+
}
|
|
679
182
|
|
|
183
|
+
@media (max-width: 576px) {
|
|
680
184
|
.form-title {
|
|
681
185
|
font-size: 1.5rem;
|
|
682
186
|
margin-bottom: 1.5rem;
|
|
683
187
|
}
|
|
684
|
-
|
|
685
|
-
.login-type-tabs {
|
|
686
|
-
gap: 0.2rem;
|
|
687
|
-
|
|
688
|
-
.tab-btn {
|
|
689
|
-
padding: 0.6rem 1rem;
|
|
690
|
-
font-size: 0.8rem;
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
188
|
}
|
|
694
189
|
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<tiny-dialog-box v-model:visible="$Data.visible" :title="$Prop.actionType === 'add' ? '添加菜单' : '编辑菜单'" width="600px" :append-to-body="true" :show-footer="true" top="10vh">
|
|
3
|
-
<tiny-form :model="$Data.formData" label-width="120px" label-position="left" :rules="$Data2.formRules" :ref="(el) => ($
|
|
3
|
+
<tiny-form :model="$Data.formData" label-width="120px" label-position="left" :rules="$Data2.formRules" :ref="(el) => ($From.form = el)">
|
|
4
4
|
<tiny-form-item label="菜单名称" prop="name">
|
|
5
5
|
<tiny-input v-model="$Data.formData.name" placeholder="请输入菜单名称" />
|
|
6
6
|
</tiny-form-item>
|
|
@@ -52,7 +52,7 @@ const $Prop = defineProps({
|
|
|
52
52
|
const $Emit = defineEmits(['update:modelValue', 'success']);
|
|
53
53
|
|
|
54
54
|
// 表单引用
|
|
55
|
-
const $
|
|
55
|
+
const $From = $shallowRef({
|
|
56
56
|
form: null
|
|
57
57
|
});
|
|
58
58
|
|
|
@@ -114,7 +114,7 @@ const $Method = {
|
|
|
114
114
|
|
|
115
115
|
async onSubmit() {
|
|
116
116
|
try {
|
|
117
|
-
const valid = await $
|
|
117
|
+
const valid = await $From.form.validate();
|
|
118
118
|
if (!valid) return;
|
|
119
119
|
|
|
120
120
|
const res = await $Http($Prop.actionType === 'add' ? '/addon/admin/menuIns' : '/addon/admin/menuUpd', $Data.formData);
|
package/src/views/menu/index.vue
CHANGED
|
@@ -100,7 +100,7 @@ const $Method = {
|
|
|
100
100
|
// 加载菜单列表
|
|
101
101
|
async apiMenuList() {
|
|
102
102
|
try {
|
|
103
|
-
const res = await $Http('/
|
|
103
|
+
const res = await $Http('/core/menu/list', {
|
|
104
104
|
page: $Data.pagerConfig.currentPage,
|
|
105
105
|
limit: $Data.pagerConfig.pageSize
|
|
106
106
|
});
|
|
@@ -123,7 +123,7 @@ const $Method = {
|
|
|
123
123
|
status: 'warning'
|
|
124
124
|
}).then(async () => {
|
|
125
125
|
try {
|
|
126
|
-
const res = await $Http('/
|
|
126
|
+
const res = await $Http('/core/menu/del', { id: row.id });
|
|
127
127
|
if (res.code === 0) {
|
|
128
128
|
Modal.message({ message: '删除成功', status: 'success' });
|
|
129
129
|
$Method.apiMenuList();
|
|
@@ -78,7 +78,7 @@ const $Method = {
|
|
|
78
78
|
// 加载所有接口
|
|
79
79
|
async apiApiAll() {
|
|
80
80
|
try {
|
|
81
|
-
const res = await $Http('/
|
|
81
|
+
const res = await $Http('/core/api/all');
|
|
82
82
|
|
|
83
83
|
// 将接口列表按 addonTitle 分组
|
|
84
84
|
const apiMap = new Map();
|
|
@@ -114,7 +114,7 @@ const $Method = {
|
|
|
114
114
|
if (!$Prop.rowData.id) return;
|
|
115
115
|
|
|
116
116
|
try {
|
|
117
|
-
const res = await $Http('/
|
|
117
|
+
const res = await $Http('/core/role/apiDetail', {
|
|
118
118
|
roleId: $Prop.rowData.id
|
|
119
119
|
});
|
|
120
120
|
|
|
@@ -159,7 +159,7 @@ const $Method = {
|
|
|
159
159
|
// 提交表单
|
|
160
160
|
async onSubmit() {
|
|
161
161
|
try {
|
|
162
|
-
const res = await $Http('/
|
|
162
|
+
const res = await $Http('/core/role/apiSave', {
|
|
163
163
|
roleId: $Prop.rowData.id,
|
|
164
164
|
apiIds: $Data.checkedApiIds
|
|
165
165
|
});
|