Files
jjx-web/pages/order/components/payList.vue
T
b2894lxlx c6fea1cc0d fix: 调整支付申请与报价查看权限
去掉货到付款和发货凭证,尾款或全款时提示交易已完结;已购单据报价次数也可查看买家信息。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-19 14:20:42 +08:00

457 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view>
<view style="margin-bottom: 16px; padding: 12px; background: #fff8e8; color: #8a5a00; line-height: 1.7;">
<view>服务提供方(卖家):请于系统确认支付方已依照协议或约定支付对应订单款项后,再启动对应服务。申请款项付款方在系统端完成划款授权确认操作后,款项到账时间约为工作日T+1,请届时查询确认。</view>
<view style="margin-top: 8px;">服务需求方(买家):请于依照交易规则和协议完成对应服务验收后,再在系统端完成对应申请款项的授权确认操作,系统默认确认时限为72小时(含工作日,届时系统仅提供信息提醒服务),请及时完成该项确认。若您届时未确认且未提出正当异议,系统将默认您已收货或同意支付申请。</view>
</view>
<view v-for="(item, index) in payList" :key="index" class="py-20 border-bottom">
<el-descriptions :title="item.type" :column="2" border :labelStyle="{width: '120px'}">
<template slot="extra">
<div class="flex justify-start items-center">
<template v-if="!item.buyerRefuse">
<template v-if="item.type !== '尾款'">
<el-button plain type="primary" size="mini" @click="showNotaryPayWithConfirm(item)"
v-if="canShowPayButton(item)">{{ isNotaryOrder() ? '公证支付' : '立即支付' }}
</el-button>
</template>
<template v-else>
<el-button plain type="primary" size="mini" @click="showPayWithConfirm(item)"
v-if="item.status === 0 && item.isBuyer && !item.hasPaid">同意授权支付
</el-button>
</template>
<el-button type="primary" size="mini" class="mx-20" @click="confirmPay(item)"
v-if="canShowConfirmButton(item)">
{{ isNotaryOrder() ? '通过申请' : '确认收款' }}
</el-button>
<el-button plain type="primary" size="mini" class="mx-20" @click="paidRefuse(item)"
v-if="canShowRefuseButton(item)">
驳回
</el-button>
</template>
</div>
</template>
<el-descriptions-item v-if="item.type !== '尾款'" label="支付金额">{{ item.amount }}</el-descriptions-item>
<template v-else>
<template v-if="item.status === 0">
<el-descriptions-item label="卖家申请金额">{{ item.amount }}</el-descriptions-item>
<el-descriptions-item label="卖家备注">{{ item.sellerRemark }}</el-descriptions-item>
<el-descriptions-item label="买家授权金额">{{ item.amount }}</el-descriptions-item>
</template>
<template v-else>
<el-descriptions-item label="支付金额">{{ item.amount }}</el-descriptions-item>
</template>
</template>
<el-descriptions-item label="支付凭证">
<template v-if="!item.buyerRefuse">
<span v-if="item.isNotaryFullPay && !item.hasPaid">待买方公证支付</span>
<span v-else-if="item.isNotaryFullPay && item.hasPaid">已支付到公证平台</span>
<span v-else-if="item.isNotaryApply">{{ item.sellerConfirm ? '买家已通过,已划付' : '无需二次支付,待买家通过申请' }}</span>
<span v-else-if="item.isSeller && !item.hasPaid">待买方支付</span>
<view v-else-if="item.paidVoucher">
<el-image :src="item.paidVoucher[0]" style="width: 80px; height: 80px" fit="cover"
:preview-src-list="item.paidVoucher"/>
</view>
<view v-else-if="!item.paidVoucher">
<span>未上传凭证</span>
</view>
</template>
<template v-else>
<div>
<span class="text-main">买家已拒绝: {{ item.refuseReason }}</span>
</div>
<div class="mt-10" v-if="!item.isNotaryApply">
<el-button
plain
type="warning"
size="mini"
@click="refundQuery(item)"
>
退款查询
</el-button>
</div>
</template>
</el-descriptions-item>
<el-descriptions-item label="备注">
<text>{{ item.remark ? item.remark : '无' }}</text>
</el-descriptions-item>
<el-descriptions-item label="买家备注">
<text>{{ item.buyerRemark ? item.buyerRemark : '无' }}</text>
</el-descriptions-item>
<el-descriptions-item label="凭证">
<template v-if="item.photos && item.photos.length > 0">
<el-image v-for="(photo, photoIndex) in item.photos" :key="photoIndex"
:src="typeof photo === 'string' ? photo : photo.url"
style="width: 80px; height: 80px; margin-right: 8px;" fit="cover"
:preview-src-list="item.photos.map(p => typeof p === 'string' ? p : p.url)"/>
</template>
<span v-else>无</span>
</el-descriptions-item>
<el-descriptions-item label="附件">
<template v-if="item.ext && item.ext.length > 0">
<el-image v-for="(file, fileIndex) in item.ext" :key="fileIndex"
:src="typeof file === 'string' ? file : file.url"
style="width: 80px; height: 80px; margin-right: 8px;" fit="cover"
:preview-src-list="item.ext.map(p => typeof p === 'string' ? p : p.url)"/>
</template>
<span v-else>无</span>
</el-descriptions-item>
<el-descriptions-item label="我方状态">
<template v-if="item.isSeller">
<span v-if="item.isNotaryFullPay && !item.hasPaid">待公证支付</span>
<span v-else-if="item.isNotaryFullPay && item.hasPaid">已支付到公证平台</span>
<span v-else-if="!item.hasPaid && !item.buyerRefuse">待买方支付</span>
<span v-else-if="!item.sellerConfirm && item.hasPaid">{{ isNotaryOrder() && item.isNotaryApply ? '待买家通过申请' : '待确认收款' }}</span>
<span v-else-if="item.sellerConfirm && item.hasPaid">{{ isNotaryOrder() && item.isNotaryApply ? '已划付' : '已完成' }}</span>
</template>
<template v-if="item.isBuyer">
<span v-if="item.isNotaryFullPay && !item.hasPaid">待公证支付</span>
<span v-else-if="item.isNotaryFullPay && item.hasPaid">已支付到公证平台</span>
<span v-else-if="!item.hasPaid && !item.buyerRefuse">待支付</span>
<span v-else-if="!item.sellerConfirm && item.hasPaid">{{ isNotaryOrder() && item.isNotaryApply ? '待通过申请' : '完成支付' }}</span>
<span v-else-if="item.sellerConfirm && item.hasPaid">{{ isNotaryOrder() && item.isNotaryApply ? '已划付' : '已完成' }}</span>
</template>
</el-descriptions-item>
<el-descriptions-item label="对方状态">
<!-- 自己是卖家则对方是买家-->
<template v-if="item.isSeller">
<span v-if="item.isNotaryFullPay && !item.hasPaid">待公证支付</span>
<span v-else-if="item.isNotaryFullPay && item.hasPaid">已支付到公证平台</span>
<span v-else-if="!item.hasPaid && !item.buyerRefuse">待支付</span>
<span v-else-if="!item.sellerConfirm && item.hasPaid">{{ isNotaryOrder() && item.isNotaryApply ? '待通过申请' : '完成支付' }}</span>
<span v-else-if="item.sellerConfirm && item.hasPaid">{{ isNotaryOrder() && item.isNotaryApply ? '已划付' : '已完成' }}</span>
</template>
<template v-if="item.isBuyer">
<span v-if="item.isNotaryFullPay && !item.hasPaid">待公证支付</span>
<span v-else-if="item.isNotaryFullPay && item.hasPaid">已支付到公证平台</span>
<span v-else-if="!item.hasPaid && !item.buyerRefuse">待买方支付</span>
<span v-else-if="!item.sellerConfirm && item.hasPaid">{{ isNotaryOrder() && item.isNotaryApply ? '待买家通过申请' : '待确认收款' }}</span>
<span v-else-if="item.sellerConfirm && item.hasPaid">{{ isNotaryOrder() && item.isNotaryApply ? '已划付' : '已完成' }}</span>
</template>
</el-descriptions-item>
</el-descriptions>
</view>
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="50%" append-to-body="">
<template v-if="dialogVisible && dialogType === 'do-pay'">
<div class="font-bold">支付金额: {{ payInfo.amount }}元</div>
<el-form ref="form" label-width="80px">
<el-form-item label="支付凭证" required>
<vk-data-upload v-model="payInfo.paidVoucher"></vk-data-upload>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="payInfo.buyerRemark"/>
</el-form-item>
<el-form-item label="图片">
<vk-data-upload v-model="payInfo.buyerPhotos"></vk-data-upload>
</el-form-item>
</el-form>
<el-row>
<el-col :span="24" class="text-center">
<el-button type="primary" size="mini" @click="uploadPayVoucher">提交</el-button>
<el-button type="warning" size="mini" @click="dialogVisible = false">取消
</el-button>
</el-col>
</el-row>
</template>
</el-dialog>
</view>
</template>
<script>
import ExpressInfo from "./expressInfo.vue";
import Goods from "./goods.vue";
import SetExpress from "./setExpress.vue";
import MakePay from "./makePay.vue";
import {Loading} from "element-ui";
import dayjs from "dayjs";
const NOTARY_PAY_CONFIRM_CONTENT = `1、您已充分知悉、了解并认可本订单及合同的全部内容,以及各方的权利义务;<br>2、您需将本订单全部货款支付至金久信平台银联监管账户;<br>3、供货或服务提供方提起付款申请后,在满足双方约定条款的前提下,您应及时批准划付申请款项;若您未及时处理,系统将在7个工作日内自动默认您无异议,并自动同意该付款申请。如您对供货或服务提供存在异议,请及时在供货或服务提供方平台申请单中驳回申请,并说明驳回意见并及时与对方沟通原因;若您支付合同金额与实际交易应付金额存在差额,您可办理补付或申请退款。`
const OpenSdk = require('../../user/lib/base').default;
const sdk = new OpenSdk({
// appId: '10037e6f6823b20801682b6a5e5a0006',
// appKey: '1c4e3b16066244ae9b236a09e5b312e8'
// 正式
appId: '8a81c1db8fc5238d01910b9e312d0692',
appKey: 'a15ceac60f5b464eb758c4fe7800ee9f'
// 测试分账
// appId: 'f0ec96ad2c3848b5b810e7aadf369e2f',
// appKey: '775481e2556e4564985f5439a5e6a277'
})
// 正式
// const mid = '898450108428573'
// const tid = 'ZDUL21ZA'
const mid = '898450100002303'
const tid = 'G5SBN2XJ'
export default {
name: "payList",
components: {MakePay, SetExpress, Goods, ExpressInfo},
props: {
payList: {
type: Array,
default: []
},
orderInfo: {
type: Object,
default: () => {
return {}
}
}
},
data() {
return {
dialogVisible: false,
dialogType: '',
dialogTitle: '',
payInfo: null,
rate: 0,
subMerchantIdMain: ''
}
},
mounted() {
this.getPlatformRate()
this.getSubMerchantIdMain()
console.log('this.orderInfo', this.orderInfo)
},
methods: {
isNotaryOrder() {
return !!(this.orderInfo && Number(this.orderInfo.signMethod) === 0 && Number(this.orderInfo.type) > 3)
},
canShowPayButton(item) {
console.log('canShowPayButton this.isNotaryOrder()', item.isNotaryFullPay, item.status, item.isBuyer)
if (this.isNotaryOrder()) return item.isNotaryFullPay && item.status === 0 && item.isBuyer && !item.hasPaid
return item.status === 0 && item.isBuyer && !item.hasPaid
},
canShowConfirmButton(item) {
// console.log('canShowConfirmButton this.isNotaryOrder()', item.isNotaryApply , item.hasPaid , item.isBuyer , !item.sellerConfirm , !item.buyerRefuse)
if (this.isNotaryOrder()) return item.isNotaryApply && item.hasPaid && item.isBuyer && !item.sellerConfirm && !item.buyerRefuse
return item.hasPaid && item.isSeller && !item.sellerConfirm
},
canShowRefuseButton(item) {
if (this.isNotaryOrder()) return item.isNotaryApply && item.isBuyer && item.status === 0 && !item.sellerConfirm && !item.buyerRefuse
return item.isBuyer && item.status === 0 && !item.sellerConfirm && !item.hasPaid
},
getSellerMid(item) {
const seller = (item && item.seller) || (this.orderInfo && this.orderInfo.seller) || {}
return String(seller.mid || '').trim()
},
async getPlatformRate() {
const res = await vk.callFunction({
url: 'client/dict/pub/getDetail',
data: {
id: 'd84694f2696818f20c28f55f36764783'
},
})
this.rate = res.content
},
async getSubMerchantIdMain() {
const res = await vk.callFunction({
url: 'client/dict/pub/getDetail',
data: {
id: '345cf9926ab107ad00db527f06fdbb6e'
},
})
this.subMerchantIdMain = String((res && res.content) || '').trim()
},
async unionPay(item) {
const subMerchantId = this.getSellerMid(item)
if (!subMerchantId) {
return this.$message.error('乙方未配置商户号,无法支付')
}
if (!this.subMerchantIdMain) {
await this.getSubMerchantIdMain()
}
if (!this.subMerchantIdMain) {
return this.$message.error('平台分账商户号未配置,无法支付')
}
const res = await vk.callFunction({
url: 'client/order/kh/resetPayListOrderNo',
data: {
id: item._id
},
})
let rate = this.rate
if (this.orderInfo.sheet && this.orderInfo.sheet.notaryServiceRate)
rate = this.orderInfo.sheet.notaryServiceRate
const orderNo = res.data
let subAmount = parseInt(item.amount * 100 * ((100 - parseFloat(rate)) / 100)).toFixed(0)
let platformAmount = parseInt(item.amount * 100 * (parseFloat(rate) / 100)).toFixed(0)
// let subAmount = parseInt(item.amount * (100 - parseFloat(this.rate))).toFixed(0)
const requestTimestamp = dayjs().format('YYYY-MM-DD HH:mm:ss')
const timestamp = dayjs().format('YYYYMMDDHHmmss')
console.log('subAmount', subAmount, subMerchantId)
console.log('subAmountMain', platformAmount, this.subMerchantIdMain)
// const goodsList = [{
// goodsId: item._id,
// goodsName: item.type,
// quantity: 1,
// price: parseInt(item.amount * 100).toFixed(0),
// }]
let data = {
queryUrl: 'https://api-mop.chinaums.com/v1/netpay/upg/order',
timestamp,
authorization: 'OPEN-FORM-PARAM',
nonce: 'rp84ufhfn20yneo3tp',
content: {
merOrderId: orderNo,
requestTimestamp,
mid,
tid,
instMid: 'WGDEFAULT',
chnlType: 'PC',
totalAmount: parseInt(item.amount * 100).toFixed(0),
notifyUrl: 'https://tcb-n44byxi8bmrfrki-d4bn1c4a206d.service.tcloudbase.com/pay_notify',
// transType: vk.getVuex('$user.userInfo.accountType') === 1 ? 'UPG_PERSONAL' : 'UPG_BUSINESS',
transType: 'UPG_BUSINESS',
bizType: '100003',
feeRatio: 'aaa',
// notifyUrl: 'https://www.jinjiuxinzg.cn/pay_notify',
// goods: goodsList,
}
}
data['content']['divisionFlag'] = true
data['content']['platformAmount'] = 0
data['content']['subOrders'] = [
{
mid: subMerchantId,
totalAmount: subAmount,
},
{
mid: this.subMerchantIdMain,
totalAmount: platformAmount,
},
]
console.log(data)
/**
* 调用函数
*/
const loadingInstance = Loading.service({fullscreen: true, text: '请求中'});
// const res = sdk.exec(data)
window.open(await sdk.exec(data))
loadingInstance.close()
this.showPayResultConfirm()
},
showNotaryPayWithConfirm(item) {
if (!this.isNotaryOrder()) return this.unionPay(item)
this.$confirm(NOTARY_PAY_CONFIRM_CONTENT, '公证支付', {
confirmButtonText: '我已知晓',
cancelButtonText: '取消',
showCancelButton: true,
type: 'warning',
dangerouslyUseHTMLString: true
}).then(() => {
this.unionPay(item)
}).catch(() => {})
},
showPayResultConfirm() {
this.$confirm('您是否已支付成功', '提示', {
confirmButtonText: '已支付成功',
cancelButtonText: '未支付成功',
showCancelButton: true,
distinguishCancelAndClose: true,
closeOnClickModal: false,
closeOnPressEscape: false,
}).then(() => {
this.$emit('refresh')
}).catch(() => {
this.$emit('refresh')
})
},
showPay(item) {
this.payInfo = item;
this.dialogTitle = '支付'
this.dialogType = 'do-pay';
this.dialogVisible = true;
},
showPayWithConfirm(item) {
this.$confirm('尾款为双方交易最后一次结算,请交易双方协商共同确定最终结算金额后进行,结算完毕将默认此订单结束,无法再次系统发起请款或付款动作,如您已知晓并双方已经协商确认最终结算金额,请进行确认后进入尾款流程',
'温馨提示', {
showCancelButton: true,
}).then(async ({value}) => {
this.payInfo = item;
this.dialogTitle = '支付'
this.dialogType = 'do-pay';
this.dialogVisible = true;
})
},
async confirmPay({_id, type}) {
await vk.callFunction({
url: 'client/order/kh/paidConfirm',
title: '请求中...',
data: {
id: _id
}
})
this.$message({
type: 'success',
message: this.isNotaryOrder() ? '确认划付成功' : '确认成功'
})
if (['尾款', '货到付款'].includes(type)) this.$emit('refresh', '4')
else this.$emit('refresh')
},
paidRefuse({_id}) {
this.$prompt('请输入驳回理由', '提示', {
showCancelButton: true,
showInput: true,
}).then(async ({value}) => {
await vk.callFunction({
url: 'client/order/kh/payRefuse',
title: '请求中...',
data: {
id: _id,
refuseReason: value,
}
})
this.$emit('refresh')
this.$message({
type: 'success',
message: '驳回成功'
})
})
},
async refundQuery(item) {
try {
const res = await vk.callFunction({
url: 'client/order/kh/refundQuery',
title: '请求中...',
data: {
id: item._id
}
})
const result = res.data || {}
const msg = result.errMsg || result.msg || res.msg || '查询完成'
this.$alert(
`退款单号: ${item.refundApplyPayload && item.refundApplyPayload.refundOrderId ? item.refundApplyPayload.refundOrderId : '无'}\n状态码: ${result.errCode || '无'}\n信息: ${msg}`,
'退款查询结果',
{
confirmButtonText: '确定'
}
)
this.$emit('refresh')
} catch (err) {
this.$message.error((err && err.message) || '退款查询失败')
}
},
async uploadPayVoucher() {
if (this.payInfo.paidVoucher.length === 0) return this.$message.error()
await vk.callFunction({
url: 'client/order/kh/uploadPayVoucher',
title: '请求中...',
data: this.payInfo
})
this.$message({
type: 'success',
message: '上传成功'
})
this.$emit('refresh')
this.dialogVisible = false
},
}
}
</script>