同步小程序与管理端更新,完善抽烟记录和解绑冷静期
This commit is contained in:
+154
-38
@@ -1,12 +1,25 @@
|
||||
const { withDataCache } = require('../../utils/page-cache');
|
||||
const { getLayout } = require('../../utils/layout');
|
||||
// pages/profile/profile.js - 与原网站一致的个人中心
|
||||
const { api, getImageUrl } = require('../../utils/request');
|
||||
const { saveScrollPosition, getScrollPosition } = require('../../utils/scroll-pos');
|
||||
const { saveScrollPosition, resetScrollOnTabShow } = require('../../utils/scroll-pos');
|
||||
const { requestSubscribe } = require('../../utils/subscribe');
|
||||
|
||||
Page({
|
||||
Page(withDataCache({
|
||||
onResize: function() { this.setData(getLayout()); },
|
||||
data: {
|
||||
scrollTop: 0,
|
||||
statsLoading:false, statsError:false,
|
||||
statisticItems:[
|
||||
{key:'timeline',label:'记忆日',icon:'stat-timeline',count:'—',color:'pink'},
|
||||
{key:'album',label:'相册',icon:'stat-album',count:'—',color:'yellow'},
|
||||
{key:'diary',label:'日记',icon:'stat-book',count:'—',color:'mint'},
|
||||
{key:'songs',label:'歌曲',icon:'stat-music',count:'—',color:'blue'},
|
||||
{key:'checkin',label:'打卡',icon:'stat-check',count:'—',color:'purple'},
|
||||
{key:'pet',label:'宠物',icon:'stat-pet',count:'—',color:'pink'},
|
||||
{key:'period',label:'姨姨',icon:'stat-j-flower',count:'',color:'pink'},
|
||||
{key:'settings',label:'更多',icon:'stat-settings',count:'',color:'gray'}
|
||||
],
|
||||
|
||||
// 我的信息
|
||||
myNickname: '未登录',
|
||||
@@ -26,6 +39,7 @@ Page({
|
||||
bindingKnown: false, bindingError: false,
|
||||
partnerName: 'TA',
|
||||
partnerDisplayId: '',
|
||||
partnerId: 0,
|
||||
partnerDetail: '',
|
||||
partnerAvatarUrl: '',
|
||||
partnerInitial: '?',
|
||||
@@ -54,8 +68,9 @@ Page({
|
||||
tempLoveDate: '',
|
||||
tempLoveStory: '',
|
||||
|
||||
// 查看TA资料(只读)弹窗
|
||||
// 编辑TA资料弹窗
|
||||
showEditPartnerModal: false,
|
||||
partnerSaving: false, partnerAvatarUploading: false,
|
||||
editPartnerNickname: '',
|
||||
editPartnerGender: 'male',
|
||||
editPartnerGenderText: '男',
|
||||
@@ -127,6 +142,7 @@ Page({
|
||||
_needRefresh: true,
|
||||
|
||||
onScroll: function(e) {
|
||||
this._scrollTop = e.detail.scrollTop;
|
||||
saveScrollPosition('profile', e.detail.scrollTop);
|
||||
},
|
||||
|
||||
@@ -137,7 +153,7 @@ Page({
|
||||
this.setData({
|
||||
userId: wx.getStorageSync('userId'),
|
||||
coupleId: wx.getStorageSync('coupleId'),
|
||||
scrollTop: getScrollPosition('profile')
|
||||
scrollTop: 0
|
||||
});
|
||||
this.loadData();
|
||||
this.loadUnbindStatus();
|
||||
@@ -153,23 +169,28 @@ Page({
|
||||
// 从分享邀请链接进入
|
||||
if (options && options.inviter) {
|
||||
var self = this;
|
||||
setTimeout(function() { self.handleShareInvite(options.inviter); }, 800);
|
||||
setTimeout(function() { self.handleShareInvite(options.inviter, options.invite_code); }, 800);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
onShow: function() {
|
||||
resetScrollOnTabShow(this, 'profile');
|
||||
if (!wx.getStorageSync('coupleId') && !this.data.shareOutgoingCode) api.generateInviteLink().then(res => this.setData({shareOutgoingCode:res.code || ''})).catch(() => {});
|
||||
const tabBar = this.getTabBar && this.getTabBar();
|
||||
if (tabBar) tabBar.syncActive();
|
||||
var uid = wx.getStorageSync('userId');
|
||||
var cid = wx.getStorageSync('coupleId');
|
||||
var self = this;
|
||||
var savedTop = getScrollPosition('profile');
|
||||
this.setData({ scrollTop: savedTop, bindingKnown: false, myLocation: '' });
|
||||
// 延迟重新设置 scrollTop,解决从子页面 navigateBack 返回后滚动位置丢失的问题
|
||||
setTimeout(function() {
|
||||
self.setData({ scrollTop: savedTop });
|
||||
}, 100);
|
||||
this.setData({ userId: uid, coupleId: cid });
|
||||
const app = getApp();
|
||||
if (app.globalData.openProfileBind) {
|
||||
app.globalData.openProfileBind = false;
|
||||
this._openBindOnLoad = true;
|
||||
this._dataLoads = {};
|
||||
}
|
||||
this.loadData();
|
||||
this.loadProfileStats();
|
||||
if (!cid && this.data.showInvitePanel && !this._pollTimer) this.startPollCoupleStatus();
|
||||
// 如果已绑定情侣,关闭邀请面板
|
||||
if (cid && this.data.showInvitePanel) {
|
||||
this.setData({ showInvitePanel: false });
|
||||
@@ -180,6 +201,10 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
onHide: function() {
|
||||
if (this._pollTimer) { clearInterval(this._pollTimer); this._pollTimer = null; }
|
||||
},
|
||||
|
||||
onUnload: function() {
|
||||
if (this._pollTimer) {
|
||||
clearInterval(this._pollTimer);
|
||||
@@ -188,7 +213,7 @@ Page({
|
||||
},
|
||||
|
||||
onPullDownRefresh: async function() {
|
||||
await this.loadData();
|
||||
await Promise.all([this.loadData(),this.loadProfileStats()]);
|
||||
wx.stopPullDownRefresh();
|
||||
},
|
||||
|
||||
@@ -229,6 +254,7 @@ Page({
|
||||
hasPartner: false,
|
||||
partnerName: 'TA',
|
||||
partnerDisplayId: '',
|
||||
partnerId: 0,
|
||||
partnerDetail: '',
|
||||
partnerAvatarUrl: '',
|
||||
partnerInitial: '?',
|
||||
@@ -322,6 +348,7 @@ Page({
|
||||
hasPartner: true,
|
||||
partnerName: partner.nickname || partner.username || 'TA',
|
||||
partnerDisplayId: partner.user_id || '',
|
||||
partnerId: Number(partner.id),
|
||||
partnerDetail: details.join(' · ') || 'TA的信息',
|
||||
partnerAvatarUrl: getImageUrl(partner.avatar),
|
||||
partnerInitial: (partner.nickname || partner.username || '?')[0],
|
||||
@@ -405,6 +432,11 @@ Page({
|
||||
}).catch(function() {});
|
||||
},
|
||||
|
||||
_syncProfileTabBar: function() {
|
||||
const tabBar = this.getTabBar && this.getTabBar();
|
||||
if (tabBar && tabBar.setHidden) tabBar.setHidden(this.data.showEditProfileModal || this.data.showEditPartnerModal);
|
||||
},
|
||||
|
||||
// 编辑资料
|
||||
showEditProfileModal: function() {
|
||||
var d = this.data;
|
||||
@@ -421,6 +453,7 @@ Page({
|
||||
editAvatarUrl: d.myAvatarUrl || '',
|
||||
editNicknameInitial: d.myInitial || '?'
|
||||
});
|
||||
this._syncProfileTabBar();
|
||||
},
|
||||
onEditGenderChange: function(e) {
|
||||
var idx = e.detail.value;
|
||||
@@ -430,6 +463,7 @@ Page({
|
||||
},
|
||||
hideEditProfileModal: function() {
|
||||
this.setData({ showEditProfileModal: false });
|
||||
this._syncProfileTabBar();
|
||||
},
|
||||
onEditNicknameInput: function(e) {
|
||||
this.setData({ editNickname: e.detail.value });
|
||||
@@ -559,9 +593,11 @@ Page({
|
||||
this.setData({ showPartnerDetailModal: false });
|
||||
},
|
||||
|
||||
// 查看TA资料(只读)
|
||||
// 编辑TA资料
|
||||
showEditPartnerModal: function() {
|
||||
const d = this.data;
|
||||
this._editPartnerId = d.partnerId;
|
||||
this._partnerOriginalStory = d.tempLoveStory;
|
||||
var rawGender = d.partnerGenderRaw || '';
|
||||
var genderText = rawGender === 'male' ? '男' : (rawGender === 'female' ? '女' : '未设置');
|
||||
// 从 partnerDetail 中解析年龄(格式:XX岁)
|
||||
@@ -570,7 +606,7 @@ Page({
|
||||
this.setData({
|
||||
showEditPartnerModal: true,
|
||||
editPartnerNickname: d.partnerName === 'TA' ? '' : d.partnerName,
|
||||
editPartnerGender: rawGender || 'male',
|
||||
editPartnerGender: rawGender || '',
|
||||
editPartnerGenderText: genderText,
|
||||
editPartnerAge: partnerAge,
|
||||
editPartnerBirthday: d.partnerBirthday || '',
|
||||
@@ -578,10 +614,65 @@ Page({
|
||||
editPartnerAvatarPath: '',
|
||||
editPartnerNameInitial: d.partnerInitial || '?'
|
||||
});
|
||||
this._syncProfileTabBar();
|
||||
},
|
||||
hideEditPartnerModal: function() {
|
||||
if (this.data.partnerSaving || this.data.partnerAvatarUploading) return;
|
||||
this.setData({ showEditPartnerModal: false });
|
||||
this._syncProfileTabBar();
|
||||
},
|
||||
onEditPartnerNicknameInput: function(e) {
|
||||
if (!this.data.partnerSaving) this.setData({editPartnerNickname:e.detail.value});
|
||||
},
|
||||
onEditPartnerGenderChange: function(e) {
|
||||
if (this.data.partnerSaving) return;
|
||||
const index = Number(e.detail.value);
|
||||
this.setData({editPartnerGender:['male','female'][index],editPartnerGenderText:['男','女'][index]});
|
||||
},
|
||||
onEditPartnerBirthdayInput: function(e) {
|
||||
if (this.data.partnerSaving) return;
|
||||
const birthday = e.detail.value;
|
||||
const birth = new Date(birthday), today = new Date();
|
||||
let age = today.getFullYear() - birth.getFullYear();
|
||||
if (today.getMonth() < birth.getMonth() || (today.getMonth() === birth.getMonth() && today.getDate() < birth.getDate())) age--;
|
||||
this.setData({editPartnerBirthday:birthday,editPartnerAge:String(Math.max(0,age))});
|
||||
},
|
||||
choosePartnerAvatar: function() {
|
||||
if (this.data.partnerSaving || this.data.partnerAvatarUploading || !this._editPartnerId) return;
|
||||
const partnerId = this._editPartnerId;
|
||||
wx.chooseImage({count:1,sizeType:['compressed'],sourceType:['album','camera'],success:async res=>{
|
||||
if (!this.data.showEditPartnerModal || partnerId !== this._editPartnerId) return;
|
||||
this.setData({partnerAvatarUploading:true});
|
||||
try {
|
||||
const uploaded = await api.uploadPartnerAvatar(res.tempFilePaths[0],partnerId);
|
||||
this.setData({editPartnerAvatarUrl:getImageUrl(uploaded.path),editPartnerAvatarPath:uploaded.path});
|
||||
} catch(error) { wx.showToast({title:error.error || '头像上传失败',icon:'none'}); }
|
||||
finally { this.setData({partnerAvatarUploading:false}); }
|
||||
}});
|
||||
},
|
||||
savePartnerProfile: async function() {
|
||||
const d = this.data;
|
||||
if (d.partnerSaving || d.partnerAvatarUploading) return;
|
||||
if (!d.hasPartner || !this._editPartnerId || this._editPartnerId !== d.partnerId) {
|
||||
wx.showToast({title:'绑定信息已变化,请重新打开资料',icon:'none'});return;
|
||||
}
|
||||
const nickname = d.editPartnerNickname.trim();
|
||||
if (!nickname) { wx.showToast({title:'请输入TA的昵称',icon:'none'});return; }
|
||||
this.setData({partnerSaving:true});
|
||||
try {
|
||||
const result = await api.updatePartnerProfile({partner_id:this._editPartnerId,nickname,gender:d.editPartnerGender,age:parseInt(d.editPartnerAge) || 0,birthday:d.editPartnerBirthday,avatar:d.editPartnerAvatarPath || undefined});
|
||||
if (!result || !result.success) throw result || {};
|
||||
if (d.coupleId && (d.tempLoveDate !== d.loveStartDate || d.tempLoveStory !== this._partnerOriginalStory)) {
|
||||
await api.updateCoupleInfo({love_start_date:d.tempLoveDate,love_story:d.tempLoveStory || ''});
|
||||
}
|
||||
this.setData({partnerSaving:false});
|
||||
this.hideEditPartnerModal();
|
||||
await this.loadData();
|
||||
wx.showToast({title:'TA的资料已保存',icon:'success'});
|
||||
} catch(error) { wx.showToast({title:error.error || '保存失败,请重试',icon:'none'}); }
|
||||
finally { this.setData({partnerSaving:false}); }
|
||||
},
|
||||
|
||||
// 加载解绑状态
|
||||
loadUnbindStatus: function() {
|
||||
var self = this;
|
||||
@@ -610,8 +701,8 @@ Page({
|
||||
} else {
|
||||
this.doRespondUnbind();
|
||||
}
|
||||
} else if (status === 'agreed') {
|
||||
wx.showToast({ title: '双方已同意解绑,正在处理中', icon: 'none' });
|
||||
} else if (status === 'cooling') {
|
||||
wx.showToast({ title: '正在72小时冷静期', icon: 'none' });
|
||||
wx.navigateTo({ url: '/pages/unbind/unbind' });
|
||||
} else {
|
||||
this.doRequestUnbind();
|
||||
@@ -622,7 +713,7 @@ Page({
|
||||
var self = this;
|
||||
wx.showModal({
|
||||
title: '💔 解除绑定',
|
||||
content: '发起解绑请求后,对方需要在72小时内确认同意。\n\n对方同意后,所有情侣记录将被永久删除(记忆日、日记、相册、纪念日、情话、歌曲、打卡),仅保留双方个人资料。\n\n你也可以在对方确认前撤销请求。',
|
||||
content: '对方同意后进入72小时冷静期,期间任一方可取消。到期自动解绑并永久删除共同数据;个人抽烟记录保留。',
|
||||
cancelText: '取消',
|
||||
confirmText: '发起解绑',
|
||||
confirmColor: '#FF4757',
|
||||
@@ -647,7 +738,7 @@ Page({
|
||||
var self = this;
|
||||
wx.showModal({
|
||||
title: '↩️ 撤销解绑',
|
||||
content: '确定要撤销解绑请求吗?对方将不会收到任何通知。',
|
||||
content: '取消后关系继续保留。确定取消解绑吗?',
|
||||
cancelText: '取消',
|
||||
confirmText: '撤销请求',
|
||||
confirmColor: '#FF6B9D',
|
||||
@@ -676,7 +767,7 @@ Page({
|
||||
if (res.tapIndex === 0) {
|
||||
wx.showModal({
|
||||
title: '⚠️ 确认同意',
|
||||
content: name + ' 发起了解绑请求。\n\n同意后,所有情侣记录将被永久删除(记忆日、日记、相册、歌曲、打卡),仅保留双方个人资料。\n\n此操作不可恢复!',
|
||||
content: name + ' 发起了解绑请求。同意后进入72小时冷静期,期间可取消;到期自动解绑并永久删除共同数据,个人抽烟记录保留。',
|
||||
cancelText: '取消',
|
||||
confirmText: '同意解绑',
|
||||
confirmColor: '#FF4757',
|
||||
@@ -685,15 +776,8 @@ Page({
|
||||
wx.showLoading({ title: '处理中...' });
|
||||
api.unbindRespond({ agree: true }).then(function() {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: '已同意解绑', icon: 'success' });
|
||||
wx.removeStorageSync('coupleId');
|
||||
wx.removeStorageSync('partnerId');
|
||||
wx.removeStorageSync('partnerName');
|
||||
wx.removeStorageSync('partnerAvatar');
|
||||
wx.removeStorageSync('petHasPet');
|
||||
setTimeout(function() {
|
||||
wx.reLaunch({ url: '/pages/index/index' });
|
||||
}, 1500);
|
||||
wx.showToast({ title: '已进入72小时冷静期', icon: 'none' });
|
||||
self.loadUnbindStatus();
|
||||
}).catch(function(err) {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: err.error || '操作失败', icon: 'none' });
|
||||
@@ -747,7 +831,7 @@ Page({
|
||||
|
||||
// 跳转前保存当前滚动位置
|
||||
_savePosBeforeLeave: function() {
|
||||
saveScrollPosition('profile', this.data.scrollTop);
|
||||
saveScrollPosition('profile', this._scrollTop == null ? this.data.scrollTop : this._scrollTop);
|
||||
},
|
||||
|
||||
// ===== 邀请绑定 =====
|
||||
@@ -796,9 +880,12 @@ Page({
|
||||
},
|
||||
|
||||
sendInvite: async function() {
|
||||
const { inviteTargetId, inviteMessage } = this.data;
|
||||
const inviteTargetId = String(this.data.inviteTargetId || '').trim();
|
||||
const { inviteMessage } = this.data;
|
||||
if (!inviteTargetId) { wx.showToast({ title: '请输入对方ID', icon: 'none' }); return; }
|
||||
if (inviteTargetId.length < 6) { wx.showToast({ title: 'ID为6位数字', icon: 'none' }); return; }
|
||||
if (!/^[0-9]{6}$/.test(inviteTargetId)) { wx.showToast({ title: 'ID为6位数字', icon: 'none' }); return; }
|
||||
// 邀请成功且对方接受时,需要通知邀请人,提前申请一次性订阅授权
|
||||
setTimeout(function() { requestSubscribe('notify').catch(function() {}); }, 1500);
|
||||
try {
|
||||
wx.showLoading({ title: '发送中...' });
|
||||
const res = await api.invitePartner({ target_user_id: inviteTargetId, message: inviteMessage });
|
||||
@@ -880,6 +967,7 @@ Page({
|
||||
|
||||
// ===== 分享绑定 =====
|
||||
onShareAppMessage: function() {
|
||||
if (!this.data.shareOutgoingCode) return {title:'邀请你绑定情侣', path:'/pages/profile/profile'};
|
||||
var displayId = wx.getStorageSync('displayId') || this.data.myDisplayId;
|
||||
var nick = wx.getStorageSync('nickname') || '我';
|
||||
if (!displayId) {
|
||||
@@ -888,22 +976,22 @@ Page({
|
||||
}
|
||||
return {
|
||||
title: nick + ' 邀请你绑定情侣 💕',
|
||||
path: '/pages/profile/profile?inviter=' + displayId,
|
||||
path: '/pages/profile/profile?inviter=' + displayId + '&invite_code=' + encodeURIComponent(this.data.shareOutgoingCode || ''),
|
||||
imageUrl: '/images/share.png'
|
||||
};
|
||||
},
|
||||
|
||||
// 从分享链接进入时处理邀请绑定
|
||||
handleShareInvite: function(inviterId) {
|
||||
handleShareInvite: function(inviterId, code) {
|
||||
if (!inviterId) return;
|
||||
this.setData({ shareInviterId: inviterId, showShareBindModal: true, shareDisagree: false });
|
||||
this.setData({ shareInviterId: inviterId, shareInviteCode: code || '', showShareBindModal: true, shareDisagree: false });
|
||||
},
|
||||
|
||||
acceptShareBind: async function() {
|
||||
var self = this;
|
||||
try {
|
||||
wx.showLoading({ title: '处理中...' });
|
||||
const res = await api.acceptShareInvite({ inviter_id: this.data.shareInviterId });
|
||||
const res = await api.acceptShareInvite({ inviter_id: this.data.shareInviterId, invite_code: this.data.shareInviteCode });
|
||||
wx.hideLoading();
|
||||
if (res.couple_id) {
|
||||
wx.setStorageSync('coupleId', res.couple_id);
|
||||
@@ -925,8 +1013,36 @@ Page({
|
||||
this.setData({ showShareBindModal: false });
|
||||
},
|
||||
|
||||
loadProfileStats: async function() {
|
||||
this.setData({statsLoading:true,statsError:false});
|
||||
const keys=['timeline','album','diary','songs','checkin','pet'];
|
||||
const results=await Promise.allSettled([
|
||||
api.timelineList(),api.albumList(),api.diaryList(),api.songsList(),api.checkinList(),
|
||||
(this.data.coupleId || wx.getStorageSync('coupleId')) ? api.petInfo() : Promise.resolve({has_pet:false})
|
||||
]);
|
||||
const counts={};let failed=false;
|
||||
results.forEach((result,index)=>{
|
||||
const key=keys[index];
|
||||
if(result.status !== 'fulfilled') { counts[key]='—';failed=true;return; }
|
||||
const value=result.value;
|
||||
if(key==='album') counts[key]=(Array.isArray(value)?value:[]).reduce((sum,album)=>sum+(Number(album.photo_count)||0),0);
|
||||
else if(key==='diary') counts[key]=Number(value && value.total)||0;
|
||||
else if(key==='checkin') counts[key]=value && value.checkin_log_total !== undefined ? Number(value.checkin_log_total)||0 : (Array.isArray(value)?value.length:(value && value.items || []).length);
|
||||
else if(key==='pet') counts[key]=value && value.has_pet && value.pet ? 'Lv.'+(Number(value.pet.level)||0) : '未领养';
|
||||
else counts[key]=Array.isArray(value)?value.length:0;
|
||||
});
|
||||
this.setData({statisticItems:this.data.statisticItems.map(item=>({...item,count:counts[item.key]===undefined?item.count:counts[item.key]})),statsLoading:false,statsError:failed});
|
||||
},
|
||||
openStatistic: function(e) {
|
||||
const routes={timeline:'timeline',album:'albums',diary:'diary',songs:'lovewords',checkin:'punch',pet:'pet',period:'period',settings:'settings'};
|
||||
const route=routes[e.currentTarget.dataset.key];
|
||||
if(!route)return;
|
||||
this._savePosBeforeLeave();
|
||||
wx.navigateTo({url:'/pages/'+route+'/'+route});
|
||||
},
|
||||
|
||||
// 页面跳转
|
||||
manageRelationship: function() { wx.navigateTo({ url: '/pages/unbind/unbind' }); },
|
||||
goToSettings: function() { this._savePosBeforeLeave(); wx.navigateTo({ url: '/pages/settings/settings' }); },
|
||||
goHome: function() { this._savePosBeforeLeave(); wx.redirectTo({ url: '/pages/index/index' }); }
|
||||
});
|
||||
goHome: function() { this._savePosBeforeLeave(); wx.switchTab({ url: '/pages/index/index' }); }
|
||||
}, {"loadData": ["coupleInfo"], "loadProfileStats": ["timelineList","albumList","diaryList","songsList","checkinList","petInfo"]}));
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"usingComponents": {
|
||||
"app-tabbar": "/components/app-tabbar/app-tabbar",
|
||||
"page-state": "/components/page-state/page-state"
|
||||
},
|
||||
"navigationStyle": "custom",
|
||||
|
||||
@@ -1,47 +1,56 @@
|
||||
<view class="app-shell" style="{{layoutStyle}}">
|
||||
<view class="app-shell j-handwritten-page" style="{{layoutStyle}}">
|
||||
<launch-transition />
|
||||
<!-- pages/profile/profile.wxml -->
|
||||
<view wx:if="{{!showEditProfileModal && !showEditPartnerModal}}" class="j-fixed-header"><view class="j-fixed-heading" style="height:{{barHeight}}px;padding-right:{{navSide}}px;"><text class="j-eyebrow">MY CORNER</text><text class="j-page-title">我的小角落</text></view></view>
|
||||
<view wx:if="{{!showEditProfileModal && !showEditPartnerModal}}" class="page-root" bindtouchstart="onTouchStart" bindtouchend="onTouchEnd">
|
||||
<scroll-view class="page-bg j-main-scroll" scroll-y show-scrollbar="{{false}}" bounces="{{true}}" bindscroll="onScroll" scroll-top="{{scrollTop}}">
|
||||
<view class="j-body">
|
||||
<view class="j-profile-summary" bindtap="showEditProfileModal"><view class="j-profile-info"><text class="j-profile-name">{{myNickname}}</text><text class="j-caption">ID {{myDisplayId}}</text><text class="j-caption">{{myGender}} {{myAge}} {{myBirthday}}</text><text class="j-link">编辑资料 →</text></view><view class="j-avatar"><image wx:if="{{myAvatarUrl}}" src="{{myAvatarUrl}}" mode="aspectFill" /><text wx:else>{{myInitial}}</text></view></view>
|
||||
<view class="j-profile-summary" bindtap="showEditProfileModal"><view class="j-profile-info"><text class="j-profile-name">{{myNickname}}</text><text class="j-caption">ID {{myDisplayId}}</text><text class="j-caption">{{myGender}} {{myAge}} {{myBirthday}}</text></view><view class="j-avatar"><image wx:if="{{myAvatarUrl}}" src="{{myAvatarUrl}}" mode="aspectFill" /><text wx:else>{{myInitial}}</text></view></view>
|
||||
<view class="j-section-head"><text>我们的关系</text></view>
|
||||
<view wx:if="{{bindingKnown && hasPartner}}" class="j-relation-card"><view class="j-row" bindtap="showEditPartnerModal"><view><text class="j-small-title">{{partnerName}}</text><text class="j-caption" wx:if="{{partnerDisplayId}}">ID {{partnerDisplayId}}</text><text class="j-caption">{{partnerDetail}}</text><text class="j-link">查看TA的资料 →</text></view><view class="j-avatar"><image wx:if="{{partnerAvatarUrl}}" src="{{partnerAvatarUrl}}" mode="aspectFill" /><text wx:else>{{partnerInitial}}</text></view></view><view class="j-profile-setting" bindtap="manageRelationship"><image src="/images/heart.svg" /><view><text class="j-small-title">关系管理</text><text class="j-caption">绑定信息与解绑</text></view><text class="j-link">›</text></view></view>
|
||||
<view wx:if="{{bindingKnown && hasPartner}}" class="j-relation-card" bindtap="showEditPartnerModal"><view class="j-row"><view><text class="j-small-title">{{partnerName}}</text><text class="j-caption" wx:if="{{partnerDisplayId}}">ID {{partnerDisplayId}}</text><text class="j-caption">{{partnerDetail}}</text></view><view class="j-avatar"><image wx:if="{{partnerAvatarUrl}}" src="{{partnerAvatarUrl}}" mode="aspectFill" /><text wx:else>{{partnerInitial}}</text></view></view></view>
|
||||
<view wx:elif="{{bindingKnown}}" class="j-invite" bindtap="showInvitePanel"><view><text class="j-small-title">另一半还没有加入</text><text class="j-caption">邀请TA,共写这本生活手账</text></view><text class="j-outline-label">绑定情侣</text></view>
|
||||
<page-state wx:elif="{{bindingError}}" kind="error" title="绑定状态加载失败" action="重新加载" bind:action="loadData" /><page-state wx:else kind="loading" title="正在获取绑定状态" />
|
||||
<view class="j-profile-setting" bindtap="goToSettings"><image src="/images/settings.svg" /><view><text class="j-small-title">外观与通知</text><text class="j-caption">背景、通知与账号设置</text></view><text class="j-link">›</text></view>
|
||||
<view class="profile-statistics">
|
||||
<view class="profile-stat-grid">
|
||||
<view class="profile-stat-item" wx:for="{{statisticItems}}" wx:key="key" data-key="{{item.key}}" bindtap="openStatistic" hover-class="profile-stat-pressed">
|
||||
<view class="profile-stat-icon {{item.color}}"><image src="/images/{{item.icon}}.svg" mode="aspectFit" /></view>
|
||||
<view class="profile-stat-label"><text>{{item.label}}</text><text wx:if="{{item.count !== ''}}" class="profile-stat-count">{{item.count}}</text></view>
|
||||
</view>
|
||||
</view>
|
||||
<view wx:if="{{statsError}}" class="profile-stats-retry" bindtap="loadProfileStats">部分统计未加载,点击重试</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<app-tabbar />
|
||||
|
||||
|
||||
<view wx:if="{{showEditProfileModal}}" class="edit-root" bindtouchstart="onTouchStart" bindtouchend="onTouchEnd">
|
||||
<view class="edit-nav"><view class="back-btn" bindtap="hideEditProfileModal"><image class="back-icon" src="/images/back.svg" mode="aspectFit" /></view></view>
|
||||
<view class="edit-body" bindtouchstart="onTouchStart" bindtouchend="onTouchEnd">
|
||||
<scroll-view class="edit-body" scroll-y show-scrollbar="{{false}}" bindtouchstart="onTouchStart" bindtouchend="onTouchEnd">
|
||||
<view class="edit-avatar-wrap" bindtap="chooseAvatar"><image wx:if="{{editAvatarUrl}}" src="{{editAvatarUrl}}" mode="aspectFill" class="edit-avatar-img"></image><text wx:else class="edit-avatar-placeholder">{{editNicknameInitial || '?'}}</text><text class="edit-avatar-hint">点击更换头像</text></view>
|
||||
<text class="edit-id">我的ID: {{myDisplayId}}</text>
|
||||
<view class="input-group"><label>昵称</label><input class="input" placeholder="你的昵称" value="{{editNickname}}" bindinput="onEditNicknameInput" /></view>
|
||||
<view class="input-group"><label>昵称</label><input placeholder-class="handwritten-placeholder" class="input" placeholder="你的昵称" value="{{editNickname}}" bindinput="onEditNicknameInput" /></view>
|
||||
<view class="input-group"><label>性别</label><picker mode="selector" range="{{genderOptions}}" bindchange="onEditGenderChange"><view class="input">{{editGenderText || '请选择'}}</view></picker></view>
|
||||
<view class="input-group"><label>生日</label><picker mode="date" value="{{editBirthday}}" bindchange="onEditBirthdayInput"><view class="input">{{editBirthday || '请选择日期'}}</view></picker><text style="font-size:24rpx;color:#B74768;margin-top:8rpx;display:block;" wx:if="{{editAge}}">自动计算:{{editAge}}岁</text></view>
|
||||
<view class="input-group" wx:if="{{hasPartner}}"><label>恋爱纪念日</label><picker mode="date" value="{{tempLoveDate}}" bindchange="onLoveDateInput"><view class="input">{{tempLoveDate || '设置你们在一起的日期'}}</view></picker></view>
|
||||
<view class="input-group" wx:if="{{hasPartner}}"><label>恋爱故事</label><textarea class="input" style="min-height:120rpx;" placeholder="记录你们的故事..." value="{{tempLoveStory}}" bindinput="onLoveStoryInput"></textarea></view>
|
||||
</view>
|
||||
<view class="input-group" wx:if="{{hasPartner}}"><label>恋爱故事</label><textarea placeholder-class="handwritten-placeholder" class="input" style="min-height:120rpx;" placeholder="记录你们的故事..." value="{{tempLoveStory}}" bindinput="onLoveStoryInput"></textarea></view>
|
||||
</scroll-view>
|
||||
<view class="edit-footer"><button class="btn btn-primary" bindtap="saveProfile" hover-class="none">保存</button></view>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{showEditPartnerModal}}" class="edit-root partner-view" bindtouchstart="onTouchStart" bindtouchend="onTouchEnd">
|
||||
<view class="edit-nav"><view class="back-btn" bindtap="hideEditPartnerModal"><image class="back-icon" src="/images/back.svg" mode="aspectFit" /></view><text class="partner-nav-title">TA的资料</text></view>
|
||||
<view class="edit-body" bindtouchstart="onTouchStart" bindtouchend="onTouchEnd">
|
||||
<view class="edit-avatar-wrap"><image wx:if="{{editPartnerAvatarUrl}}" src="{{editPartnerAvatarUrl}}" mode="aspectFill" class="edit-avatar-img"></image><text wx:else class="edit-avatar-placeholder">{{editPartnerNameInitial || '?'}}</text></view>
|
||||
<view wx:if="{{showEditPartnerModal}}" class="edit-root partner-edit" bindtouchstart="onTouchStart" bindtouchend="onTouchEnd">
|
||||
<view class="edit-nav"><view class="back-btn" bindtap="hideEditPartnerModal"><image class="back-icon" src="/images/back.svg" mode="aspectFit" /></view><text class="partner-nav-title">编辑TA的资料</text></view>
|
||||
<scroll-view class="edit-body" scroll-y show-scrollbar="{{false}}">
|
||||
<view class="edit-avatar-wrap" bindtap="choosePartnerAvatar"><image wx:if="{{editPartnerAvatarUrl}}" src="{{editPartnerAvatarUrl}}" mode="aspectFill" class="edit-avatar-img" /><text wx:else class="edit-avatar-placeholder">{{editPartnerNameInitial || '?'}}</text><text class="edit-avatar-hint">{{partnerAvatarUploading ? '正在上传头像…' : '点击更换头像'}}</text></view>
|
||||
<text class="edit-id" wx:if="{{partnerDisplayId}}">TA的ID: {{partnerDisplayId}}</text>
|
||||
<view class="input-group readonly"><label>昵称</label><view class="input readonly-text">{{editPartnerNickname || '未设置'}}</view></view>
|
||||
<view class="input-group readonly"><label>性别</label><view class="input readonly-text">{{editPartnerGenderText || '-'}}</view></view>
|
||||
<view class="input-group readonly"><label>生日</label><view class="input readonly-text">{{editPartnerBirthday || '-'}}</view></view>
|
||||
<view class="input-group readonly"><label>恋爱纪念日</label><view class="input readonly-text">{{tempLoveDate || '未设置'}}</view></view>
|
||||
<view class="input-group readonly"><label>恋爱故事</label><view class="input readonly-text" style="min-height:60rpx;">{{tempLoveStory || '未设置'}}</view></view>
|
||||
</view>
|
||||
<view class="input-group"><label>昵称</label><input placeholder-class="handwritten-placeholder" class="input" value="{{editPartnerNickname}}" placeholder="TA的昵称" bindinput="onEditPartnerNicknameInput" disabled="{{partnerSaving}}" /></view>
|
||||
<view class="input-group"><label>性别</label><picker mode="selector" range="{{genderOptions}}" bindchange="onEditPartnerGenderChange" disabled="{{partnerSaving}}"><view class="input">{{editPartnerGenderText || '请选择'}}</view></picker></view>
|
||||
<view class="input-group"><label>生日</label><picker mode="date" value="{{editPartnerBirthday}}" bindchange="onEditPartnerBirthdayInput" disabled="{{partnerSaving}}"><view class="input">{{editPartnerBirthday || '请选择日期'}}</view></picker><text class="edit-avatar-hint" wx:if="{{editPartnerAge}}">自动计算:{{editPartnerAge}}岁</text></view>
|
||||
<view class="input-group"><label>恋爱纪念日</label><picker mode="date" value="{{tempLoveDate}}" bindchange="onLoveDateInput" disabled="{{partnerSaving}}"><view class="input">{{tempLoveDate || '设置你们在一起的日期'}}</view></picker></view>
|
||||
<view class="input-group"><label>恋爱故事</label><textarea placeholder-class="handwritten-placeholder" class="input" style="min-height:120rpx;" value="{{tempLoveStory}}" placeholder="记录你们的故事…" bindinput="onLoveStoryInput" disabled="{{partnerSaving}}" /></view>
|
||||
</scroll-view>
|
||||
<view class="edit-footer"><button class="btn btn-primary" bindtap="savePartnerProfile" loading="{{partnerSaving}}" disabled="{{partnerSaving || partnerAvatarUploading}}" hover-class="none">保存</button></view>
|
||||
</view>
|
||||
|
||||
<!-- ===== 邀请绑定面板 ===== -->
|
||||
@@ -62,7 +71,7 @@
|
||||
|
||||
<view class="input-group">
|
||||
<label>TA的ID</label>
|
||||
<input class="input" type="tel" placeholder="输入对方的6位ID" value="{{inviteTargetId}}" bindinput="onInviteTargetIdInput" maxlength="6" />
|
||||
<input placeholder-class="handwritten-placeholder" class="input" type="tel" placeholder="输入对方的6位ID" value="{{inviteTargetId}}" bindinput="onInviteTargetIdInput" maxlength="6" />
|
||||
</view>
|
||||
<button class="btn btn-primary" bindtap="sendInvite" hover-class="none">
|
||||
<text>💕</text> 发送邀请
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* pages/profile/profile.wxss */
|
||||
@import '../../styles/common.wxss';
|
||||
page { background: linear-gradient(180deg, #F4E2E3 0%, #FAF5EE 55%, #FAF5EE 100%); height: 100vh; overflow: hidden; }
|
||||
page { background: linear-gradient(180deg, #FDE4EC 0%, #FFF0F5 48%, #FFF7FA 100%); height: 100vh; overflow: hidden; }
|
||||
.container { padding-top: 16rpx; padding-bottom: 300rpx; }
|
||||
.page-root { height: 100vh; overflow: hidden; }
|
||||
scroll-view.page-bg { height: 100vh; overflow-y: scroll; -webkit-overflow-scrolling: touch; }
|
||||
@@ -301,8 +301,67 @@ scroll-view.page-bg { height: 100vh; overflow-y: scroll; -webkit-overflow-scroll
|
||||
|
||||
@import '../../styles/journal.wxss';
|
||||
|
||||
/* TA 的资料仅供查看,不预留编辑操作区。 */
|
||||
.partner-view .edit-body { min-height: 0; padding-bottom: calc(40rpx + env(safe-area-inset-bottom)); }
|
||||
.partner-view .edit-nav { position: relative; }
|
||||
/* TA 资料编辑页的标题与滚动区域。 */
|
||||
.partner-edit .edit-body { min-height: 0; padding-bottom: calc(40rpx + env(safe-area-inset-bottom)); }
|
||||
|
||||
.partner-nav-title { position: absolute; left: 120rpx; right: 120rpx; text-align: center; font-size: 32rpx; font-weight: 600; color: #342F2B; pointer-events: none; }
|
||||
.partner-view .readonly-text { white-space: pre-wrap; overflow-wrap: anywhere; }
|
||||
.partner-edit .readonly-text { white-space: pre-wrap; overflow-wrap: anywhere; }
|
||||
|
||||
/* 编辑内容独立滚动,底部保存区始终保留空间。 */
|
||||
.edit-root > .edit-body { flex:1; height:0; min-height:0; box-sizing:border-box; padding-bottom:24rpx; }
|
||||
.edit-root > .edit-footer { flex-shrink:0; box-sizing:border-box; }
|
||||
.edit-footer > .btn { width:100%; margin:0; }
|
||||
|
||||
/* 个人页八宫格统计入口。 */
|
||||
.profile-statistics { margin-top:32rpx; padding:28rpx 16rpx; background:#FFFDF8; border:1rpx solid #F1DCE4; border-radius:32rpx; }
|
||||
.profile-stat-grid { display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:28rpx 6rpx; }
|
||||
.profile-stat-item { min-width:0; display:flex; flex-direction:column; align-items:center; padding:8rpx 0; }
|
||||
.profile-stat-icon { width:94rpx; height:94rpx; border-radius:30rpx; display:flex; align-items:center; justify-content:center; }
|
||||
.profile-stat-icon image { width:58rpx; height:58rpx; }
|
||||
.profile-stat-icon.pink { background:#FCE5ED; }.profile-stat-icon.yellow { background:#FFF3DC; }.profile-stat-icon.mint { background:#E5F5ED; }.profile-stat-icon.blue { background:#EAF0FD; }.profile-stat-icon.purple { background:#F1EAFB; }.profile-stat-icon.gray { background:#F0EFF2; }
|
||||
.profile-stat-label { display:flex; flex-wrap:wrap; justify-content:center; align-items:baseline; gap:6rpx; margin-top:14rpx; font-family:'Kaiti SC','STKaiti','KaiTi',cursive; font-size:25rpx; line-height:1.5; color:#64424D; }
|
||||
.profile-stat-count { font-family:-apple-system,BlinkMacSystemFont,sans-serif; font-size:19rpx; color:#A39386; }
|
||||
.profile-stat-pressed { opacity:.65; }
|
||||
.profile-stats-retry { text-align:center; color:#B74768; font-size:22rpx; padding:24rpx 0 0; }
|
||||
|
||||
/* 本人与对方资料卡共用完整样式,整卡点击编辑。 */
|
||||
.j-body > .j-profile-summary,
|
||||
.j-body > .j-relation-card {
|
||||
height:216rpx;
|
||||
box-sizing:border-box;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
padding:24rpx 30rpx;
|
||||
margin:20rpx 0 24rpx;
|
||||
background:#FFFDF8;
|
||||
border:1rpx solid #E9DDD0;
|
||||
border-radius:12rpx 40rpx 12rpx 40rpx;
|
||||
box-shadow:none;
|
||||
}
|
||||
.j-relation-card > .j-row { width:100%; gap:30rpx; }
|
||||
.j-profile-summary .j-profile-name,
|
||||
.j-relation-card .j-small-title {
|
||||
display:block;
|
||||
font-family:'Kaiti SC','STKaiti','KaiTi',cursive;
|
||||
font-size:30rpx;
|
||||
font-weight:400;
|
||||
font-style:normal;
|
||||
line-height:1.6;
|
||||
color:#64424D;
|
||||
overflow:hidden;
|
||||
white-space:nowrap;
|
||||
text-overflow:ellipsis;
|
||||
}
|
||||
.j-profile-summary .j-avatar,
|
||||
.j-relation-card .j-avatar {
|
||||
width:96rpx;
|
||||
height:96rpx;
|
||||
flex-shrink:0;
|
||||
box-sizing:border-box;
|
||||
border:6rpx solid #FFFDF8;
|
||||
font-size:32rpx;
|
||||
}
|
||||
|
||||
@import '../../styles/button-theme.wxss';
|
||||
|
||||
@import '../../styles/typography.wxss';
|
||||
|
||||
Reference in New Issue
Block a user