一、云函数
1、rewarded-video-ad-notify-url
这个功能未知?是签到?视频ad的回调函数?
'use strict'; const uniADConfig = require('uni-config-center')({pluginId: 'uni-ad'}).config() const signIn = require('sign-in') let ip = null async function nextFn(data) { //写自己的业务逻辑 switch (data.extra) { case "uniSignIn": //签到 let {user_id} = data; await signIn({user_id,ip}) break; default: break; } return { "isValid": true //如果不返回,广点通会2次调用本云函数 } } const crypto = require('crypto'); const db = uniCloud.database(); exports.main = async (event, context) => { ip = context.CLIENTIP; //event为客户端上传的参数 console.log('event : ', event); const {path,queryStringParameters} = event; const data = { adpid: event.adpid, platform: event.platform, provider: event.provider, trans_id: event.trans_id, sign: event.sign, user_id: event.user_id, extra: event.extra, } // 注意::必须验签请求来源 const trans_id = event.trans_id; //去uni-config-center通过adpid获取secret const secret = uniADConfig[event.adpid] const sign2 = crypto.createHash('sha256').update(`${secret}:${trans_id}`).digest('hex'); if (event.sign !== sign2) { console.log('验签失败'); return null; } //自己的逻辑 try { return await nextFn(data) } catch (e) { console.error(e) return { "isValid": false } } };
2、uni-analyse-searchhot
服务端自动执行,每两小时自动执行一次
根据搜索记录,设定时间间隔来归纳出热搜数据并存储在热搜表中
'use strict'; exports.main = async (event, context) => { /** * 根据搜索记录,设定时间间隔来归纳出热搜数据并存储在热搜表中 */ const SEARCHHOT = 'opendb-search-hot'; // 热搜数据库名称 const SEARCHLOG = 'opendb-search-log'; // 搜索记录数据库名称 const SEARCHLOG_timeZone = 604800000; // 归纳搜索记录时间间隔,毫秒数,默认为最近7天 const SEARCHHOT_size = 10; // 热搜条数 const DB = uniCloud.database(); const DBCmd = DB.command; const $ = DB.command.aggregate; const SEARCHHOT_db = DB.collection(SEARCHHOT); const SEARCHLOG_db = DB.collection(SEARCHLOG); const timeEnd = Date.now() - SEARCHLOG_timeZone; let { data: searchHotData } = await SEARCHLOG_db .aggregate() .match({ create_date: DBCmd.gt(timeEnd) }) .group({ _id: { 'content': '$content', }, count: $.sum(1) }) .replaceRoot({ newRoot: $.mergeObjects(['$_id', '$$ROOT']) }) .project({ _id: false }) .sort({ count: -1 }) .end(); let now = Date.now(); searchHotData.map(item => { item.create_date = now; return item; }).slice(0, SEARCHHOT_size); // searchHotData = searchHotData.sort((a, b) => b.count - a.count).slice(0, SEARCHHOT_size); return searchHotData.length ? await SEARCHHOT_db.add(searchHotData) : '' };
这个数据库语法相当复杂!可当典型
3、uni-portal
统一发布页
'use strict'; const success = {success: true} const fail = {success: false} const createPublishHtml = require('./createPublishHtml') exports.main = async (event, context) => { //event为客户端上传的参数 console.log('event : ', event) let res = {}; let params = event.data || event.params; switch (event.action) { case 'createPublishHtml': res = createPublishHtml(params.id) break; } //返回数据给客户端 return res };
createPublishHtml
const fs = require('fs') const path = require('path') const TE = require('./lib/art-template.js'); // 标准语法的界定符规则 TE.defaults.openTag = '{@' TE.defaults.closeTag = '@}' const success = { success: true } const fail = { success: false } async function translateTCB(_fileList = []) { if (!_fileList.length) return _fileList // 腾讯云和阿里云下载链接不同,需要处理一下,阿里云会原样返回 const { fileList } = await uniCloud.getTempFileURL({ fileList: _fileList }); return fileList.map((item, index) => item.tempFileURL ? item.tempFileURL : _fileList[index]) } function hasValue(value) { if (typeof value !== 'object') return !!value if (value instanceof Array) return !!value.length return !!(value && Object.keys(value).length) } module.exports = async function(id) { if (!id) { return { ...fail, code: -1, errMsg: 'id required' }; } // 根据sitemap配置加载页面模板,例如列表页,详情页 let templatePage = fs.readFileSync(path.resolve(__dirname, './template.html'), 'utf8'); if (!templatePage) { return { ...fail, code: -2, errMsg: 'page template no found' }; } const db = uniCloud.database() let dbPublishList try { dbPublishList = db.collection('opendb-app-list') } catch (e) {} if (!dbPublishList) return fail; const record = await dbPublishList.where({ _id: id }).get({ getOne: true }) if (record && record.data && record.data.length) { const appInfo = record.data[0] const defaultOptions = { hasApp: false, hasMP: false, hasH5: false, hasQuickApp: false } defaultOptions.mpNames = { 'mp_weixin': '微信', 'mp_alipay': '支付宝', 'mp_baidu': '百度', 'mp_toutiao': '字节', 'mp_qq': 'QQ', 'mp_dingtalk': '钉钉', 'mp_kuaishou': '快手', 'mp_lark': '飞书', 'mp_jd': '京东' } const imageList = []; ['app_android'].forEach(key => { if (!hasValue(appInfo[key])) return imageList.push({ key, urlKey: 'url', url: appInfo[key].url }) }) Object.keys(defaultOptions.mpNames).concat('quickapp').forEach(key => { if (!hasValue(appInfo[key])) return imageList.push({ key, urlKey: 'qrcode_url', url: appInfo[key].qrcode_url }) }); ['icon_url'].forEach(key => { if (!hasValue(appInfo[key])) return imageList.push({ key, url: appInfo[key] }) }) const filelist = await translateTCB(imageList.map(item => item.url)) imageList.forEach((item, index) => { if (item.urlKey) { appInfo[item.key][item.urlKey] = filelist[index] } else { appInfo[item.key] = filelist[index] } }) if (hasValue(appInfo.screenshot)) { appInfo.screenshot = await translateTCB(appInfo.screenshot) } { const appInfoKeys = Object.keys(appInfo) if (appInfoKeys.some(key => { return key.indexOf('app_') !== -1 && hasValue(appInfo[key]) })) { defaultOptions.hasApp = true } if (appInfoKeys.some(key => { return key.indexOf('mp') !== -1 && hasValue(appInfo[key]) })) { defaultOptions.hasMP = true } if (appInfo.h5 && appInfo.h5.url) { defaultOptions.hasH5 = true } if (appInfo.quickapp && appInfo.quickapp.qrcode_url) { defaultOptions.hasQuickApp = true } // app if (defaultOptions.hasApp && appInfo.app_android && appInfo.app_android.url) { defaultOptions.android_url = appInfo.app_android.url } else { defaultOptions.android_url = '' } if (defaultOptions.hasApp && appInfo.app_ios && appInfo.app_ios.url) { defaultOptions.ios_url = appInfo.app_ios.url } else { defaultOptions.ios_url = '' } // mp defaultOptions.mpKeys = Object.keys(appInfo).filter(key => { return key.indexOf('mp') !== -1 && hasValue(appInfo[key]) }) } const html = TE.render(templatePage)(Object.assign({}, appInfo, defaultOptions)); if (!(defaultOptions.hasApp || defaultOptions.hasH5 || defaultOptions.hasMP || defaultOptions .hasQuickApp)) { return { ...fail, code: -100, errMsg: '缺少应用信息,App、小程序、H5、快应用请至少填写一项' } } return { ...success, mpserverlessComposedResponse: true, // 使用阿里云返回集成响应是需要此字段为true statusCode: 200, headers: { 'content-type': 'text/html' }, body: html }; } return { ...fail, code: -3, errMsg: 'no record' }; }
4、uni-stat-cron
在服务器上运行,每个小时执行一次,整点执行。统计专用???
'use strict'; const uniStat = require('uni-stat') exports.main = async (event, context) => { //数据跑批处理函数 return await uniStat.initStat().cron(context) };
uni-stat
const { createApi } = require('./shared/index') let reportDataReceiver, dataStatCron module.exports = { //uni统计数据上报数据接收器初始化 initReceiver: (options = {}) => { if(!reportDataReceiver) { reportDataReceiver = require('./stat/receiver') } options.clientType = options.clientType || __ctx__.PLATFORM return createApi(reportDataReceiver, options) }, //uni统计数据统计模块初始化 initStat: (options = {}) => { if(!dataStatCron) { dataStatCron = require('./stat/stat') } options.clientType = options.clientType || __ctx__.PLATFORM return createApi(dataStatCron, options) } }
end
5、uni-upgrade-center
升级,客户端运行
'use strict'; const success = { success: true } const fail = { success: false } const checkVersion = require('./checkVersion') exports.main = async (event, context) => { //event为客户端上传的参数 const db = uniCloud.database() const appListDBName = 'opendb-app-list' const appVersionDBName = 'opendb-app-versions' let res = {}; if (event.headers) { try { if (event.httpMethod.toLocaleLowerCase() === 'get') { event = event.queryStringParameters; } else { event = JSON.parse(event.body); } } catch (e) { return { code: 500, msg: '请求错误' }; } } let params = event.data || event.params; switch (event.action) { case 'checkVersion': res = await checkVersion(event, context) break; case 'deleteFile': res = await uniCloud.deleteFile({ fileList: params.fileList }) break; case 'setNewAppData': params.value.create_date = Date.now() res = await db.collection(appListDBName).doc(params.id).set(params.value) break; case 'getAppInfo': let dbAppList try { dbAppList = db.collection(appListDBName) } catch (e) {} if (!dbAppList) return fail; const dbAppListRecord = await dbAppList.where({ appid: params.appid }).get() if (dbAppListRecord && dbAppListRecord.data.length) return Object.assign({}, success, dbAppListRecord.data[0]) //返回数据给客户端 return fail break; case 'getAppVersionInfo': let dbVersionList try { dbVersionList = db.collection(appVersionDBName) } catch (e) {} if (!dbVersionList) return fail; const dbVersionListrecord = await dbVersionList.where({ appid: params.appid, platform: params.platform, type: "native_app", stable_publish: true }) .orderBy('create_date', 'desc') .get(); if (dbVersionListrecord && dbVersionListrecord.data && dbVersionListrecord.data.length > 0) return Object.assign({}, dbVersionListrecord.data[0], success) return fail break; } //返回数据给客户端 return res };
客户端 /uni_modules/uni-upgrade-center-app/utils/call-check-version.js
export default function() { // #ifdef APP-PLUS return new Promise((resolve, reject) => { plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) { const data = { action: 'checkVersion', appid: plus.runtime.appid, appVersion: plus.runtime.version, wgtVersion: widgetInfo.version } console.log("data: ",data); uniCloud.callFunction({ name: 'uni-upgrade-center', data, success: (e) => { console.log("e: ", e); resolve(e) }, fail: (error) => { reject(error) } }) }) }) // #endif // #ifndef APP-PLUS return new Promise((resolve, reject) => { reject({ message: '请在App中使用' }) }) // #endif }
end
二、云对象
1、uni-captcha-co
说明:图形验证码
服务器代码
// 开发文档: https://uniapp.dcloud.net.cn/uniCloud/cloud-obj
//导入验证码公共模块
const uniCaptcha = require('uni-captcha')
//获取数据库对象
const db = uniCloud.database();
//获取数据表opendb-verify-codes对象
const verifyCodes = db.collection('opendb-verify-codes')
module.exports = {
async getImageCaptcha({
scene
}) {
//获取设备id
let {
deviceId,
platform
} = this.getClientInfo();
//根据:设备id、场景值、状态,查找记录是否存在
let res = await verifyCodes.where({
scene,
deviceId,
state: 0
}).limit(1).get()
//如果已存在则调用刷新接口,反之调用插件接口
let action = res.data.length ? 'refresh' : 'create'
//执行并返回结果
//导入配置,配置优先级说明:此处配置 > uni-config-center
return await uniCaptcha[action]({
scene, //来源客户端传递,表示:使用场景值,用于防止不同功能的验证码混用
uniPlatform: platform
})
}
}
客户端调用:/uni_modules/uni-captcha/components/uni-captcha/uni-captcha.vue
定义对象
const uniIdCo = uniCloud.importObject("uni-captcha-co", {
customUI: true
})
getImageCaptcha方法
说明
uniIdCo.getImageCaptcha({ scene: this.scene }).then(result => { // console.log(result); this.captchaBase64 = result.captchaBase64 }) .catch(e => { uni.showToast({ title: e.message, icon: 'none' }); }).finally(e => { this.loging = false })
输入参数:
这个要试一下!
2、uni-open-bridge???
服务器代码
'use strict';
const {
PlatformType
} = require('./consts.js')
const runTask = require('./index.task.js')
const weixinCommand = require('./index.mp-weixin.js')
async function executeCommand() {
const methodName = this.getMethodName()
const parameters = JSON.parse(this.getHttpInfo().body)
if (parameters.platform === PlatformType.MP_WEIXIN) {
return await weixinCommand.execute(methodName, parameters)
}
throw new Error('Invalid Platform')
}
module.exports = {
async _timing() {
console.log('triggered by timing')
await runTask()
},
async _before() {
const clientInfo = this.getClientInfo()
if (!weixinCommand.checkIP(clientInfo.clientIP)) {
throw new Error("Invalid IP:" + clientInfo.clientIP)
}
},
// async runTask() {
// await runTask()
// },
async getAccessToken() {
return await executeCommand.call(this)
},
async setAccessToken() {
return await executeCommand.call(this)
},
async removeAccessToken() {
return await executeCommand.call(this)
},
async getUserKey() {
return await executeCommand.call(this)
},
async setUserKey() {
return await executeCommand.call(this)
},
async removeUserKey() {
return await executeCommand.call(this)
},
async getTicket() {
return await executeCommand.call(this)
},
async setTicket() {
return await executeCommand.call(this)
},
async removeTicket() {
return await executeCommand.call(this)
}
}
客户端无
3、uni-stat-receiver
功能可能是统计
服务器代码:
const uniStat = require('uni-stat')
const uniID = require('uni-id-common')
module.exports = {
report: async function (params = {}) {
//客户端信息
const clientInfo = this.getClientInfo()
//云服务信息
const cloudInfo = this.getCloudInfo()
//token信息
const token = this.getUniIdToken()
//当前登录用户id
let uid
if(token) {
const tokenRes = await uniID.createInstance({
clientInfo
}).checkToken(token)
if(tokenRes.uid) {
uid = tokenRes.uid
}
}
//数据上报
return await uniStat.initReceiver().report(params, {
...clientInfo,
...cloudInfo,
uid
})
}
}
客户端无
4、uni-sms-co
服务器代码:
// 云对象教程: https://uniapp.dcloud.net.cn/uniCloud/cloud-obj
// jsdoc语法提示教程:https://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/129
const createConfig = require('uni-config-center')
const buildTemplateData = require('./build-template-data')
const { parserDynamicField, checkIsStaticTemplate } = require('./utils')
const schemaNameAdapter = require('./schema-name-adapter')
const uniSmsCo = uniCloud.importObject('uni-sms-co')
const db = uniCloud.database()
const smsConfig = createConfig({
pluginId: 'uni-sms-co'
}).config()
function errCode(code) {
return 'uni-sms-co-' + code
}
const tableNames = {
template: 'opendb-sms-template',
task: 'opendb-sms-task',
log: 'opendb-sms-log'
}
module.exports = {
_before: async function () { // 通用预处理器
if (!smsConfig.smsKey || smsConfig.smsKey.length <= 20 || !smsConfig.smsSecret || smsConfig.smsSecret.length <= 20) {
throw new Error('请先配置smsKey和smsSecret')
}
this.tableNames = tableNames
/**
* 优化 schema 的命名规范,需要兼容 uni-admin@2.1.6 以下版本
* 如果是在uni-admin@2.1.6版本以上创建的项目可以将其注释
* */
await schemaNameAdapter.call(this)
},
_after: function (error, result) {
if (error) {
if (error instanceof Error) {
return {
errCode: 'error',
errMsg: error.message
}
}
if (error.errCode) {
return error
}
throw error
}
return result
},
/**
* 创建短信任务
* @param {Object} to
* @param {Boolean} to.all=false 全部用户发送
* @param {String} to.type=user to.all=true时用来区分发送类型
* @param {Array} to.receiver 用户ID's / 用户标签ID's
* @param {String} templateId 短信模板ID
* @param {Array} templateData 短信模板数据
* @param {String} options.taskName 任务名称
*/
async createSmsTask(to, templateId, templateData, options = {}) {
if (!templateId) {
return {
errCode: errCode('template-id-required'),
errMsg: '缺少templateId'
}
}
if (!to.all && (!to.receiver || to.receiver.length <= 0)) {
return {
errCode: errCode('send-users-is-null'),
errMsg: '请选择要发送的用户'
}
}
const clientInfo = this.getClientInfo()
const {data: templates} = await db.collection(this.tableNames.template).where({_id: templateId}).get()
if (templates.length <= 0) {
return {
errCode: errCode('template-not-found'),
errMsg: '短信模板不存在'
}
}
const [template] = templates
// 创建短信任务
const task = await db.collection(this.tableNames.task).add({
app_id: clientInfo.appId,
name: options.taskName,
template_id: templateId,
template_contnet: template.content,
vars: templateData,
to,
send_qty: 0,
success_qty: 0,
fail_qty: 0,
create_date: Date.now()
})
uniSmsCo.createUserSmsMessage(task.id)
return new Promise(resolve => setTimeout(() => resolve({
errCode: 0,
errMsg: '任务创建成功',
taskId: task.id
}), 300))
},
async createUserSmsMessage(taskId, execData = {}) {
const parallel = 100
let beforeId
const { data: tasks } = await db.collection(this.tableNames.task).where({ _id: taskId }).get()
if (tasks.length <= 0) {
return {
errCode: errCode('task-id-not-found'),
errMsg: '任务ID不存在'
}
}
const [task] = tasks
const query = {
mobile: db.command.exists(true)
}
// 指定用户发送
if (!task.to.all && task.to.type === 'user') {
let index = 0
if (execData.beforeId) {
const i = task.to.receiver.findIndex(id => id === execData.beforeId)
index = i !== -1 ? i + 1 : 0
}
const receiver = task.to.receiver.slice(index, index + parallel)
query._id = db.command.in(receiver)
beforeId = receiver[receiver.length - 1]
}
// 指定用户标签
if (task.to.type === 'userTags') {
query.tags = db.command.in(task.to.receiver)
}
// 全部用户
if (task.to.all && execData.beforeId) {
query._id = db.command.gt(execData.beforeId)
}
// 动态数据仅支持uni-id-users表字段
const dynamicField = parserDynamicField(task.vars)
const userFields = dynamicField['uni-id-users'] ? dynamicField['uni-id-users'].reduce((res, field) => {
res[field] = true
return res
}, {}): {}
const { data: users } = await db.collection('uni-id-users')
.where(query)
.field({
mobile: true,
...userFields
})
.limit(parallel)
.orderBy('_id', 'asc')
.get()
if (users.length <= 0) {
// 更新要发送的短信数量
const count = await db.collection(this.tableNames.log).where({ task_id: taskId }).count()
await db.collection(this.tableNames.task).where({ _id: taskId }).update({
send_qty: count.total
})
// 开始发送
uniSmsCo.sendSms(taskId)
return new Promise(resolve => setTimeout(() => resolve({
errCode: 0,
errMsg: '创建完成'
}), 500))
}
if (!beforeId) {
beforeId = users[users.length - 1]._id
}
let docs = []
for (const user of users) {
const varData = await buildTemplateData(task.vars, user)
docs.push({
uid: user._id,
task_id: taskId,
mobile: user.mobile,
var_data: varData,
status: 0,
create_date: Date.now()
})
}
await db.collection(this.tableNames.log).add(docs)
uniSmsCo.createUserSmsMessage(taskId, { beforeId })
return new Promise(resolve => setTimeout(() => resolve(), 500))
},
async sendSms(taskId) {
const { data: tasks } = await db.collection(this.tableNames.task).where({ _id: taskId }).get()
if (tasks.length <= 0) {
console.warn(`task [${taskId}] not found`)
return
}
const [task] = tasks
const isStaticTemplate = !task.vars.length
let sendData = {
appId: task.app_id,
smsKey: smsConfig.smsKey,
smsSecret: smsConfig.smsSecret,
templateId: task.template_id,
data: {}
}
const { data: records } = await db.collection(this.tableNames.log)
.where({ task_id: taskId, status: 0 })
.limit(isStaticTemplate ? 50 : 1)
.field({ mobile: true, var_data: true })
.get()
if (records.length <= 0) {
return {
errCode: 0,
errMsg: '发送完成'
}
}
if (isStaticTemplate) {
sendData.phoneList = records.reduce((res, user) => {
res.push(user.mobile)
return res
}, [])
} else {
const [record] = records
sendData.phone = record.mobile
sendData.data = record.var_data
}
try {
// await sendSms(sendData)
await uniCloud.sendSms(sendData)
// 修改发送状态为已发送
await db.collection(this.tableNames.log).where({
_id: db.command.in(records.map(record => record._id))
}).update({
status: 1,
send_date: Date.now()
})
// 更新任务的短信成功数
await db.collection(this.tableNames.task).where({ _id: taskId })
.update({
success_qty: db.command.inc(records.length)
})
} catch (e) {
console.error('[sendSms Fail]', e)
// 修改发送状态为发送失败
await db.collection(this.tableNames.log).where({
_id: db.command.in(records.map(record => record._id))
}).update({
status: 2,
reason: e.errMsg || '未知原因',
send_date: Date.now()
})
// 更新任务的短信失败数
await db.collection(this.tableNames.task).where({ _id: taskId })
.update({
fail_qty: db.command.inc(records.length)
})
}
uniSmsCo.sendSms(taskId)
return new Promise(resolve => setTimeout(() => resolve(), 500))
},
async template() {
const {data: templates = []} = await db.collection(this.tableNames.template).get()
return templates
},
async task (id) {
const {data: tasks} = await db.collection(this.tableNames.task).where({_id: id}).get()
if (tasks.length <= 0) {
return null
}
return tasks[0]
},
async updateTemplates (templates) {
if (templates.length <= 0) {
return {
errCode: errCode('template-is-null'),
errMsg: '缺少模板信息'
}
}
let group = []
for (const template of templates) {
group.push(
db.collection(this.tableNames.template).doc(String(template.templateId)).set({
name: template.templateName,
content: template.templateContent,
type: template.templateType,
sign: template.templateSign
})
)
}
await Promise.all(group)
return {
errCode: 0,
errMsg: '更新成功'
}
},
async preview (to, templateId, templateData) {
const count = 1
let query = {
mobile: db.command.exists(true)
}
// 指定用户发送
if (!to.all && to.type === 'user') {
const receiver = to.receiver.slice(0, 10)
query._id = db.command.in(receiver)
}
// 指定用户标签
if (to.type === 'userTags') {
query.tags = db.command.in(to.receiver)
}
const {data: users} = await db.collection('uni-id-users').where(query).limit(count).get()
console.log({users, query})
if (users.length <= 0) {
return {
errCode: errCode('users-is-null'),
errMsg: '请添加要发送的用户'
}
}
const {data: templates} = await db.collection(this.tableNames.template).where({_id: templateId}).get()
if (templates.length <= 0) {
return {
errCode: errCode('template-not-found'),
errMsg: '模板不存在'
}
}
const [template] = templates
let docs = []
for (const user of users) {
const varData = buildTemplateData(templateData, user)
const content = template.content.replace(/\$\{(.*?)\}/g, ($1, param) => varData[param] || $1)
docs.push(`【${template.sign}】${content}`)
}
return {
errCode: 0,
errMsg: '',
list: docs
}
}
}
createSmsTask
- 创建短信任务
- @param {Object} to
- @param {Boolean} to.all=false 全部用户发送
- @param {String} to.type=user to.all=true时用来区分发送类型
- @param {Array} to.receiver 用户ID’s / 用户标签ID’s
- @param {String} templateId 短信模板ID
- @param {Array} templateData 短信模板数据
- @param {String} options.taskName 任务名称
没有测过
async createSmsTask(to, templateId, templateData, options = {}) { if (!templateId) { return { errCode: errCode('template-id-required'), errMsg: '缺少templateId' } } if (!to.all && (!to.receiver || to.receiver.length <= 0)) { return { errCode: errCode('send-users-is-null'), errMsg: '请选择要发送的用户' } } const clientInfo = this.getClientInfo() const {data: templates} = await db.collection(this.tableNames.template).where({_id: templateId}).get() if (templates.length <= 0) { return { errCode: errCode('template-not-found'), errMsg: '短信模板不存在' } } const [template] = templates // 创建短信任务 const task = await db.collection(this.tableNames.task).add({ app_id: clientInfo.appId, name: options.taskName, template_id: templateId, template_contnet: template.content, vars: templateData, to, send_qty: 0, success_qty: 0, fail_qty: 0, create_date: Date.now() }) uniSmsCo.createUserSmsMessage(task.id) return new Promise(resolve => setTimeout(() => resolve({ errCode: 0, errMsg: '任务创建成功', taskId: task.id }), 300)) },
createUserSmsMessage
功能未测,应该是发短信用任务id
async createUserSmsMessage(taskId, execData = {}) { const parallel = 100 let beforeId const { data: tasks } = await db.collection(this.tableNames.task).where({ _id: taskId }).get() if (tasks.length <= 0) { return { errCode: errCode('task-id-not-found'), errMsg: '任务ID不存在' } } const [task] = tasks const query = { mobile: db.command.exists(true) } // 指定用户发送 if (!task.to.all && task.to.type === 'user') { let index = 0 if (execData.beforeId) { const i = task.to.receiver.findIndex(id => id === execData.beforeId) index = i !== -1 ? i + 1 : 0 } const receiver = task.to.receiver.slice(index, index + parallel) query._id = db.command.in(receiver) beforeId = receiver[receiver.length - 1] } // 指定用户标签 if (task.to.type === 'userTags') { query.tags = db.command.in(task.to.receiver) } // 全部用户 if (task.to.all && execData.beforeId) { query._id = db.command.gt(execData.beforeId) } // 动态数据仅支持uni-id-users表字段 const dynamicField = parserDynamicField(task.vars) const userFields = dynamicField['uni-id-users'] ? dynamicField['uni-id-users'].reduce((res, field) => { res[field] = true return res }, {}): {} const { data: users } = await db.collection('uni-id-users') .where(query) .field({ mobile: true, ...userFields }) .limit(parallel) .orderBy('_id', 'asc') .get() if (users.length <= 0) { // 更新要发送的短信数量 const count = await db.collection(this.tableNames.log).where({ task_id: taskId }).count() await db.collection(this.tableNames.task).where({ _id: taskId }).update({ send_qty: count.total }) // 开始发送 uniSmsCo.sendSms(taskId) return new Promise(resolve => setTimeout(() => resolve({ errCode: 0, errMsg: '创建完成' }), 500)) } if (!beforeId) { beforeId = users[users.length - 1]._id } let docs = [] for (const user of users) { const varData = await buildTemplateData(task.vars, user) docs.push({ uid: user._id, task_id: taskId, mobile: user.mobile, var_data: varData, status: 0, create_date: Date.now() }) } await db.collection(this.tableNames.log).add(docs) uniSmsCo.createUserSmsMessage(taskId, { beforeId }) return new Promise(resolve => setTimeout(() => resolve(), 500)) },
sendSms
以任务号发短信,未测
async sendSms(taskId) { const { data: tasks } = await db.collection(this.tableNames.task).where({ _id: taskId }).get() if (tasks.length <= 0) { console.warn(`task [${taskId}] not found`) return } const [task] = tasks const isStaticTemplate = !task.vars.length let sendData = { appId: task.app_id, smsKey: smsConfig.smsKey, smsSecret: smsConfig.smsSecret, templateId: task.template_id, data: {} } const { data: records } = await db.collection(this.tableNames.log) .where({ task_id: taskId, status: 0 }) .limit(isStaticTemplate ? 50 : 1) .field({ mobile: true, var_data: true }) .get() if (records.length <= 0) { return { errCode: 0, errMsg: '发送完成' } } if (isStaticTemplate) { sendData.phoneList = records.reduce((res, user) => { res.push(user.mobile) return res }, []) } else { const [record] = records sendData.phone = record.mobile sendData.data = record.var_data } try { // await sendSms(sendData) await uniCloud.sendSms(sendData) // 修改发送状态为已发送 await db.collection(this.tableNames.log).where({ _id: db.command.in(records.map(record => record._id)) }).update({ status: 1, send_date: Date.now() }) // 更新任务的短信成功数 await db.collection(this.tableNames.task).where({ _id: taskId }) .update({ success_qty: db.command.inc(records.length) }) } catch (e) { console.error('[sendSms Fail]', e) // 修改发送状态为发送失败 await db.collection(this.tableNames.log).where({ _id: db.command.in(records.map(record => record._id)) }).update({ status: 2, reason: e.errMsg || '未知原因', send_date: Date.now() }) // 更新任务的短信失败数 await db.collection(this.tableNames.task).where({ _id: taskId }) .update({ fail_qty: db.command.inc(records.length) }) } uniSmsCo.sendSms(taskId) return new Promise(resolve => setTimeout(() => resolve(), 500)) }
template/task/updateTemplates
功能不清楚:
async template() { const {data: templates = []} = await db.collection(this.tableNames.template).get() return templates }, async task (id) { const {data: tasks} = await db.collection(this.tableNames.task).where({_id: id}).get() if (tasks.length <= 0) { return null } return tasks[0] }, async updateTemplates (templates) { if (templates.length <= 0) { return { errCode: errCode('template-is-null'), errMsg: '缺少模板信息' } } let group = [] for (const template of templates) { group.push( db.collection(this.tableNames.template).doc(String(template.templateId)).set({ name: template.templateName, content: template.templateContent, type: template.templateType, sign: template.templateSign }) ) } await Promise.all(group) return { errCode: 0, errMsg: '更新成功' } },
preview
未用
async preview (to, templateId, templateData) { const count = 1 let query = { mobile: db.command.exists(true) } // 指定用户发送 if (!to.all && to.type === 'user') { const receiver = to.receiver.slice(0, 10) query._id = db.command.in(receiver) } // 指定用户标签 if (to.type === 'userTags') { query.tags = db.command.in(to.receiver) } const {data: users} = await db.collection('uni-id-users').where(query).limit(count).get() console.log({users, query}) if (users.length <= 0) { return { errCode: errCode('users-is-null'), errMsg: '请添加要发送的用户' } } const {data: templates} = await db.collection(this.tableNames.template).where({_id: templateId}).get() if (templates.length <= 0) { return { errCode: errCode('template-not-found'), errMsg: '模板不存在' } } const [template] = templates let docs = [] for (const user of users) { const varData = buildTemplateData(templateData, user) const content = template.content.replace(/\$\{(.*?)\}/g, ($1, param) => varData[param] || $1) docs.push(`【${template.sign}】${content}`) } return { errCode: 0, errMsg: '', list: docs } }