chore: establish V1.1 recovery baseline
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* 基础资料页 U06(Phase 04 P04-T21)
|
||||
*
|
||||
* 重构要点(遵循 AGENTS.md 不变量):
|
||||
* - 数据:profileService.getProfile + userStore.updateProfile,不再直连 api(第 9 条)
|
||||
* - 性别/出生日期:由身份证自动生成,只读展示(第 8 条:本地不长期保存身份证/完整生日)
|
||||
* - 草稿恢复:onLoad 读 ONBOARDING_DRAFT.basic,保存前写回(验收条件"Draft退出后可恢复")
|
||||
* - 数量限制:本页无数值型限制字段,选项列表遵循 §4.1 配置
|
||||
* - 下一步:跳 profile-lifestyle
|
||||
*/
|
||||
const { userStore, appStore } = require('../../stores');
|
||||
const { profileService } = require('../../services');
|
||||
const { ROUTE, STORAGE_KEYS } = require('../../constants');
|
||||
|
||||
const MARITAL_OPTIONS = [
|
||||
{ value: 'never_married', label: '未婚' },
|
||||
{ value: 'divorced', label: '离异' },
|
||||
{ value: 'widowed', label: '丧偶' },
|
||||
];
|
||||
|
||||
const CHILDREN_OPTIONS = [
|
||||
{ value: 'none', label: '无子女' },
|
||||
{ value: 'has', label: '有子女' },
|
||||
];
|
||||
|
||||
const EDUCATION_OPTIONS = [
|
||||
{ value: 'high_school', label: '高中/中专' },
|
||||
{ value: 'college', label: '大专' },
|
||||
{ value: 'bachelor', label: '本科' },
|
||||
{ value: 'master', label: '硕士' },
|
||||
{ value: 'phd', label: '博士' },
|
||||
];
|
||||
|
||||
const OCCUPATION_OPTIONS = [
|
||||
{ value: 'government', label: '机关事业单位' },
|
||||
{ value: 'education', label: '教育' },
|
||||
{ value: 'medical', label: '医疗' },
|
||||
{ value: 'enterprise', label: '企业职员' },
|
||||
{ value: 'technical', label: '技术人员' },
|
||||
{ value: 'self_employed', label: '个体经营' },
|
||||
{ value: 'freelance', label: '自由职业' },
|
||||
{ value: 'service', label: '服务行业' },
|
||||
{ value: 'agriculture', label: '农业' },
|
||||
{ value: 'other', label: '其他' },
|
||||
];
|
||||
|
||||
const REGION_OPTIONS = ['丹阳', '镇江市区', '镇江其他辖区', '南京'];
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 20,
|
||||
navBarHeight: 44,
|
||||
loading: false,
|
||||
saving: false,
|
||||
// 身份证自动生成(只读)
|
||||
gender: '',
|
||||
genderLabel: '',
|
||||
ageText: '',
|
||||
// 用户填写
|
||||
regionName: '',
|
||||
heightCm: '',
|
||||
maritalStatus: '',
|
||||
hasChildren: '',
|
||||
educationCode: '',
|
||||
occupationCode: '',
|
||||
// 选项
|
||||
maritalOptions: MARITAL_OPTIONS,
|
||||
childrenOptions: CHILDREN_OPTIONS,
|
||||
educationOptions: EDUCATION_OPTIONS,
|
||||
occupationOptions: OCCUPATION_OPTIONS,
|
||||
regionOptions: REGION_OPTIONS,
|
||||
regionIndex: -1,
|
||||
maritalIndex: -1,
|
||||
childrenIndex: -1,
|
||||
educationIndex: -1,
|
||||
occupationIndex: -1,
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this._initSystemInfo();
|
||||
this._applyDraft();
|
||||
this.loadProfile();
|
||||
},
|
||||
|
||||
_initSystemInfo() {
|
||||
try {
|
||||
const sysInfo = wx.getSystemInfoSync();
|
||||
this.setData({
|
||||
statusBarHeight: sysInfo.statusBarHeight || 20,
|
||||
navBarHeight: 44,
|
||||
});
|
||||
} catch (e) { /* 使用默认值 */ }
|
||||
},
|
||||
|
||||
/** 从服务端拉取已有资料(合并草稿) */
|
||||
async loadProfile() {
|
||||
this.setData({ loading: true });
|
||||
try {
|
||||
const profile = await profileService.getProfile();
|
||||
this._mergeProfile(profile);
|
||||
} catch (err) {
|
||||
// 首次填写时无资料,使用草稿默认值
|
||||
} finally {
|
||||
this.setData({ loading: false });
|
||||
}
|
||||
},
|
||||
|
||||
/** 合并服务端资料到表单(草稿优先,草稿未填则用服务端值) */
|
||||
_mergeProfile(profile) {
|
||||
if (!profile) return;
|
||||
const draft = this._readDraft();
|
||||
const regionName = draft.regionName || profile.regionName || '';
|
||||
const maritalStatus = draft.maritalStatus || profile.maritalStatus || '';
|
||||
const hasChildren = draft.hasChildren || (profile.hasChildren !== undefined ? (profile.hasChildren ? 'has' : 'none') : '');
|
||||
const educationCode = draft.educationCode || profile.educationCode || '';
|
||||
const occupationCode = draft.occupationCode || profile.occupationCode || '';
|
||||
const heightCm = draft.heightCm || profile.heightCm || '';
|
||||
|
||||
this.setData({
|
||||
gender: profile.gender || draft.gender || '',
|
||||
genderLabel: profile.gender === 'male' ? '男' : (profile.gender === 'female' ? '女' : ''),
|
||||
ageText: profile.age ? `${profile.age}岁` : '',
|
||||
regionName,
|
||||
heightCm,
|
||||
maritalStatus,
|
||||
hasChildren,
|
||||
educationCode,
|
||||
occupationCode,
|
||||
regionIndex: REGION_OPTIONS.indexOf(regionName),
|
||||
maritalIndex: MARITAL_OPTIONS.findIndex((o) => o.value === maritalStatus),
|
||||
childrenIndex: CHILDREN_OPTIONS.findIndex((o) => o.value === hasChildren),
|
||||
educationIndex: EDUCATION_OPTIONS.findIndex((o) => o.value === educationCode),
|
||||
occupationIndex: OCCUPATION_OPTIONS.findIndex((o) => o.value === occupationCode),
|
||||
});
|
||||
},
|
||||
|
||||
// ============ 草稿 ============
|
||||
_readDraft() {
|
||||
try {
|
||||
const draft = wx.getStorageSync(STORAGE_KEYS.ONBOARDING_DRAFT) || {};
|
||||
return draft.basic || {};
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
|
||||
/** 把草稿值填入表单(loadProfile 失败时也能恢复) */
|
||||
_applyDraft() {
|
||||
const d = this._readDraft();
|
||||
if (!d || Object.keys(d).length === 0) return;
|
||||
this.setData({
|
||||
regionName: d.regionName || '',
|
||||
heightCm: d.heightCm || '',
|
||||
maritalStatus: d.maritalStatus || '',
|
||||
hasChildren: d.hasChildren || '',
|
||||
educationCode: d.educationCode || '',
|
||||
occupationCode: d.occupationCode || '',
|
||||
regionIndex: REGION_OPTIONS.indexOf(d.regionName || ''),
|
||||
maritalIndex: MARITAL_OPTIONS.findIndex((o) => o.value === (d.maritalStatus || '')),
|
||||
childrenIndex: CHILDREN_OPTIONS.findIndex((o) => o.value === (d.hasChildren || '')),
|
||||
educationIndex: EDUCATION_OPTIONS.findIndex((o) => o.value === (d.educationCode || '')),
|
||||
occupationIndex: OCCUPATION_OPTIONS.findIndex((o) => o.value === (d.occupationCode || '')),
|
||||
});
|
||||
},
|
||||
|
||||
_writeDraft() {
|
||||
try {
|
||||
const draft = wx.getStorageSync(STORAGE_KEYS.ONBOARDING_DRAFT) || {};
|
||||
draft.basic = {
|
||||
regionName: this.data.regionName,
|
||||
heightCm: this.data.heightCm,
|
||||
maritalStatus: this.data.maritalStatus,
|
||||
hasChildren: this.data.hasChildren,
|
||||
educationCode: this.data.educationCode,
|
||||
occupationCode: this.data.occupationCode,
|
||||
};
|
||||
draft.currentStep = 'basic';
|
||||
wx.setStorageSync(STORAGE_KEYS.ONBOARDING_DRAFT, draft);
|
||||
} catch (e) { /* ignore */ }
|
||||
},
|
||||
|
||||
// ============ 表单交互 ============
|
||||
onRegionChange(e) {
|
||||
const idx = Number(e.detail.value);
|
||||
this.setData({ regionIndex: idx, regionName: REGION_OPTIONS[idx] });
|
||||
},
|
||||
|
||||
onHeightInput(e) {
|
||||
this.setData({ heightCm: e.detail.value });
|
||||
},
|
||||
|
||||
onMaritalChange(e) {
|
||||
const idx = Number(e.detail.value);
|
||||
this.setData({ maritalIndex: idx, maritalStatus: MARITAL_OPTIONS[idx].value });
|
||||
},
|
||||
|
||||
onChildrenChange(e) {
|
||||
const idx = Number(e.detail.value);
|
||||
this.setData({ childrenIndex: idx, hasChildren: CHILDREN_OPTIONS[idx].value });
|
||||
},
|
||||
|
||||
onEducationChange(e) {
|
||||
const idx = Number(e.detail.value);
|
||||
this.setData({ educationIndex: idx, educationCode: EDUCATION_OPTIONS[idx].value });
|
||||
},
|
||||
|
||||
onOccupationChange(e) {
|
||||
const idx = Number(e.detail.value);
|
||||
this.setData({ occupationIndex: idx, occupationCode: OCCUPATION_OPTIONS[idx].value });
|
||||
},
|
||||
|
||||
// ============ 导航 ============
|
||||
onBack() {
|
||||
this._writeDraft();
|
||||
wx.navigateBack();
|
||||
},
|
||||
|
||||
/** 下一步:校验必填 → 保存草稿 → 提交服务端 → 跳 profile-lifestyle */
|
||||
async onNext() {
|
||||
if (this.data.saving) return;
|
||||
const { regionName, heightCm, maritalStatus, hasChildren, educationCode, occupationCode } = this.data;
|
||||
if (!regionName) return appStore.toast('请选择居住区域');
|
||||
if (!heightCm) return appStore.toast('请填写身高');
|
||||
if (!maritalStatus) return appStore.toast('请选择婚姻状况');
|
||||
if (!hasChildren) return appStore.toast('请选择子女情况');
|
||||
if (!educationCode) return appStore.toast('请选择学历');
|
||||
if (!occupationCode) return appStore.toast('请选择职业类型');
|
||||
|
||||
this.setData({ saving: true });
|
||||
this._writeDraft();
|
||||
try {
|
||||
await userStore.updateProfile({
|
||||
regionName,
|
||||
heightCm: Number(heightCm),
|
||||
maritalStatus,
|
||||
hasChildren: hasChildren === 'has',
|
||||
educationCode,
|
||||
occupationCode,
|
||||
});
|
||||
this.setData({ saving: false });
|
||||
wx.navigateTo({ url: ROUTE.ONBOARDING.PROFILE_LIFESTYLE });
|
||||
} catch (err) {
|
||||
this.setData({ saving: false });
|
||||
appStore.toastError(err, '保存失败');
|
||||
}
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user