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
+9
View File
@@ -160,6 +160,15 @@ export default {
}).then(() => { }).then(() => {
vk.userCenter.logout({ vk.userCenter.logout({
success: (data) => { success: (data) => {
try {
if (typeof sessionStorage !== 'undefined') {
Object.keys(sessionStorage).forEach((key) => {
if (key.indexOf('notaryAutoTransferTipShown_') === 0) {
sessionStorage.removeItem(key)
}
})
}
} catch (e) {}
// 退出登录成功后的逻辑 // 退出登录成功后的逻辑
uni.reLaunch({ uni.reLaunch({
url: '/' url: '/'
+2 -2
View File
@@ -26,8 +26,8 @@
<meta name="description" content="金久信签约宝专注线上电子签约,金久信签约宝会员服务.致力于为您提供一站式金久信签约宝会员服务."> <meta name="description" content="金久信签约宝专注线上电子签约,金久信签约宝会员服务.致力于为您提供一站式金久信签约宝会员服务.">
<!--preload-links--> <!--preload-links-->
<!--app-context--> <!--app-context-->
<!-- 配置H5的 web图标static/logo.png --> <!-- 配置H5的 web图标 -->
<link rel="icon" href="./static/logo.png"/> <link rel="icon" type="image/png" href="./static/favicon.png"/>
<script type="text/javascript" src="http://qzonestyle.gtimg.cn/qzone/openapi/qc_loader.js" data-appid="101415280" <script type="text/javascript" src="http://qzonestyle.gtimg.cn/qzone/openapi/qc_loader.js" data-appid="101415280"
data-redirecturi="http://127.0.0.1:8080/" data-redirecturi="http://127.0.0.1:8080/"
charset="utf-8"></script> charset="utf-8"></script>
+2 -3
View File
@@ -92,13 +92,12 @@
</a> </a>
</div> </div>
<!-- 暂时隐藏微信登录
<div class=" threeBorder"><span>第三方登录</span></div> <div class=" threeBorder"><span>第三方登录</span></div>
<div class="input-groupwpg clear"> <div class="input-groupwpg clear">
<a href="javascript:;" @click="toWechat" class="dsf-wetChat" title="微信"><i></i></a> <a href="javascript:;" @click="toWechat" class="dsf-wetChat" title="微信"><i></i></a>
<!-- <a href="javascript:;" @click="toQQ" class="dsf-qq" title="QQ"><i></i></a>-->
<!-- <a href="" class="dsf-dx" title="短信"><i></i></a>-->
</div> </div>
-->
</div> </div>
</div> </div>
</div> </div>
+2 -3
View File
@@ -98,13 +98,12 @@
<navigator url="/pages/auth/login/login">已有账号?<span <navigator url="/pages/auth/login/login">已有账号?<span
style="color: #a92924">去登录</span></navigator> style="color: #a92924">去登录</span></navigator>
</div> </div>
<!-- 暂时隐藏微信登录
<div class=" threeBorder"><span>第三方登录</span></div> <div class=" threeBorder"><span>第三方登录</span></div>
<div class="input-groupwpg clear"> <div class="input-groupwpg clear">
<a href="javascript:;" @click="toWechat" class="dsf-wetChat" title="微信"><i></i></a> <a href="javascript:;" @click="toWechat" class="dsf-wetChat" title="微信"><i></i></a>
<!-- <a href="javascript:;" @click="toQQ" class="dsf-qq" title="QQ"><i></i></a>-->
<!-- <a href="" class="dsf-dx" title="短信"><i></i></a>-->
</div> </div>
-->
</div> </div>
</div> </div>
</div> </div>
+121 -20
View File
@@ -833,6 +833,42 @@
<el-dialog title="支付凭证" :visible.sync="showPayVoucher" width="50%"> <el-dialog title="支付凭证" :visible.sync="showPayVoucher" width="50%">
<el-image :src="payVoucher" :preview-src-list="[payVoucher]"/> <el-image :src="payVoucher" :preview-src-list="[payVoucher]"/>
</el-dialog> </el-dialog>
<el-dialog
title="重要提示"
:visible.sync="signTipDialog.show"
width="640px"
:close-on-click-modal="false"
append-to-body
custom-class="sign-tip-dialog"
@close="onSignTipDialogClose"
>
<div class="sign-tip-content">
<p>1、若全体签约方未完成全部签约流程,本签约文件不发生法律效力,系统无法为该文件提供存储及司法调证服务;</p>
<p>2、本次签约的实名主体信息须与注册认证阶段提交的信息保持一致;若信息发生变更,您须完成重新认证后方可继续签约。本次签约系由实名认证主体操作或经其全权授权操作,以此防范法律风险及经济损失;</p>
<p>
3、因法律法规及监管政策可能发生不定期更新,请您在使用我方产品及服务前,查阅最新版
<span class="sign-tip-link" @click.stop="openUsageAgreement">《使用协议和隐私协议》</span>
;若系统提示您需完成实名认证更新、证书续期等相关事项,您须在签约前完成对应操作,否则由此产生的一切损失,本平台不承担任何责任;您使用本平台服务即视为您已同意前述全部内容。
</p>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="confirmSignTipDialog">知悉同意</el-button>
</div>
</el-dialog>
<el-dialog
:title="agreementDialog.title || '使用协议和隐私协议'"
:visible.sync="agreementDialog.show"
width="70%"
append-to-body
top="5vh"
>
<div class="agreement-dialog-body" v-loading="agreementDialog.loading" v-html="agreementDialog.content"></div>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="agreementDialog.show = false">关闭</el-button>
</div>
</el-dialog>
</view> </view>
</template> </template>
@@ -851,6 +887,17 @@ export default {
qybNum: 0 qybNum: 0
}, },
dialogVisible: false, dialogVisible: false,
signTipDialog: {
show: false,
resolve: null,
reject: null
},
agreementDialog: {
show: false,
loading: false,
title: '',
content: ''
},
qybPackageList: [], qybPackageList: [],
selectedQyb: null, selectedQyb: null,
contractTemplate: '', contractTemplate: '',
@@ -1155,18 +1202,16 @@ export default {
this.form2.props.loading = false this.form2.props.loading = false
return false return false
} }
const res = await this.$confirm(`1、您确认,若全体各签约方未完成全部签约流程,本签约文件不发生法律效力,系统无法对该签约文件予以保存及提供司法调证服务;<br>2、您确认,当前签约的实名主体名称、手机号码与注册认证阶段提交的信息未发生变更;若发生变更,必须及时进行重新认证后方可继续签约,避免产生严重法律风险与经济损失;<br>3、您确认,本次签约为本系统实名认证主体操作,如若不是实名认证主体操作,授权委托人需本系统进行授权认证后签约;<br>4、您确认,您与其他签约方均系在平等、自愿的基础上完成本次签约;<br>5、你确认,此次签约内容符合《中华人民共和国电子签名法》《民法典》生效保护范畴;<br>6、如因法律法规、监管部门政策更新等原因,系统提示您重新进行实名认证、证书续期等重要提示时,请您必须在签约前完成,否则造成任何损失,平台不承担任何责任;以上签约条件您均已经知悉并确认,否则您有权拒绝本次签约。`, '特别重要提示', { try {
confirmButtonText: '知悉同意', await this.showSignImportantTip()
showCancelButton: false,
type: 'warning',
dangerouslyUseHTMLString: true
})
if (res === 'confirm') {
await vk.callFunction({ await vk.callFunction({
url: 'client/contract/kh/addSign', url: 'client/contract/kh/addSign',
data: this.form2.data data: this.form2.data
}) })
vk.redirectTo({url: '/pages/contract/index?tab=1'}) vk.redirectTo({url: '/pages/contract/index?tab=1'})
} catch (e) {
this.form2.props.loading = false
return false
} }
} }
console.log('complete:', pdfRes) console.log('complete:', pdfRes)
@@ -2052,15 +2097,47 @@ export default {
* @param sign * @param sign
* @param contract * @param contract
*/ */
showSignImportantTip() {
return new Promise((resolve, reject) => {
this.signTipDialog.resolve = resolve
this.signTipDialog.reject = reject
this.signTipDialog.show = true
})
},
confirmSignTipDialog() {
const resolve = this.signTipDialog.resolve
this.signTipDialog.resolve = null
this.signTipDialog.reject = null
this.signTipDialog.show = false
if (typeof resolve === 'function') resolve('confirm')
},
onSignTipDialogClose() {
const reject = this.signTipDialog.reject
this.signTipDialog.resolve = null
this.signTipDialog.reject = null
if (typeof reject === 'function') reject('cancel')
},
async openUsageAgreement() {
this.agreementDialog.show = true
this.agreementDialog.loading = true
this.agreementDialog.content = ''
try {
const data = await vk.callFunction({
url: 'client/otherArticle/list/pub/getDetail',
data: { id: 'adea4666684a336402937a2c5dcc448e' }
})
this.agreementDialog.title = data.name || data.title || '使用协议和隐私协议'
this.agreementDialog.content = data.content || ''
} catch (e) {
this.agreementDialog.content = '<p>协议内容加载失败,请稍后重试</p>'
} finally {
this.agreementDialog.loading = false
}
},
async extSign(sign, contract) { async extSign(sign, contract) {
if (sign) return if (sign) return
try { try {
await this.$confirm(`1、您确认,若全体各签约方未完成全部签约流程,本签约文件不发生法律效力,系统无法对该签约文件予以保存及提供司法调证服务;<br>2、您确认,当前签约的实名主体名称、手机号码与注册认证阶段提交的信息未发生变更;若发生变更,必须及时进行重新认证后方可继续签约,避免产生严重法律风险与经济损失;<br>3、您确认,本次签约为本系统实名认证主体操作,如若不是实名认证主体操作,授权委托人需本系统进行授权认证后签约;<br>4、您确认,您与其他签约方均系在平等、自愿的基础上完成本次签约;<br>5、你确认,此次签约内容符合《中华人民共和国电子签名法》《民法典》生效保护范畴;<br>6、如因法律法规、监管部门政策更新等原因,系统提示您重新进行实名认证、证书续期等重要提示时,请您必须在签约前完成,否则造成任何损失,平台不承担任何责任;以上签约条件您均已经知悉并确认,否则您有权拒绝本次签约。`, '提示', { await this.showSignImportantTip()
confirmButtonText: '知悉同意',
showCancelButton: false,
type: 'warning',
dangerouslyUseHTMLString: true
})
} catch (e) { } catch (e) {
return return
} }
@@ -2500,18 +2577,16 @@ export default {
this.form1.props.loading = false this.form1.props.loading = false
return false return false
} }
const res = await this.$confirm(`1、您确认,若全体各签约方未完成全部签约流程,本签约文件不发生法律效力,系统无法对该签约文件予以保存及提供司法调证服务;<br>2、您确认,当前签约的实名主体名称、手机号码与注册认证阶段提交的信息未发生变更;若发生变更,必须及时进行重新认证后方可继续签约,避免产生严重法律风险与经济损失;<br>3、您确认,本次签约为本系统实名认证主体操作,如若不是实名认证主体操作,授权委托人需本系统进行授权认证后签约;<br>4、您确认,您与其他签约方均系在平等、自愿的基础上完成本次签约;<br>5、你确认,此次签约内容符合《中华人民共和国电子签名法》《民法典》生效保护范畴;<br>6、如因法律法规、监管部门政策更新等原因,系统提示您重新进行实名认证、证书续期等重要提示时,请您必须在签约前完成,否则造成任何损失,平台不承担任何责任;以上签约条件您均已经知悉并确认,否则您有权拒绝本次签约。`, '提示', { try {
confirmButtonText: '知悉同意', await this.showSignImportantTip()
showCancelButton: false,
type: 'warning',
dangerouslyUseHTMLString: true
})
if (res === 'confirm') {
await vk.callFunction({ await vk.callFunction({
url: 'client/contract/kh/launch', url: 'client/contract/kh/launch',
data: this.form1.data data: this.form1.data
}) })
vk.redirectTo({url: '/pages/contract/index?tab=1'}) vk.redirectTo({url: '/pages/contract/index?tab=1'})
} catch (e) {
this.form1.props.loading = false
return false
} }
} }
uni.hideLoading() uni.hideLoading()
@@ -3182,4 +3257,30 @@ export default {
.report-item .report-info { .report-item .report-info {
flex: 1; flex: 1;
} }
.sign-tip-content {
color: #333;
font-size: 14px;
line-height: 1.8;
max-height: 60vh;
overflow-y: auto;
p {
margin: 0 0 12px;
text-align: justify;
}
}
.sign-tip-link {
color: #bd3124;
cursor: pointer;
text-decoration: underline;
}
.agreement-dialog-body {
max-height: 70vh;
overflow-y: auto;
line-height: 1.7;
padding: 0 8px;
}
</style> </style>
+1 -1
View File
@@ -629,7 +629,7 @@ export default {
}, },
openQuoteServiceFeeDialog() { openQuoteServiceFeeDialog() {
const rate = this.sheet.notaryServiceRate || 0.1 const rate = this.sheet.notaryServiceRate || 0.1
return this.$confirm(`提示着您成功签约交易,平台将收取总交易金额 ${rate}%服务费,如您存在利用系统漏洞恶意逃避支付服务费的情况,平台有将您的失信行为进行公布,情况严重的平台予以劝退。 return this.$confirm(`若您成功签约交易,平台将收取总交易金额 ${rate}%服务费,如您存在利用系统漏洞恶意逃避支付服务费的情况,平台有将您的失信行为进行公布,情况严重的平台予以劝退。
并有权依法追回平台服务费。您承诺此次交易为合法经营,如违反相关法律法规您将承担全部任与平台无关。您已经完全理解并知悉,您不同意请点击'取消',取消报价,您同意以上约定请点击'同意并知悉'。`, '重要提示', { 并有权依法追回平台服务费。您承诺此次交易为合法经营,如违反相关法律法规您将承担全部任与平台无关。您已经完全理解并知悉,您不同意请点击'取消',取消报价,您同意以上约定请点击'同意并知悉'。`, '重要提示', {
confirmButtonText: '同意并知悉', confirmButtonText: '同意并知悉',
cancelButtonText: '取消', cancelButtonText: '取消',
+2 -7
View File
@@ -227,13 +227,8 @@
</el-radio-group> </el-radio-group>
</view> </view>
</view> </view>
<view class="text-25 text-main mb-20 flex justify-start items-start"> <view class="text-25 text-main mb-20">
<p>重要提示:</p> 重要提示:在自主交易模式下,本平台仅承担信息交互服务职能,仅确保入驻本平台的交易双方已完成实名认证;对于交易的真实性及交易过程中的任一环节,本平台均不承担责任,请用户完成风险评估与风险尽职调查后,审慎开展交易。
<view class="flex flex-col justify-start items-start">
<p>1.系统不支持个人用户操作,请使用企业或个体户进行交易或选择自主交易;</p>
<p class="my-15">2.企业用户需平台内进行电子签约,您也可线下双方补充纸质合同:</p>
<p>3.购销双方签约后需向平台银联监管账户支付全部货款您选择即为确认并符合以上条件。</p>
</view>
</view> </view>
<view class="form-title-wrap"> <view class="form-title-wrap">
+41 -15
View File
@@ -116,7 +116,6 @@
<div class="mod-inner2Listcenter clearfix sliper" style="margin-top: 0"> <div class="mod-inner2Listcenter clearfix sliper" style="margin-top: 0">
<ul class="clearfix flex justify-start items-start flex-wrap"> <ul class="clearfix flex justify-start items-start flex-wrap">
<li v-for="(item, index) in enquirySheetData" class="inli-mask" :key="index" <li v-for="(item, index) in enquirySheetData" class="inli-mask" :key="index"
style="height: 200px"
@click="vk.navigateTo('/pages/enquiry/detail?id=' + item._id);"> @click="vk.navigateTo('/pages/enquiry/detail?id=' + item._id);">
<a href="javascript:void(0)" style="display: block;" rel="nofollow"> <a href="javascript:void(0)" style="display: block;" rel="nofollow">
<div class="detail"> <div class="detail">
@@ -127,7 +126,7 @@
<div class="text-30 py-10 text-black line-1"> <div class="text-30 py-10 text-black line-1">
<span>{{ item.title.split('-')[0] }}</span> <span>{{ item.title.split('-')[0] }}</span>
</div> </div>
<div class="text-30 py-10 text-black line-1"> <div class="text-30 py-10 text-black line-1" v-if="item.title.split('-')[1]">
<span>{{ item.title.split('-')[1] }}</span> <span>{{ item.title.split('-')[1] }}</span>
</div> </div>
<div class="text-30 py-10 text-black line-1"> <div class="text-30 py-10 text-black line-1">
@@ -135,7 +134,7 @@
item.productList.map(product => (product.procureNumber ? product.procureNumber : '') + (product.procureUnit ? product.procureUnit : ''))[0] item.productList.map(product => (product.procureNumber ? product.procureNumber : '') + (product.procureUnit ? product.procureUnit : ''))[0]
}}</span> }}</span>
</div> </div>
<div class="text-25 mt-25"> <div class="text-25 mt-25 line-1">
<span>{{ item.fullAddress }}</span> <span>{{ item.fullAddress }}</span>
</div> </div>
<div class="detail-num flex flex-col justify-start items-start"> <div class="detail-num flex flex-col justify-start items-start">
@@ -575,7 +574,7 @@
<div slot="header" class="clearfix pointer"> <div slot="header" class="clearfix pointer">
<span @click="navTo(`/pages/otherArticle/list?id=${item.id}`)">{{ item.title }}</span> <span @click="navTo(`/pages/otherArticle/list?id=${item.id}`)">{{ item.title }}</span>
</div> </div>
<div class="news-list" style="height: 140px"> <div class="news-list news-list--zx">
<el-link @click="navTo(`/pages/otherArticle/detail?id=${article._id}`)" <el-link @click="navTo(`/pages/otherArticle/detail?id=${article._id}`)"
v-for="(article, articleIndex) in item.list" :key="articleIndex" v-for="(article, articleIndex) in item.list" :key="articleIndex"
:underline="false"> :underline="false">
@@ -757,21 +756,31 @@ export default {
vk.navigateTo(path); vk.navigateTo(path);
}, },
async checkExpiringNotaryPayList() { async checkExpiringNotaryPayList() {
if (!vk.getVuex('$user.userInfo._id')) return const userId = vk.getVuex('$user.userInfo._id')
if (!userId) return
const tipKey = `notaryAutoTransferTipShown_${userId}`
// 同一登录会话只提示一次(退出登录会清除)
try {
if (typeof sessionStorage !== 'undefined' && sessionStorage.getItem(tipKey) === '1') return
} catch (e) {}
try { try {
const res = await vk.callFunction({ const res = await vk.callFunction({
url: 'client/order/kh/getExpiringNotaryPayList', url: 'client/order/kh/getExpiringNotaryPayList',
loading: false, loading: false,
}) })
const count = res.data && res.data.count ? res.data.count : 0 const count = res.data && res.data.count ? res.data.count : 0
if (!count) return const content = res.data && res.data.content ? res.data.content : ''
this.$confirm(`您有${count}笔付款申请将在24小时内自动划付,请及时处理。`, '付款申请即将到期', { if (!count || !content) return
confirmButtonText: '立即处理', try {
cancelButtonText: '稍后处理', if (typeof sessionStorage !== 'undefined') sessionStorage.setItem(tipKey, '1')
showCancelButton: true, } catch (e) {}
this.$alert(content, '重要提示', {
confirmButtonText: '悉知同意',
dangerouslyUseHTMLString: false,
type: 'warning', type: 'warning',
}).then(() => { closeOnClickModal: false,
vk.navigateTo({url: '/pages/order/order?menuIndex=1'}) closeOnPressEscape: false,
showClose: false,
}).catch(() => {}) }).catch(() => {})
} catch (err) { } catch (err) {
console.error('checkExpiringNotaryPayList error:', err) console.error('checkExpiringNotaryPayList error:', err)
@@ -1031,9 +1040,20 @@ export default {
margin: 0 auto; margin: 0 auto;
.inli-mask { .inli-mask {
padding: 10px; padding: 10px 10px 16px;
height: 400rpx; min-height: 200px;
flex: 0 0 232px height: auto;
box-sizing: border-box;
flex: 0 0 232px;
overflow: visible;
.detail-num {
margin-top: 8px;
}
.time {
margin-top: 4px;
}
} }
} }
@@ -1269,6 +1289,12 @@ export default {
flex-direction: column; flex-direction: column;
align-items: self-start; align-items: self-start;
line-height: 1.8em; line-height: 1.8em;
&--zx {
min-height: 140px;
padding-bottom: 16px;
box-sizing: border-box;
}
} }
.news-card { .news-card {
+5
View File
@@ -325,6 +325,11 @@ export default {
vk.redirectTo({ vk.redirectTo({
url: '/pages/contract/index?tab=sign', url: '/pages/contract/index?tab=sign',
}) })
} else if (this.info.type === 1 || this.info.type === 14) {
// 金久信自营:返回订单页后展示提交成功弹窗
vk.redirectTo({
url: '/pages/order/order?menuIndex=1&selfSupportPaySuccess=1',
})
} else { } else {
vk.redirectTo({ vk.redirectTo({
url: '/pages/order/order?menuIndex=1', url: '/pages/order/order?menuIndex=1',
+11
View File
@@ -460,6 +460,17 @@ export default {
this.userInfo = data.userInfo this.userInfo = data.userInfo
} }
}) })
if (options.selfSupportPaySuccess === '1' || options.selfSupportPaySuccess === 1) {
this.$nextTick(() => {
this.$alert('您已成功提交订单,请等待信息提示或平台服务人员通知。', '提示', {
confirmButtonText: '确定',
showClose: false,
closeOnClickModal: false,
closeOnPressEscape: false,
type: 'success'
}).catch(() => {})
})
}
}, },
methods: { methods: {
dayjs, dayjs,
Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

+2 -2
View File
@@ -26,8 +26,8 @@
<%= htmlWebpackPlugin.options.title %> <%= htmlWebpackPlugin.options.title %>
</title> </title>
<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" /> <link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
<!-- 配置H5的 web图标static/logo.png --> <!-- 配置H5的 web图标 -->
<link rel="icon" href="<%= BASE_URL %>static/logo.png"> <link rel="icon" type="image/png" href="<%= BASE_URL %>static/favicon.png">
</head> </head>
<body> <body>
<!-- 该文件为 H5 平台的模板 HTML,并非应用入口。 --> <!-- 该文件为 H5 平台的模板 HTML,并非应用入口。 -->
@@ -95,14 +95,14 @@ module.exports = {
const num = Number(value); const num = Number(value);
return Number.isNaN(num) ? defaultValue : num; 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 userIds = res.rows.map(item => item._id).filter(Boolean);
const qybStatMap = {}; const qybStatMap = {};
userIds.forEach(userId => { userIds.forEach(userId => {
qybStatMap[userId] = { qybStatMap[userId] = {
qybBuyNum: 0, qybBuyNum: 0,
qybUsedNum: 0, qybUsedNum: 0,
qybGiftNum: 0, qybPackageGiftNum: 0,
qybTotalGetNum: 0 qybTotalGetNum: 0
}; };
}); });
@@ -174,14 +174,18 @@ module.exports = {
} }
Object.keys(qybStatMap).forEach(userId => { 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 => { res.rows.forEach(item => {
const qybStat = qybStatMap[item._id] || {}; const qybStat = qybStatMap[item._id] || {};
const adminGiftNum = toNum(item.qybTotalGiftNum, 0);
// 用户表上的 qybGiftNum 为后台赠送累加值;套餐优惠政策赠送从订单统计
const storedGiftNum = toNum(item.qybGiftNum, 0);
item.qybBuyNum = qybStat.qybBuyNum || 0; item.qybBuyNum = qybStat.qybBuyNum || 0;
item.qybUsedNum = qybStat.qybUsedNum || 0; item.qybUsedNum = qybStat.qybUsedNum || 0;
item.qybNum = toNum(item.qybNum, 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'; '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 = { module.exports = {
/** /**
* 查询当前买家 24 小时内即将自动划付的公证付款申请。 * 查询当前买家 24 小时内即将自动划付的公证付款申请。
*/ * @url client/order/kh/getExpiringNotaryPayList
main: async (event) => { */
const {data = {}, util} = event; main: async (event) => {
const {uid} = data; const { data = {}, util } = event;
const {vk, _} = util; const { uid } = data;
const now = Date.now(); const { vk, _ } = util;
const deadline = now + 24 * 60 * 60 * 1000; const now = Date.now();
const deadline = now + 24 * 60 * 60 * 1000;
const result = await vk.baseDao.select({ const result = await vk.baseDao.select({
dbName: 'jjx-order-pay-list', dbName: 'jjx-order-pay-list',
whereJson: _.and([ whereJson: _.and([
{ {
buyerUid: uid, buyerUid: uid,
isNotaryPay: true, isNotaryPay: true,
isNotaryApply: true, isNotaryApply: true,
hasPaid: true, hasPaid: true,
buyerRefuse: false, buyerRefuse: false,
sellerConfirm: false, sellerConfirm: false,
}, },
{autoTransferTimestamp: _.gte(now)}, { autoTransferTimestamp: _.gte(now) },
{autoTransferTimestamp: _.lte(deadline)}, { autoTransferTimestamp: _.lte(deadline) },
]), ]),
sortArr: [{name: 'autoTransferTimestamp', type: 'asc'}], sortArr: [{ name: 'autoTransferTimestamp', type: 'asc' }],
pageIndex: 1, pageIndex: 1,
pageSize: 20, pageSize: 20,
}); });
return { const rows = (result.rows || []).map(item => ({
code: 0, orderId: item.orderId,
msg: '', type: item.type,
data: { amount: item.amount,
count: (result.rows || []).length, autoTransferAt: item.autoTransferAt,
rows: (result.rows || []).map(item => ({ autoTransferTimestamp: item.autoTransferTimestamp,
orderId: item.orderId, autoTransferAtText: formatZhDateTime(vk, item.autoTransferTimestamp, item.autoTransferAt),
type: item.type, }));
amount: item.amount,
autoTransferAt: item.autoTransferAt, const nearest = rows[0] || null;
autoTransferTimestamp: item.autoTransferTimestamp, 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({ await uniCloud.callFunction({
name: "router", name: "router",
data: { data: {
Binary file not shown.
Binary file not shown.