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