feat(share): 启用全站系统分享 + 完善分享文案配置
- 各 Page 补齐 onShareAppMessage/onShareTimeline,修复右上角转发/朋友圈按钮灰色 - ui-btn 透传 open-type,完成弹窗接入分享按钮 - config.share 集中维护文案,动态标题用 titleTemplate 占位符 - leaderboard 的 myEntry.rank 缺失时回退静态标题,避免出现"排第 undefined" - 完成弹窗分享按钮高度对齐 88rpx,与同排按钮等高 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,13 @@ Component({
|
|||||||
block: { type: Boolean, value: false },
|
block: { type: Boolean, value: false },
|
||||||
disabled: { type: Boolean, value: false },
|
disabled: { type: Boolean, value: false },
|
||||||
iconSrc: { type: String, value: '' },
|
iconSrc: { type: String, value: '' },
|
||||||
customStyle: { type: String, value: '' }
|
customStyle: { type: String, value: '' },
|
||||||
|
// 透传微信原生 button 的 open-type:
|
||||||
|
// share — 触发 Page.onShareAppMessage(分享给朋友)
|
||||||
|
// contact / feedback / shareToPhone … 等
|
||||||
|
// 设置后会在底层 button 上挂 open-type="{{openType}}",配合 Page 的
|
||||||
|
// onShareAppMessage 即可让自定义按钮真正调起原生分享面板。
|
||||||
|
openType: { type: String, value: '' }
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onTap() {
|
onTap() {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
style="{{customStyle}}"
|
style="{{customStyle}}"
|
||||||
bindtap="onTap"
|
bindtap="onTap"
|
||||||
disabled="{{disabled}}"
|
disabled="{{disabled}}"
|
||||||
|
open-type="{{openType}}"
|
||||||
hover-class="none"
|
hover-class="none"
|
||||||
>
|
>
|
||||||
<image
|
<image
|
||||||
|
|||||||
@@ -52,5 +52,55 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
|
|
||||||
/** 姿势要领每条显示的秒数 */
|
/** 姿势要领每条显示的秒数 */
|
||||||
tipInterval: 10
|
tipInterval: 10,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 小程序分享配置。微信分享能力依赖每个 Page 实现 onShareAppMessage /
|
||||||
|
* onShareTimeline,这里集中维护所有场景的分享文案,改这里即可。
|
||||||
|
*
|
||||||
|
* 各 Page 根据自身场景从 share 字典里取对应的文案:
|
||||||
|
* - share.default 默认(打开小程序时的转发)
|
||||||
|
* - share.timer 训练完成时(最常见的分享节点)
|
||||||
|
* - share.records 训练记录页(晒成绩)
|
||||||
|
* - share.leaderboard 排行榜页(榜单拉人)
|
||||||
|
* - share.settings 设置页(基本不会分享)
|
||||||
|
*
|
||||||
|
* 每个场景的 title 是静态兜底文案;带动态数据的场景额外提供
|
||||||
|
* titleTemplate,用 {占位符} 标记运行时替换的位置,页面 replace 后使用:
|
||||||
|
* - timer.titleTemplate {elapsed} 实际撑的秒数
|
||||||
|
* - timer.timelineTitleTemplate {elapsed} 朋友圈晒成绩
|
||||||
|
* - records.titleTemplate {minutes} 累计训练分钟数
|
||||||
|
* - leaderboard.titleTemplate {period}/{rank} 榜单周期与名次
|
||||||
|
* 数据缺失时页面回退到静态 title,避免分享卡片出现裸占位符。
|
||||||
|
*
|
||||||
|
* timelineTitle 用于非 timer 页的 onShareTimeline(分享到朋友圈)。
|
||||||
|
* shareImageUrl 为空时微信自动用页面截图,无需提前准备图片。
|
||||||
|
*/
|
||||||
|
share: {
|
||||||
|
default: {
|
||||||
|
title: '平板支撑训练 — 每天一分钟,撑出好体态',
|
||||||
|
path: '/pages/index/index'
|
||||||
|
},
|
||||||
|
timer: {
|
||||||
|
title: '我刚完成一次平板支撑训练,一起来打卡!',
|
||||||
|
titleTemplate: '我刚撑了 {elapsed} 秒!一起来平板支撑打卡',
|
||||||
|
timelineTitleTemplate: '今天平板支撑 {elapsed} 秒,你能超过我吗?',
|
||||||
|
path: '/pages/index/index'
|
||||||
|
},
|
||||||
|
records: {
|
||||||
|
title: '看看我的平板支撑训练记录',
|
||||||
|
titleTemplate: '累计平板支撑 {minutes} 分钟,你也来试试',
|
||||||
|
path: '/pages/records/records'
|
||||||
|
},
|
||||||
|
leaderboard: {
|
||||||
|
title: '平板支撑训练排行榜,看看你能撑多久?',
|
||||||
|
titleTemplate: '我在平板支撑{period}榜排第 {rank},你能超过我吗?',
|
||||||
|
path: '/pages/leaderboard/leaderboard'
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
title: '平板支撑训练小程序',
|
||||||
|
path: '/pages/settings/settings'
|
||||||
|
},
|
||||||
|
timelineTitle: '平板支撑训练 — 一起打卡'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const planMod = require('../../utils/plan')
|
|||||||
const util = require('../../utils/util')
|
const util = require('../../utils/util')
|
||||||
const themeMod = require('../../utils/theme')
|
const themeMod = require('../../utils/theme')
|
||||||
const iconsMod = require('../../utils/icons')
|
const iconsMod = require('../../utils/icons')
|
||||||
|
const config = require('../../config')
|
||||||
|
|
||||||
const MAX_CUSTOM_DURATION = 3600 // 1 hour max
|
const MAX_CUSTOM_DURATION = 3600 // 1 hour max
|
||||||
|
|
||||||
@@ -190,5 +191,29 @@ Page({
|
|||||||
}
|
}
|
||||||
this.setData({ showPicker: false })
|
this.setData({ showPicker: false })
|
||||||
wx.navigateTo({ url: `/pages/timer/timer?free=${dur}` })
|
wx.navigateTo({ url: `/pages/timer/timer?free=${dur}` })
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享给朋友。微信在用户点击右上角"···"菜单里的"转发给朋友"、
|
||||||
|
* 或者页面内任何 `<button open-type="share">` / `<button open-type="share">`
|
||||||
|
* 时,都会调用这个钩子,返回值即分享卡片的内容。
|
||||||
|
* 没声明这个方法时分享按钮就是灰色的,见上轮分析。
|
||||||
|
*/
|
||||||
|
onShareAppMessage() {
|
||||||
|
const s = config.share.default
|
||||||
|
return {
|
||||||
|
title: s.title,
|
||||||
|
path: s.path
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享到朋友圈。基础库 2.11.3+ 可用。同样不实现就让"分享到朋友圈"按钮
|
||||||
|
* 灰掉。各页统一用 config.share.timelineTitle 作为朋友圈文案。
|
||||||
|
*/
|
||||||
|
onShareTimeline() {
|
||||||
|
return {
|
||||||
|
title: config.share.timelineTitle
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -120,5 +120,32 @@ Page({
|
|||||||
} else {
|
} else {
|
||||||
this.setData({ loading: false, empty: true })
|
this.setData({ loading: false, empty: true })
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享给朋友 — 排行榜页。把用户当前名次写进标题,有"攀比"属性,
|
||||||
|
* 分享欲望会强一些。
|
||||||
|
*/
|
||||||
|
onShareAppMessage() {
|
||||||
|
const me = this.data.myEntry
|
||||||
|
const s = config.share.leaderboard
|
||||||
|
// myEntry.rank 依赖云函数返回,缺失时回退静态 title,避免出现"排第 undefined"
|
||||||
|
if (me && me.rank) {
|
||||||
|
const periodLabel = { day: '日', month: '月', year: '年' }[this.data.activePeriod] || ''
|
||||||
|
return {
|
||||||
|
title: s.titleTemplate.replace('{period}', periodLabel).replace('{rank}', me.rank),
|
||||||
|
path: s.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { title: s.title, path: s.path }
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享到朋友圈。
|
||||||
|
*/
|
||||||
|
onShareTimeline() {
|
||||||
|
return {
|
||||||
|
title: config.share.timelineTitle
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const storage = require('../../utils/storage')
|
|||||||
const util = require('../../utils/util')
|
const util = require('../../utils/util')
|
||||||
const themeMod = require('../../utils/theme')
|
const themeMod = require('../../utils/theme')
|
||||||
const iconsMod = require('../../utils/icons')
|
const iconsMod = require('../../utils/icons')
|
||||||
|
const config = require('../../config')
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
@@ -163,5 +164,28 @@ Page({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享给朋友 — 训练记录页。把累计训练时长带进标题,
|
||||||
|
* 让分享卡片有点击欲(看到对方"已经练了 X 小时"会想点开)。
|
||||||
|
*/
|
||||||
|
onShareAppMessage() {
|
||||||
|
const stats = storage.getTotalStats()
|
||||||
|
const minutes = Math.round((stats.totalDuration || 0) / 60)
|
||||||
|
const s = config.share.records
|
||||||
|
return {
|
||||||
|
title: s.titleTemplate.replace('{minutes}', minutes),
|
||||||
|
path: s.path
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享到朋友圈。
|
||||||
|
*/
|
||||||
|
onShareTimeline() {
|
||||||
|
return {
|
||||||
|
title: config.share.timelineTitle
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -542,5 +542,26 @@ Page({
|
|||||||
wx.showToast({ title: '已恢复默认', icon: 'success', duration: 1200 })
|
wx.showToast({ title: '已恢复默认', icon: 'success', duration: 1200 })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享给朋友 — 设置页(很少有人会从这里分享,但微信要求每个 Page 都
|
||||||
|
* 实现钩子,否则对应页面的右上角菜单的转发按钮就是灰色的)。
|
||||||
|
*/
|
||||||
|
onShareAppMessage() {
|
||||||
|
const s = config.share.settings
|
||||||
|
return {
|
||||||
|
title: s.title,
|
||||||
|
path: s.path
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享到朋友圈。
|
||||||
|
*/
|
||||||
|
onShareTimeline() {
|
||||||
|
return {
|
||||||
|
title: config.share.timelineTitle
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
+24
-1
@@ -470,5 +470,28 @@ Page({
|
|||||||
// No-op handler for catchtouchmove. Swallows move events that would
|
// No-op handler for catchtouchmove. Swallows move events that would
|
||||||
// otherwise bubble to underlying timer page controls (causing missed
|
// otherwise bubble to underlying timer page controls (causing missed
|
||||||
// taps on the completion modal).
|
// taps on the completion modal).
|
||||||
onNoop() { /* swallow */ }
|
onNoop() { /* swallow */ },
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享给朋友。训练完成弹窗里的分享按钮会走到这里,标题里拼上用户
|
||||||
|
* 刚才撑了多久,转化率更高;右上角"···"菜单也共用同一份文案。
|
||||||
|
*/
|
||||||
|
onShareAppMessage() {
|
||||||
|
const elapsed = this.data.completionElapsed || this.data.duration
|
||||||
|
const s = config.share.timer
|
||||||
|
return {
|
||||||
|
title: s.titleTemplate.replace('{elapsed}', elapsed),
|
||||||
|
path: s.path
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享到朋友圈,同样带上刚完成的时长晒成绩。
|
||||||
|
*/
|
||||||
|
onShareTimeline() {
|
||||||
|
const elapsed = this.data.completionElapsed || this.data.duration
|
||||||
|
return {
|
||||||
|
title: config.share.timer.timelineTitleTemplate.replace('{elapsed}', elapsed)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -164,6 +164,16 @@
|
|||||||
<view class="completion-btn" bindtap="onViewRecords">
|
<view class="completion-btn" bindtap="onViewRecords">
|
||||||
<text>查看记录</text>
|
<text>查看记录</text>
|
||||||
</view>
|
</view>
|
||||||
|
<!-- openType="share" 会触发 Page.onShareAppMessage(已实现),
|
||||||
|
没有这个属性 + onShareAppMessage 时分享按钮就是灰色的。
|
||||||
|
ui-btn 透传 openType 到内部原生 button。 -->
|
||||||
|
<ui-btn
|
||||||
|
variant="ghost"
|
||||||
|
size="md"
|
||||||
|
customStyle="flex:1; height:88rpx;"
|
||||||
|
text="分享"
|
||||||
|
openType="share"
|
||||||
|
></ui-btn>
|
||||||
</view>
|
</view>
|
||||||
<view class="completion-btn completion-btn--text" bindtap="onCloseCompletion">
|
<view class="completion-btn completion-btn--text" bindtap="onCloseCompletion">
|
||||||
<text>回到首页</text>
|
<text>回到首页</text>
|
||||||
|
|||||||
Reference in New Issue
Block a user