feat: 签约提示/赠送次数/自动划付提醒,自营支付成功弹窗,隐藏微信登录

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-27 03:28:31 +08:00
parent 85cddfbf8d
commit 683a9411fd
19 changed files with 469 additions and 99 deletions
@@ -95,14 +95,14 @@ module.exports = {
const num = Number(value);
return Number.isNaN(num) ? defaultValue : num;
};
if (data.formData && data.formData.isSignOnly && res.rows && res.rows.length > 0) {
if (res.rows && res.rows.length > 0) {
const userIds = res.rows.map(item => item._id).filter(Boolean);
const qybStatMap = {};
userIds.forEach(userId => {
qybStatMap[userId] = {
qybBuyNum: 0,
qybUsedNum: 0,
qybGiftNum: 0,
qybPackageGiftNum: 0,
qybTotalGetNum: 0
};
});
@@ -174,14 +174,18 @@ module.exports = {
}
Object.keys(qybStatMap).forEach(userId => {
qybStatMap[userId].qybGiftNum = Math.max(qybStatMap[userId].qybTotalGetNum - qybStatMap[userId].qybBuyNum, 0);
qybStatMap[userId].qybPackageGiftNum = Math.max(qybStatMap[userId].qybTotalGetNum - qybStatMap[userId].qybBuyNum, 0);
});
res.rows.forEach(item => {
const qybStat = qybStatMap[item._id] || {};
const adminGiftNum = toNum(item.qybTotalGiftNum, 0);
// 用户表上的 qybGiftNum 为后台赠送累加值;套餐优惠政策赠送从订单统计
const storedGiftNum = toNum(item.qybGiftNum, 0);
item.qybBuyNum = qybStat.qybBuyNum || 0;
item.qybUsedNum = qybStat.qybUsedNum || 0;
item.qybNum = toNum(item.qybNum, 0);
item.qybGiftNum = qybStat.qybGiftNum || 0;
item.qybGiftNum = (qybStat.qybPackageGiftNum || 0) + storedGiftNum;
item.qybTotalGiftNum = adminGiftNum || storedGiftNum;
});
}
}
@@ -0,0 +1,46 @@
'use strict';
module.exports = {
/**
* 后台赠送签约宝次数
* @url admin/system/user/sys/giftQybNum
* @param {String} user_id 用户ID
* @param {Number} giftNum 赠送次数
*/
main: async (event) => {
let { data = {}, util } = event;
let { vk, _ } = util;
let res = { code: 0, msg: '' };
const { user_id, giftNum } = data;
const num = Number(giftNum);
if (!user_id) {
return { code: -1, msg: '用户ID不能为空' };
}
if (!Number.isInteger(num) || num <= 0) {
return { code: -1, msg: '赠送次数必须为正整数' };
}
const user = await vk.baseDao.findById({
dbName: 'uni-id-users',
id: user_id
});
if (!user) {
return { code: -1, msg: '用户不存在' };
}
// 剩余签约次数、优惠政策赠送次数、累计赠送次数同步累加
await vk.baseDao.updateById({
dbName: 'uni-id-users',
id: user_id,
dataJson: {
qybNum: _.inc(num),
qybGiftNum: _.inc(num),
qybTotalGiftNum: _.inc(num)
}
});
res.msg = '赠送成功';
return res;
}
};
@@ -1,48 +1,71 @@
'use strict';
function formatZhDateTime(vk, timestamp, fallbackText) {
if (fallbackText) {
const matched = String(fallbackText).match(/^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2})/);
if (matched) {
return `${matched[1]}年${matched[2]}月${matched[3]}日${matched[4]}:${matched[5]}`;
}
}
const date = new Date(Number(timestamp) || Date.now());
return vk.pubfn.timeFormat(date, 'yyyy年MM月dd日hh:mm');
}
module.exports = {
/**
* 查询当前买家 24 小时内即将自动划付的公证付款申请。
*/
main: async (event) => {
const {data = {}, util} = event;
const {uid} = data;
const {vk, _} = util;
const now = Date.now();
const deadline = now + 24 * 60 * 60 * 1000;
/**
* 查询当前买家 24 小时内即将自动划付的公证付款申请。
* @url client/order/kh/getExpiringNotaryPayList
*/
main: async (event) => {
const { data = {}, util } = event;
const { uid } = data;
const { vk, _ } = util;
const now = Date.now();
const deadline = now + 24 * 60 * 60 * 1000;
const result = await vk.baseDao.select({
dbName: 'jjx-order-pay-list',
whereJson: _.and([
{
buyerUid: uid,
isNotaryPay: true,
isNotaryApply: true,
hasPaid: true,
buyerRefuse: false,
sellerConfirm: false,
},
{autoTransferTimestamp: _.gte(now)},
{autoTransferTimestamp: _.lte(deadline)},
]),
sortArr: [{name: 'autoTransferTimestamp', type: 'asc'}],
pageIndex: 1,
pageSize: 20,
});
const result = await vk.baseDao.select({
dbName: 'jjx-order-pay-list',
whereJson: _.and([
{
buyerUid: uid,
isNotaryPay: true,
isNotaryApply: true,
hasPaid: true,
buyerRefuse: false,
sellerConfirm: false,
},
{ autoTransferTimestamp: _.gte(now) },
{ autoTransferTimestamp: _.lte(deadline) },
]),
sortArr: [{ name: 'autoTransferTimestamp', type: 'asc' }],
pageIndex: 1,
pageSize: 20,
});
return {
code: 0,
msg: '',
data: {
count: (result.rows || []).length,
rows: (result.rows || []).map(item => ({
orderId: item.orderId,
type: item.type,
amount: item.amount,
autoTransferAt: item.autoTransferAt,
autoTransferTimestamp: item.autoTransferTimestamp,
})),
},
};
},
const rows = (result.rows || []).map(item => ({
orderId: item.orderId,
type: item.type,
amount: item.amount,
autoTransferAt: item.autoTransferAt,
autoTransferTimestamp: item.autoTransferTimestamp,
autoTransferAtText: formatZhDateTime(vk, item.autoTransferTimestamp, item.autoTransferAt),
}));
const nearest = rows[0] || null;
const autoConfirmTimeText = nearest ? nearest.autoTransferAtText : '';
const content = autoConfirmTimeText
? `重要提示:您在金久信公正交易项下待确认业务的系统自动确认时间为${autoConfirmTimeText},该期限即将届满;若到期未完成相关处理,系统将依据本平台交易规则自动确认收货或处理申请金额,请您及时登录平台完成对应操作,避免产生利益损失。若您已完成相关处理,可忽略本提示,如有疑问请联系客服咨询。`
: '';
return {
code: 0,
msg: '',
data: {
count: rows.length,
rows,
autoConfirmTimeText,
content,
},
};
},
};
@@ -0,0 +1,143 @@
'use strict';
const notaryPay = require('../../order/kh/util/notaryPay');
/** 短信模板字典 ID,content 填阿里云模板号,如 SMS_xxxxx;模板变量为 time */
const AUTO_TRANSFER_REMIND_SMS_DICT_ID = 'auto_transfer_remind_sms_template';
/** 兜底短信模板 ID(模板变量:time),上线前请替换为已审核通过的阿里云模板 */
const AUTO_TRANSFER_REMIND_SMS_TEMPLATE_ID = '';
function formatZhDateTime(vk, timestamp) {
const date = new Date(Number(timestamp) || Date.now());
return vk.pubfn.timeFormat(date, 'yyyy年MM月dd日hh:mm');
}
function buildRemindContent(autoConfirmTimeText) {
return `重要提示:您在金久信公正交易项下待确认业务的系统自动确认时间为${autoConfirmTimeText},该期限即将届满;若到期未完成相关处理,系统将依据本平台交易规则自动确认收货或处理申请金额,请您及时登录平台完成对应操作,避免产生利益损失。若您已完成相关处理,可忽略本提示,如有疑问请联系客服咨询。`;
}
async function getRemindSmsTemplateId(vk) {
try {
const config = await vk.baseDao.findByWhereJson({
dbName: 'jjx-dict',
whereJson: {
_id: AUTO_TRANSFER_REMIND_SMS_DICT_ID
}
});
if (config && config.content) return String(config.content).trim();
const configByKey = await vk.baseDao.findByWhereJson({
dbName: 'jjx-dict',
whereJson: {
key: AUTO_TRANSFER_REMIND_SMS_DICT_ID
}
});
if (configByKey && configByKey.content) return String(configByKey.content).trim();
} catch (err) {
console.error('getRemindSmsTemplateId error:', err);
}
return AUTO_TRANSFER_REMIND_SMS_TEMPLATE_ID;
}
module.exports = {
/**
* 距离自动划付不足 24 小时时,发送短信 + 站内信提醒(每笔申请仅提醒一次)
* @url client/timedTask/pub/remindAutoTransferPayList
*/
main: async (event) => {
let { data = {}, util } = event;
let { vk, _, pubFun } = util;
let res = { code: 0, msg: '', data: [] };
if (data.key !== 'lsgjoksdjf') return { code: 1, msg: '非法请求' };
const now = Date.now();
const deadline = now + 24 * 60 * 60 * 1000;
const smsTemplateId = await getRemindSmsTemplateId(vk);
const payList = await vk.baseDao.select({
dbName: 'jjx-order-pay-list',
whereJson: _.and([
{
isNotaryPay: true,
isNotaryApply: true,
hasPaid: true,
buyerRefuse: false,
sellerConfirm: false,
autoTransferRemindSent: _.neq(true)
},
{ autoTransferTimestamp: _.gt(now) },
{ autoTransferTimestamp: _.lte(deadline) }
]),
sortArr: [{ name: 'autoTransferTimestamp', type: 'asc' }],
pageIndex: 1,
pageSize: 200
});
for (const payRecord of payList.rows || []) {
const itemRes = {
_id: payRecord._id,
orderId: payRecord.orderId,
buyerUid: payRecord.buyerUid,
message: false,
sms: false,
msg: ''
};
try {
if (!payRecord.buyerUid) {
itemRes.msg = '缺少买家用户';
res.data.push(itemRes);
continue;
}
const autoConfirmTimeText = payRecord.autoTransferAt
? String(payRecord.autoTransferAt).replace(
/^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}).*$/,
'$1年$2月$3日$4:$5'
)
: formatZhDateTime(vk, payRecord.autoTransferTimestamp);
const content = buildRemindContent(autoConfirmTimeText);
await notaryPay.addMessage(vk, {
uid: payRecord.buyerUid,
title: '重要提示',
content,
type: 'notary-auto-transfer-remind',
pk: payRecord.orderId
});
itemRes.message = true;
if (smsTemplateId) {
try {
if (typeof pubFun.sendNotifySms === 'function') {
await pubFun.sendNotifySms(payRecord.buyerUid, smsTemplateId, {
time: autoConfirmTimeText
});
itemRes.sms = true;
}
} catch (smsErr) {
console.error('remindAutoTransferPayList sms error:', payRecord._id, smsErr);
itemRes.msg = smsErr.message || '短信发送失败';
}
} else {
itemRes.msg = '未配置短信模板';
}
await vk.baseDao.updateById({
dbName: 'jjx-order-pay-list',
id: payRecord._id,
dataJson: {
autoTransferRemindSent: true,
autoTransferRemindAt: vk.pubfn.timeFormat(new Date(), 'yyyy-MM-dd hh:mm:ss'),
autoTransferRemindTimestamp: Date.now()
}
});
} catch (err) {
console.error('remindAutoTransferPayList error:', payRecord._id, err);
itemRes.msg = err.message || '提醒失败';
}
res.data.push(itemRes);
}
res.msg = `已处理${res.data.length}笔即将自动划付提醒`;
return res;
}
};
@@ -55,6 +55,15 @@ exports.main = async (event, context) => {
}
}
});
await uniCloud.callFunction({
name: "router",
data: {
$url: "client/timedTask/pub/remindAutoTransferPayList",
data: {
key: "lsgjoksdjf"
}
}
});
await uniCloud.callFunction({
name: "router",
data: {