5 changed files with 408 additions and 0 deletions
@ -0,0 +1,75 @@ |
|||||
|
'use strict' |
||||
|
|
||||
|
module.exports = dc => { |
||||
|
const DataTypes = dc.ORM |
||||
|
|
||||
|
const WorkOrderNotice = dc.orm.define( |
||||
|
'workOrderNotice', |
||||
|
{ |
||||
|
id: { |
||||
|
field: 'id', |
||||
|
type: dc.ORM.INTEGER, |
||||
|
primaryKey: true, |
||||
|
unique: true, |
||||
|
allowNull: false, |
||||
|
autoIncrement: true, |
||||
|
unique: 'work_order_notice_pk', |
||||
|
}, |
||||
|
planTime: { |
||||
|
field: 'plan_time', |
||||
|
type: DataTypes.DATE, |
||||
|
allowNull: true, |
||||
|
comment: '', |
||||
|
primaryKey: false, |
||||
|
autoIncrement: false, |
||||
|
}, |
||||
|
processingPersonnelId: { |
||||
|
field: 'processing_personnel_id', |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: true, |
||||
|
comment: '', |
||||
|
primaryKey: false, |
||||
|
autoIncrement: false, |
||||
|
}, |
||||
|
processingPersonnelPhone: { |
||||
|
field: 'processing_personnel_phone', |
||||
|
type: DataTypes.STRING, |
||||
|
allowNull: true, |
||||
|
comment: '', |
||||
|
primaryKey: false, |
||||
|
autoIncrement: false, |
||||
|
}, |
||||
|
isSend: { |
||||
|
field: 'is_send', |
||||
|
type: DataTypes.BOOLEAN, |
||||
|
allowNull: true, |
||||
|
comment: '', |
||||
|
primaryKey: false, |
||||
|
autoIncrement: false, |
||||
|
}, |
||||
|
procinstId: { |
||||
|
field: 'procinst_id', |
||||
|
type: DataTypes.STRING, |
||||
|
allowNull: true, |
||||
|
comment: '', |
||||
|
primaryKey: false, |
||||
|
autoIncrement: false, |
||||
|
}, |
||||
|
haveDone: { |
||||
|
field: 'have_done', |
||||
|
type: DataTypes.BOOLEAN, |
||||
|
allowNull: true, |
||||
|
comment: '', |
||||
|
primaryKey: false, |
||||
|
autoIncrement: false, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
tableName: 'work_order_notice', |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
dc.models.WorkOrderNotice = WorkOrderNotice |
||||
|
|
||||
|
return WorkOrderNotice |
||||
|
} |
@ -0,0 +1,189 @@ |
|||||
|
/** |
||||
|
* 运维中台售后问题处理工单,根据计划修复时间(pa3aGiey3N),发送企业微信通知,因为不是必填项,没有填写的不推送!!!! |
||||
|
*1.已完成的工单 |
||||
|
* 根据表单数据中的是否已完成字段(Solution_Status)判断,该单子是否推送通知, |
||||
|
* 已完成的不推送,未完成的推送通知 |
||||
|
* 推送给处理人(Processing_Personnel) |
||||
|
* 2.未完成的工单 |
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
const schedule = require('node-schedule') |
||||
|
const moment = require('moment') |
||||
|
const request = require('superagent') |
||||
|
let isDev = false |
||||
|
isDev = true |
||||
|
const sendType = { |
||||
|
'mini': 'miniprogram_notice', |
||||
|
} |
||||
|
|
||||
|
module.exports = function (app, opts) { |
||||
|
const workOrderNotice = app.fs.scheduleInit( |
||||
|
{ |
||||
|
interval: '0 * * * *',//一小时执行一次
|
||||
|
immediate: isDev, |
||||
|
proRun: !isDev, |
||||
|
}, |
||||
|
async () => { |
||||
|
try { |
||||
|
//前一次执行时间
|
||||
|
console.log('运维中台售后问题处理工单数据抽取开始', moment().format('YYYY-MM-DD HH:mm:ss')) |
||||
|
const { parseProcessData,getUserId,sendWechat } = app.fs.utils |
||||
|
const startTime = moment().format('YYYY-MM-DD HH:mm:ss') |
||||
|
const { models } = app.fs.dc |
||||
|
const { clickHouse } = app.fs |
||||
|
const { database: camWorkflow } = clickHouse.camWorkflow.opts.config |
||||
|
const formRes = await clickHouse.pepEmis.query( |
||||
|
`SELECT
|
||||
|
story.id AS historyId, |
||||
|
story.procinst_id as procinstId, |
||||
|
story.apply_user AS pepUserId, |
||||
|
story.form_data AS formData, |
||||
|
story.submit_form_data AS submitFormData, |
||||
|
story.create_at as createTime, |
||||
|
fform.form_schema AS formSchema, |
||||
|
fprocess.name AS processName, |
||||
|
procin.state_ AS state, |
||||
|
procin.end_time_ as endTime, |
||||
|
fform.id AS formId, |
||||
|
fversion.id AS versionId, |
||||
|
fgroup.name AS groupName |
||||
|
FROM |
||||
|
workflow_process_history AS story |
||||
|
INNER JOIN workflow_process_version AS fversion |
||||
|
ON fversion.id = story.version_id |
||||
|
INNER JOIN workflow_process_form AS fform |
||||
|
ON fform.id = fversion.form_id |
||||
|
AND fform.form_schema IS NOT NULL |
||||
|
INNER JOIN workflow_process AS fprocess |
||||
|
ON fprocess.id = fform.process_id |
||||
|
AND fprocess.name = '运维中台售后问题处理工单' |
||||
|
INNER JOIN workflow_group AS fgroup |
||||
|
ON fgroup.id = fprocess.group_id |
||||
|
INNER JOIN ${camWorkflow}.act_hi_procinst AS procin |
||||
|
ON procin.id_ = story.procinst_id |
||||
|
AND procin.state_ in ('COMPLETED','ACTIVE')` |
||||
|
).toPromise() |
||||
|
if (formRes && formRes.length > 0) { |
||||
|
for (let f of formRes) { |
||||
|
let user = {} |
||||
|
const parseData = f.formSchema && parseProcessData({ |
||||
|
formSchema: JSON.parse(f.formSchema), |
||||
|
formData: JSON.parse(f.formData) |
||||
|
}) |
||||
|
const rlst = await models.WorkOrderNotice.findOne({ |
||||
|
where: { |
||||
|
procinstId: f.procinstId, |
||||
|
} |
||||
|
}) |
||||
|
//没有计划完成时间,没有处理人,没有是否解决,都不推送通知
|
||||
|
if (parseData.processing_personnel.value && parseData.planTime.value && parseData.solution_status.value) { |
||||
|
user = await clickHouse.pepEmis.query(`select * from user where id=${Number(parseData.processing_personnel.value)}`).toPromise() |
||||
|
if (!rlst) { |
||||
|
await models.WorkOrderNotice.create({ |
||||
|
procinstId: f.procinstId, |
||||
|
planTime: parseData.planTime.value, |
||||
|
processingPersonnelId: parseData.processing_personnel.value, |
||||
|
processingPersonnelPhone: user && user.length && user[0].phone, |
||||
|
isSend: false, |
||||
|
haveDone: parseData.solution_status.value === '否' ? false : true, |
||||
|
}) |
||||
|
} |
||||
|
} else { |
||||
|
console.log('没有对应的处理人', f.procinstId) |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
} else { |
||||
|
console.log('未查询到数据') |
||||
|
} |
||||
|
//数据全部插入完成之后(筛选数据进行发送企业微信通知)
|
||||
|
// 获取当前时间
|
||||
|
// 计算当前时间之后一天的日期
|
||||
|
const lastDay = moment().subtract(1, 'days') |
||||
|
//需要发送提醒的数据
|
||||
|
const sendRslt=await models.WorkOrderNotice.findAll({ |
||||
|
where: { |
||||
|
isSend: false,//未发送
|
||||
|
haveDone: false,//未完成
|
||||
|
|
||||
|
planTime:{ |
||||
|
$gte: lastDay |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
//发送企业微信通知
|
||||
|
if(sendRslt&&sendRslt.length){ |
||||
|
for (let { dataValues: c } of sendRslt) { |
||||
|
//根据电话号码查询企业微信对应的userId
|
||||
|
//15083558812,兰邦夫的电话号码
|
||||
|
if(c.processingPersonnelPhone==='15083558812'){ |
||||
|
const userId=await getUserId(opts,c.processingPersonnelPhone) |
||||
|
if(userId){ |
||||
|
const res= await sendWechat({ |
||||
|
opts, msgtype: sendType["mini"], |
||||
|
data: { userId:userId, touser: [userId] } |
||||
|
}) |
||||
|
if(res.body.errmsg==='ok'){ |
||||
|
//将已发送的记录的isSend修改为true(已发送)
|
||||
|
await models.WorkOrderNotice.update({ isSend: true }, { where: { id: c.id } }) |
||||
|
}else{ |
||||
|
console.log('发送消息失败',res.body.errmsg) |
||||
|
} |
||||
|
}else{ |
||||
|
console.log('查询不到对应的userId',c.processingPersonnelPhone) |
||||
|
} |
||||
|
} |
||||
|
const userId=await getUserId(opts,c.processingPersonnelPhone) |
||||
|
const userLan=await getUserId(opts,'15083558812') |
||||
|
//根据查询的userId发送通知
|
||||
|
if(userId){ |
||||
|
const res= await sendWechat({ |
||||
|
opts, msgtype: sendType["mini"], |
||||
|
data: { userId:userId, touser: [userId] } |
||||
|
}) |
||||
|
if(res.body.errmsg==='ok'){ |
||||
|
//将已发送的记录的isSend修改为true(已发送)
|
||||
|
await models.WorkOrderNotice.update({ isSend: true }, { where: { id: c.id } }) |
||||
|
}else{ |
||||
|
console.log('发送消息失败',res.body.errmsg) |
||||
|
} |
||||
|
}else{ |
||||
|
console.log('查询不到对应的userId',c.processingPersonnelPhone) |
||||
|
} |
||||
|
if(userLan){ |
||||
|
const res= await sendWechat({ |
||||
|
opts, msgtype: sendType["mini"], |
||||
|
data: { userId:userLan, touser: [userLan] } |
||||
|
}) |
||||
|
if(res.body.errmsg==='ok'){ |
||||
|
//将已发送的记录的isSend修改为true(已发送)
|
||||
|
console.log('已发送给兰邦夫') |
||||
|
// await models.WorkOrderNotice.update({ isSend: true }, { where: { id: c.id } })
|
||||
|
}else{ |
||||
|
console.log('发送消息失败',res.body.errmsg) |
||||
|
} |
||||
|
}else{ |
||||
|
console.log('查询不到对应的userId','15083558812') |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
} catch (error) { |
||||
|
console.error('失败原因', error) |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
return { |
||||
|
workOrderNotice, |
||||
|
} |
||||
|
} |
@ -0,0 +1,113 @@ |
|||||
|
'use strict'; |
||||
|
const request = require('superagent'); |
||||
|
const moment = require('moment') |
||||
|
let wechatExpires = {//企业微信access_token过期
|
||||
|
accessToken: null, |
||||
|
expire: null |
||||
|
} |
||||
|
//相应的
|
||||
|
const WechatApi = { |
||||
|
getAccessToken: '/gettoken',//获取企业微信token相当于鉴权
|
||||
|
getUserId: '/user/getuserid',//根据电话号码查询企业用户id
|
||||
|
postSendMesg: '/message/send',//发送信息
|
||||
|
|
||||
|
} |
||||
|
const sendType = { |
||||
|
'mini': 'miniprogram_notice', |
||||
|
} |
||||
|
|
||||
|
module.exports = function (app, opts) { |
||||
|
const getGetToken = async (opts) => { |
||||
|
console.log(`wechatInfo , accessToken:${wechatExpires && wechatExpires.accessToken}, expire: ${wechatExpires && wechatExpires.expire}`) |
||||
|
/**if access_token超时,重新请求 */ |
||||
|
if (wechatExpires && wechatExpires.accessToken && wechatExpires.expire && moment(wechatExpires.expire).isSameOrAfter(moment())) { |
||||
|
return true; |
||||
|
} else { |
||||
|
const { reqUrl, corpid, corpsecret } = opts.weChat || {}; |
||||
|
console.log('Wechat getAccessToken:', moment()); |
||||
|
const accessToken = await request.get(`${reqUrl}${WechatApi.getAccessToken}?corpid=${corpid}&corpsecret=${corpsecret}`); |
||||
|
// const accessToken = await ctx.app.business.request.get(`${reqUrl}${WechatApi.getAccessToken}?corpid=${corpid}&corpsecret=${corpsecret}`);
|
||||
|
const { errmsg, access_token, expires_in } = accessToken && accessToken.body; |
||||
|
if ('ok' != errmsg) { |
||||
|
console.log('请求企业微信鉴权失败') |
||||
|
} else { |
||||
|
wechatExpires = { |
||||
|
accessToken: access_token, |
||||
|
expire: moment().add(expires_in - 600, 's').format('YYYY-MM-DD HH:mm:ss') |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//获取用户id
|
||||
|
const getUserId = async (opts, phoneNum) => { |
||||
|
console.log(`info: getGetToken--start-- `) |
||||
|
await getGetToken(opts) |
||||
|
console.log(`info: getGetToken--end-- `) |
||||
|
const res = await request.post(`${opts.weChat.reqUrl}${WechatApi.getUserId}?access_token=${wechatExpires.accessToken}`, { mobile: phoneNum }) |
||||
|
if(res.body.errmsg==='ok'){ |
||||
|
return res.body.userid |
||||
|
|
||||
|
}else{ |
||||
|
return null |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
//发送超期提醒消息
|
||||
|
async function sendWechat({ opts, data, msgtype = sendType["mini"], exDep = '' }) { |
||||
|
let rslt={} |
||||
|
console.log(`info: sendMesg--enter-- `); |
||||
|
try { |
||||
|
const { touser } = data; |
||||
|
if (touser && touser.length) { |
||||
|
let sendData = {}; |
||||
|
if (sendType["mini"] == msgtype) {//小程序通知
|
||||
|
const { appid } = opts.weChat || {}; |
||||
|
const { userId, content, url, title, description, noDescription = false } = data; |
||||
|
sendData = { |
||||
|
"touser": touser.join("|"), |
||||
|
"msgtype": "miniprogram_notice", |
||||
|
"miniprogram_notice": { |
||||
|
"appid": appid, |
||||
|
"page": `${url ? url : 'package/approvalCenter/approvalCenter'}?userId=${userId}&msgRet=${true}`, |
||||
|
"title": title || "超期提醒", |
||||
|
"description": description || "详情如下,请您尽快处理", |
||||
|
"content_item": content |
||||
|
} |
||||
|
} |
||||
|
if (noDescription) { |
||||
|
delete sendData.miniprogram_notice.description; |
||||
|
} |
||||
|
} |
||||
|
console.log(`info: getGetToken--start-- `) |
||||
|
await getGetToken(opts) |
||||
|
console.log(`info: getGetToken--end-- `) |
||||
|
/** |
||||
|
* 返回示例 |
||||
|
* {"errcode" : 0, |
||||
|
"errmsg" : "ok", |
||||
|
"invaliduser" : ["userid1","userid2","CorpId1/userid1","CorpId2/userid2"], // 不区分大小写,返回的列表都统一转为小写
|
||||
|
"invalidparty" : ["partyid1","partyid2","LinkedId1/partyid1","LinkedId2/partyid2"], |
||||
|
"invalidtag":["tagid1","tagid2"] |
||||
|
} |
||||
|
* |
||||
|
*/ |
||||
|
rslt = await request.post(`${opts.weChat.reqUrl}${WechatApi.postSendMesg}?access_token=${wechatExpires.accessToken}`, sendData) |
||||
|
console.log(`info: WechatApi.postSendMesg----end-- `) |
||||
|
return rslt |
||||
|
} else { |
||||
|
console.log('缺少参数,请检查') |
||||
|
return rslt |
||||
|
} |
||||
|
} catch (err) { |
||||
|
console.log('发送消息失败', err && err.message) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
getGetToken, |
||||
|
getUserId, |
||||
|
sendWechat |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue