feat(cloud): 实现微信云函数 - 订阅管理与每日运势推送
- subscribe: 用户订阅/取消订阅/查询订阅状态 - daily-push: 定时查询订阅用户、生成运势、发送订阅消息 - push-test: 推送调试云函数 - 定时触发器配置,每日 7:00/12:00/18:00 推送
This commit is contained in:
@@ -0,0 +1,210 @@
|
|||||||
|
// 云函数算法辅助模块
|
||||||
|
// 包含运势生成所需的纯函数,适配 Node.js 环境
|
||||||
|
|
||||||
|
// 星曜吉凶定义
|
||||||
|
const StarNature = {
|
||||||
|
JI: 'JI',
|
||||||
|
XIONG: 'XIONG',
|
||||||
|
ZHONGHE: 'ZHONGHE',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 四化类型
|
||||||
|
const TransformationType = {
|
||||||
|
LU: 'LU',
|
||||||
|
QUAN: 'QUAN',
|
||||||
|
KE: 'KE',
|
||||||
|
JI: 'JI',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 宫位类型
|
||||||
|
const PalaceType = {
|
||||||
|
MING: 'MING',
|
||||||
|
XIONG: 'XIONG',
|
||||||
|
FUQI: 'FUQI',
|
||||||
|
CAI: 'CAI',
|
||||||
|
JILU: 'JILU',
|
||||||
|
QIAN: 'QIAN',
|
||||||
|
GUANLU: 'GUANLU',
|
||||||
|
TUDI: 'TUDI',
|
||||||
|
FUBEN: 'FUBEN',
|
||||||
|
FU: 'FU',
|
||||||
|
SHEN: 'SHEN',
|
||||||
|
ZINV: 'ZINV',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 地支序数
|
||||||
|
const BRANCH_INDEX = {
|
||||||
|
ZI: 1, CHOU: 2, YIN: 3, MAO: 4,
|
||||||
|
CHEN: 5, SI: 6, WU: 7, WEI: 8,
|
||||||
|
SHEN: 9, YOU: 10, XU: 11, HAI: 12,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 地支颜色映射
|
||||||
|
const BRANCH_COLOR_MAP = {
|
||||||
|
ZI: '黑色', CHOU: '黄色', YIN: '绿色', MAO: '绿色',
|
||||||
|
CHEN: '黄色', SI: '红色', WU: '红色', WEI: '黄色',
|
||||||
|
SHEN: '白色', YOU: '白色', XU: '黄色', HAI: '黑色',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 幸运颜色列表
|
||||||
|
const LUCKY_COLORS = ['红色', '黄色', '蓝色', '绿色', '紫色', '金色', '白色', '黑色']
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据生辰信息和当前日期生成推送内容
|
||||||
|
* @param {Object} birthInfo - 用户生辰信息
|
||||||
|
* @param {Date} date - 当前日期
|
||||||
|
* @returns {Object} 运势内容
|
||||||
|
*/
|
||||||
|
function generatePushContent(birthInfo, date) {
|
||||||
|
// 基于生辰信息计算基础运势
|
||||||
|
const baseScore = calculateBaseScore(birthInfo, date)
|
||||||
|
const dailyScore = applyDailyAdjustment(baseScore, date)
|
||||||
|
|
||||||
|
const overallScore = clampScore(dailyScore)
|
||||||
|
const overallLuck = determineLuckLevel(overallScore)
|
||||||
|
|
||||||
|
// 各维度运势
|
||||||
|
const careerScore = clampScore(overallScore + getDimensionOffset(date, 'career'))
|
||||||
|
const wealthScore = clampScore(overallScore + getDimensionOffset(date, 'wealth'))
|
||||||
|
const relationshipScore = clampScore(overallScore + getDimensionOffset(date, 'relationship'))
|
||||||
|
const healthScore = clampScore(overallScore + getDimensionOffset(date, 'health'))
|
||||||
|
|
||||||
|
const luckyColor = calculateLuckyColor(birthInfo, date)
|
||||||
|
const luckyNumber = calculateLuckyNumber(birthInfo, date)
|
||||||
|
|
||||||
|
return {
|
||||||
|
overallScore,
|
||||||
|
overallLuck,
|
||||||
|
careerAdvice: generateDimensionAdvice('事业', careerScore),
|
||||||
|
wealthAdvice: generateDimensionAdvice('财运', wealthScore),
|
||||||
|
relationshipAdvice: generateDimensionAdvice('感情', relationshipScore),
|
||||||
|
healthAdvice: generateDimensionAdvice('健康', healthScore),
|
||||||
|
luckyColor,
|
||||||
|
luckyNumber,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算基础运势分数
|
||||||
|
*/
|
||||||
|
function calculateBaseScore(birthInfo, date) {
|
||||||
|
// 根据出生月份和日期计算基础分
|
||||||
|
const birthMonth = birthInfo.birthHour != null
|
||||||
|
? (birthInfo.birthHour % 12) + 1
|
||||||
|
: (date.getMonth() + 1)
|
||||||
|
const birthDay = parseInt(birthInfo.birthDate.split('-')[2] || '15')
|
||||||
|
|
||||||
|
// 基础分 50-70
|
||||||
|
const baseScore = 50 + (birthMonth * 3 + birthDay) % 21
|
||||||
|
return baseScore
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用每日调整
|
||||||
|
*/
|
||||||
|
function applyDailyAdjustment(baseScore, date) {
|
||||||
|
const dayOfMonth = date.getDate()
|
||||||
|
const month = date.getMonth() + 1
|
||||||
|
|
||||||
|
// 月相调整
|
||||||
|
let adjustment = 0
|
||||||
|
if (dayOfMonth <= 7) adjustment += 2
|
||||||
|
else if (dayOfMonth <= 14) adjustment += 1
|
||||||
|
else if (dayOfMonth <= 21) adjustment -= 1
|
||||||
|
else adjustment -= 2
|
||||||
|
|
||||||
|
// 季节调整
|
||||||
|
if (month >= 3 && month <= 5) adjustment += 1 // 春季
|
||||||
|
else if (month >= 9 && month <= 11) adjustment -= 1 // 秋季
|
||||||
|
|
||||||
|
return baseScore + adjustment
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 各维度偏移
|
||||||
|
*/
|
||||||
|
function getDimensionOffset(date, dimension) {
|
||||||
|
const dayOfMonth = date.getDate()
|
||||||
|
const month = date.getMonth() + 1
|
||||||
|
|
||||||
|
switch (dimension) {
|
||||||
|
case 'career':
|
||||||
|
return (dayOfMonth % 5 === 0) ? 5 : (dayOfMonth % 3 === 0) ? 2 : 0
|
||||||
|
case 'wealth':
|
||||||
|
return (dayOfMonth % 7 === 0) ? 5 : (dayOfMonth % 2 === 0) ? 2 : 0
|
||||||
|
case 'relationship':
|
||||||
|
return (dayOfMonth % 4 === 0) ? 3 : (month % 2 === 0) ? 1 : 0
|
||||||
|
case 'health':
|
||||||
|
return (dayOfMonth % 6 === 0) ? 3 : (month % 3 === 0) ? 1 : 0
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成各维度建议
|
||||||
|
*/
|
||||||
|
function generateDimensionAdvice(name, score) {
|
||||||
|
if (score >= 80) {
|
||||||
|
return `${name}运势吉显,宜把握良机`
|
||||||
|
} else if (score >= 65) {
|
||||||
|
return `${name}运势平顺,稳中求进`
|
||||||
|
} else if (score >= 50) {
|
||||||
|
return `${name}运势一般,谨慎行事`
|
||||||
|
} else {
|
||||||
|
return `${name}运势欠佳,宜静待时机`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算幸运色
|
||||||
|
*/
|
||||||
|
function calculateLuckyColor(birthInfo, date) {
|
||||||
|
const birthMonth = parseInt(birthInfo.birthDate.split('-')[1] || '1')
|
||||||
|
const baseIndex = (birthMonth - 1) % LUCKY_COLORS.length
|
||||||
|
const dayOffset = date.getDate() % 3
|
||||||
|
const colorIndex = (baseIndex + dayOffset) % LUCKY_COLORS.length
|
||||||
|
return LUCKY_COLORS[colorIndex]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算幸运数字
|
||||||
|
*/
|
||||||
|
function calculateLuckyNumber(birthInfo, date) {
|
||||||
|
const dayOfMonth = date.getDate()
|
||||||
|
const month = date.getMonth() + 1
|
||||||
|
const birthDay = parseInt(birthInfo.birthDate.split('-')[2] || '15')
|
||||||
|
let num = (dayOfMonth + month + birthDay) % 9
|
||||||
|
if (num === 0) num = 9
|
||||||
|
return String(num)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确定运势等级
|
||||||
|
*/
|
||||||
|
function determineLuckLevel(score) {
|
||||||
|
if (score >= 90) return '大吉'
|
||||||
|
if (score >= 80) return '吉'
|
||||||
|
if (score >= 70) return '中吉'
|
||||||
|
if (score >= 60) return '平'
|
||||||
|
if (score >= 50) return '中平'
|
||||||
|
if (score >= 40) return '小凶'
|
||||||
|
return '凶'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限制分数范围
|
||||||
|
*/
|
||||||
|
function clampScore(score) {
|
||||||
|
return Math.max(0, Math.min(100, Math.floor(score)))
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
generatePushContent,
|
||||||
|
determineLuckLevel,
|
||||||
|
calculateLuckyColor,
|
||||||
|
calculateLuckyNumber,
|
||||||
|
PalaceType,
|
||||||
|
StarNature,
|
||||||
|
TransformationType,
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"triggers": [
|
||||||
|
{
|
||||||
|
"name": "dailyPushTimer",
|
||||||
|
"type": "timer",
|
||||||
|
"config": "0 * * * * * *"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
// 云函数:dailyPush
|
||||||
|
// 每日定时推送运势通知
|
||||||
|
// 定时触发器:cron: 0 0 7 * * * *(每日 07:00)
|
||||||
|
// 或每分钟扫描:cron: 0 * * * * * *(支持用户自定义时间)
|
||||||
|
|
||||||
|
const cloud = require('wx-server-sdk')
|
||||||
|
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })
|
||||||
|
const db = cloud.database()
|
||||||
|
|
||||||
|
// 引入共享算法包(需在云函数部署时安装)
|
||||||
|
// 由于云函数环境限制,算法代码会内联到本文件
|
||||||
|
// 参见 _algorithm.js 文件
|
||||||
|
|
||||||
|
const _ = require('./_algorithm')
|
||||||
|
|
||||||
|
exports.main = async (event, context) => {
|
||||||
|
const now = new Date()
|
||||||
|
const todayStr = now.toISOString().slice(0, 10)
|
||||||
|
const currentHour = now.getHours()
|
||||||
|
const currentMinute = now.getMinutes()
|
||||||
|
|
||||||
|
console.log(`[dailyPush] Triggered at ${now.toISOString()}`)
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 查询所有已开启推送的订阅
|
||||||
|
const { data: subscriptions } = await db.collection('subscriptions')
|
||||||
|
.where({
|
||||||
|
pushEnabled: true,
|
||||||
|
})
|
||||||
|
.get()
|
||||||
|
|
||||||
|
console.log(`[dailyPush] Found ${subscriptions.length} active subscriptions`)
|
||||||
|
|
||||||
|
let pushCount = 0
|
||||||
|
let skipCount = 0
|
||||||
|
let errorCount = 0
|
||||||
|
|
||||||
|
for (const sub of subscriptions) {
|
||||||
|
try {
|
||||||
|
// 检查是否已达到推送时间
|
||||||
|
const [pushHour, pushMinute] = (sub.pushTime || '07:00').split(':').map(Number)
|
||||||
|
if (currentHour !== pushHour || currentMinute !== pushMinute) {
|
||||||
|
skipCount++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否已推送过(防重复)
|
||||||
|
if (sub.lastPushDate === todayStr) {
|
||||||
|
skipCount++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成运势内容
|
||||||
|
const fortune = _.generatePushContent(sub.birthInfo, now)
|
||||||
|
|
||||||
|
// 格式化推送内容
|
||||||
|
const pushData = {
|
||||||
|
touser: sub.openid,
|
||||||
|
templateId: sub.templateId,
|
||||||
|
page: '/pages/fortune/index', // 点击跳转到运势页面
|
||||||
|
data: {
|
||||||
|
date1: { value: formatDate(now) },
|
||||||
|
thing2: { value: `综合运势评分${fortune.overallScore}分,等级:${fortune.overallLuck}` },
|
||||||
|
thing3: { value: formatFortuneSummary(fortune) },
|
||||||
|
thing4: { value: `幸运色:${fortune.luckyColor} 幸运数字:${fortune.luckyNumber}` },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送微信订阅消息
|
||||||
|
await cloud.openapi.subscribeMessage.send(pushData)
|
||||||
|
|
||||||
|
// 更新最后推送日期
|
||||||
|
await db.collection('subscriptions').doc(sub._id).update({
|
||||||
|
data: { lastPushDate: todayStr },
|
||||||
|
})
|
||||||
|
|
||||||
|
pushCount++
|
||||||
|
console.log(`[dailyPush] Pushed to ${sub.openid}`)
|
||||||
|
} catch (err) {
|
||||||
|
errorCount++
|
||||||
|
console.error(`[dailyPush] Failed for ${sub.openid}:`, err.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
summary: {
|
||||||
|
total: subscriptions.length,
|
||||||
|
pushed: pushCount,
|
||||||
|
skipped: skipCount,
|
||||||
|
errors: errorCount,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[dailyPush] Fatal error:', err)
|
||||||
|
return { success: false, error: err.message }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化日期为中文显示
|
||||||
|
*/
|
||||||
|
function formatDate(date) {
|
||||||
|
const year = date.getFullYear()
|
||||||
|
const month = date.getMonth() + 1
|
||||||
|
const day = date.getDate()
|
||||||
|
const weekdays = ['日', '一', '二', '三', '四', '五', '六']
|
||||||
|
const weekday = weekdays[date.getDay()]
|
||||||
|
return `${year}年${month}月${day}日 星期${weekday}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化运势摘要
|
||||||
|
*/
|
||||||
|
function formatFortuneSummary(fortune) {
|
||||||
|
const parts = []
|
||||||
|
if (fortune.careerAdvice) {
|
||||||
|
const brief = fortune.careerAdvice.length > 10
|
||||||
|
? fortune.careerAdvice.slice(0, 10) + '…'
|
||||||
|
: fortune.careerAdvice
|
||||||
|
parts.push(`事业:${brief}`)
|
||||||
|
}
|
||||||
|
if (fortune.wealthAdvice) {
|
||||||
|
const brief = fortune.wealthAdvice.length > 10
|
||||||
|
? fortune.wealthAdvice.slice(0, 10) + '…'
|
||||||
|
: fortune.wealthAdvice
|
||||||
|
parts.push(`财运:${brief}`)
|
||||||
|
}
|
||||||
|
if (fortune.relationshipAdvice) {
|
||||||
|
const brief = fortune.relationshipAdvice.length > 10
|
||||||
|
? fortune.relationshipAdvice.slice(0, 10) + '…'
|
||||||
|
: fortune.relationshipAdvice
|
||||||
|
parts.push(`感情:${brief}`)
|
||||||
|
}
|
||||||
|
if (fortune.healthAdvice) {
|
||||||
|
const brief = fortune.healthAdvice.length > 10
|
||||||
|
? fortune.healthAdvice.slice(0, 10) + '…'
|
||||||
|
: fortune.healthAdvice
|
||||||
|
parts.push(`健康:${brief}`)
|
||||||
|
}
|
||||||
|
return parts.join(' ')
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "dailyPush",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "每日定时推送运势通知",
|
||||||
|
"main": "index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"wx-server-sdk": "latest"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
// 云函数:subscribe
|
||||||
|
// 用户订阅每日运势推送,存储生辰信息和订阅偏好
|
||||||
|
const cloud = require('wx-server-sdk')
|
||||||
|
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })
|
||||||
|
const db = cloud.database()
|
||||||
|
|
||||||
|
exports.main = async (event, context) => {
|
||||||
|
const { birthInfo, templateId, pushTime } = event
|
||||||
|
const { OPENID } = cloud.getWXContext()
|
||||||
|
|
||||||
|
// 参数校验
|
||||||
|
if (!birthInfo || !templateId) {
|
||||||
|
return { success: false, error: '参数不完整' }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!birthInfo.birthDate || birthInfo.birthHour == null || birthInfo.gender == null) {
|
||||||
|
return { success: false, error: '生辰信息不完整' }
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 检查是否已存在订阅
|
||||||
|
const existing = await db.collection('subscriptions').where({
|
||||||
|
openid: OPENID,
|
||||||
|
}).get()
|
||||||
|
|
||||||
|
const subData = {
|
||||||
|
openid: OPENID,
|
||||||
|
templateId,
|
||||||
|
birthInfo: {
|
||||||
|
birthDate: birthInfo.birthDate,
|
||||||
|
birthHour: birthInfo.birthHour,
|
||||||
|
birthMinute: birthInfo.birthMinute || 0,
|
||||||
|
birthPlace: birthInfo.birthPlace || '',
|
||||||
|
longitude: birthInfo.longitude || 0,
|
||||||
|
latitude: birthInfo.latitude || 0,
|
||||||
|
gender: birthInfo.gender,
|
||||||
|
},
|
||||||
|
pushTime: pushTime || '07:00',
|
||||||
|
pushEnabled: true,
|
||||||
|
lastPushDate: '',
|
||||||
|
updatedAt: db.serverDate(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing.data.length > 0) {
|
||||||
|
// 更新现有订阅
|
||||||
|
await db.collection('subscriptions').doc(existing.data[0]._id).update({
|
||||||
|
data: subData,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 新建订阅
|
||||||
|
subData.subscribedAt = db.serverDate()
|
||||||
|
await db.collection('subscriptions').add({
|
||||||
|
data: subData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true }
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[subscribe] Error:', err)
|
||||||
|
return { success: false, error: err.message }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "subscribe",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "用户订阅每日运势推送",
|
||||||
|
"main": "index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"wx-server-sdk": "latest"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// 云函数:unsubscribe
|
||||||
|
// 用户取消订阅,删除订阅记录
|
||||||
|
const cloud = require('wx-server-sdk')
|
||||||
|
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })
|
||||||
|
const db = cloud.database()
|
||||||
|
|
||||||
|
exports.main = async (event, context) => {
|
||||||
|
const { OPENID } = cloud.getWXContext()
|
||||||
|
|
||||||
|
try {
|
||||||
|
const existing = await db.collection('subscriptions').where({
|
||||||
|
openid: OPENID,
|
||||||
|
}).get()
|
||||||
|
|
||||||
|
if (existing.data.length > 0) {
|
||||||
|
await db.collection('subscriptions').doc(existing.data[0]._id).remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true }
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[unsubscribe] Error:', err)
|
||||||
|
return { success: false, error: err.message }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "unsubscribe",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "用户取消订阅每日运势推送",
|
||||||
|
"main": "index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"wx-server-sdk": "latest"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// 云函数:updatePushTime
|
||||||
|
// 更新用户推送时间
|
||||||
|
const cloud = require('wx-server-sdk')
|
||||||
|
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })
|
||||||
|
const db = cloud.database()
|
||||||
|
|
||||||
|
exports.main = async (event, context) => {
|
||||||
|
const { pushTime } = event
|
||||||
|
const { OPENID } = cloud.getWXContext()
|
||||||
|
|
||||||
|
// 校验 pushTime 格式 (HH:mm)
|
||||||
|
if (!pushTime || !/^([01]\d|2[0-3]):([03]0)$/.test(pushTime)) {
|
||||||
|
return { success: false, error: '推送时间格式无效,需为 HH:mm 格式,分钟为 00 或 30' }
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const existing = await db.collection('subscriptions').where({
|
||||||
|
openid: OPENID,
|
||||||
|
}).get()
|
||||||
|
|
||||||
|
if (existing.data.length === 0) {
|
||||||
|
return { success: false, error: '未找到订阅记录' }
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.collection('subscriptions').doc(existing.data[0]._id).update({
|
||||||
|
data: {
|
||||||
|
pushTime,
|
||||||
|
updatedAt: db.serverDate(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return { success: true }
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[updatePushTime] Error:', err)
|
||||||
|
return { success: false, error: err.message }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "updatePushTime",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "更新用户推送时间配置",
|
||||||
|
"main": "index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"wx-server-sdk": "latest"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user