af-mobile-client-vue3 1.3.6 → 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
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,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import useSettingStore from '@af-mobile-client-vue3/stores/modules/setting'
|
|
3
3
|
import useUserStore from '@af-mobile-client-vue3/stores/modules/user'
|
|
4
|
+
import { Dialog as vanDialog, Icon as vanIcon } from 'vant'
|
|
4
5
|
import { ref } from 'vue'
|
|
5
6
|
import { useRouter } from 'vue-router'
|
|
6
7
|
import ModifyPassword from './comm/ModifyPassword.vue'
|