feat(personal-info): 优化个人信息页面功能
- 添加修改手机号功能 - 实现头像上传和裁剪 - 优化用户信息编辑界面 - 增加表单验证和错误提示 - 实现验证码发送和倒计时功能
This commit is contained in:
@ -50,7 +50,6 @@ export const fetchNewKeywordDetail = (params: any) => {
|
|||||||
// 使用Http.get方法,发送GET请求,获取行业话题列表
|
// 使用Http.get方法,发送GET请求,获取行业话题列表
|
||||||
return Http.get('/v1/industry-new-keywords/' + params, {});
|
return Http.get('/v1/industry-new-keywords/' + params, {});
|
||||||
};
|
};
|
||||||
fetchIndustryTopicDetail;
|
|
||||||
|
|
||||||
// 导出一个函数fetchUserPainPointsList,用于获取用户痛点列表
|
// 导出一个函数fetchUserPainPointsList,用于获取用户痛点列表
|
||||||
export const fetchUserPainPointsList = (params: any) => {
|
export const fetchUserPainPointsList = (params: any) => {
|
||||||
@ -116,3 +115,28 @@ export const trialProduct = (id: number) => {
|
|||||||
export const updateEnterpriseName = (data: any) => {
|
export const updateEnterpriseName = (data: any) => {
|
||||||
return Http.patch(`/v1/enterprises/name`, data, { headers: { 'enterprise-id': 1 } });
|
return Http.patch(`/v1/enterprises/name`, data, { headers: { 'enterprise-id': 1 } });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 发送修改手机号验证码
|
||||||
|
export const sendUpdateMobileCaptcha = (data: any) => {
|
||||||
|
return Http.post(`/v1/sms/update-mobile-captcha`, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 修改绑定的手机号
|
||||||
|
export const updateMobile = (data: any) => {
|
||||||
|
return Http.post(`/v1/me/mobile`, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 修改我的信息
|
||||||
|
export const updateMyInfo = (data: any) => {
|
||||||
|
return Http.put(`/v1/me`, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取企业账号分页
|
||||||
|
export const fetchSubAccountPage = (params: any) => {
|
||||||
|
return Http.get(`/v1/enterprises/users`, params, { headers: { 'enterprise-id': 1 } });
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取企业账号分页
|
||||||
|
export const fetchImageUploadFile = (params: any) => {
|
||||||
|
return Http.get(`/v1/oss/image-pre-signed-url`, params);
|
||||||
|
};
|
||||||
|
|||||||
@ -8,32 +8,73 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #mobile="{ record }">
|
<template #mobile="{ record }">
|
||||||
{{ record.mobile.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') }}
|
{{ record.mobile.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') }}
|
||||||
<icon-edit size="13" class="ml-8px" />
|
<icon-edit size="13" class="ml-8px" @click="openEditMobileModal" />
|
||||||
</template>
|
</template>
|
||||||
</a-table>
|
</a-table>
|
||||||
<Modal v-model:visible="infoVisible" title="修改用户信息">
|
<Modal v-model:visible="infoVisible" title="修改用户信息" @ok="handleSubmitUserInfo">
|
||||||
<a-form :model="userInfoForm" @submit="handleSubmitUserInfo">
|
<a-form :model="userInfoForm">
|
||||||
<a-form-item field="head_image" label="头像">
|
<a-form-item field="head_image" label="头像">
|
||||||
<a-avatar :image-url="userInfoForm.head_image" :size="48" />
|
<div class="flex item-center">
|
||||||
<a-upload action="/" />
|
<a-avatar :image-url="userInfoForm.file_url" :size="48" />
|
||||||
<a-button @click="openEditImageModal"><icon-upload />上传新头像</a-button>
|
<span class="upload-button" @click="triggerFileInput">
|
||||||
|
<input
|
||||||
|
ref="uploadInputRef"
|
||||||
|
accept="image/*"
|
||||||
|
type="file"
|
||||||
|
style="display: none"
|
||||||
|
@change="handleFileChange"
|
||||||
|
/>
|
||||||
|
<a-button><icon-upload />上传新头像</a-button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item field="name" label="昵称">
|
<a-form-item field="name" label="昵称">
|
||||||
<a-input v-model="userInfoForm.name" placeholder="请输入昵称" />
|
<a-input v-model.trim="userInfoForm.name" placeholder="请输入昵称" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
</Modal>
|
</Modal>
|
||||||
<Modal v-model:visible="imageVisible" title="头像裁剪">
|
<Modal v-model:visible="imageVisible" title="头像裁剪">
|
||||||
<VueCropper></VueCropper>
|
<VueCropper></VueCropper>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<Modal v-model:visible="mobileVisible" title="修改手机号" @ok="handleUpdateMobile">
|
||||||
|
<a-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
class="form"
|
||||||
|
:rules="formRules"
|
||||||
|
:label-col-props="{ span: 6, offset: 0 }"
|
||||||
|
:wrapper-col-props="{ span: 18, offset: 0 }"
|
||||||
|
label-align="left"
|
||||||
|
>
|
||||||
|
<a-form-item required field="mobile" label="新手机号">
|
||||||
|
<a-input v-model.trim="form.mobile" size="small" placeholder="请输入新的手机号" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item required field="captcha" label="获取验证码">
|
||||||
|
<a-input v-model.trim="form.captcha" size="small" placeholder="请输入验证码">
|
||||||
|
<template #suffix>
|
||||||
|
<span v-if="countdown <= 0" @click="sendCaptcha">发送验证码</span>
|
||||||
|
<span v-else>{{ countdown }}s</span>
|
||||||
|
</template>
|
||||||
|
</a-input>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
<PuzzleVerification
|
||||||
|
:show="verificationVisible"
|
||||||
|
@submit="handleVerificationSubmit"
|
||||||
|
@cancel="verificationVisible = false"
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
</Container>
|
</Container>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Container from '@/components/container.vue';
|
import Container from '@/components/container.vue';
|
||||||
import Modal from '@/components/modal.vue';
|
import Modal from '@/components/modal.vue';
|
||||||
|
import PuzzleVerification from '@/views/components/login/PuzzleVerification.vue';
|
||||||
import { ref, reactive } from 'vue';
|
import { ref, reactive } from 'vue';
|
||||||
import 'vue-cropper/dist/index.css';
|
import 'vue-cropper/dist/index.css';
|
||||||
import { VueCropper } from 'vue-cropper';
|
import { VueCropper } from 'vue-cropper';
|
||||||
|
import { sendUpdateMobileCaptcha, updateMobile, fetchImageUploadFile, updateMyInfo } from '@/api/all';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
const userInfo = reactive({
|
const userInfo = reactive({
|
||||||
id: 1,
|
id: 1,
|
||||||
@ -53,28 +94,201 @@ const columns = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
const data = reactive([userInfo]);
|
const data = reactive([userInfo]);
|
||||||
const infoVisible = ref(true);
|
const infoVisible = ref(false);
|
||||||
const imageVisible = ref(false);
|
const imageVisible = ref(false);
|
||||||
|
const mobileVisible = ref(false);
|
||||||
|
const verificationVisible = ref(false);
|
||||||
|
const timer = ref();
|
||||||
|
const countdown = ref(0);
|
||||||
|
const formRef = ref();
|
||||||
|
const isSendCaptcha = ref(false);
|
||||||
|
const uploadInputRef = ref();
|
||||||
|
|
||||||
|
// 表单校验规则
|
||||||
|
const formRules = {
|
||||||
|
mobile: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请填写手机号',
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: (value: string, callback: (error?: string) => void) => {
|
||||||
|
if (!/^1[3-9]\d{9}$/.test(value)) {
|
||||||
|
callback('手机号格式不正确');
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
captcha: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请填写验证码',
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: (value: string, callback: (error?: string) => void) => {
|
||||||
|
if (!/^\d{6}$/.test(value)) {
|
||||||
|
callback('验证码必须是6位数字');
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const form = reactive({
|
||||||
|
mobile: '',
|
||||||
|
captcha: '',
|
||||||
|
});
|
||||||
|
|
||||||
const userInfoForm = reactive({
|
const userInfoForm = reactive({
|
||||||
name: '',
|
name: '',
|
||||||
head_image: '',
|
head_image: '',
|
||||||
|
file_url: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function triggerFileInput() {
|
||||||
|
uploadInputRef.value.click();
|
||||||
|
}
|
||||||
|
|
||||||
function openEditInfoModal() {
|
function openEditInfoModal() {
|
||||||
infoVisible.value = true;
|
infoVisible.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleFileChange(event: Event) {
|
||||||
|
const target = event.target as HTMLInputElement;
|
||||||
|
const file = target.files?.[0];
|
||||||
|
if (file) {
|
||||||
|
console.log('已选择的文件:', file);
|
||||||
|
const fileExtension = getFileExtension(file.name);
|
||||||
|
const res = await fetchImageUploadFile({
|
||||||
|
suffix: fileExtension,
|
||||||
|
});
|
||||||
|
const blob = new Blob([file], { type: file.type });
|
||||||
|
await axios.put(res.upload_url, blob, {
|
||||||
|
headers: { 'Content-Type': file.type },
|
||||||
|
});
|
||||||
|
userInfoForm.head_image = res.file_name;
|
||||||
|
userInfoForm.file_url = res.file_url;
|
||||||
|
}
|
||||||
|
}
|
||||||
function openEditImageModal() {
|
function openEditImageModal() {
|
||||||
imageVisible.value = true;
|
imageVisible.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSubmitUserInfo() {
|
function openEditMobileModal() {
|
||||||
console.log(123);
|
mobileVisible.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleSubmitUserInfo() {
|
||||||
|
await updateMyInfo(userInfoForm);
|
||||||
|
AMessage.success('修改成功!');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendCaptcha() {
|
||||||
|
try {
|
||||||
|
const result = await formRef.value.validateField('mobile');
|
||||||
|
if (result === true || result === undefined) {
|
||||||
|
verificationVisible.value = true;
|
||||||
|
isSendCaptcha.value = true;
|
||||||
|
}
|
||||||
|
AMessage.error('请填写正确的手机号!');
|
||||||
|
} catch (error) {
|
||||||
|
console.log('手机号验证失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function beginCountdown() {
|
||||||
|
timer.value = setInterval(() => {
|
||||||
|
countdown.value--;
|
||||||
|
if (countdown.value <= 0) {
|
||||||
|
clearInterval(timer.value);
|
||||||
|
timer.value = null;
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleVerificationSubmit() {
|
||||||
|
await sendUpdateMobileCaptcha({ mobile: form.mobile });
|
||||||
|
AMessage.success('发送成功');
|
||||||
|
verificationVisible.value = false;
|
||||||
|
countdown.value = 60;
|
||||||
|
beginCountdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleUpdateMobile() {
|
||||||
|
if (!isSendCaptcha.value) {
|
||||||
|
AMessage.error('请先获取验证码!');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const res = await formRef.value.validate();
|
||||||
|
if (res === true || res === undefined) {
|
||||||
|
await updateMobile(form);
|
||||||
|
AMessage.success('修改成功!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFileExtension(filename: string): string {
|
||||||
|
const match = filename.match(/\.([^.]+)$/);
|
||||||
|
return match ? match[1].toLowerCase() : '';
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
.form {
|
||||||
|
:deep(.arco-form-item-label) {
|
||||||
|
font-family: Alibaba PuHuiTi, serif;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
:deep(.arco-input-wrapper) {
|
||||||
|
background: white;
|
||||||
|
border: 1px solid var(--BG-400, rgba(215, 215, 217, 1));
|
||||||
|
font-family: Alibaba PuHuiTi, serif;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
input::placeholder {
|
||||||
|
font-family: Alibaba PuHuiTi, serif;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--Text-4, rgba(147, 148, 153, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:deep(.arco-input-disabled) {
|
||||||
|
background: var(--BG-200, rgba(242, 243, 245, 1));
|
||||||
|
border: 1px solid var(--BG-400, rgba(215, 215, 217, 1));
|
||||||
|
.arco-input:disabled {
|
||||||
|
font-family: Alibaba PuHuiTi, serif;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:deep(.arco-input-focus) {
|
||||||
|
border: 1px solid var(--Brand-Brand-6, rgba(109, 76, 254, 1));
|
||||||
|
box-shadow: 0 2px 4px 0 rgba(109, 76, 254, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.upload-button {
|
||||||
|
width: 104px;
|
||||||
|
height: 24px;
|
||||||
|
margin-left: 12px;
|
||||||
|
:deep(.arco-btn) {
|
||||||
|
width: 104px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 2px 12px;
|
||||||
|
border: 1px solid var(--BG-500, rgba(177, 178, 181, 1));
|
||||||
|
font-family: Alibaba PuHuiTi, serif;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 12px;
|
||||||
|
vertical-align: middle;
|
||||||
|
color: var(--Text-2, rgba(60, 64, 67, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user