af-mobile-client-vue3 1.3.5 → 1.3.7
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 +1 -1
- package/src/services/api/user.ts +17 -0
- package/src/views/user/my/comm/ModifyPassword.vue +346 -0
- package/src/views/user/my/index.vue +292 -185
package/package.json
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { post } from '@af-mobile-client-vue3/services/restTools'
|
|
2
|
+
|
|
3
|
+
const userApi = {
|
|
4
|
+
// 修改密码
|
|
5
|
+
modifyPassword: '/af-system/user/modifypwd',
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 修改密码
|
|
10
|
+
* @param data 修改密码参数
|
|
11
|
+
* @returns Promise
|
|
12
|
+
*/
|
|
13
|
+
export function modifyPassword(data: any) {
|
|
14
|
+
return post(userApi.modifyPassword, JSON.stringify(data))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { userApi }
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { modifyPassword } from '@af-mobile-client-vue3/services/api/user'
|
|
3
|
+
import { useUserStore } from '@af-mobile-client-vue3/stores/modules/user'
|
|
4
|
+
import { showDialog, showToast, Button as vanButton, Field as vanField, Form as vanForm, Icon as vanIcon, Popup as vanPopup } from 'vant'
|
|
5
|
+
import { reactive, ref, watch } from 'vue'
|
|
6
|
+
import { useRouter } from 'vue-router'
|
|
7
|
+
|
|
8
|
+
// 定义 props 和 emits
|
|
9
|
+
const props = defineProps<{
|
|
10
|
+
visible: boolean
|
|
11
|
+
}>()
|
|
12
|
+
|
|
13
|
+
const emit = defineEmits<{
|
|
14
|
+
(event: 'update:visible', value: boolean): void
|
|
15
|
+
}>()
|
|
16
|
+
|
|
17
|
+
const router = useRouter()
|
|
18
|
+
const userStore = useUserStore()
|
|
19
|
+
|
|
20
|
+
// 表单引用
|
|
21
|
+
const formRef = ref()
|
|
22
|
+
|
|
23
|
+
// 表单数据
|
|
24
|
+
const formData = reactive({
|
|
25
|
+
oldPassword: '',
|
|
26
|
+
newPassword: '',
|
|
27
|
+
confirmPassword: '',
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
// 密码显示状态
|
|
31
|
+
const showOldPassword = ref(false)
|
|
32
|
+
const showNewPassword = ref(false)
|
|
33
|
+
const showConfirmPassword = ref(false)
|
|
34
|
+
|
|
35
|
+
// 加载状态
|
|
36
|
+
const loading = ref(false)
|
|
37
|
+
|
|
38
|
+
// 密码强度验证正则
|
|
39
|
+
const strongPasswordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/
|
|
40
|
+
|
|
41
|
+
// 验证密码强度
|
|
42
|
+
function validatePasswordStrength(password: string): boolean {
|
|
43
|
+
return strongPasswordRegex.test(password)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 验证确认密码
|
|
47
|
+
function validateConfirmPassword(value: string): boolean {
|
|
48
|
+
return value === formData.newPassword
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 表单验证规则
|
|
52
|
+
const rules = {
|
|
53
|
+
oldPassword: [
|
|
54
|
+
{ required: true, message: '请输入旧密码' },
|
|
55
|
+
],
|
|
56
|
+
newPassword: [
|
|
57
|
+
{ required: true, message: '请输入新密码' },
|
|
58
|
+
{
|
|
59
|
+
validator: (value: string) => {
|
|
60
|
+
if (value && !validatePasswordStrength(value)) {
|
|
61
|
+
return '新密码必须包含大小写字母、数字和特殊字符,且长度不少于8位'
|
|
62
|
+
}
|
|
63
|
+
return true
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
confirmPassword: [
|
|
68
|
+
{ required: true, message: '请再次输入新密码' },
|
|
69
|
+
{
|
|
70
|
+
validator: (value: string) => {
|
|
71
|
+
if (value && !validateConfirmPassword(value)) {
|
|
72
|
+
return '两次密码输入不一致'
|
|
73
|
+
}
|
|
74
|
+
return true
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 提交表单
|
|
81
|
+
async function handleSubmit() {
|
|
82
|
+
try {
|
|
83
|
+
loading.value = true
|
|
84
|
+
|
|
85
|
+
// 验证表单
|
|
86
|
+
await formRef.value?.validate()
|
|
87
|
+
|
|
88
|
+
// 调用修改密码API
|
|
89
|
+
const result = await handleModifyPassword({ data: {
|
|
90
|
+
ename: userStore.getUserInfo().username,
|
|
91
|
+
password: formData.oldPassword,
|
|
92
|
+
newpassword: formData.newPassword,
|
|
93
|
+
affirmpassword: formData.confirmPassword,
|
|
94
|
+
} })
|
|
95
|
+
if (result.success) {
|
|
96
|
+
showDialog({
|
|
97
|
+
title: '成功',
|
|
98
|
+
message: '修改密码成功,请重新登录',
|
|
99
|
+
confirmButtonText: '立即重新登录',
|
|
100
|
+
}).then(() => {
|
|
101
|
+
// 退出登录
|
|
102
|
+
userStore.logout()
|
|
103
|
+
// 跳转到登录页
|
|
104
|
+
router.push('/login')
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
showToast(result.message || '修改密码失败')
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
console.error('修改密码失败:', error)
|
|
113
|
+
showToast('修改密码失败,请检查输入信息')
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
loading.value = false
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 关闭弹窗
|
|
121
|
+
function closeModal() {
|
|
122
|
+
emit('update:visible', false)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 修改密码API调用
|
|
126
|
+
async function handleModifyPassword(data: any) {
|
|
127
|
+
try {
|
|
128
|
+
const res = await modifyPassword(data)
|
|
129
|
+
if (res && res === 'true') {
|
|
130
|
+
return {
|
|
131
|
+
success: true,
|
|
132
|
+
message: '修改成功',
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
return {
|
|
137
|
+
success: false,
|
|
138
|
+
message: '修改密码失败,请检查原始密码是否正确!',
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (error: any) {
|
|
143
|
+
return {
|
|
144
|
+
success: false,
|
|
145
|
+
message: error?.message || '修改密码失败',
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 监听visible变化,重置表单
|
|
151
|
+
watch(() => props.visible, (newVal) => {
|
|
152
|
+
if (!newVal) {
|
|
153
|
+
// 弹窗关闭时重置表单
|
|
154
|
+
formData.oldPassword = ''
|
|
155
|
+
formData.newPassword = ''
|
|
156
|
+
formData.confirmPassword = ''
|
|
157
|
+
showOldPassword.value = false
|
|
158
|
+
showNewPassword.value = false
|
|
159
|
+
showConfirmPassword.value = false
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
</script>
|
|
163
|
+
|
|
164
|
+
<template>
|
|
165
|
+
<van-popup
|
|
166
|
+
:show="props.visible"
|
|
167
|
+
position="center"
|
|
168
|
+
:close-on-click-overlay="false"
|
|
169
|
+
round
|
|
170
|
+
class="modify-password-popup"
|
|
171
|
+
@update:show="emit('update:visible', $event)"
|
|
172
|
+
>
|
|
173
|
+
<div class="popup-content">
|
|
174
|
+
<!-- 标题 -->
|
|
175
|
+
<div class="popup-header">
|
|
176
|
+
<h3 class="popup-title">
|
|
177
|
+
修改密码
|
|
178
|
+
</h3>
|
|
179
|
+
<van-icon name="cross" class="close-icon" @click="closeModal" />
|
|
180
|
+
</div>
|
|
181
|
+
|
|
182
|
+
<!-- 表单 -->
|
|
183
|
+
<van-form ref="formRef" class="password-form" @submit="handleSubmit">
|
|
184
|
+
<!-- 旧密码 -->
|
|
185
|
+
<van-field
|
|
186
|
+
v-model="formData.oldPassword"
|
|
187
|
+
name="oldPassword"
|
|
188
|
+
label="旧密码"
|
|
189
|
+
placeholder="请输入旧密码"
|
|
190
|
+
:type="showOldPassword ? 'text' : 'password'"
|
|
191
|
+
:rules="rules.oldPassword"
|
|
192
|
+
@click-right-icon="showOldPassword = !showOldPassword"
|
|
193
|
+
>
|
|
194
|
+
<template #right-icon>
|
|
195
|
+
<van-icon
|
|
196
|
+
:name="showOldPassword ? 'eye-o' : 'closed-eye'"
|
|
197
|
+
color="#666"
|
|
198
|
+
/>
|
|
199
|
+
</template>
|
|
200
|
+
</van-field>
|
|
201
|
+
|
|
202
|
+
<!-- 新密码 -->
|
|
203
|
+
<van-field
|
|
204
|
+
v-model="formData.newPassword"
|
|
205
|
+
name="newPassword"
|
|
206
|
+
label="新密码"
|
|
207
|
+
placeholder="请输入新密码"
|
|
208
|
+
:type="showNewPassword ? 'text' : 'password'"
|
|
209
|
+
:rules="rules.newPassword"
|
|
210
|
+
@click-right-icon="showNewPassword = !showNewPassword"
|
|
211
|
+
>
|
|
212
|
+
<template #right-icon>
|
|
213
|
+
<van-icon
|
|
214
|
+
:name="showNewPassword ? 'eye-o' : 'closed-eye'"
|
|
215
|
+
color="#666"
|
|
216
|
+
/>
|
|
217
|
+
</template>
|
|
218
|
+
</van-field>
|
|
219
|
+
|
|
220
|
+
<!-- 确认新密码 -->
|
|
221
|
+
<van-field
|
|
222
|
+
v-model="formData.confirmPassword"
|
|
223
|
+
name="confirmPassword"
|
|
224
|
+
label="确认新密码"
|
|
225
|
+
placeholder="请再次输入新密码"
|
|
226
|
+
:type="showConfirmPassword ? 'text' : 'password'"
|
|
227
|
+
:rules="rules.confirmPassword"
|
|
228
|
+
@click-right-icon="showConfirmPassword = !showConfirmPassword"
|
|
229
|
+
>
|
|
230
|
+
<template #right-icon>
|
|
231
|
+
<van-icon
|
|
232
|
+
:name="showConfirmPassword ? 'eye-o' : 'closed-eye'"
|
|
233
|
+
color="#666"
|
|
234
|
+
/>
|
|
235
|
+
</template>
|
|
236
|
+
</van-field>
|
|
237
|
+
|
|
238
|
+
<!-- 按钮组 -->
|
|
239
|
+
<div class="form-buttons">
|
|
240
|
+
<van-button
|
|
241
|
+
plain
|
|
242
|
+
type="default"
|
|
243
|
+
size="large"
|
|
244
|
+
class="cancel-btn"
|
|
245
|
+
@click="closeModal"
|
|
246
|
+
>
|
|
247
|
+
取消
|
|
248
|
+
</van-button>
|
|
249
|
+
<van-button
|
|
250
|
+
type="primary"
|
|
251
|
+
size="large"
|
|
252
|
+
native-type="submit"
|
|
253
|
+
:loading="loading"
|
|
254
|
+
class="submit-btn"
|
|
255
|
+
>
|
|
256
|
+
确认修改
|
|
257
|
+
</van-button>
|
|
258
|
+
</div>
|
|
259
|
+
</van-form>
|
|
260
|
+
</div>
|
|
261
|
+
</van-popup>
|
|
262
|
+
</template>
|
|
263
|
+
|
|
264
|
+
<style scoped lang="less">
|
|
265
|
+
.modify-password-popup {
|
|
266
|
+
width: 90%;
|
|
267
|
+
max-width: 400px;
|
|
268
|
+
|
|
269
|
+
.popup-content {
|
|
270
|
+
padding: 20px;
|
|
271
|
+
|
|
272
|
+
.popup-header {
|
|
273
|
+
display: flex;
|
|
274
|
+
justify-content: space-between;
|
|
275
|
+
align-items: center;
|
|
276
|
+
margin-bottom: 20px;
|
|
277
|
+
|
|
278
|
+
.popup-title {
|
|
279
|
+
font-size: 18px;
|
|
280
|
+
font-weight: 600;
|
|
281
|
+
color: #333;
|
|
282
|
+
margin: 0;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.close-icon {
|
|
286
|
+
font-size: 20px;
|
|
287
|
+
color: #999;
|
|
288
|
+
cursor: pointer;
|
|
289
|
+
padding: 4px;
|
|
290
|
+
|
|
291
|
+
&:hover {
|
|
292
|
+
color: #666;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.password-form {
|
|
298
|
+
.form-buttons {
|
|
299
|
+
display: flex;
|
|
300
|
+
gap: 12px;
|
|
301
|
+
margin-top: 24px;
|
|
302
|
+
|
|
303
|
+
.cancel-btn,
|
|
304
|
+
.submit-btn {
|
|
305
|
+
flex: 1;
|
|
306
|
+
height: 44px;
|
|
307
|
+
border-radius: 8px;
|
|
308
|
+
font-size: 16px;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.cancel-btn {
|
|
312
|
+
border-color: #ddd;
|
|
313
|
+
color: #666;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.submit-btn {
|
|
317
|
+
background-color: #3b82f6;
|
|
318
|
+
border-color: #3b82f6;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// 覆盖vant默认样式
|
|
326
|
+
:deep(.van-field) {
|
|
327
|
+
padding: 12px 0;
|
|
328
|
+
|
|
329
|
+
.van-field__label {
|
|
330
|
+
color: #333;
|
|
331
|
+
font-weight: 500;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.van-field__control {
|
|
335
|
+
color: #333;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.van-field__right-icon {
|
|
339
|
+
padding: 4px;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
:deep(.van-popup) {
|
|
344
|
+
border-radius: 12px;
|
|
345
|
+
}
|
|
346
|
+
</style>
|
|
@@ -1,230 +1,337 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import useSettingStore from '@af-mobile-client-vue3/stores/modules/setting'
|
|
2
3
|
import useUserStore from '@af-mobile-client-vue3/stores/modules/user'
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Row as VanRow,
|
|
8
|
-
} from 'vant/es'
|
|
4
|
+
import { Dialog as vanDialog, Icon as vanIcon } from 'vant'
|
|
5
|
+
import { ref } from 'vue'
|
|
6
|
+
import { useRouter } from 'vue-router'
|
|
7
|
+
import ModifyPassword from './comm/ModifyPassword.vue'
|
|
9
8
|
|
|
9
|
+
const router = useRouter()
|
|
10
10
|
const username = useUserStore().getUserInfo().name
|
|
11
|
-
const fullnames = useUserStore().getLogin().f.resources.
|
|
11
|
+
const fullnames = useUserStore().getLogin().f.resources.fullnames
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
// 修改密码弹窗显示状态
|
|
14
|
+
const showModifyPassword = ref(false)
|
|
15
|
+
// 退出登录确认弹窗显示状态
|
|
16
|
+
const showLogoutConfirm = ref(false)
|
|
17
|
+
|
|
18
|
+
function exit_login() {
|
|
19
|
+
showLogoutConfirm.value = true
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function confirmLogout() {
|
|
23
|
+
useUserStore().logout()
|
|
24
|
+
showLogoutConfirm.value = false
|
|
15
25
|
}
|
|
26
|
+
|
|
27
|
+
function cancelLogout() {
|
|
28
|
+
showLogoutConfirm.value = false
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function goToAttendance() {
|
|
32
|
+
router.push('/user/attendance')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function openModifyPassword() {
|
|
36
|
+
showModifyPassword.value = true
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const webMobileConfig = useSettingStore().getSetting()
|
|
16
40
|
</script>
|
|
17
41
|
|
|
18
42
|
<template>
|
|
19
|
-
<main class="my_main
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<
|
|
43
|
+
<main class="my_main">
|
|
44
|
+
<!-- 顶部导航栏 -->
|
|
45
|
+
<nav class="header_nav">
|
|
46
|
+
<div class="header_content">
|
|
47
|
+
<h1 class="main_title">
|
|
48
|
+
我的
|
|
49
|
+
</h1>
|
|
50
|
+
<!-- <div class="setting_section"> -->
|
|
51
|
+
<!-- <van-icon name="setting-o" class="setting-icon" /> -->
|
|
52
|
+
<!-- </div> -->
|
|
24
53
|
</div>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
</div>
|
|
29
|
-
<div class="user_content">
|
|
30
|
-
<VanRow :gutter="18">
|
|
31
|
-
<VanCol>
|
|
32
|
-
<img alt="default-user-profile" class="default_user_profile" src="../../../assets/common/default-user-profile.png">
|
|
33
|
-
</VanCol>
|
|
34
|
-
<VanCol class="user_info_col">
|
|
35
|
-
<p class="user_nickname">
|
|
36
|
-
{{ username }}
|
|
37
|
-
</p>
|
|
38
|
-
<p class="user_remark">
|
|
39
|
-
{{ fullnames }}
|
|
40
|
-
</p>
|
|
41
|
-
</VanCol>
|
|
42
|
-
</VanRow>
|
|
43
|
-
</div>
|
|
44
|
-
</div>
|
|
45
|
-
</div>
|
|
54
|
+
</nav>
|
|
55
|
+
|
|
56
|
+
<!-- 主要内容区域 -->
|
|
46
57
|
<div class="content">
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
58
|
+
<!-- 用户信息卡片 -->
|
|
59
|
+
<div class="user-card">
|
|
60
|
+
<div class="user-info">
|
|
61
|
+
<div class="avatar-wrap">
|
|
62
|
+
<img alt="default-user-profile" class="avatar" src="../../../assets/common/default-user-profile.png">
|
|
63
|
+
<div class="status-dot" />
|
|
64
|
+
</div>
|
|
65
|
+
<div class="user-detail">
|
|
66
|
+
<h2 class="username">
|
|
67
|
+
{{ username }}
|
|
68
|
+
</h2>
|
|
69
|
+
<p class="user-role">
|
|
70
|
+
{{ fullnames }}
|
|
52
71
|
</p>
|
|
53
|
-
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<!-- 工作统计 -->
|
|
77
|
+
<div class="stats-card">
|
|
78
|
+
<div class="stats-grid">
|
|
79
|
+
<div class="stat-item">
|
|
80
|
+
<div class="stat-value">
|
|
81
|
+
0
|
|
82
|
+
</div>
|
|
83
|
+
<div class="stat-label">
|
|
54
84
|
待办任务
|
|
55
|
-
</
|
|
56
|
-
</
|
|
57
|
-
<
|
|
58
|
-
<
|
|
59
|
-
|
|
60
|
-
</
|
|
61
|
-
<
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
<div class="stat-item">
|
|
88
|
+
<div class="stat-value">
|
|
89
|
+
0
|
|
90
|
+
</div>
|
|
91
|
+
<div class="stat-label">
|
|
62
92
|
待办流程
|
|
63
|
-
</
|
|
64
|
-
</
|
|
65
|
-
<
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
</
|
|
69
|
-
<
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="stat-item">
|
|
96
|
+
<div class="stat-value">
|
|
97
|
+
0
|
|
98
|
+
</div>
|
|
99
|
+
<div class="stat-label">
|
|
70
100
|
新消息
|
|
71
|
-
</
|
|
72
|
-
</
|
|
73
|
-
</
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
74
104
|
</div>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
105
|
+
|
|
106
|
+
<!-- 功能列表 -->
|
|
107
|
+
<div class="menu-card">
|
|
108
|
+
<div class="menu-section">
|
|
109
|
+
<h3 class="menu-title">
|
|
110
|
+
系统功能
|
|
111
|
+
</h3>
|
|
112
|
+
<div class="menu-list">
|
|
113
|
+
<div v-if="webMobileConfig?.isAttendance" class="menu-item" @click="goToAttendance">
|
|
114
|
+
<div class="menu-item-content">
|
|
115
|
+
<van-icon name="user-o" class="menu-icon" />
|
|
116
|
+
<span class="menu-text">考勤管理</span>
|
|
117
|
+
</div>
|
|
118
|
+
<van-icon name="arrow" class="menu-arrow" />
|
|
119
|
+
</div>
|
|
120
|
+
<div class="menu-item" @click="openModifyPassword">
|
|
121
|
+
<div class="menu-item-content">
|
|
122
|
+
<van-icon name="lock" class="menu-icon" />
|
|
123
|
+
<span class="menu-text">修改密码</span>
|
|
124
|
+
</div>
|
|
125
|
+
<van-icon name="arrow" class="menu-arrow" />
|
|
126
|
+
</div>
|
|
127
|
+
<div class="menu-item" @click="exit_login">
|
|
128
|
+
<div class="menu-item-content">
|
|
129
|
+
<van-icon name="sign" class="menu-icon logout-icon" />
|
|
130
|
+
<span class="menu-text">退出登录</span>
|
|
131
|
+
</div>
|
|
132
|
+
<van-icon name="arrow" class="menu-arrow" />
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
93
136
|
</div>
|
|
94
137
|
</div>
|
|
138
|
+
|
|
139
|
+
<!-- 修改密码弹窗 -->
|
|
140
|
+
<ModifyPassword
|
|
141
|
+
v-model:visible="showModifyPassword"
|
|
142
|
+
/>
|
|
143
|
+
|
|
144
|
+
<!-- 退出登录确认弹窗 -->
|
|
145
|
+
<van-dialog
|
|
146
|
+
v-model:show="showLogoutConfirm"
|
|
147
|
+
title="确认退出"
|
|
148
|
+
message="确定要退出登录吗?"
|
|
149
|
+
show-cancel-button
|
|
150
|
+
confirm-button-text="确认退出"
|
|
151
|
+
cancel-button-text="取消"
|
|
152
|
+
@confirm="confirmLogout"
|
|
153
|
+
@cancel="cancelLogout"
|
|
154
|
+
/>
|
|
95
155
|
</main>
|
|
96
156
|
</template>
|
|
97
157
|
|
|
98
158
|
<style scoped lang="less">
|
|
99
159
|
.my_main {
|
|
100
|
-
|
|
160
|
+
min-height: 100vh;
|
|
161
|
+
background-color: #f7f8fa;
|
|
162
|
+
|
|
163
|
+
// 顶部导航栏
|
|
164
|
+
.header_nav {
|
|
165
|
+
background-color: #fff;
|
|
166
|
+
padding: 0 16px;
|
|
167
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
101
168
|
position: relative;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
left: -50px;
|
|
116
|
-
z-index: 3;
|
|
117
|
-
}
|
|
118
|
-
.circle2 {
|
|
119
|
-
background-color: #3c75f9;
|
|
120
|
-
width: 300px;
|
|
121
|
-
height: 300px;
|
|
122
|
-
top: -80px;
|
|
123
|
-
left: 10px;
|
|
124
|
-
z-index: 2;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
.header_main {
|
|
128
|
-
padding: var(--base-interval-1);
|
|
129
|
-
.user_nav {
|
|
130
|
-
padding: 0 var(--base-interval-0);
|
|
131
|
-
color: #fff;
|
|
132
|
-
position: relative;
|
|
133
|
-
z-index: 4;
|
|
134
|
-
font-size: 26px;
|
|
135
|
-
text-align: right;
|
|
136
|
-
.user_setting_icon {
|
|
137
|
-
width: 26px;
|
|
138
|
-
height: 26px;
|
|
139
|
-
}
|
|
169
|
+
z-index: 50;
|
|
170
|
+
|
|
171
|
+
.header_content {
|
|
172
|
+
display: flex;
|
|
173
|
+
justify-content: space-between;
|
|
174
|
+
align-items: center;
|
|
175
|
+
height: 56px;
|
|
176
|
+
|
|
177
|
+
.main_title {
|
|
178
|
+
font-size: 1.25rem;
|
|
179
|
+
font-weight: 600;
|
|
180
|
+
color: #333;
|
|
181
|
+
margin: 0;
|
|
140
182
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
height: 76px;
|
|
150
|
-
box-shadow:
|
|
151
|
-
0 10px 20px rgba(0, 0, 0, 0.05),
|
|
152
|
-
0 6px 6px rgba(0, 0, 0, 0.05);
|
|
153
|
-
}
|
|
154
|
-
.van-row {
|
|
155
|
-
flex-wrap: nowrap;
|
|
156
|
-
align-items: center;
|
|
157
|
-
.user_info_col {
|
|
158
|
-
flex-grow: 1;
|
|
159
|
-
p {
|
|
160
|
-
margin: 0;
|
|
161
|
-
}
|
|
162
|
-
.user_nickname {
|
|
163
|
-
font-size: 20px;
|
|
164
|
-
font-weight: bold;
|
|
165
|
-
margin-bottom: 4px;
|
|
166
|
-
}
|
|
167
|
-
.user_remark {
|
|
168
|
-
font-size: 14px;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
183
|
+
|
|
184
|
+
.setting_section {
|
|
185
|
+
padding: 8px;
|
|
186
|
+
cursor: pointer;
|
|
187
|
+
|
|
188
|
+
.setting-icon {
|
|
189
|
+
font-size: 20px;
|
|
190
|
+
color: #666;
|
|
171
191
|
}
|
|
172
192
|
}
|
|
173
193
|
}
|
|
174
194
|
}
|
|
195
|
+
|
|
175
196
|
.content {
|
|
176
|
-
padding:
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
padding: 16px 0;
|
|
197
|
+
padding: 16px;
|
|
198
|
+
|
|
199
|
+
// 用户信息卡片
|
|
200
|
+
.user-card {
|
|
181
201
|
background-color: #fff;
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
.
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
202
|
+
border-radius: 8px;
|
|
203
|
+
padding: 16px;
|
|
204
|
+
margin-bottom: 16px;
|
|
205
|
+
|
|
206
|
+
.user-info {
|
|
207
|
+
display: flex;
|
|
208
|
+
align-items: center;
|
|
209
|
+
|
|
210
|
+
.avatar-wrap {
|
|
211
|
+
position: relative;
|
|
212
|
+
margin-right: 16px;
|
|
213
|
+
|
|
214
|
+
.avatar {
|
|
215
|
+
width: 80px;
|
|
216
|
+
height: 80px;
|
|
217
|
+
border-radius: 50%;
|
|
218
|
+
object-fit: cover;
|
|
194
219
|
}
|
|
195
|
-
|
|
220
|
+
|
|
221
|
+
.status-dot {
|
|
222
|
+
position: absolute;
|
|
223
|
+
bottom: 2px;
|
|
224
|
+
right: 2px;
|
|
225
|
+
width: 16px;
|
|
226
|
+
height: 16px;
|
|
227
|
+
border-radius: 50%;
|
|
228
|
+
background-color: #10b981;
|
|
229
|
+
border: 2px solid #fff;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.user-detail {
|
|
234
|
+
.username {
|
|
196
235
|
font-size: 20px;
|
|
197
|
-
font-weight:
|
|
236
|
+
font-weight: 600;
|
|
237
|
+
color: #333;
|
|
238
|
+
margin: 0 0 4px 0;
|
|
198
239
|
}
|
|
199
|
-
|
|
240
|
+
|
|
241
|
+
.user-role {
|
|
200
242
|
font-size: 14px;
|
|
201
|
-
color: #
|
|
243
|
+
color: #666;
|
|
244
|
+
margin: 0;
|
|
202
245
|
}
|
|
203
246
|
}
|
|
204
247
|
}
|
|
205
248
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
249
|
+
|
|
250
|
+
// 工作统计卡片
|
|
251
|
+
.stats-card {
|
|
252
|
+
background-color: #fff;
|
|
253
|
+
border-radius: 8px;
|
|
254
|
+
padding: 16px;
|
|
255
|
+
margin-bottom: 16px;
|
|
256
|
+
|
|
257
|
+
.stats-grid {
|
|
258
|
+
display: grid;
|
|
259
|
+
grid-template-columns: repeat(3, 1fr);
|
|
260
|
+
gap: 16px;
|
|
261
|
+
text-align: center;
|
|
262
|
+
|
|
263
|
+
.stat-item {
|
|
264
|
+
.stat-value {
|
|
265
|
+
font-size: 24px;
|
|
266
|
+
font-weight: 600;
|
|
267
|
+
color: #3b82f6;
|
|
268
|
+
margin-bottom: 4px;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.stat-label {
|
|
272
|
+
font-size: 14px;
|
|
273
|
+
color: #666;
|
|
219
274
|
}
|
|
220
275
|
}
|
|
221
276
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// 功能列表卡片
|
|
280
|
+
.menu-card {
|
|
281
|
+
background-color: #fff;
|
|
282
|
+
border-radius: 8px;
|
|
283
|
+
overflow: hidden;
|
|
284
|
+
|
|
285
|
+
.menu-section {
|
|
286
|
+
padding: 16px;
|
|
287
|
+
|
|
288
|
+
.menu-title {
|
|
289
|
+
font-size: 14px;
|
|
290
|
+
font-weight: 500;
|
|
291
|
+
color: #666;
|
|
292
|
+
margin-bottom: 12px;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.menu-list {
|
|
296
|
+
.menu-item {
|
|
297
|
+
display: flex;
|
|
298
|
+
align-items: center;
|
|
299
|
+
justify-content: space-between;
|
|
300
|
+
padding: 12px;
|
|
301
|
+
background-color: #f7f8fa;
|
|
302
|
+
border-radius: 8px;
|
|
303
|
+
margin-bottom: 8px;
|
|
304
|
+
cursor: pointer;
|
|
305
|
+
|
|
306
|
+
&:last-child {
|
|
307
|
+
margin-bottom: 0;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.menu-item-content {
|
|
311
|
+
display: flex;
|
|
312
|
+
align-items: center;
|
|
313
|
+
gap: 12px;
|
|
314
|
+
|
|
315
|
+
.menu-icon {
|
|
316
|
+
font-size: 24px;
|
|
317
|
+
color: #3b82f6;
|
|
318
|
+
|
|
319
|
+
&.logout-icon {
|
|
320
|
+
color: #ef4444;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.menu-text {
|
|
325
|
+
font-size: 16px;
|
|
326
|
+
color: #333;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.menu-arrow {
|
|
331
|
+
color: #999;
|
|
332
|
+
font-size: 16px;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
228
335
|
}
|
|
229
336
|
}
|
|
230
337
|
}
|