636 lines
18 KiB
Vue
636 lines
18 KiB
Vue
<template>
|
|
<div class="profile-edit-page">
|
|
<!-- 导航栏 -->
|
|
<nav class="navbar">
|
|
<div class="nav-left">
|
|
<router-link to="/myprofile" class="back-btn">
|
|
<el-icon><ArrowLeft /></el-icon>
|
|
返回
|
|
</router-link>
|
|
</div>
|
|
<div class="nav-center">
|
|
<h1 class="nav-title">编辑个人资料</h1>
|
|
</div>
|
|
<div class="nav-right"></div>
|
|
</nav>
|
|
|
|
<!-- 个人信息 -->
|
|
<div class="profile-content">
|
|
<!-- 个人资料表单 -->
|
|
<div class="profile-form">
|
|
<el-form
|
|
ref="profileFormRef"
|
|
:model="form"
|
|
:rules="rules"
|
|
label-width="80px"
|
|
>
|
|
<el-form-item label="用户名" prop="username">
|
|
<el-input v-model="form.username" placeholder="请输入用户名" />
|
|
</el-form-item>
|
|
|
|
<el-form-item label="昵称" prop="nickname">
|
|
<el-input v-model="form.nickname" placeholder="请输入昵称" />
|
|
</el-form-item>
|
|
|
|
<el-form-item label="真实姓名" prop="realName">
|
|
<el-input v-model="form.realName" placeholder="请输入真实姓名" />
|
|
</el-form-item>
|
|
|
|
<el-form-item label="身份证号" prop="idCard">
|
|
<el-input v-model="form.idCard" placeholder="请输入身份证号" maxlength="18" />
|
|
</el-form-item>
|
|
|
|
<el-form-item label="手机号" prop="phone">
|
|
<el-input v-model="form.phone" placeholder="请输入手机号" maxlength="11" />
|
|
</el-form-item>
|
|
|
|
<el-form-item label="微信收款码" prop="wechatQr">
|
|
<div class="qr-upload-container">
|
|
<el-upload
|
|
class="qr-uploader"
|
|
:action="uploadUrl"
|
|
:headers="uploadHeaders"
|
|
:before-upload="beforeQrUpload"
|
|
:on-success="(response) => handleQrUploadSuccess(response, 'wechat')"
|
|
:on-error="handleQrUploadError"
|
|
:show-file-list="false"
|
|
accept="image/*"
|
|
>
|
|
<img v-if="form.wechatQr" :src="formatImageUrl(form.wechatQr)" class="qr-preview" />
|
|
<div v-else class="qr-upload-placeholder">
|
|
<el-icon class="qr-upload-icon"><Plus /></el-icon>
|
|
<div class="qr-upload-text">上传微信收款码</div>
|
|
</div>
|
|
</el-upload>
|
|
<el-button v-if="form.wechatQr" type="danger" size="small" @click="removeQrCode('wechat')" class="remove-btn">
|
|
删除
|
|
</el-button>
|
|
</div>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="支付宝收款码" prop="alipayQr">
|
|
<div class="qr-upload-container">
|
|
<el-upload
|
|
class="qr-uploader"
|
|
:action="uploadUrl"
|
|
:headers="uploadHeaders"
|
|
:before-upload="beforeQrUpload"
|
|
:on-success="(response) => handleQrUploadSuccess(response, 'alipay')"
|
|
:on-error="handleQrUploadError"
|
|
:show-file-list="false"
|
|
accept="image/*"
|
|
>
|
|
<img v-if="form.alipayQr" :src="formatImageUrl(form.alipayQr)" class="qr-preview" />
|
|
<div v-else class="qr-upload-placeholder">
|
|
<el-icon class="qr-upload-icon"><Plus /></el-icon>
|
|
<div class="qr-upload-text">上传支付宝收款码</div>
|
|
</div>
|
|
</el-upload>
|
|
<el-button v-if="form.alipayQr" type="danger" size="small" @click="removeQrCode('alipay')" class="remove-btn">
|
|
删除
|
|
</el-button>
|
|
</div>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="银行卡号" prop="bankCard">
|
|
<el-input v-model="form.bankCard" placeholder="请输入银行卡号" />
|
|
</el-form-item>
|
|
|
|
<el-form-item label="云闪付收款码" prop="unionpayQr">
|
|
<div class="qr-upload-container">
|
|
<el-upload
|
|
class="qr-uploader"
|
|
:action="uploadUrl"
|
|
:headers="uploadHeaders"
|
|
:before-upload="beforeQrUpload"
|
|
:on-success="(response) => handleQrUploadSuccess(response, 'unionpay')"
|
|
:on-error="handleQrUploadError"
|
|
:show-file-list="false"
|
|
accept="image/*"
|
|
>
|
|
<img v-if="form.unionpayQr" :src="formatImageUrl(form.unionpayQr)" class="qr-preview" />
|
|
<div v-else class="qr-upload-placeholder">
|
|
<el-icon class="qr-upload-icon"><Plus /></el-icon>
|
|
<div class="qr-upload-text">上传云闪付收款码</div>
|
|
</div>
|
|
</el-upload>
|
|
<el-button v-if="form.unionpayQr" type="danger" size="small" @click="removeQrCode('unionpay')" class="remove-btn">
|
|
删除
|
|
</el-button>
|
|
</div>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="营业执照" prop="businessLicense">
|
|
<div class="qr-upload-container">
|
|
<el-upload
|
|
class="qr-uploader"
|
|
:action="uploadUrl"
|
|
:headers="uploadHeaders"
|
|
:before-upload="beforeDocumentUpload"
|
|
:on-success="(response) => handleDocumentUploadSuccess(response, 'businessLicense')"
|
|
:on-error="handleQrUploadError"
|
|
:show-file-list="false"
|
|
accept="image/*"
|
|
>
|
|
<img v-if="form.businessLicense" :src="formatImageUrl(form.businessLicense)" class="qr-preview" />
|
|
<div v-else class="qr-upload-placeholder">
|
|
<el-icon class="qr-upload-icon"><Plus /></el-icon>
|
|
<div class="qr-upload-text">上传营业执照</div>
|
|
</div>
|
|
</el-upload>
|
|
<el-button v-if="form.businessLicense" type="danger" size="small" @click="removeDocument('businessLicense')" class="remove-btn">
|
|
删除
|
|
</el-button>
|
|
</div>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="身份证正面" prop="idCardFront">
|
|
<div class="qr-upload-container">
|
|
<el-upload
|
|
class="qr-uploader"
|
|
:action="uploadUrl"
|
|
:headers="uploadHeaders"
|
|
:before-upload="beforeDocumentUpload"
|
|
:on-success="(response) => handleDocumentUploadSuccess(response, 'idCardFront')"
|
|
:on-error="handleQrUploadError"
|
|
:show-file-list="false"
|
|
accept="image/*"
|
|
>
|
|
<img v-if="form.idCardFront" :src="formatImageUrl(form.idCardFront)" class="qr-preview" />
|
|
<div v-else class="qr-upload-placeholder">
|
|
<el-icon class="qr-upload-icon"><Plus /></el-icon>
|
|
<div class="qr-upload-text">上传身份证正面</div>
|
|
</div>
|
|
</el-upload>
|
|
<el-button v-if="form.idCardFront" type="danger" size="small" @click="removeDocument('idCardFront')" class="remove-btn">
|
|
删除
|
|
</el-button>
|
|
</div>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="身份证反面" prop="idCardBack">
|
|
<div class="qr-upload-container">
|
|
<el-upload
|
|
class="qr-uploader"
|
|
:action="uploadUrl"
|
|
:headers="uploadHeaders"
|
|
:before-upload="beforeDocumentUpload"
|
|
:on-success="(response) => handleDocumentUploadSuccess(response, 'idCardBack')"
|
|
:on-error="handleQrUploadError"
|
|
:show-file-list="false"
|
|
accept="image/*"
|
|
>
|
|
<img v-if="form.idCardBack" :src="formatImageUrl(form.idCardBack)" class="qr-preview" />
|
|
<div v-else class="qr-upload-placeholder">
|
|
<el-icon class="qr-upload-icon"><Plus /></el-icon>
|
|
<div class="qr-upload-text">上传身份证反面</div>
|
|
</div>
|
|
</el-upload>
|
|
<el-button v-if="form.idCardBack" type="danger" size="small" @click="removeDocument('idCardBack')" class="remove-btn">
|
|
删除
|
|
</el-button>
|
|
</div>
|
|
</el-form-item>
|
|
</el-form>
|
|
|
|
<div class="form-actions">
|
|
<el-button @click="resetForm">重置</el-button>
|
|
<el-button type="primary" @click="saveProfile" :loading="saving">
|
|
保存资料
|
|
</el-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, reactive, onMounted, computed } from 'vue'
|
|
import { useRouter, useRoute } from 'vue-router'
|
|
import { useUserStore } from '@/stores/user'
|
|
import { ElMessage } from 'element-plus'
|
|
import { ArrowLeft, Plus } from '@element-plus/icons-vue'
|
|
import api from '@/utils/api'
|
|
import { uploadURL, getImageUrl, getUploadConfig } from '@/config'
|
|
|
|
const router = useRouter()
|
|
const route = useRoute()
|
|
const userStore = useUserStore()
|
|
|
|
// 响应式数据
|
|
const form = reactive({
|
|
username: '',
|
|
nickname: '',
|
|
phone: '',
|
|
realName: '',
|
|
idCard: '',
|
|
wechatQr: '',
|
|
alipayQr: '',
|
|
bankCard: '',
|
|
unionpayQr: '',
|
|
businessLicense: '',
|
|
idCardFront: '',
|
|
idCardBack: ''
|
|
})
|
|
|
|
const saving = ref(false)
|
|
const profileFormRef = ref()
|
|
|
|
// 上传配置
|
|
const uploadUrl = ref(uploadURL)
|
|
const uploadHeaders = computed(() => getUploadConfig().headers)
|
|
|
|
// 表单验证规则
|
|
const rules = {
|
|
username: [
|
|
{ required: true, message: '请输入用户名', trigger: 'blur' },
|
|
{ min: 3, max: 20, message: '用户名长度在 3 到 20 个字符', trigger: 'blur' }
|
|
],
|
|
realName: [
|
|
{ required: true, message: '请输入真实姓名', trigger: 'blur' },
|
|
{ min: 2, max: 10, message: '真实姓名长度在 2 到 10 个字符', trigger: 'blur' }
|
|
],
|
|
idCard: [
|
|
{ required: true, message: '请输入身份证号', trigger: 'blur' },
|
|
{ pattern: /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/, message: '请输入正确的身份证号', trigger: 'blur' }
|
|
],
|
|
phone: [
|
|
{ required: true, message: '请输入手机号', trigger: 'blur' },
|
|
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
|
|
]
|
|
}
|
|
|
|
// 方法
|
|
/**
|
|
* 获取用户信息
|
|
*/
|
|
const getUserInfo = async () => {
|
|
try {
|
|
const response = await api.get('/users/profile')
|
|
console.log(response.data, 'response.data.data')
|
|
|
|
// 同步到表单
|
|
Object.keys(form).forEach(key => {
|
|
form[key] = response.data.user[key] || ''
|
|
})
|
|
} catch (error) {
|
|
console.error('获取用户信息失败:', error)
|
|
ElMessage.error('获取用户信息失败')
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 保存个人资料
|
|
*/
|
|
const saveProfile = async () => {
|
|
try {
|
|
await profileFormRef.value.validate()
|
|
|
|
saving.value = true
|
|
form.wechatQr = form.wechatQr.replace('https://minio.zrbjr.com', '')
|
|
form.alipayQr = form.alipayQr.replace('https://minio.zrbjr.com', '')
|
|
form.unionpayQr = form.unionpayQr.replace('https://minio.zrbjr.com', '')
|
|
form.businessLicense = form.businessLicense.replace('https://minio.zrbjr.com', '')
|
|
form.idCardFront = form.idCardFront.replace('https://minio.zrbjr.com', '')
|
|
form.idCardBack = form.idCardBack.replace('https://minio.zrbjr.com', '')
|
|
const response = await api.put('/users/profile', form)
|
|
|
|
// 更新本地数据
|
|
if (response.data.success) {
|
|
ElMessage.success(response.data.message || '保存成功')
|
|
router.back() // 保存成功后返回上一页
|
|
} else {
|
|
ElMessage.error(response.data.message || '保存失败')
|
|
}
|
|
} catch (error) {
|
|
console.error('保存个人资料失败:', error)
|
|
if (error.response) {
|
|
ElMessage.error(error.response.data.message || '保存失败')
|
|
} else {
|
|
ElMessage.error('保存失败')
|
|
}
|
|
} finally {
|
|
saving.value = false
|
|
}
|
|
}
|
|
|
|
const resetForm = () => {
|
|
getUserInfo() // 重置为原始数据
|
|
}
|
|
|
|
/**
|
|
* 二维码上传前的验证
|
|
* @param {File} file - 上传的文件
|
|
* @returns {boolean} 是否通过验证
|
|
*/
|
|
const beforeQrUpload = (file) => {
|
|
const isImage = file.type.startsWith('image/')
|
|
const isLt5M = file.size / 1024 / 1024 < 5
|
|
|
|
if (!isImage) {
|
|
ElMessage.error('只能上传图片文件!')
|
|
return false
|
|
}
|
|
if (!isLt5M) {
|
|
ElMessage.error('图片大小不能超过 5MB!')
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
/**
|
|
* 处理二维码上传成功回调
|
|
* @param {Object} response - 上传接口返回的响应数据
|
|
* @param {string} type - 二维码类型 (wechat/alipay/unionpay)
|
|
*/
|
|
const handleQrUploadSuccess = (response, type) => {
|
|
if (response.success) {
|
|
// 更新对应的二维码字段
|
|
const fieldMap = {
|
|
wechat: 'wechatQr',
|
|
alipay: 'alipayQr',
|
|
unionpay: 'unionpayQr'
|
|
}
|
|
|
|
form[fieldMap[type]] = response.data.url
|
|
ElMessage.success('收款码上传成功')
|
|
} else {
|
|
ElMessage.error(response.message || '上传失败')
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 处理二维码上传错误
|
|
* @param {Object} error - 错误信息
|
|
*/
|
|
const handleQrUploadError = (error) => {
|
|
console.error('上传错误:', error)
|
|
ElMessage.error('上传失败,请重试')
|
|
}
|
|
|
|
/**
|
|
* 删除二维码
|
|
* @param {string} type - 二维码类型 (wechat/alipay/unionpay)
|
|
*/
|
|
const removeQrCode = (type) => {
|
|
const fieldMap = {
|
|
wechat: 'wechatQr',
|
|
alipay: 'alipayQr',
|
|
unionpay: 'unionpayQr'
|
|
}
|
|
|
|
form[fieldMap[type]] = ''
|
|
ElMessage.success('收款码已删除')
|
|
}
|
|
|
|
/**
|
|
* 证件上传前的验证
|
|
* @param {File} file - 上传的文件
|
|
* @returns {boolean} 是否通过验证
|
|
*/
|
|
const beforeDocumentUpload = (file) => {
|
|
const isImage = file.type.startsWith('image/')
|
|
const isLt10M = file.size / 1024 / 1024 < 10
|
|
|
|
if (!isImage) {
|
|
ElMessage.error('只能上传图片文件!')
|
|
return false
|
|
}
|
|
if (!isLt10M) {
|
|
ElMessage.error('图片大小不能超过 10MB!')
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
/**
|
|
* 处理证件上传成功回调
|
|
* @param {Object} response - 上传接口返回的响应数据
|
|
* @param {string} type - 证件类型 (businessLicense/idCardFront/idCardBack)
|
|
*/
|
|
const handleDocumentUploadSuccess = (response, type) => {
|
|
console.log(response, 'response');
|
|
|
|
if (response.success) {
|
|
form[type] = response.data.url
|
|
const typeNames = {
|
|
businessLicense: '营业执照',
|
|
idCardFront: '身份证正面',
|
|
idCardBack: '身份证反面'
|
|
}
|
|
ElMessage.success(`${typeNames[type]}上传成功`)
|
|
} else {
|
|
ElMessage.error(response.message || '上传失败')
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 删除证件
|
|
* @param {string} type - 证件类型 (businessLicense/idCardFront/idCardBack)
|
|
*/
|
|
const removeDocument = (type) => {
|
|
form[type] = ''
|
|
const typeNames = {
|
|
businessLicense: '营业执照',
|
|
idCardFront: '身份证正面',
|
|
idCardBack: '身份证反面'
|
|
}
|
|
ElMessage.success(`${typeNames[type]}已删除`)
|
|
}
|
|
|
|
/**
|
|
* 获取图片URL - 使用配置文件处理
|
|
* @param {string} url - 相对路径或完整URL
|
|
* @returns {string} 处理后的图片URL
|
|
*/
|
|
const formatImageUrl = (url) => {
|
|
return getImageUrl(url)
|
|
}
|
|
|
|
// 生命周期
|
|
onMounted(() => {
|
|
getUserInfo()
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.profile-edit-page {
|
|
min-height: 100vh;
|
|
background-color: #f5f5f5;
|
|
}
|
|
|
|
.navbar {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0 16px;
|
|
height: 56px;
|
|
background: white;
|
|
border-bottom: 1px solid #eee;
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 100;
|
|
}
|
|
|
|
.nav-left,
|
|
.nav-right {
|
|
flex: 1;
|
|
}
|
|
|
|
.nav-right {
|
|
text-align: right;
|
|
}
|
|
|
|
.back-btn {
|
|
color: #409eff;
|
|
font-size: 14px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
}
|
|
|
|
.nav-title {
|
|
margin: 0;
|
|
font-size: 18px;
|
|
font-weight: 500;
|
|
color: #333;
|
|
}
|
|
|
|
.profile-content {
|
|
padding: 20px 16px;
|
|
}
|
|
|
|
.profile-form {
|
|
background: white;
|
|
border-radius: 12px;
|
|
padding: 25px;
|
|
margin-bottom: 20px;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
border: 1px solid rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.form-actions {
|
|
text-align: center;
|
|
margin-top: 30px;
|
|
display: flex;
|
|
flex-direction: column; // 修改为垂直排列
|
|
gap: 15px;
|
|
align-items: center; // 水平居中对齐
|
|
}
|
|
|
|
.form-actions .el-button {
|
|
width: 100%; // 按钮宽度占满容器
|
|
max-width: 220px; // 最大宽度限制
|
|
border-radius: 8px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* 二维码上传样式 */
|
|
.qr-upload-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
gap: 10px;
|
|
}
|
|
|
|
.qr-uploader {
|
|
width: 120px;
|
|
}
|
|
|
|
.qr-uploader :deep(.el-upload) {
|
|
border: 2px dashed #d9d9d9;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
position: relative;
|
|
overflow: hidden;
|
|
transition: 0.3s;
|
|
width: 120px;
|
|
height: 120px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background-color: #fafafa;
|
|
}
|
|
|
|
.qr-uploader :deep(.el-upload:hover) {
|
|
border-color: #409eff;
|
|
background-color: #f0f9ff;
|
|
}
|
|
|
|
.qr-upload-placeholder {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 100%;
|
|
height: 100%;
|
|
text-align: center;
|
|
}
|
|
|
|
.qr-upload-icon {
|
|
font-size: 24px;
|
|
color: #8c939d;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.qr-upload-text {
|
|
font-size: 12px;
|
|
color: #8c939d;
|
|
line-height: 1.2;
|
|
}
|
|
|
|
.qr-preview {
|
|
width: 120px;
|
|
height: 120px;
|
|
object-fit: cover;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.remove-btn {
|
|
align-self: flex-start;
|
|
}
|
|
|
|
/* 响应式设计 */
|
|
@media (max-width: 768px) {
|
|
.profile-content {
|
|
padding: 10px;
|
|
}
|
|
|
|
.profile-form {
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.qr-uploader {
|
|
width: 100px;
|
|
}
|
|
|
|
.qr-uploader :deep(.el-upload) {
|
|
width: 100px;
|
|
height: 100px;
|
|
}
|
|
|
|
.qr-preview {
|
|
width: 100px;
|
|
height: 100px;
|
|
}
|
|
|
|
.form-actions {
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
.form-actions .el-button {
|
|
width: 100%;
|
|
max-width: 200px;
|
|
}
|
|
|
|
.el-form {
|
|
:deep(.el-form-item__label) {
|
|
width: 80px !important;
|
|
font-size: 14px;
|
|
}
|
|
}
|
|
}
|
|
</style> |