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' }) } } })