/* ═════ 档案填写页:出生年月/性别/地区 + 日常肤质轮播 → 拍照 对照 H5 index.html #s-profile(L61-108)、#p-photoguide(L311-327) 档案字段与 H5 一致:{ real_age, gender, region, daily_skin_type } 三个选择器均用底部滚轮弹层,滚动只修改草稿,确定后写回字段。 ═════ */ var api = require('../../utils/api.js'); var REGION_DATA = require('../../utils/region-data.js'); var swipe = require('../../utils/swipe-gesture'); // 肤质选项(与 H5 SKINS 一致,图片远程加载;第一条描述在 H5 里含
,拆成两行) var SKINS = [ { img: 'img/ui-20261009/skin-0-dry.png', name: '干性肌肤', desc: '全脸干燥,容易紧绷、', desc2: '缺乏光泽' }, { img: 'img/ui-20261009/skin-1-mixeddry.png', name: '混合偏干肌肤', desc: '两颊偏干,T区油脂较少或偶尔出油' }, { img: 'img/ui-20261009/skin-2-neutral.png', name: '中性肌肤', desc: '水油平衡,肤感舒适,无明显干燥出油' }, { img: 'img/ui-20261009/skin-3-oily.png', name: '油性肌肤', desc: '全脸易出油,容易泛油光、毛孔明显' }, { img: 'img/ui-20261009/skin-4-mixedoily.png', name: '混合偏油肌肤', desc: 'T区易出油,两颊相对清爽或轻微干燥' } ]; var NOW = new Date(), NOW_Y = NOW.getFullYear(), NOW_M = NOW.getMonth() + 1; var YEARS = [], MONTHS = []; for (var y = NOW_Y - 99; y <= NOW_Y - 1; y++) YEARS.push(y + '年'); for (var m = 1; m <= 12; m++) MONTHS.push(m + '月'); function ageFromBirth(y, m) { return NOW_Y - y - (NOW_M < m ? 1 : 0); } // 未过生日月份按少一岁(与 H5 一致) Page(require('../../utils/page-header').page({ onShareAppMessage: function () { return require('../../utils/share').message(); }, data: { bgUrl: api.assetUrl('img/ui-20261009/bg-profile-h5.jpg'), guideBgUrl: api.assetUrl('img/ui-20261009/bg-splash-h5.jpg'), sloganUrl: api.assetUrl('img/ui-20261012/splash-slogan.png'), closeIconUrl: api.assetUrl('img/ui-20261009/icon-close.png'), // 出生年月(两列滚轮:年+月,默认 30 岁 1 月) birthRange: [YEARS, MONTHS], birthIndex: [YEARS.indexOf((NOW_Y - 30) + '年'), 0], birthText: '', birth: '', // 'YYYY-MM' age: 0, // real_age // 性别 genderRange: ['女', '男'], genderText: '', // 所在地区(省 + 市两列) regionRange: [ REGION_DATA.map(function (p) { return p[0]; }), REGION_DATA[0][1] ], regionIndex: [0, 0], regionText: '', // 肤质轮播 skins: SKINS.map(function (s) { return { img: api.assetUrl(s.img), name: s.name, desc: s.desc, desc2: s.desc2 || '' }; }), skinIndex: 0, skinPercent: 0, skinDragOffset: 0, skinDragging: false, skinLastIndex: SKINS.length - 1, showGuide: false, picker: '', pickerTitle: '', pickerValue: [0, 0], toastText: '', toastOn: false, identityChecking: true, identityError: '' }, onLoad: function () { if (!api.user()) { my.redirectTo({ url: '/pages/login/login' }); return; } this.ownerId = api.user().id; if (api.user().kind !== 'taobao_guest') try { var saved = my.getStorageSync({ key: 'juzi.taobao.profile.' + api.user().id }).data; if (saved) { saved.age = ageFromBirth(Number(saved.birth.split('-')[0]), Number(saved.birth.split('-')[1])); this.setData(saved); } } catch (_) {} // H5 goSkin(0) 的等价初始化:轨道位移与当前下标同步 this.setData({ skinIndex: this.data.skinIndex || 0, skinPercent: (this.data.skinIndex || 0) * 100 }); }, onShow: function () { this.disableSwipeBack(); this.visible = true; if (!api.user() || this.ownerId !== api.user().id) { this.clearPrivateProfile(); return Promise.resolve(false); } if (api.user().kind === 'taobao_guest') { this.identityPending = false; var guestPage = this; this.setData({ identityChecking: false, identityError: '' }, function () { guestPage.measureSkin(); }); return Promise.resolve(true); } var that = this, seq = this.identitySeq = (this.identitySeq || 0) + 1; this.identityPending = true; this.setData({ identityChecking: true, identityError: '' }); return (typeof api.restore === 'function' ? api.restore() : Promise.resolve(api.user())).then(function (user) { if (!that.visible || seq !== that.identitySeq) return false; if (!user || user.id !== that.ownerId) { that.clearPrivateProfile(); return false; } that.identityPending = false; that.setData({ identityChecking: false }, function () { that.measureSkin(); }); return true; }).catch(function (err) { if (!that.visible || seq !== that.identitySeq) return false; if (err.status === 401 || !api.user() || api.user().id !== that.ownerId) { that.clearPrivateProfile(); return false; } that.setData({ identityChecking: false, identityError: '网络异常,暂时无法确认当前账号,请重试。' }); return false; }); }, onRetryIdentity: function () { return this.onShow(); }, disableSwipeBack: function () { // Disable the native page-exit gesture, leaving skin carousel touches intact. try { if (my.tb && typeof my.tb.enableSwipeBack === 'function') { var pending = my.tb.enableSwipeBack({ enable: 0 }); if (pending && typeof pending.catch === 'function') pending.catch(function () {}); } } catch (_) {} }, onReady: function () { this.disableSwipeBack(); this.measureSkin(); }, measureSkin: function () { if (typeof my.createSelectorQuery !== 'function') return; var that = this; try { my.createSelectorQuery().select('.skin-carousel').boundingClientRect().exec(function (rows) { if (that.visible && rows && rows[0] && rows[0].width > 0) that.skinWidth = rows[0].width; }); } catch (_) {} }, onResize: function () { this.onSkinTouchCancel(); this.skinWidth = 0; this.measureSkin(); }, clearPrivateProfile: function () { this.identityPending = true; this.setData({ birthText: '', birth: '', age: 0, genderText: '', regionText: '', showGuide: false, picker: '', identityChecking: true, identityError: '' }); my.redirectTo({ url: '/pages/login/login' }); }, onHide: function () { this.visible = false; this.identitySeq = (this.identitySeq || 0) + 1; this.onSkinTouchCancel(); if (api.user() && api.user().kind !== 'taobao_guest') { this.identityPending = true; this.setData({ identityChecking: true, identityError: '' }); } }, onUnload: function () { this.onHide(); clearTimeout(this.toastTimer); }, // H5 .toast toast: function (msg) { var that = this; this.setData({ toastText: msg, toastOn: true }); clearTimeout(this.toastTimer); this.toastTimer = setTimeout(function () { that.setData({ toastOn: false }); }, Math.max(1800, String(msg).length * 130)); }, onOpenBirth: function () { // H5 的 mobile-select title 为「出生年月」/「所在地区」 this.setData({ picker: 'birth', pickerTitle: '出生年月', pickerValue: this.data.birthIndex.slice() }); }, onOpenGender: function () { var index = this.data.genderRange.indexOf(this.data.genderText); this.setData({ picker: 'gender', pickerTitle: '性别', pickerValue: [index < 0 ? 0 : index] }); }, onOpenRegion: function () { var index = this.data.regionIndex.slice(); // A canceled draft may have changed the cities while the saved province stayed put. this.setData({ picker: 'region', pickerTitle: '所在地区', pickerValue: index, regionRange: [REGION_DATA.map(function (p) { return p[0]; }), REGION_DATA[index[0]][1]] }); }, onPickerChange: function (e) { var value = e.detail.value; if (this.data.picker === 'region' && value[0] !== this.data.pickerValue[0]) value[1] = 0; var patch = { pickerValue: value }; if (this.data.picker === 'region') patch.regionRange = [REGION_DATA.map(function (p) { return p[0]; }), REGION_DATA[value[0]][1]]; this.setData(patch); }, onPickerConfirm: function () { var e = { detail: { value: this.data.pickerValue } }; if (this.data.picker === 'birth') this.onBirthChange(e); else if (this.data.picker === 'gender') this.onGenderChange(e); else if (this.data.picker === 'region') this.onRegionChange(e); this.onPickerClose(); }, onPickerClose: function () { this.setData({ picker: '' }); }, /* ─── 出生年月 ─── */ onBirthChange: function (e) { var idx = e.detail.value; var yv = parseInt(YEARS[idx[0]], 10); var mv = idx[1] + 1; this.setData({ birthIndex: idx, birthText: yv + '年' + mv + '月', birth: yv + '-' + (mv < 10 ? '0' : '') + mv, age: ageFromBirth(yv, mv) }); }, /* ─── 性别 ─── */ onGenderChange: function (e) { var value = e.detail.value, index = Array.isArray(value) ? value[0] : value; if (index === 0 || index === 1) this.setData({ genderText: this.data.genderRange[index] }); }, /* ─── 地区:省份列滚动时联动城市列 ─── */ onRegionColumnChange: function (e) { if (e.detail.column !== 0) return; var cities = REGION_DATA[e.detail.value][1]; this.setData({ 'regionRange[1]': cities, regionIndex: [e.detail.value, 0] }); }, onRegionChange: function (e) { var idx = e.detail.value; var prov = REGION_DATA[idx[0]][0]; var city = REGION_DATA[idx[0]][1][idx[1]]; // 直辖市/港澳台只显示一级(与 H5 一致) var text = !city || city === prov ? prov : prov + ' ' + city; this.setData({ regionIndex: idx, regionText: text }); }, /* ─── 肤质轮播(H5 goSkin 的等价实现:轨道 translateX) ─── */ applySkin: function (index) { var i = Math.max(0, Math.min(SKINS.length - 1, index)); this.skinGesture = null; this.setData({ skinIndex: i, skinPercent: i * 100, skinDragOffset: 0, skinDragging: false }); }, onSkinPrev: function () { this.applySkin(this.data.skinIndex - 1); }, onSkinNext: function () { this.applySkin(this.data.skinIndex + 1); }, onSkinTouchStart: function (e) { if (this.identityPending) return; var info = typeof my.getSystemInfoSync === 'function' ? my.getSystemInfoSync() : {}; this.skinGesture = swipe.start(e, this.data.skinIndex, this.skinWidth || (info.windowWidth || 375) * 191 / 375, SKINS.length); }, onSkinTouchMove: function (e) { var value = swipe.move(this.skinGesture, e); if (!value) { this.onSkinTouchCancel(); return; } if (value.dragging) this.setData({ skinDragOffset: value.offset, skinDragging: true }); }, onSkinTouchEnd: function (e) { var value = swipe.end(this.skinGesture, e, false); if (value) this.applySkin(value.index); }, onSkinTouchCancel: function () { this.skinGesture = null; if (this.data.skinDragging || this.data.skinDragOffset) this.setData({ skinDragOffset: 0, skinDragging: false }); }, /* ─── 提交 → 拍照引导弹窗(H5 data-action="submit-profile") ─── */ onSubmit: function () { if (this.identityPending) return; var d = this.data; if (!d.birth || !(d.age >= 1 && d.age <= 99)) { this.toast('请选择出生年月'); return; } if (!d.genderText) { this.toast('请选择性别'); return; } if (!d.regionText) { this.toast('请选择所在地区'); return; } this.setData({ showGuide: true }); }, onCloseGuide: function () { this.setData({ showGuide: false }); }, // H5 data-action="start-camera":档案入全局态,进入拍照页 onStartCamera: function () { if (this.identityPending) return; if (!api.user()) { my.redirectTo({ url: '/pages/login/login' }); return; } var d = this.data; getApp().globalData.profile = { real_age: d.age, gender: d.genderText, region: d.regionText, daily_skin_type: SKINS[d.skinIndex].name }; if (api.user().kind !== 'taobao_guest') my.setStorageSync({ key: 'juzi.taobao.profile.' + api.user().id, data: { birth: d.birth, birthIndex: d.birthIndex, birthText: d.birthText, genderText: d.genderText, regionIndex: d.regionIndex, regionText: d.regionText, regionRange: d.regionRange, skinIndex: d.skinIndex } }); this.setData({ showGuide: false }); my.navigateTo({ url: '/pages/camera/camera' }); }, noop: function () {} }, typeof my === 'undefined' ? {} : my));