xiangqinxiaochengxu/miniprogram/pages/profile-edit/profile-edit.js

371 lines
11 KiB
JavaScript
Raw Normal View History

2026-04-17 10:49:14 +08:00
const request = require('../../utils/request')
const AUDIT_REQUIRED_FIELDS = ['personality_tags', 'hobbies', 'wechat_id', 'phone']
const PROFILE_LIMITS = {
nickname: 50,
real_name: 20,
city: 30,
job_industry: 50,
job_company: 100,
prefer_city: 30,
self_intro: 500,
wechat_id: 64,
phone: 20,
tagItem: 20,
listItems: 20
}
Page({
data: {
form: {
nickname: '',
real_name: '',
gender: null,
birth_year: null,
city: '',
height: null,
education: null,
job_industry: '',
job_company: '',
income_range: null,
prefer_city: '',
self_intro: '',
personality_tags: [],
hobbies: [],
wechat_id: '',
phone: ''
},
tagsText: '',
hobbiesText: '',
genderOptions: [
{ label: '男', value: 1 },
{ label: '女', value: 2 }
],
educationOptions: [
{ label: '高中', value: 1 },
{ label: '大专', value: 2 },
{ label: '本科', value: 3 },
{ label: '硕士', value: 4 },
{ label: '博士', value: 5 }
],
incomeOptions: [
{ label: '5k以下', value: 1 },
{ label: '5k-10k', value: 2 },
{ label: '10k-20k', value: 3 },
{ label: '20k以上', value: 4 }
],
genderText: '请选择',
educationText: '请选择',
incomeText: '请选择',
loading: false,
saving: false
},
onLoad() {
this.syncPickerTexts(this.data.form)
this.syncExtraTexts(this.data.form)
this.loadProfile()
},
syncExtraTexts(form) {
this.setData({
tagsText: (form.personality_tags || []).join(''),
hobbiesText: (form.hobbies || []).join('')
})
},
parseListText(text) {
return (text || '')
.split(/[,\n]/)
.map((item) => item.trim())
.filter(Boolean)
},
async loadProfile() {
this.setData({ loading: true })
try {
const data = await request({ url: '/users/me' })
const form = {
...this.data.form,
...data,
gender: data.gender == null ? null : Number(data.gender),
birth_year: data.birth_year == null ? null : Number(data.birth_year),
height: data.height == null ? null : Number(data.height),
education: data.education == null ? null : Number(data.education),
income_range: data.income_range == null ? null : Number(data.income_range),
personality_tags: data.personality_tags || [],
hobbies: data.hobbies || [],
wechat_id: data.wechat_id || '',
phone: data.phone || ''
}
this.setData({ form })
this.syncPickerTexts(form)
this.syncExtraTexts(form)
} catch (err) {
console.error('Load profile edit data failed:', err)
} finally {
this.setData({ loading: false })
}
},
handleInput(e) {
const field = e.currentTarget.dataset.field
const value = e.detail.value
if (field === 'personality_tags') {
const tags = this.parseListText(value)
this.setData({
form: { ...this.data.form, personality_tags: tags },
tagsText: value
})
return
}
if (field === 'hobbies') {
const hobbies = this.parseListText(value)
this.setData({
form: { ...this.data.form, hobbies },
hobbiesText: value
})
return
}
this.setData({ [`form.${field}`]: value })
},
handlePickerChange(e) {
const field = e.currentTarget.dataset.field
const optionKeyMap = {
income_range: 'incomeOptions'
}
const options = this.data[optionKeyMap[field] || `${field}Options`]
const index = Number(e.detail.value)
if (!options || !options[index]) {
return
}
const form = {
...this.data.form,
[field]: options[index].value
}
this.setData({ form })
this.syncPickerTexts(form)
},
syncPickerTexts(form) {
this.setData({
genderText: this.getOptionLabel(this.data.genderOptions, form.gender, '请选择'),
educationText: this.getOptionLabel(this.data.educationOptions, form.education, '请选择'),
incomeText: this.getOptionLabel(this.data.incomeOptions, form.income_range, '请选择')
})
},
getOptionLabel(options, value, fallback) {
const normalizedValue = value === null || value === undefined || value === '' ? value : Number(value)
const matched = (options || []).find((item) => item.value === normalizedValue)
return matched ? matched.label : fallback
},
sanitizeText(value, maxLength) {
if (value === null || value === undefined) {
return ''
}
return String(value).trim().slice(0, maxLength)
},
sanitizeNumber(value) {
if (value === null || value === undefined || value === '') {
return null
}
const num = Number(value)
return Number.isFinite(num) ? num : null
},
buildProfilePayload() {
const payload = {
nickname: this.sanitizeText(this.data.form.nickname, PROFILE_LIMITS.nickname) || null,
real_name: this.sanitizeText(this.data.form.real_name, PROFILE_LIMITS.real_name) || null,
gender: this.sanitizeNumber(this.data.form.gender),
birth_year: this.sanitizeNumber(this.data.form.birth_year),
city: this.sanitizeText(this.data.form.city, PROFILE_LIMITS.city) || null,
height: this.sanitizeNumber(this.data.form.height),
education: this.sanitizeNumber(this.data.form.education),
job_industry: this.sanitizeText(this.data.form.job_industry, PROFILE_LIMITS.job_industry) || null,
job_company: this.sanitizeText(this.data.form.job_company, PROFILE_LIMITS.job_company) || null,
income_range: this.sanitizeNumber(this.data.form.income_range),
prefer_city: this.sanitizeText(this.data.form.prefer_city, PROFILE_LIMITS.prefer_city) || null,
self_intro: this.sanitizeText(this.data.form.self_intro, PROFILE_LIMITS.self_intro) || null,
personality_tags: Array.isArray(this.data.form.personality_tags)
? this.data.form.personality_tags.map((item) => this.sanitizeText(item, PROFILE_LIMITS.tagItem)).filter(Boolean).slice(0, PROFILE_LIMITS.listItems)
: [],
hobbies: Array.isArray(this.data.form.hobbies)
? this.data.form.hobbies.map((item) => this.sanitizeText(item, PROFILE_LIMITS.tagItem)).filter(Boolean).slice(0, PROFILE_LIMITS.listItems)
: [],
wechat_id: this.sanitizeText(this.data.form.wechat_id, PROFILE_LIMITS.wechat_id) || null,
phone: this.sanitizeText(this.data.form.phone, PROFILE_LIMITS.phone) || null
}
return payload
},
getValidationLabel(field) {
const labels = {
nickname: '昵称',
real_name: '真实姓名',
city: '所在城市',
job_industry: '行业',
job_company: '公司',
prefer_city: '期望城市',
self_intro: '个人介绍',
wechat_id: '微信号',
phone: '手机号',
personality_tags: '性格标签',
hobbies: '兴趣爱好',
gender: '性别',
birth_year: '出生年份',
height: '身高',
education: '学历',
income_range: '收入范围'
}
return labels[field] || field
},
validateProfilePayload(payload) {
const errors = []
const checkTextLength = (field, maxLength) => {
const value = payload[field]
if (typeof value === 'string' && value.length > maxLength) {
errors.push(`${this.getValidationLabel(field)}不能超过${maxLength}个字符`)
}
}
checkTextLength('nickname', PROFILE_LIMITS.nickname)
checkTextLength('real_name', PROFILE_LIMITS.real_name)
checkTextLength('city', PROFILE_LIMITS.city)
checkTextLength('job_industry', PROFILE_LIMITS.job_industry)
checkTextLength('job_company', PROFILE_LIMITS.job_company)
checkTextLength('prefer_city', PROFILE_LIMITS.prefer_city)
checkTextLength('self_intro', PROFILE_LIMITS.self_intro)
checkTextLength('wechat_id', PROFILE_LIMITS.wechat_id)
checkTextLength('phone', PROFILE_LIMITS.phone)
;['personality_tags', 'hobbies'].forEach((field) => {
const list = payload[field]
const label = this.getValidationLabel(field)
if (!Array.isArray(list)) {
errors.push(`${label}格式不正确`)
return
}
if (list.length > PROFILE_LIMITS.listItems) {
errors.push(`${label}最多${PROFILE_LIMITS.listItems}`)
}
list.forEach((item) => {
if (item.length > PROFILE_LIMITS.tagItem) {
errors.push(`${label}单项不能超过${PROFILE_LIMITS.tagItem}个字符`)
}
})
})
;['gender', 'birth_year', 'height', 'education', 'income_range'].forEach((field) => {
const value = payload[field]
if (value !== null && value !== undefined && !Number.isFinite(value)) {
errors.push(`${this.getValidationLabel(field)}格式不正确`)
}
})
return errors
},
async saveProfile() {
this.setData({ saving: true })
try {
const payload = this.buildProfilePayload()
const validationErrors = this.validateProfilePayload(payload)
if (validationErrors.length > 0) {
wx.showModal({
title: '资料有误',
content: validationErrors.slice(0, 3).join(''),
showCancel: false
})
return false
}
await request({
url: '/users/me',
method: 'PUT',
data: payload
})
this.setData({
form: { ...this.data.form, ...payload }
})
this.syncPickerTexts(this.data.form)
wx.showToast({ title: '保存成功', icon: 'success' })
return true
} catch (err) {
console.error('Save profile failed:', err)
wx.showToast({ title: err.message || '保存失败', icon: 'none' })
return false
} finally {
this.setData({ saving: false })
}
},
async submitAudit() {
const saveOk = await this.saveProfile()
if (!saveOk) {
return
}
const payload = this.buildProfilePayload()
const validationErrors = this.validateProfilePayload(payload)
if (validationErrors.length > 0) {
wx.showModal({
title: '资料有误',
content: validationErrors.slice(0, 3).join(''),
showCancel: false
})
return
}
const missingFields = AUDIT_REQUIRED_FIELDS.filter((field) => {
const value = payload[field]
if (Array.isArray(value)) {
return value.length === 0
}
if (value && typeof value === 'object') {
return Object.keys(value).length === 0
}
return value === null || value === undefined || value === ''
})
if (missingFields.length > 0) {
const labelMap = {
personality_tags: '性格标签',
hobbies: '兴趣爱好',
wechat_id: '微信号',
phone: '手机号'
}
wx.showModal({
title: '资料未完善',
content: `提交审核前请先补充:${missingFields.map((field) => labelMap[field] || field).join('、')}`,
showCancel: false
})
return
}
try {
await request({
url: '/users/submit-audit',
method: 'POST'
})
wx.showToast({ title: '已提交审核', icon: 'success' })
setTimeout(() => {
wx.navigateTo({ url: '/pages/audit-status/audit-status' })
}, 300)
} catch (err) {
console.error('Submit audit failed:', err)
wx.showToast({ title: err.message || '提交审核失败', icon: 'none' })
}
}
})