chore: establish V1.1 recovery baseline
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* 兴趣与生活方式页 U09(Phase 04 P04-T24)
|
||||
*
|
||||
* 重构要点(遵循 AGENTS.md 不变量):
|
||||
* - 数据:profileService.getProfile + userStore.updateProfile(第 9 条)
|
||||
* - 数量限制:BUSINESS_LIMITS.MAX_INTEREST_TAGS(第 12 条,不硬编码)
|
||||
* - 草稿恢复:onLoad 读 ONBOARDING_DRAFT.interests,保存前写回
|
||||
* - 下一步:跳 profile-intent
|
||||
*/
|
||||
const { userStore, appStore } = require('../../stores');
|
||||
const { profileService } = require('../../services');
|
||||
const { ROUTE, STORAGE_KEYS, BUSINESS_LIMITS } = require('../../constants');
|
||||
|
||||
const INTEREST_OPTIONS = [
|
||||
{ code: 'travel', name: '旅行' },
|
||||
{ code: 'reading', name: '阅读' },
|
||||
{ code: 'sports', name: '运动' },
|
||||
{ code: 'fitness', name: '健身' },
|
||||
{ code: 'photography', name: '摄影' },
|
||||
{ code: 'movie', name: '电影' },
|
||||
{ code: 'music', name: '音乐' },
|
||||
{ code: 'food', name: '美食' },
|
||||
{ code: 'cooking', name: '烹饪' },
|
||||
{ code: 'outdoor', name: '户外' },
|
||||
{ code: 'pets', name: '宠物' },
|
||||
{ code: 'games', name: '游戏' },
|
||||
{ code: 'culture', name: '传统文化' },
|
||||
{ code: 'charity', name: '公益活动' },
|
||||
{ code: 'other', name: '其他' },
|
||||
];
|
||||
|
||||
const LIFESTYLE_OPTIONS = [
|
||||
{ code: 'quiet', name: '喜欢安静' },
|
||||
{ code: 'social', name: '喜欢社交' },
|
||||
{ code: 'outdoor', name: '喜欢户外' },
|
||||
{ code: 'homebody', name: '居家型' },
|
||||
{ code: 'regular_work', name: '工作规律' },
|
||||
{ code: 'frequent_travel', name: '经常出差' },
|
||||
{ code: 'family_oriented', name: '注重家庭' },
|
||||
{ code: 'other', name: '其他' },
|
||||
];
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 20,
|
||||
navBarHeight: 44,
|
||||
loading: false,
|
||||
saving: false,
|
||||
interests: INTEREST_OPTIONS.map((o) => ({ ...o, selected: false })),
|
||||
lifestyles: LIFESTYLE_OPTIONS.map((o) => ({ ...o, selected: false })),
|
||||
maxTags: BUSINESS_LIMITS.MAX_INTEREST_TAGS,
|
||||
selectedInterestsCount: 0,
|
||||
},
|
||||
|
||||
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 d = this._readDraft();
|
||||
const savedInterests = d.interests || profile.interests || [];
|
||||
const savedLifestyles = d.lifestyles || profile.lifestyles || [];
|
||||
const interests = this.data.interests.map((o) => ({
|
||||
...o,
|
||||
selected: savedInterests.includes(o.code),
|
||||
}));
|
||||
const lifestyles = this.data.lifestyles.map((o) => ({
|
||||
...o,
|
||||
selected: savedLifestyles.includes(o.code),
|
||||
}));
|
||||
this.setData({
|
||||
interests,
|
||||
lifestyles,
|
||||
selectedInterestsCount: interests.filter((o) => o.selected).length,
|
||||
});
|
||||
},
|
||||
|
||||
// ============ 草稿 ============
|
||||
_readDraft() {
|
||||
try {
|
||||
const draft = wx.getStorageSync(STORAGE_KEYS.ONBOARDING_DRAFT) || {};
|
||||
return draft.interests || {};
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
|
||||
_applyDraft() {
|
||||
const d = this._readDraft();
|
||||
if (!d || Object.keys(d).length === 0) return;
|
||||
const savedInterests = d.interests || [];
|
||||
const savedLifestyles = d.lifestyles || [];
|
||||
const interests = this.data.interests.map((o) => ({
|
||||
...o,
|
||||
selected: savedInterests.includes(o.code),
|
||||
}));
|
||||
const lifestyles = this.data.lifestyles.map((o) => ({
|
||||
...o,
|
||||
selected: savedLifestyles.includes(o.code),
|
||||
}));
|
||||
this.setData({
|
||||
interests,
|
||||
lifestyles,
|
||||
selectedInterestsCount: interests.filter((o) => o.selected).length,
|
||||
});
|
||||
},
|
||||
|
||||
_writeDraft() {
|
||||
try {
|
||||
const draft = wx.getStorageSync(STORAGE_KEYS.ONBOARDING_DRAFT) || {};
|
||||
draft.interests = {
|
||||
interests: this.data.interests.filter((o) => o.selected).map((o) => o.code),
|
||||
lifestyles: this.data.lifestyles.filter((o) => o.selected).map((o) => o.code),
|
||||
};
|
||||
draft.currentStep = 'interests';
|
||||
wx.setStorageSync(STORAGE_KEYS.ONBOARDING_DRAFT, draft);
|
||||
} catch (e) { /* ignore */ }
|
||||
},
|
||||
|
||||
// ============ 交互 ============
|
||||
onInterestTap(e) {
|
||||
const code = e.currentTarget.dataset.code;
|
||||
const interests = this.data.interests.map((o) => {
|
||||
if (o.code !== code) return o;
|
||||
// 取消选中直接切换;选中需检查上限
|
||||
if (!o.selected && this.data.selectedInterestsCount >= this.data.maxTags) {
|
||||
appStore.toast(`最多选择 ${this.data.maxTags} 个兴趣`);
|
||||
return o;
|
||||
}
|
||||
return { ...o, selected: !o.selected };
|
||||
});
|
||||
this.setData({
|
||||
interests,
|
||||
selectedInterestsCount: interests.filter((o) => o.selected).length,
|
||||
});
|
||||
},
|
||||
|
||||
onLifestyleTap(e) {
|
||||
const code = e.currentTarget.dataset.code;
|
||||
const lifestyles = this.data.lifestyles.map((o) => {
|
||||
if (o.code !== code) return o;
|
||||
return { ...o, selected: !o.selected };
|
||||
});
|
||||
this.setData({ lifestyles });
|
||||
},
|
||||
|
||||
// ============ 导航 ============
|
||||
onBack() {
|
||||
this._writeDraft();
|
||||
wx.navigateBack();
|
||||
},
|
||||
|
||||
async onNext() {
|
||||
if (this.data.saving) return;
|
||||
this.setData({ saving: true });
|
||||
this._writeDraft();
|
||||
try {
|
||||
await userStore.updateProfile({
|
||||
interests: this.data.interests.filter((o) => o.selected).map((o) => o.code),
|
||||
lifestyles: this.data.lifestyles.filter((o) => o.selected).map((o) => o.code),
|
||||
});
|
||||
this.setData({ saving: false });
|
||||
wx.navigateTo({ url: ROUTE.ONBOARDING.PROFILE_INTENT });
|
||||
} catch (err) {
|
||||
this.setData({ saving: false });
|
||||
appStore.toastError(err, '保存失败');
|
||||
}
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user