更新最新代码
This commit is contained in:
@@ -0,0 +1,400 @@
|
||||
const { getLayout } = require('../../utils/layout');
|
||||
// pages/settings/settings.js
|
||||
const { api, getImageUrl, API_BASE, uploadFileCompat } = require('../../utils/request');
|
||||
const { requestSubscribe, getSubscribeStatus } = require('../../utils/subscribe');
|
||||
Page({
|
||||
onResize: function() { this.setData(getLayout()); },
|
||||
data: {
|
||||
showBgModal: false,
|
||||
bgPreview: '',
|
||||
bgFilePath: '',
|
||||
|
||||
|
||||
hasPartner: false,
|
||||
bindingKnown: false, bindingError:false,
|
||||
|
||||
// 解绑状态
|
||||
unbindStatus: '', // '' / 'pending' / 'agreed' / 'rejected' / 'cancelled' / 'expired'
|
||||
unbindIsRequester: false, // 当前用户是否是发起方
|
||||
unbindRequesterName: '', // 发起方昵称
|
||||
unbindRemaining: 0, // 剩余秒数
|
||||
|
||||
// 消息通知设置
|
||||
showSubscribeModal: false,
|
||||
subscribeStatus: {},
|
||||
subscribeItems: [],
|
||||
subscribeLoading: false,
|
||||
|
||||
// 打卡:抽烟打卡默认事件是否显示
|
||||
smokingVisible: true,
|
||||
|
||||
// 我们past
|
||||
showAboutModal: false,
|
||||
// 联系我们
|
||||
showContactModal: false,
|
||||
},
|
||||
|
||||
onLoad: function() {
|
||||
this.setData(getLayout());
|
||||
this.refreshSmokingVisible();},
|
||||
|
||||
onPullDownRefresh: function() {
|
||||
wx.stopPullDownRefresh();
|
||||
},
|
||||
|
||||
onShow: async function() {
|
||||
this.refreshSmokingVisible();
|
||||
this.setData({ bindingKnown: false, bindingError:false });
|
||||
try {
|
||||
var info = await api.coupleInfo();
|
||||
var hasPartner = !!(info && !info.not_bound && info.id);
|
||||
this.setData({ hasPartner: hasPartner, bindingKnown: true });
|
||||
if (hasPartner) {
|
||||
wx.setStorageSync('coupleId', info.id);
|
||||
this.loadUnbindStatus();
|
||||
} else {
|
||||
wx.removeStorageSync('coupleId');
|
||||
this.setData({ unbindStatus: '', unbindIsRequester: false, unbindRequesterName: '' });
|
||||
}
|
||||
} catch (e) {
|
||||
this.setData({bindingError:true});
|
||||
console.error('获取绑定状态失败', e);
|
||||
}
|
||||
},
|
||||
|
||||
goBind: function() {
|
||||
getApp().globalData.openProfileBind = true;
|
||||
wx.switchTab({ url: '/pages/profile/profile' });
|
||||
},
|
||||
|
||||
// 加载解绑状态
|
||||
loadUnbindStatus: function() {
|
||||
var self = this;
|
||||
api.unbindStatus().then(function(res) {
|
||||
if (res && res.status && res.status !== 'none') {
|
||||
self.setData({
|
||||
unbindStatus: res.status,
|
||||
unbindIsRequester: !!res.is_requester,
|
||||
unbindRequesterName: res.requester_name || '对方',
|
||||
unbindRemaining: res.remaining_seconds || 0
|
||||
});
|
||||
} else {
|
||||
self.setData({ unbindStatus: '', unbindIsRequester: false, unbindRequesterName: '' });
|
||||
}
|
||||
}).catch(function() {});
|
||||
},
|
||||
|
||||
noop: function() {},
|
||||
|
||||
// ===== 抽烟打卡默认事件显示开关 =====
|
||||
refreshSmokingVisible: function() {
|
||||
var v = wx.getStorageSync('smokingVisible');
|
||||
this.setData({ smokingVisible: (v === '' || v == null) ? true : !!v });
|
||||
},
|
||||
toggleSmoking: function(e) {
|
||||
var visible = !!e.detail.value;
|
||||
this.setData({ smokingVisible: visible });
|
||||
wx.setStorageSync('smokingVisible', visible);
|
||||
wx.showToast({ title: visible ? '已显示抽烟打卡' : '已隐藏抽烟打卡', icon: 'none' });
|
||||
},
|
||||
|
||||
// ===== 消息通知管理(统一使用一个模板) =====
|
||||
showSubscribeModal: async function() {
|
||||
this.setData({ showSubscribeModal: true, subscribeLoading: true });
|
||||
try {
|
||||
// forceRefresh=true 确保从后端获取最新状态
|
||||
const status = await getSubscribeStatus(true);
|
||||
this.setData({
|
||||
subscribeStatus: status,
|
||||
subscribeChecked: !!status['notify'],
|
||||
subscribeLoading: false
|
||||
});
|
||||
} catch (e) {
|
||||
this.setData({ subscribeLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
hideSubscribeModal: function() {
|
||||
this.setData({ showSubscribeModal: false });
|
||||
},
|
||||
|
||||
// ===== 我们past =====
|
||||
showAboutModal: function() {
|
||||
this.setData({ showAboutModal: true });
|
||||
},
|
||||
hideAboutModal: function() {
|
||||
this.setData({ showAboutModal: false });
|
||||
},
|
||||
|
||||
// ===== 联系我们 =====
|
||||
showContactModal: function() {
|
||||
this.setData({ showContactModal: true });
|
||||
},
|
||||
hideContactModal: function() {
|
||||
this.setData({ showContactModal: false });
|
||||
},
|
||||
|
||||
toggleSubscribe: async function(e) {
|
||||
const type = 'notify';
|
||||
const current = this.data.subscribeChecked;
|
||||
|
||||
// 防止重复点击
|
||||
if (this._subscribing) return;
|
||||
this._subscribing = true;
|
||||
|
||||
if (current) {
|
||||
// 取消订阅
|
||||
try {
|
||||
await api.unsubscribeTemplate({ template_type: type });
|
||||
this.setData({ subscribeChecked: false });
|
||||
wx.setStorageSync('subscribed_notify', false);
|
||||
wx.showToast({ title: '已关闭通知', icon: 'success' });
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '操作失败', icon: 'none' });
|
||||
}
|
||||
} else {
|
||||
// 请求订阅授权
|
||||
try {
|
||||
const results = await requestSubscribe(type);
|
||||
if (results[type]) {
|
||||
this.setData({ subscribeChecked: true });
|
||||
wx.setStorageSync('subscribed_notify', true);
|
||||
wx.showToast({ title: '已开启通知', icon: 'success' });
|
||||
} else {
|
||||
wx.showToast({ title: '订阅被拒绝,可在设置中重新开启', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '订阅失败', icon: 'none' });
|
||||
}
|
||||
}
|
||||
|
||||
this._subscribing = false;
|
||||
},
|
||||
|
||||
renewSubscribe: async function() {
|
||||
if (this._subscribing) return;
|
||||
this._subscribing = true;
|
||||
try {
|
||||
const results = await requestSubscribe('notify');
|
||||
if (results.notify) {
|
||||
this.setData({ subscribeChecked: true });
|
||||
wx.showToast({ title: '已订阅一次提醒', icon: 'success' });
|
||||
} else {
|
||||
wx.showToast({ title: '本次未授权提醒', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '订阅失败,请重试', icon: 'none' });
|
||||
} finally {
|
||||
this._subscribing = false;
|
||||
}
|
||||
},
|
||||
|
||||
// ===== 背景图 =====
|
||||
showBgModal: async function() {
|
||||
this.setData({ showBgModal: true, bgPreview: '', bgFilePath: '' });
|
||||
try {
|
||||
var cfg = await api.getBgConfig();
|
||||
if (!this.data.bgFilePath) this.setData({ bgPreview: cfg && cfg.image ? getImageUrl(cfg.image) : '' });
|
||||
} catch (e) { console.error(e); }
|
||||
},
|
||||
hideBgModal: function() { this.setData({ showBgModal: false }); },
|
||||
|
||||
// 背景编辑页左滑返回设置页面
|
||||
bgTouchStartX: 0, bgTouchStartY: 0,
|
||||
onBgTouchStart: function(e) {
|
||||
this.bgTouchStartX = e.touches[0].clientX;
|
||||
this.bgTouchStartY = e.touches[0].clientY;
|
||||
},
|
||||
onBgTouchEnd: function(e) {
|
||||
var dx = this.bgTouchStartX - e.changedTouches[0].clientX;
|
||||
var dy = Math.abs(this.bgTouchStartY - e.changedTouches[0].clientY);
|
||||
if (dx < 20 && dy < 20) return;
|
||||
if (Math.abs(dx) > dy && dx > 80) this.hideBgModal();
|
||||
},
|
||||
chooseBgImage: function() {
|
||||
var self = this;
|
||||
wx.chooseImage({ count: 1, sizeType: ['compressed'], sourceType: ['album'],
|
||||
success: function(res) {
|
||||
self.setData({ bgPreview: res.tempFilePaths[0], bgFilePath: res.tempFilePaths[0] });
|
||||
}
|
||||
});
|
||||
},
|
||||
saveBgImage: async function() {
|
||||
var fp = this.data.bgFilePath;
|
||||
if (!fp) {
|
||||
if (this.data.bgPreview) {
|
||||
wx.showToast({ title: '背景已设置', icon: 'success' });
|
||||
this.hideBgModal();
|
||||
return;
|
||||
}
|
||||
wx.showToast({ title: '请先选择图片', icon: 'none' }); return;
|
||||
}
|
||||
var self = this;
|
||||
wx.showLoading({ title: '上传中...' });
|
||||
try {
|
||||
var data = await uploadFileCompat({
|
||||
url: API_BASE + '/setBgImage',
|
||||
filePath: fp,
|
||||
name: 'bg',
|
||||
formData: {}
|
||||
});
|
||||
wx.hideLoading();
|
||||
if (data && data.path) {
|
||||
var imgUrl = getImageUrl(data.path);
|
||||
wx.showToast({ title: '背景已保存 ✨', icon: 'success' });
|
||||
self.setData({ bgPreview: imgUrl, bgFilePath: '' });
|
||||
self.hideBgModal();
|
||||
} else {
|
||||
var errMsg = (data && data.error) || '上传失败';
|
||||
if (data && data.code) errMsg += ' (错误码: ' + data.code + ')';
|
||||
wx.showToast({ title: errMsg, icon: 'none' });
|
||||
}
|
||||
} catch(e) {
|
||||
wx.hideLoading();
|
||||
var errMsg = (e && e.error) || '上传失败';
|
||||
if (e && e.code) errMsg += ' (错误码: ' + e.code + ')';
|
||||
wx.showToast({ title: errMsg, icon: 'none' });
|
||||
}
|
||||
},
|
||||
removeBgImage: async function() {
|
||||
try { await api.deleteBgImage(); } catch(e) {}
|
||||
wx.showToast({ title: '已恢复默认', icon: 'success' });
|
||||
this.setData({ bgPreview: '', bgFilePath: '' });
|
||||
this.hideBgModal();
|
||||
},
|
||||
|
||||
// ===== 解除绑定(根据状态显示不同操作)=====
|
||||
showUnbind: function() {
|
||||
var status = this.data.unbindStatus;
|
||||
var isRequester = this.data.unbindIsRequester;
|
||||
|
||||
if (status === 'pending') {
|
||||
if (isRequester) {
|
||||
// 发起方:撤销解绑
|
||||
this.doCancelUnbind();
|
||||
} else {
|
||||
// 对方:同意或拒绝
|
||||
this.doRespondUnbind();
|
||||
}
|
||||
} else if (status === 'cooling') {
|
||||
wx.showToast({ title: '正在72小时冷静期', icon: 'none' });
|
||||
wx.navigateTo({ url: '/pages/unbind/unbind' });
|
||||
} else {
|
||||
// 无解绑请求或已结束:发起新解绑
|
||||
this.doRequestUnbind();
|
||||
}
|
||||
},
|
||||
|
||||
// 发起解绑请求
|
||||
doRequestUnbind: function() {
|
||||
var self = this;
|
||||
wx.showModal({
|
||||
title: '💔 解除绑定',
|
||||
content: '对方同意后进入72小时冷静期,期间任一方可取消。到期自动解绑并永久删除共同数据;个人抽烟记录保留。',
|
||||
cancelText: '取消',
|
||||
confirmText: '发起解绑',
|
||||
confirmColor: '#FF4757',
|
||||
success: function(res) {
|
||||
if (res.confirm) {
|
||||
wx.showLoading({ title: '发送请求...' });
|
||||
api.unbindRequest().then(function() {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: '解绑请求已发送', icon: 'success' });
|
||||
self.loadUnbindStatus();
|
||||
wx.navigateTo({ url: '/pages/unbind/unbind' });
|
||||
}).catch(function(err) {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: err.error || '操作失败', icon: 'none' });
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 撤销解绑请求
|
||||
doCancelUnbind: function() {
|
||||
var self = this;
|
||||
wx.showModal({
|
||||
title: '↩️ 撤销解绑',
|
||||
content: '取消后关系继续保留。确定取消解绑吗?',
|
||||
cancelText: '取消',
|
||||
confirmText: '撤销请求',
|
||||
confirmColor: '#FF6B9D',
|
||||
success: function(res) {
|
||||
if (res.confirm) {
|
||||
wx.showLoading({ title: '撤销中...' });
|
||||
api.unbindCancel().then(function() {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: '已撤销解绑请求', icon: 'success' });
|
||||
self.loadUnbindStatus();
|
||||
}).catch(function(err) {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: err.error || '操作失败', icon: 'none' });
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 回应解绑请求(对方视角)
|
||||
doRespondUnbind: function() {
|
||||
var self = this;
|
||||
var name = this.data.unbindRequesterName;
|
||||
wx.showActionSheet({
|
||||
itemList: ['✅ 同意解绑', '❌ 拒绝解绑'],
|
||||
success: function(res) {
|
||||
if (res.tapIndex === 0) {
|
||||
// 同意
|
||||
wx.showModal({
|
||||
title: '⚠️ 确认同意',
|
||||
content: name + ' 发起了解绑请求。同意后进入72小时冷静期,期间可取消;到期自动解绑并永久删除共同数据,个人抽烟记录保留。',
|
||||
cancelText: '取消',
|
||||
confirmText: '同意解绑',
|
||||
confirmColor: '#FF4757',
|
||||
success: function(r) {
|
||||
if (r.confirm) {
|
||||
wx.showLoading({ title: '处理中...' });
|
||||
api.unbindRespond({ agree: true }).then(function() {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: '已进入72小时冷静期', icon: 'none' });
|
||||
self.loadUnbindStatus();
|
||||
wx.navigateTo({ url: '/pages/unbind/unbind' });
|
||||
}).catch(function(err) {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: err.error || '操作失败', icon: 'none' });
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (res.tapIndex === 1) {
|
||||
// 拒绝
|
||||
wx.showModal({
|
||||
title: '拒绝解绑',
|
||||
content: '确定要拒绝 ' + name + ' 的解绑请求吗?',
|
||||
cancelText: '取消',
|
||||
confirmText: '拒绝',
|
||||
confirmColor: '#FF6B9D',
|
||||
success: function(r) {
|
||||
if (r.confirm) {
|
||||
wx.showLoading({ title: '处理中...' });
|
||||
api.unbindRespond({ agree: false }).then(function() {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: '已拒绝解绑请求', icon: 'success' });
|
||||
self.loadUnbindStatus();
|
||||
}).catch(function(err) {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: err.error || '操作失败', icon: 'none' });
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 导航
|
||||
goToHistory: function() { wx.navigateTo({ url: '/pages/history/history' }); },
|
||||
goHome: function() { wx.switchTab({ url: '/pages/index/index' }); },
|
||||
goToProfile: function() { wx.navigateBack(); },
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"usingComponents": {
|
||||
"app-nav": "/components/app-nav/app-nav",
|
||||
"page-state": "/components/page-state/page-state"
|
||||
},
|
||||
"enablePullDownRefresh": true
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
<view class="app-shell app-shell--secondary j-handwritten-page" style="{{layoutStyle}}">
|
||||
<launch-transition />
|
||||
<!-- pages/settings/settings.wxml -->
|
||||
<app-nav title="设置" back="{{true}}" />
|
||||
|
||||
<scroll-view class="page-bg" scroll-y show-scrollbar="{{false}}" bounces="{{true}}">
|
||||
<view class="j-body">
|
||||
<view class="section-heading">外观与通知</view>
|
||||
<!-- 首页背景 -->
|
||||
<view class="j-profile-setting" bindtap="showBgModal">
|
||||
<view class="setting-info">
|
||||
<view class="j-small-title">首页背景</view>
|
||||
<view class="j-caption">自定义上传背景图片</view>
|
||||
</view>
|
||||
<text class="j-link">›</text>
|
||||
</view>
|
||||
|
||||
<!-- 消息通知 -->
|
||||
<view class="j-profile-setting" bindtap="showSubscribeModal">
|
||||
<view class="setting-info">
|
||||
<view class="j-small-title">消息通知</view>
|
||||
<view class="j-caption">管理订阅消息推送</view>
|
||||
</view>
|
||||
<text class="j-link">›</text>
|
||||
</view>
|
||||
|
||||
<!-- 抽烟打卡默认事件 -->
|
||||
<view class="j-profile-setting">
|
||||
<view class="setting-info">
|
||||
<view class="j-small-title">抽烟打卡</view>
|
||||
<view class="j-caption">在打卡页显示「抽烟记录」默认事件</view>
|
||||
</view>
|
||||
<switch checked="{{smokingVisible}}" bindchange="toggleSmoking" color="#B74768" style="transform:scale(0.75);" />
|
||||
</view>
|
||||
|
||||
<view class="section-heading">关系与账号</view>
|
||||
<!-- 操作记录 -->
|
||||
<view class="j-profile-setting" bindtap="goToHistory">
|
||||
<view class="setting-info">
|
||||
<view class="j-small-title">操作记录</view>
|
||||
<view class="j-caption">查看双方所有操作日志</view>
|
||||
</view>
|
||||
<text class="j-link">›</text>
|
||||
</view>
|
||||
|
||||
<page-state wx:if="{{bindingError}}" kind="error" title="绑定状态加载失败" action="重试" bind:action="onShow" />
|
||||
<view class="j-profile-setting" bindtap="onShow" wx:if="{{!bindingKnown && !bindingError}}">
|
||||
<view class="setting-info"><view class="j-small-title">正在获取绑定状态</view><view class="j-caption">若加载失败,点击重试</view></view>
|
||||
<text class="j-link">›</text>
|
||||
</view>
|
||||
|
||||
<view class="j-profile-setting" bindtap="goBind" wx:if="{{bindingKnown && !hasPartner}}">
|
||||
<view class="setting-info">
|
||||
<view class="j-small-title" style="color:#B74768;">绑定情侣</view>
|
||||
<view class="j-caption">输入对方 ID 或分享邀请</view>
|
||||
</view>
|
||||
<text class="j-link">›</text>
|
||||
</view>
|
||||
|
||||
<!-- 解除绑定(根据状态动态显示) -->
|
||||
<view class="j-profile-setting" bindtap="showUnbind" wx:if="{{bindingKnown && hasPartner}}">
|
||||
<view class="setting-info">
|
||||
<view wx:if="{{unbindStatus == 'pending' && unbindIsRequester}}" class="j-small-title" style="color:#FF9800;">取消解绑请求</view>
|
||||
<view wx:elif="{{unbindStatus == 'pending' && !unbindIsRequester}}" class="j-small-title" style="color:#FF4757;">待回应的解绑请求</view>
|
||||
<view wx:elif="{{unbindStatus == 'cooling'}}" class="j-small-title">72小时冷静期</view>
|
||||
<view wx:else class="j-small-title" style="color:#FF4757;">解除绑定</view>
|
||||
<view wx:if="{{unbindStatus == 'pending' && unbindIsRequester}}" class="j-caption">点击撤销已发起的请求</view>
|
||||
<view wx:elif="{{unbindStatus == 'pending' && !unbindIsRequester}}" class="j-caption">{{unbindRequesterName}} 发起了解绑</view>
|
||||
<view wx:elif="{{unbindStatus == 'cooling'}}" class="j-caption">点击查看倒计时或取消解绑</view>
|
||||
<view wx:else class="j-caption">同意后进入72小时冷静期</view>
|
||||
</view>
|
||||
<text class="j-link">›</text>
|
||||
</view>
|
||||
|
||||
<view class="section-heading">关于与帮助</view>
|
||||
<!-- 我们past -->
|
||||
<view class="j-profile-setting" bindtap="showAboutModal">
|
||||
<view class="setting-info">
|
||||
<view class="j-small-title">我们past</view>
|
||||
<view class="j-caption">了解本小程序的功能</view>
|
||||
</view>
|
||||
<text class="j-link">›</text>
|
||||
</view>
|
||||
|
||||
<!-- 联系我们 -->
|
||||
<view class="j-profile-setting" bindtap="showContactModal">
|
||||
<view class="setting-info">
|
||||
<view class="j-small-title">联系我们</view>
|
||||
<view class="j-caption">软件功能建议与反馈</view>
|
||||
</view>
|
||||
<text class="j-link">›</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
</scroll-view>
|
||||
|
||||
<!-- 背景图编辑页 - 全屏背景预览 -->
|
||||
<view class="edit-page" wx:if="{{showBgModal}}">
|
||||
<!-- 全屏背景 -->
|
||||
<image wx:if="{{bgPreview}}" src="{{bgPreview}}" mode="aspectFill" class="bg-full" catchtouchstart="onBgTouchStart" catchtouchend="onBgTouchEnd" />
|
||||
<view wx:else class="bg-placeholder" catchtouchstart="onBgTouchStart" catchtouchend="onBgTouchEnd"></view>
|
||||
|
||||
<!-- 左滑或点击空白区域返回 -->
|
||||
<view class="edit-nav" bindtap="hideBgModal">
|
||||
<view class="back-btn-wrap transparent">
|
||||
<image src="/images/back.svg" mode="aspectFit" class="back-nav-icon" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作区 -->
|
||||
<view class="bg-edit-footer">
|
||||
<view class="bg-edit-card">
|
||||
<text class="modal-subtitle" style="text-align:center;display:block;margin-bottom:24rpx;">上传你喜欢的背景图片</text>
|
||||
<view class="bg-btn-row">
|
||||
<button class="btn btn-select" bindtap="chooseBgImage" hover-class="none">📷 选择</button>
|
||||
<button class="btn btn-save" bindtap="saveBgImage" hover-class="none">💾 保存</button>
|
||||
<button class="btn btn-restore" bindtap="removeBgImage" hover-class="none">🔄 恢复</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 消息通知管理弹窗 -->
|
||||
<view class="modal-overlay" wx:if="{{showSubscribeModal}}" bindtap="hideSubscribeModal">
|
||||
<view class="modal" catchtap="noop" style="max-height:75vh;overflow-y:auto;">
|
||||
<text class="modal-heart">🔔</text>
|
||||
<text class="title">消息通知</text>
|
||||
<text class="modal-subtitle">开启后,当TA有操作时会通过微信服务通知提醒你</text>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<view wx:if="{{subscribeLoading}}" class="subscribe-loading">
|
||||
<view class="loading-spinner"></view>
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<!-- 通知开关 -->
|
||||
<view wx:else class="subscribe-section">
|
||||
<view class="subscribe-card {{subscribeChecked ? 'active' : ''}}">
|
||||
<view class="subscribe-card-left">
|
||||
<view class="subscribe-icon-wrap" style="background:{{subscribeChecked ? '#FFE4EC' : '#F5F5F5'}};">
|
||||
<text class="subscribe-icon">💕</text>
|
||||
</view>
|
||||
<view class="subscribe-info">
|
||||
<text class="subscribe-name">操作通知</text>
|
||||
<text class="subscribe-desc">TA有新的操作时通知你</text>
|
||||
</view>
|
||||
</view>
|
||||
<switch checked="{{subscribeChecked}}" bindchange="toggleSubscribe" color="#B74768" style="transform:scale(0.75);" />
|
||||
</view>
|
||||
|
||||
<!-- 状态提示 -->
|
||||
<view class="subscribe-tip {{subscribeChecked ? 'on' : 'off'}}">
|
||||
<block wx:if="{{subscribeChecked}}">
|
||||
<text class="tip-icon">✅</text>
|
||||
<text class="tip-text">已开启接收提醒,订阅次数用完后需要再次授权</text>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<text class="tip-icon">💡</text>
|
||||
<text class="tip-text">开启并授权后,可接收一次TA的操作提醒</text>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
<button wx:if="{{subscribeChecked}}" class="subscribe-renew" bindtap="renewSubscribe">订阅一次 TA 的提醒</button>
|
||||
|
||||
<!-- 说明 -->
|
||||
<view class="subscribe-note">
|
||||
<text class="note-title">📌 温馨提示</text>
|
||||
<text class="note-item">• 通知通过微信「服务通知」推送</text>
|
||||
<text class="note-item">• 你授权的是自己接收TA提醒的次数,不能替TA授权</text>
|
||||
<text class="note-item">• 每次授权可接收一次提醒,用完后可点击上方按钮续订</text>
|
||||
<text class="note-item">• 勾选「总是保持以上选择」后,后续点击授权可免重复弹窗,仍需逐次申请</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 固定标题和关闭按钮,长内容独立滚动 -->
|
||||
<view class="modal-overlay info-overlay" wx:if="{{showAboutModal}}" bindtap="hideAboutModal">
|
||||
<view class="modal info-dialog" catchtap="noop">
|
||||
<view class="info-header">
|
||||
<image class="info-mark" src="/images/book.svg" mode="aspectFit" />
|
||||
<text class="info-title">我们 past</text>
|
||||
<text class="info-caption">把日常,写成我们的故事</text>
|
||||
</view>
|
||||
<scroll-view class="info-body" scroll-y show-scrollbar="{{false}}">
|
||||
<view class="info-content">
|
||||
<text class="about-intro">属于两个人的小世界,珍藏每一次相遇,也记录平凡日常里的心动。</text>
|
||||
<view class="about-block">
|
||||
<text class="about-block-title">我们的生活手账</text>
|
||||
<text class="about-item">日记 · 写下心情与故事</text>
|
||||
<text class="about-item">相册 · 珍藏照片与美好瞬间</text>
|
||||
<text class="about-item">记忆日 · 记住每一个重要日子</text>
|
||||
<text class="about-item">歌曲 · 收藏一起听过的旋律</text>
|
||||
<text class="about-item">打卡 · 一起完成日常约定</text>
|
||||
<text class="about-item">宠物 · 照顾属于我们的伙伴</text>
|
||||
<text class="about-item">姨姨 · 记录生理期与身体状态</text>
|
||||
</view>
|
||||
<view class="about-block">
|
||||
<text class="about-block-title">让陪伴更近一点</text>
|
||||
<text class="about-item">情侣绑定 · 邀请另一半,共享记录</text>
|
||||
<text class="about-item">消息通知 · 订阅对方的动态提醒</text>
|
||||
<text class="about-item">首页背景 · 换成喜欢的照片</text>
|
||||
<text class="about-item">所在城市 · 分享彼此的位置</text>
|
||||
</view>
|
||||
<text class="about-version info-signature">让所有的爱有迹可循</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="info-footer"><button class="info-dismiss" bindtap="hideAboutModal">知道了</button></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 联系我们弹窗 -->
|
||||
<view class="modal-overlay" wx:if="{{showContactModal}}" bindtap="hideContactModal">
|
||||
<view class="modal" catchtap="noop">
|
||||
<text class="modal-heart">💬</text>
|
||||
<text class="title">联系我们</text>
|
||||
<text class="modal-subtitle">软件功能建议与反馈</text>
|
||||
|
||||
<view class="about-section">
|
||||
<text class="about-intro">如果你在使用过程中有任何软件功能建议、优化想法或遇到的问题,欢迎随时联系我们,我们会认真听取每一位用户的声音,不断把「我们past」做得更好。💕</text>
|
||||
</view>
|
||||
|
||||
<view class="about-block">
|
||||
<text class="about-block-title">📮 联系微信</text>
|
||||
<text class="about-item">微信:e909e10</text>
|
||||
<text class="about-item">添加时请备注「我们past」,方便我们快速响应</text>
|
||||
</view>
|
||||
|
||||
<view class="about-foot">
|
||||
<text class="about-version">让所有的爱有迹可循</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</view>
|
||||
@@ -0,0 +1,388 @@
|
||||
/* pages/settings/settings.wxss */
|
||||
@import '../../styles/common.wxss';
|
||||
page { background: linear-gradient(180deg, #FDE4EC 0%, #FFF0F5 48%, #FFF7FA 100%); height: 100vh; overflow: hidden; }
|
||||
.container { padding-top: 16rpx; padding-bottom: 300rpx; }
|
||||
scroll-view.page-bg { height: 100vh; overflow-y: scroll; -webkit-overflow-scrolling: touch; }
|
||||
|
||||
|
||||
|
||||
/* 全屏编辑页样式 */
|
||||
.edit-page {
|
||||
position: fixed;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.bg-full {
|
||||
position: fixed;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
z-index: 0;
|
||||
}
|
||||
.bg-placeholder {
|
||||
position: fixed;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
z-index: 0;
|
||||
background: linear-gradient(135deg, #F4E2E3 0%, #FFF0F5 50%, #F8E1FF 100%);
|
||||
}
|
||||
.edit-nav {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
padding: 100rpx 0 0 32rpx;
|
||||
background: transparent;
|
||||
height: 180rpx;
|
||||
}
|
||||
.back-btn-wrap {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(255,255,255,0.75);
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.back-btn-wrap.transparent {
|
||||
background: transparent;
|
||||
backdrop-filter: none;
|
||||
-webkit-backdrop-filter: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.back-nav-icon {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.edit-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
.edit-body {
|
||||
flex: 1;
|
||||
padding: 0 48rpx 120rpx;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.back-btn {
|
||||
width: 56rpx; height: 56rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(255,255,255,0.9);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.08);
|
||||
}
|
||||
.back-icon {
|
||||
width: 32rpx; height: 32rpx;
|
||||
}
|
||||
|
||||
/* 背景编辑页卡片 - 固定在底部导航栏上方 */
|
||||
.bg-edit-footer {
|
||||
position: fixed;
|
||||
bottom: 360rpx;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
padding: 0 32rpx;
|
||||
}
|
||||
.bg-edit-card {
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
border-radius: 32rpx;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* 恢复默认背景按钮 */
|
||||
.btn-restore {
|
||||
background: transparent;
|
||||
color: #FF6B81;
|
||||
border: 4rpx solid #FF6B81;
|
||||
margin-top: 16rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.btn-restore:active {
|
||||
background: rgba(255,107,129,0.08);
|
||||
transform: scale(0.97);
|
||||
}
|
||||
|
||||
/* ===== 消息通知弹窗样式 ===== */
|
||||
.subscribe-loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 48rpx 0;
|
||||
}
|
||||
.loading-spinner {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
border: 4rpx solid #F4E2E3;
|
||||
border-top-color: #B74768;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
.loading-text {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
.subscribe-section {
|
||||
margin: 24rpx 0 8rpx;
|
||||
}
|
||||
.subscribe-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #FAFAFA;
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx 20rpx;
|
||||
transition: all 0.3s ease;
|
||||
border: 2rpx solid transparent;
|
||||
}
|
||||
.subscribe-card.active {
|
||||
background: #FFF5F7;
|
||||
border-color: #FFD6E0;
|
||||
}
|
||||
.subscribe-card-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
flex: 1;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
.subscribe-icon-wrap {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
.subscribe-icon {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
.subscribe-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.subscribe-name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
display: block;
|
||||
}
|
||||
.subscribe-desc {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
margin-top: 4rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.subscribe-tip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
padding: 16rpx 20rpx;
|
||||
border-radius: 16rpx;
|
||||
margin-top: 16rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.subscribe-tip.on {
|
||||
background: #E8F5E9;
|
||||
color: #2E7D32;
|
||||
}
|
||||
.subscribe-tip.off {
|
||||
background: #FFF8E1;
|
||||
color: #F57F17;
|
||||
}
|
||||
.tip-icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.tip-text {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.subscribe-renew {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
margin: 24rpx 0 0;
|
||||
padding: 0 16rpx;
|
||||
border: none;
|
||||
border-radius: 20rpx;
|
||||
background: #B74768;
|
||||
color: #FFFFFF;
|
||||
font-family: inherit;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
box-shadow: none;
|
||||
}
|
||||
.subscribe-renew::after {
|
||||
border: none;
|
||||
}
|
||||
.subscribe-renew:active {
|
||||
background: #943C58;
|
||||
}
|
||||
|
||||
.subscribe-note {
|
||||
background: #F8F8F8;
|
||||
border-radius: 16rpx;
|
||||
padding: 20rpx;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
.note-title {
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
color: #666;
|
||||
display: block;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.note-item {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
display: block;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
/* 背景编辑页按钮 - 水平排列,统一大小 */
|
||||
.bg-btn-row {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
}
|
||||
.bg-btn-row .btn {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
border-radius: 44rpx;
|
||||
padding: 0;
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
border: none;
|
||||
text-align: center;
|
||||
line-height: 88rpx;
|
||||
margin: 0;
|
||||
}
|
||||
.bg-btn-row .btn:active {
|
||||
transform: scale(0.94);
|
||||
}
|
||||
/* 三个按钮统一为半透明白色毛玻璃风格 */
|
||||
.bg-btn-row .btn-select,
|
||||
.bg-btn-row .btn-save,
|
||||
.bg-btn-row .btn-restore {
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
color: #FF6B81;
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
border: 2rpx solid rgba(255, 107, 129, 0.25);
|
||||
box-shadow: none;
|
||||
}
|
||||
.bg-btn-row .btn-select:active,
|
||||
.bg-btn-row .btn-save:active,
|
||||
.bg-btn-row .btn-restore:active {
|
||||
background: rgba(255, 107, 129, 0.15);
|
||||
transform: scale(0.94);
|
||||
}
|
||||
.bg-edit-card .btn-restore:active {
|
||||
background: rgba(255, 107, 129, 0.12);
|
||||
}
|
||||
|
||||
/* ===== 关于我们 ===== */
|
||||
.about-section {
|
||||
margin: 28rpx 0 8rpx;
|
||||
}
|
||||
.about-intro {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
line-height: 1.7;
|
||||
text-align: center;
|
||||
display: block;
|
||||
}
|
||||
.about-block {
|
||||
background: #FFF9F4;
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx 28rpx;
|
||||
margin-top: 24rpx;
|
||||
border: 2rpx solid rgba(255, 107, 157, 0.12);
|
||||
}
|
||||
.about-block-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
color: #B74768;
|
||||
display: block;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
.about-item {
|
||||
font-size: 24rpx;
|
||||
color: #555;
|
||||
display: block;
|
||||
line-height: 1.9;
|
||||
}
|
||||
.about-foot {
|
||||
margin-top: 28rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.about-version {
|
||||
font-size: 22rpx;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
@import '../../styles/design.wxss';
|
||||
|
||||
@import '../../styles/journal.wxss';
|
||||
|
||||
/* 弹窗位于页面滚动容器外,盖住底部导航。 */
|
||||
.modal-overlay { z-index:1200; }
|
||||
.info-dialog { display:flex; flex-direction:column; height:76vh; padding:0; overflow:hidden; max-width:650rpx; }
|
||||
.info-header { flex-shrink:0; display:flex; flex-direction:column; align-items:center; padding:36rpx 32rpx 24rpx; border-bottom:1rpx solid #E9DDD0; }
|
||||
.info-mark { width:48rpx; height:48rpx; margin-bottom:16rpx; }
|
||||
.info-title { font-size:34rpx; font-weight:600; color:#352E2A; }
|
||||
.info-caption { font-size:24rpx; color:#85776D; margin-top:10rpx; }
|
||||
.info-body { flex:1; height:0; min-height:0; }
|
||||
.info-content { padding:28rpx 32rpx; }
|
||||
.about-intro { color:#85776D; text-align:left; line-height:1.75; }
|
||||
.about-block { background:#FAF5EE; border:1rpx solid #E9DDD0; border-radius:16rpx; padding:24rpx; }
|
||||
.about-block-title { color:#352E2A; font-weight:600; }
|
||||
.about-item { color:#65594F; line-height:1.8; margin-top:8rpx; }
|
||||
.info-signature { display:block; margin-top:28rpx; text-align:center; color:#A39386; }
|
||||
.info-footer { flex-shrink:0; padding:20rpx 32rpx; border-top:1rpx solid #E9DDD0; }
|
||||
.info-dismiss { margin:0; width:100%; padding:0; line-height:76rpx; border-radius:16rpx; background:#B74768; color:#FFFDF8; font-size:28rpx; }
|
||||
.info-dismiss::after { border:0; }
|
||||
|
||||
/* 设置分组和弹窗标题延续主页面的端正手写风格。 */
|
||||
.section-heading,
|
||||
.info-title,
|
||||
.modal-subtitle,
|
||||
.about-block-title {
|
||||
font-family:'Kaiti SC','STKaiti','KaiTi',cursive;
|
||||
font-weight:400;
|
||||
font-style:normal;
|
||||
letter-spacing:1rpx;
|
||||
}
|
||||
|
||||
@import '../../styles/button-theme.wxss';
|
||||
|
||||
@import '../../styles/typography.wxss';
|
||||
Reference in New Issue
Block a user