uni-starter214(八)云函数云对象

一、云函数

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
    }
  }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值