feat(miniapp): 实现订阅管理页面与运势页订阅入口
- 新增订阅管理页面:订阅开关、推送时间设置、模板管理 - 运势主页添加订阅入口区域 - 更新页面路由配置 - 补充运势页相关测试
This commit is contained in:
@@ -0,0 +1,263 @@
|
||||
<template>
|
||||
<view class="subscription-manage">
|
||||
<!-- 订阅状态 -->
|
||||
<view class="status-card">
|
||||
<text class="status-title">订阅状态</text>
|
||||
<view class="status-row">
|
||||
<text class="status-label">每日运势推送</text>
|
||||
<text class="status-value active">已开启</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 推送时间设置 -->
|
||||
<view class="setting-card">
|
||||
<text class="setting-title">推送时间设置</text>
|
||||
<text class="setting-hint">每日在此时间推送当日运势(30分钟步长)</text>
|
||||
<picker
|
||||
mode="time"
|
||||
:value="selectedTime"
|
||||
:start="'06:00'"
|
||||
:end="'22:00'"
|
||||
@change="onTimeChange"
|
||||
>
|
||||
<view class="time-picker">
|
||||
<text class="time-label">推送时间</text>
|
||||
<text class="time-value">{{ selectedTime }}</text>
|
||||
</view>
|
||||
</picker>
|
||||
<button
|
||||
class="save-btn"
|
||||
:disabled="!timeChanged"
|
||||
@tap="savePushTime"
|
||||
>
|
||||
保存设置
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 取消订阅 -->
|
||||
<view class="action-card">
|
||||
<button class="unsubscribe-btn" @tap="handleUnsubscribe">
|
||||
取消订阅
|
||||
</button>
|
||||
<text class="unsubscribe-hint">取消后将不再收到每日运势推送</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
const PUSH_SUB_KEY = 'eis_push_subscription'
|
||||
|
||||
interface PushSubscription {
|
||||
pushTime: string
|
||||
pushEnabled: boolean
|
||||
subscribedAt: string
|
||||
}
|
||||
|
||||
const selectedTime = ref('07:00')
|
||||
const savedTime = ref('07:00')
|
||||
const timeChanged = ref(false)
|
||||
|
||||
onShow(() => {
|
||||
uni.setNavigationBarTitle({ title: '订阅管理' })
|
||||
loadSubscription()
|
||||
})
|
||||
|
||||
function loadSubscription() {
|
||||
try {
|
||||
const raw = uni.getStorageSync(PUSH_SUB_KEY)
|
||||
if (raw) {
|
||||
const sub = JSON.parse(raw) as PushSubscription
|
||||
selectedTime.value = sub.pushTime || '07:00'
|
||||
savedTime.value = selectedTime.value
|
||||
timeChanged.value = false
|
||||
}
|
||||
} catch {
|
||||
// 未订阅状态
|
||||
}
|
||||
}
|
||||
|
||||
function onTimeChange(e: any) {
|
||||
// 将时间四舍五入到最近的 30 分钟步长(00 或 30)
|
||||
const [hour, minute] = e.detail.value.split(':').map(Number)
|
||||
const roundedMinute = minute < 15 ? 0 : minute < 45 ? 30 : 0
|
||||
const adjustedHour = minute >= 45 ? hour + 1 : hour
|
||||
const finalHour = Math.min(Math.max(adjustedHour, 6), 22)
|
||||
selectedTime.value = `${String(finalHour).padStart(2, '0')}:${String(roundedMinute).padStart(2, '0')}`
|
||||
timeChanged.value = selectedTime.value !== savedTime.value
|
||||
}
|
||||
|
||||
async function savePushTime() {
|
||||
try {
|
||||
const result = await wx.cloud.callFunction({
|
||||
name: 'updatePushTime',
|
||||
data: { pushTime: selectedTime.value },
|
||||
})
|
||||
|
||||
if (result.result.success) {
|
||||
// 更新本地缓存
|
||||
const raw = uni.getStorageSync(PUSH_SUB_KEY)
|
||||
if (raw) {
|
||||
const sub = JSON.parse(raw) as PushSubscription
|
||||
sub.pushTime = selectedTime.value
|
||||
uni.setStorageSync(PUSH_SUB_KEY, JSON.stringify(sub))
|
||||
}
|
||||
|
||||
savedTime.value = selectedTime.value
|
||||
timeChanged.value = false
|
||||
uni.showToast({ title: '保存成功', icon: 'success' })
|
||||
} else {
|
||||
uni.showToast({ title: '保存失败,请重试', icon: 'none' })
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Save push time error:', err)
|
||||
uni.showToast({ title: '保存失败,请重试', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
async function handleUnsubscribe() {
|
||||
uni.showModal({
|
||||
title: '确认取消',
|
||||
content: '取消后将不再收到每日运势推送,确定要取消吗?',
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
const result = await wx.cloud.callFunction({
|
||||
name: 'unsubscribe',
|
||||
})
|
||||
|
||||
if (result.result.success) {
|
||||
// 清除本地缓存
|
||||
uni.removeStorageSync(PUSH_SUB_KEY)
|
||||
uni.showToast({ title: '已取消订阅', icon: 'success' })
|
||||
|
||||
// 返回上一页
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
} else {
|
||||
uni.showToast({ title: '取消失败,请重试', icon: 'none' })
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Unsubscribe error:', err)
|
||||
uni.showToast({ title: '取消失败,请重试', icon: 'none' })
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.subscription-manage {
|
||||
min-height: 100vh;
|
||||
background-color: rgba(244, 244, 245, 0.3);
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.status-card,
|
||||
.setting-card,
|
||||
.action-card {
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.status-title,
|
||||
.setting-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
display: block;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.status-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.status-label {
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.status-value {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.status-value.active {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.setting-hint {
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
display: block;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.time-picker {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 0;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.time-label {
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.time-value {
|
||||
font-size: 15px;
|
||||
color: #1677ff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
background-color: rgba(44, 24, 16, 255);
|
||||
color: #fff;
|
||||
border-radius: 20px;
|
||||
font-size: 15px;
|
||||
margin-top: 12px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.save-btn[disabled] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.unsubscribe-btn {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
background-color: #fff;
|
||||
color: #ff4d4f;
|
||||
border-radius: 20px;
|
||||
font-size: 15px;
|
||||
border: 1px solid #ff4d4f;
|
||||
}
|
||||
|
||||
.unsubscribe-hint {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin-top: 8px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user