Merge pull request !8 from 喵呀/dev
This commit is contained in:
喵呀
2024-06-04 11:12:01 +00:00
committed by Gitee
23 changed files with 472 additions and 164 deletions

View File

@@ -102,6 +102,16 @@ export function updateRate(receiverId, rate: number) {
})
}
/**
* 编码是否存在
*/
export function existsByNo(receiverNo) {
return defHttp.get<Result<boolean>>({
url: '/allocation/group/existsByGroupNo',
params: { receiverNo },
})
}
/**
* 设置默认分账组
*/
@@ -126,6 +136,10 @@ export function cancelDefaultGroup(id) {
* 分账组
*/
export interface AllocationGroup extends BaseEntity {
/**
* 分账组编号
*/
groupNo?: string
/**
* 分账组名称
*/
@@ -156,10 +170,6 @@ export interface AllocationGroupReceiver extends BaseEntity {
* 默认分账组
*/
defaultGroup?: boolean
/**
* 接收方账号别名
*/
name?: string
/**
* 分账比例
*/

View File

@@ -18,7 +18,6 @@
@edit-activated="editActivatedEvent"
>
<vxe-column type="seq" width="60" />
<vxe-column field="name" title="账号别名" :min-width="100" />
<vxe-column field="receiverType" title="接收方类型" :min-width="100">
<template #default="{ row }">
<a-tag>{{ dictConvert('AllocReceiverType', row.receiverType) }}</a-tag>
@@ -114,7 +113,6 @@
groupId: group.id,
receivers,
}
createMessage.success('添加中...')
bindReceivers(param).then(() => {
createMessage.success('添加成功')
queryPage()

View File

@@ -21,6 +21,9 @@
<a-form-item label="主键" name="id" :hidden="true">
<a-input v-model:value="form.id" :disabled="showable" />
</a-form-item>
<a-form-item label="分账组编号" name="groupNo">
<a-input v-model:value="form.groupNo" :disabled="!addable" placeholder="请输入分账组编号" />
</a-form-item>
<a-form-item label="分账组名称" name="name">
<a-input v-model:value="form.name" :disabled="showable" placeholder="请输入分账组名称" />
</a-form-item>
@@ -53,11 +56,9 @@
<script setup lang="ts">
import useFormEdit from '/@/hooks/bootx/useFormEdit'
import { useValidate } from '/@/hooks/bootx/useValidate'
import { useMessage } from '/@/hooks/web/useMessage'
import { computed, nextTick } from 'vue'
import { FormInstance, Rule } from 'ant-design-vue/lib/form'
import { get, add, update, AllocationGroup } from './AllocationGroup.api'
import { get, add, update, AllocationGroup, existsByNo } from './AllocationGroup.api'
import { FormEditType } from '/@/enums/formTypeEnum'
import { BasicModal } from '/@/components/Modal'
import { useDict } from '/@/hooks/bootx/useDict'
@@ -67,7 +68,6 @@
const {
initFormEditType,
handleCancel,
search,
labelCol,
wrapperCol,
modalWidth,
@@ -75,12 +75,9 @@
confirmLoading,
visible,
addable,
editable,
showable,
formEditType,
} = useFormEdit()
const { existsByServer } = useValidate()
const { createMessage } = useMessage()
const { dictConvert, dictDropDown } = useDict()
// 表单
@@ -91,7 +88,10 @@
// 校验
const rules = computed(() => {
return {
name: [{ required: true, message: '请输入账号别名' }],
groupNo: [
{ required: true, message: '请输入分账组编号' },
{ trigger: 'blur', validator: validateCode },
],
channel: [{ required: true, message: '请选择所属通道' }],
} as Record<string, Rule[]>
})
@@ -148,6 +148,15 @@
})
}
/**
* 校验编码重复
*/
async function validateCode() {
const { groupNo } = form
const res = await existsByNo(groupNo)
return res.data ? Promise.reject('该分账组编号已经存在') : Promise.resolve()
}
/**
* 重置表单
*/

View File

@@ -20,11 +20,12 @@
@sort-change="sortChange"
>
<vxe-column type="seq" title="序号" width="60" />
<vxe-column field="name" title="名称" :min-width="160">
<vxe-column field="groupNo" title="分组编号" :min-width="160">
<template #default="{ row }">
<a-link @click="show(row)">{{ row.name }}</a-link>
<a-link @click="show(row)">{{ row.groupNo }}</a-link>
</template>
</vxe-column>
<vxe-column field="name" title="分组名称" :min-width="160" />
<vxe-column field="channel" title="所属通道" :min-width="100">
<template #default="{ row }">
<a-tag>{{ dictConvert('PayChannel', row.channel) }}</a-tag>
@@ -83,7 +84,7 @@
<script setup lang="ts">
import { computed, onMounted } from 'vue'
import { $ref } from 'vue/macros'
import { cancelDefaultGroup, del, page, setDefaultGroup } from "./AllocationGroup.api";
import { cancelDefaultGroup, del, page, setDefaultGroup } from './AllocationGroup.api'
import useTablePage from '/@/hooks/bootx/useTablePage'
import { VxeTable, VxeTableInstance, VxeToolbarInstance } from 'vxe-table'
import { useMessage } from '/@/hooks/web/useMessage'
@@ -100,8 +101,8 @@
// 使用hooks
const { handleTableChange, pageQueryResHandel, resetQueryParams, pagination, sortChange, sortParam, pages, model, loading } =
useTablePage(queryPage)
const { notification, createMessage, createConfirm } = useMessage()
const { dictConvert, dictDropDown } = useDict()
const { createMessage, createConfirm } = useMessage()
const { dictConvert } = useDict()
const allocationGroupEdit = $ref<any>()
const allocationGroupConfig = $ref<any>()
@@ -112,6 +113,7 @@
const fields = computed(() => {
return [
{ field: 'groupNo', type: STRING, name: '分账组编号', placeholder: '请输入分账组编号' },
{ field: 'name', type: STRING, name: '分账组名称', placeholder: '请输入分账组名称' },
{ field: 'channel', type: LIST, name: '分账通道', placeholder: '请选择分账通道', selectList: payChannelList },
] as QueryField[]

View File

@@ -15,7 +15,7 @@
</vxe-toolbar>
<vxe-table row-id="id" ref="xTable" :height="350" :checkbox-config="checkboxConfig" :loading="loading" :data="pagination.records">
<vxe-column type="checkbox" width="50" />
<vxe-column field="name" title="账号别名" :min-width="100"/>
<vxe-column field="receiverNo" title="接收方编号" :min-width="160" />
<vxe-column field="receiverType" title="分账接收方类型" :min-width="100">
<template #default="{ row }">
<a-tag>{{ dictConvert('AllocReceiverType', row.receiverType) }}</a-tag>
@@ -70,14 +70,12 @@
let currentChannel = $ref<string>('')
let queryParam = $ref<any>({})
let relationTypeList = $ref<LabeledValue[]>([])
let receiverTypeList = $ref<LabeledValue[]>([])
const xTable = $ref<any>()
const fields = computed(() => {
return [
{ field: 'name', type: STRING, name: '账号别名', placeholder: '请输入账号别名' },
{ field: 'receiverNo', type: STRING, name: '接收方编号', placeholder: '请输入接收方编号' },
{ field: 'relationType', type: LIST, name: '分账关系', placeholder: '请选择分账关系', selectList: relationTypeList },
// { field: 'receiverType', type: LIST, name: '接收方类型', placeholder: '请选择分账接收方类型', selectList: receiverTypeList },
] as QueryField[]
})
const checkboxConfig = {

View File

@@ -32,6 +32,26 @@ export function get(id) {
})
}
/**
* 获取订单详细信息
*/
export function getOrderByAllocNo(allocNo: string) {
return defHttp.get<Result>({
url: '/order/allocation/findByAllocNo',
params: { allocNo },
})
}
/**
* 扩展信息
*/
export function getExtra(id) {
return defHttp.get<Result<AllocationOrder>>({
url: '/order/allocation/findById',
params: { id },
})
}
/**
* 明细列表
*/
@@ -55,27 +75,27 @@ export function detail(id) {
/**
* 分账完结
*/
export function finish(id) {
export function finish(allocationNo) {
return defHttp.post<Result<AllocationOrder>>({
url: '/order/allocation/finish',
params: { id },
params: { allocationNo },
})
}
/**
* 分账完结
*/
export function retry(id) {
export function retry(bizAllocationNo) {
return defHttp.post<Result<AllocationOrder>>({
url: '/order/allocation/retry',
params: { id },
params: { bizAllocationNo },
})
}
/**
* 查询分账结果
*/
export function sync(allocationNo){
export function sync(allocationNo) {
return defHttp.post<Result<AllocationOrder>>({
url: '/order/allocation/sync',
params: { allocationNo },
@@ -120,6 +140,22 @@ export interface AllocationOrder extends BaseEntity {
finishTime?: string
}
/**
* 分账扩展订单信息
*/
export interface AllocationOrderExtra {
// 异步通知地址
notifyUrl?: string
// 商户扩展参数
attach?: string
// 附加参数
extraParam?: string
// 请求时间
reqTime?: string
// 支付终端ip
clientIp?: string
}
/**
* 分账订单明细
*/
@@ -138,6 +174,8 @@ export interface AllocationOrderDetail extends BaseEntity {
receiverAccount?: string
// 接收方姓名
receiverName?: string
// 接收方编号
receiverNo?: string
// 分账结果
result?: string
// 错误代码

View File

@@ -10,6 +10,9 @@
>
<a-spin :spinning="confirmLoading">
<a-descriptions title="" bordered :column="{ md: 2, sm: 1, xs: 1 }">
<a-descriptions-item label="接收方编号">
{{ order.receiverNo }}
</a-descriptions-item>
<a-descriptions-item label="接收方姓名">
{{ order.receiverName }}
</a-descriptions-item>

View File

@@ -3,6 +3,7 @@
<vxe-toolbar ref="xToolbar" custom :refresh="{ queryMethod: queryPage }" />
<vxe-table row-id="id" ref="xTable" :data="records" :loading="loading" :cell-style="cellStyle">
<vxe-column type="seq" width="60" />
<vxe-column field="receiverNo" title="接收方编号" :min-width="120" />
<vxe-column field="receiverName" title="接收方姓名" :min-width="100" />
<vxe-column field="receiverType" title="接收方类型" :min-width="100">
<template #default="{ row }">

View File

@@ -52,6 +52,15 @@
<a-descriptions-item label="完成时间" :span="2">
{{ order.finishTime }}
</a-descriptions-item>
<a-descriptions-item label="商户扩展参数" :span="2">
{{ orderExtra.attach }}
</a-descriptions-item>
<a-descriptions-item label="终端IP" :span="2">
{{ orderExtra.clientIp || '空' }}
</a-descriptions-item>
<a-descriptions-item label="通知地址" :span="4">
{{ orderExtra.notifyUrl }}
</a-descriptions-item>
<a-descriptions-item v-if="order.errorCode" label="错误编码" :span="2">
{{ order.errorMsg }}
</a-descriptions-item>
@@ -71,33 +80,23 @@
<script lang="ts" setup>
import { $ref } from 'vue/macros'
import useFormEdit from '/@/hooks/bootx/useFormEdit'
import { get, AllocationOrder } from './AllocationOrder.api'
import { AllocationOrder, getOrderByAllocNo, AllocationOrderExtra } from './AllocationOrder.api'
import { BasicModal } from '/@/components/Modal'
import { useDict } from '/@/hooks/bootx/useDict'
const {
initFormEditType,
handleCancel,
search,
labelCol,
wrapperCol,
modalWidth,
title,
confirmLoading,
visible,
editable,
showable,
formEditType,
} = useFormEdit()
const { handleCancel, confirmLoading, visible, showable } = useFormEdit()
const { dictConvert } = useDict()
let order = $ref<AllocationOrder>({})
// 入口
async function init(record: AllocationOrder) {
let orderExtra = $ref<AllocationOrderExtra>({})
/**
* 入口
*/
async function init(allocationNo) {
visible.value = true
order = record
confirmLoading.value = true
await get(record.id).then(({ data }) => {
order = data
await getOrderByAllocNo(allocationNo).then(({ data }) => {
order = data.order
orderExtra = data.extra
})
confirmLoading.value = false
}

View File

@@ -38,7 +38,7 @@
<vxe-column field="amount" title="总分账金额(元)" :min-width="120">
<template #default="{ row }"> {{ row.amount ? (row.amount / 100).toFixed(2) : 0 }} </template>
</vxe-column>
<vxe-column field="status" title="状态" :min-width="100">
<vxe-column field="status" title="状态" :min-width="120">
<template #default="{ row }">
<a-tag>{{ dictConvert('AllocOrderStatus', row.status) }}</a-tag>
</template>
@@ -66,7 +66,7 @@
<a-menu-item>
<a-link @click="syncInfo(row)">同步</a-link>
</a-menu-item>
<a-menu-item v-if="row.status === 'allocation_end'">
<a-menu-item v-if="['allocation_end', 'finish_failed'].includes(row.status)">
<a-link @click="finishInfo(row)">完结</a-link>
</a-menu-item>
</a-menu>
@@ -154,7 +154,7 @@
* 查看
*/
function show(record) {
allocationOrderInfo.init(record, FormEditType.Show)
allocationOrderInfo.init(record.allocationNo, FormEditType.Show)
}
/**
@@ -199,7 +199,7 @@
title: '分账重试',
content: '确定分账重试吗?',
onOk: () => {
retry(record.id).then(() => {
retry(record.bizAllocationNo).then(() => {
createMessage.success('分账重试请求发送成功')
queryPage()
})
@@ -216,7 +216,7 @@
title: '完结分账',
content: '确定完结分账吗?',
onOk: () => {
finish(record.id).then(() => {
finish(record.allocationNo).then(() => {
createMessage.success('完结请求发送成功')
queryPage()
})

View File

@@ -52,6 +52,16 @@ export function add(data: AllocationReceiver) {
})
}
/**
* 编码是否存在
*/
export function existsByNo(receiverNo) {
return defHttp.get<Result<boolean>>({
url: '/allocation/receiver/existsByReceiverNo',
params: { receiverNo },
})
}
/**
* 修改
*/
@@ -72,32 +82,12 @@ export function del(id) {
})
}
/**
* 同步到三方支付系统中
*/
export function registerByGateway(id) {
return defHttp.post<Result<null>>({
url: '/allocation/receiver/registerByGateway',
params: { id },
})
}
/**
* 从三方支付系统中删除
*/
export function removeByGateway(id) {
return defHttp.post<Result<null>>({
url: '/allocation/receiver/removeByGateway',
params: { id },
})
}
/**
* 分账接收方
*/
export interface AllocationReceiver extends BaseEntity {
// 账号别名
name?: string
// 分账接收方编号
receiverNo?: string
// 所属通道
channel?: string
// 分账接收方类型
@@ -110,6 +100,4 @@ export interface AllocationReceiver extends BaseEntity {
relationType?: string
// 关系名称
relationName?: string
// 是否已经同步到网关
sync?: boolean
}

View File

@@ -2,7 +2,7 @@
<basic-modal
v-bind="$attrs"
:loading="confirmLoading"
:width="modalWidth"
:width="900"
:title="title"
:visible="visible"
:mask-closable="showable"
@@ -21,8 +21,8 @@
<a-form-item label="主键" name="id" :hidden="true">
<a-input v-model:value="form.id" :disabled="showable" />
</a-form-item>
<a-form-item label="账号别名" name="name">
<a-input v-model:value="form.name" :disabled="showable" placeholder="请输入账号别名" />
<a-form-item label="接收方编号" validate-first name="receiverNo">
<a-input v-model:value="form.receiverNo" :disabled="!addable" placeholder="请输入接收方编号" />
</a-form-item>
<a-form-item label="所属通道" name="channel">
<a-select
@@ -38,31 +38,32 @@
<a-select
style="width: 100%"
v-model:value="form.receiverType"
:disabled="showable || form.sync"
:disabled="!addable"
:options="receiverTypeList"
placeholder="请选择接收方类型"
/>
</a-form-item>
<a-form-item label="接收方账号" name="receiverAccount">
<a-input v-model:value="form.receiverAccount" :disabled="showable || form.sync" placeholder="请输入接收方账号" />
<a-input v-model:value="form.receiverAccount" :disabled="!addable" placeholder="请输入接收方账号">
<template v-if="['wx_personal', 'ali_open_id'].includes(form.receiverType as string)" #suffix>
<icon icon="ant-design:qrcode-outlined" @click="showQrCode" />
</template>
</a-input>
</a-form-item>
<a-form-item label="接收方姓名" name="receiverName">
<a-input v-model:value="form.receiverName" :disabled="showable || form.sync" placeholder="请输入接收方姓名" />
<a-input v-model:value="form.receiverName" :disabled="!addable" placeholder="请输入接收方姓名" />
</a-form-item>
<a-form-item label="分账关系类型" name="relationType">
<a-select
style="width: 100%"
v-model:value="form.relationType"
:disabled="showable || form.sync"
:disabled="!addable"
:options="relationTypeList"
placeholder="请选择分账关系类型"
/>
</a-form-item>
<a-form-item v-if="form.relationType === 'CUSTOM'" label="接收者关系名称" name="relationName">
<a-input v-model:value="form.relationName" :disabled="showable || form.sync" placeholder="请输入接收者关系名称" />
</a-form-item>
<a-form-item label="备注" name="remark">
<a-textarea :disabled="showable" placeholder="请输入备注" v-model:value="form.remark" />
<a-input v-model:value="form.relationName" :disabled="!addable" placeholder="请输入接收者关系名称" />
</a-form-item>
</a-form>
</a-spin>
@@ -81,11 +82,12 @@
import { useMessage } from '/@/hooks/web/useMessage'
import { computed, nextTick } from 'vue'
import { FormInstance, Rule } from 'ant-design-vue/lib/form'
import { add, get, AllocationReceiver, update, findChannels, findReceiverTypeByChannel } from './AllocationReceiver.api'
import { add, get, AllocationReceiver, update, findChannels, findReceiverTypeByChannel, existsByNo } from './AllocationReceiver.api'
import { FormEditType } from '/@/enums/formTypeEnum'
import { BasicModal } from '/@/components/Modal'
import { useDict } from '/@/hooks/bootx/useDict'
import { LabeledValue } from 'ant-design-vue/lib/select'
import Icon from '/@/components/Icon'
const {
initFormEditType,
@@ -98,7 +100,6 @@
confirmLoading,
visible,
addable,
editable,
showable,
formEditType,
} = useFormEdit()
@@ -117,7 +118,10 @@
// 校验
const rules = computed(() => {
return {
name: [{ required: true, message: '请输入账号别名' }],
receiverNo: [
{ required: true, message: '请输入账号编号' },
{ trigger: 'blur', validator: validateCode },
],
channel: [{ required: true, message: '请选择所属通道' }],
receiverType: [{ required: true, message: '请选择分账接收方类型' }],
receiverAccount: [{ required: true, message: '请输入接收方账号' }],
@@ -143,7 +147,7 @@
*/
async function initData() {
findChannels().then(({ data }) => (payChannelList = data))
relationTypeList = await dictDropDown('AllocationRelationType')
relationTypeList = await dictDropDown('AllocRelationType')
}
/**
@@ -191,6 +195,22 @@
})
}
/**
* 扫码绑定
*/
function showQrCode() {
createMessage.info('扫码获取OpenID开发中, 敬请期待')
}
/**
* 校验编码重复
*/
async function validateCode() {
const { receiverNo } = form
const res = await existsByNo(receiverNo)
return res.data ? Promise.reject('该接收方编号已经存在') : Promise.resolve()
}
/**
* 重置表单
*/

View File

@@ -20,7 +20,11 @@
@sort-change="sortChange"
>
<vxe-column type="seq" title="序号" width="60" />
<vxe-column field="name" title="账号别名" :min-width="100"/>
<vxe-column field="receiverNo" title="接收方编号" :min-width="180">
<template #default="{ row }">
<a-link @click="show(row)">{{ row.receiverNo }}</a-link>
</template>
</vxe-column>
<vxe-column field="channel" title="所属通道" :min-width="100">
<template #default="{ row }">
<a-tag>{{ dictConvert('PayChannel', row.channel) }}</a-tag>
@@ -38,21 +42,11 @@
<a-tag>{{ dictConvert('AllocRelationType', row.relationType) }}</a-tag>
</template>
</vxe-column>
<vxe-column field="sync" title="是否同步" :min-width="100">
<template #default="{ row }">
<a-tag>{{ row.sync ? '已同步' : '未同步' }}</a-tag>
</template>
</vxe-column>
<vxe-column fixed="right" min-width="220" :showOverflow="false" title="操作">
<vxe-column fixed="right" min-width="100" :showOverflow="false" title="操作">
<template #default="{ row }">
<a-link @click="show(row)">查看</a-link>
<a-divider type="vertical" />
<a-link @click="edit(row)">编辑</a-link>
<a-divider type="vertical" />
<a-link :disabled="row.sync" @click="remove(row)">删除</a-link>
<a-divider type="vertical" />
<a-link v-if="!row.sync" @click="bind(row)">同步</a-link>
<a-link v-else @click="unbind(row)">取消同步</a-link>
<a-link @click="remove(row)">删除</a-link>
</template>
</vxe-column>
</vxe-table>
@@ -72,7 +66,7 @@
<script setup lang="ts">
import { computed, onMounted } from 'vue'
import { $ref } from 'vue/macros'
import { del, findChannels, page, registerByGateway, removeByGateway } from './AllocationReceiver.api'
import { del, findChannels, page } from './AllocationReceiver.api'
import useTablePage from '/@/hooks/bootx/useTablePage'
import { VxeTable, VxeTableInstance, VxeToolbarInstance } from 'vxe-table'
import { useMessage } from '/@/hooks/web/useMessage'
@@ -95,15 +89,13 @@
const xToolbar = $ref<VxeToolbarInstance>()
let payChannelList = $ref<LabeledValue[]>([])
let receiverTypeList = $ref<LabeledValue[]>([])
let relationTypeList = $ref<LabeledValue[]>([])
const fields = computed(() => {
return [
{ field: 'name', type: STRING, name: '账号别名', placeholder: '请输入账号别名' },
{ field: 'receiverNo', type: STRING, name: '接收方编号', placeholder: '请输入接收方编号' },
{ field: 'channel', type: LIST, name: '分账通道', placeholder: '请选择分账通道', selectList: payChannelList },
{ field: 'relationType', type: LIST, name: '分账关系', placeholder: '请选择分账关系', selectList: relationTypeList },
// { field: 'receiverType', type: LIST, name: '接收方类型', placeholder: '请选择分账接收方类型', selectList: receiverTypeList },
] as QueryField[]
})
onMounted(() => {
@@ -125,7 +117,6 @@
async function initData() {
findChannels().then(({ data }) => (payChannelList = data))
relationTypeList = await dictDropDown('AllocationRelationType')
// receiverTypeList = await dictDropDown('AllocationReceiverType')
}
/**
@@ -168,11 +159,6 @@
* 删除
*/
function remove(record) {
// 判断是否未进行注册
if (record.sync) {
createMessage.warning('该接收方已同步到三方支付系统中,无法删除')
return
}
createConfirm({
iconType: 'warning',
title: '警告',
@@ -186,42 +172,6 @@
},
})
}
/**
* 同步到三方支付系统中
*/
function bind(record) {
createConfirm({
iconType: 'info',
title: '警告',
content: '是否确认同步该条数据?',
onOk: () => {
loading.value = true
registerByGateway(record.id).then(({ data }) => {
createMessage.success('该分账接收方成功同步到三方支付系统中')
queryPage()
})
},
})
}
/**
* 从三方支付系统中删除
*/
function unbind(record) {
createConfirm({
iconType: 'info',
title: '警告',
content: '是否确认取消同步该条数据?',
onOk: () => {
loading.value = true
removeByGateway(record.id).then(({ data }) => {
createMessage.success('该分账接收方从三方支付系统中取消成功')
queryPage()
})
},
})
}
</script>
<style scoped lang="less"></style>

View File

@@ -88,6 +88,8 @@ export interface PayOrder extends BaseEntity {
description?: any
// 是否支持分账
allocation?: boolean
// 自动分账
autoAllocation?: boolean
// 支付通道
channel?: string
// 支付方式

View File

@@ -49,6 +49,12 @@
<a-descriptions-item label="通知地址" :span="2">
{{ orderExtra.notifyUrl || '无' }}
</a-descriptions-item>
<a-descriptions-item label="自动分账" :span="1">
{{ order.autoAllocation || '无' }}
</a-descriptions-item>
<a-descriptions-item label="描述" :span="2">
{{ order.description }}
</a-descriptions-item>
<a-descriptions-item label="客户IP">
{{ orderExtra.clientIp }}
</a-descriptions-item>
@@ -70,9 +76,6 @@
<a-descriptions-item label="创建时间">
{{ order.createTime }}
</a-descriptions-item>
<a-descriptions-item label="描述" :span="1">
{{ order.description }}
</a-descriptions-item>
</a-descriptions>
</a-spin>
<template #footer>

View File

@@ -27,7 +27,7 @@ export function get(id) {
*/
export function getByRefundNo(refundNo) {
return defHttp.get<Result<any>>({
url: '/order/refund/findByOrderNo',
url: '/order/refund/findByRefundNo',
params: { refundNo },
})
}

View File

@@ -61,5 +61,5 @@ export interface DiffInfo {
// 本地订单字段值
localValue?: string
// 网关订单字段值
gatewayValue?: string
outValue?: string
}

View File

@@ -42,7 +42,7 @@
</a-descriptions-item>
<template v-if="form.diffs">
<a-descriptions-item :label="`${item.fieldName}[差异]`" :key="item" v-for="item in form.diffs">
<a-tag>本地</a-tag> : {{ item.localValue }}<br /><a-tag>远程</a-tag> : {{ item.gatewayValue }}
<a-tag>本地</a-tag> : {{ item.localValue }}<br /><a-tag>远程</a-tag> : {{ item.outValue }}
</a-descriptions-item>
</template>
</a-descriptions>

View File

@@ -0,0 +1,43 @@
import { defHttp } from '/@/utils/http/axios'
import { PageResult, Result } from '/#/axios'
import { BaseEntity } from '/#/web'
/**
* 分页
*/
export function page(params) {
return defHttp.get<Result<PageResult<TradeFlowRecord>>>({
url: '/record/flow/page',
params,
})
}
/**
* 获取单条
*/
export function get(id) {
return defHttp.get<Result<TradeFlowRecord>>({
url: '/record/flow/findById',
params: { id },
})
}
/**
* 支付同步记录
*/
export interface TradeFlowRecord extends BaseEntity {
// 订单标题
title?: string
// 金额
amount?: number
// 业务类型
type?: string
// 同步通道
channel?: string
// 修复号
tradeNo?: string
// 商户交易号
bizTradeNo?: string
// 通道交易号
outTradeNo?: string
}

View File

@@ -0,0 +1,76 @@
<template>
<basic-modal
title="查看同步信息"
v-bind="$attrs"
:loading="confirmLoading"
:width="1200"
:visible="visible"
:mask-closable="showable"
@cancel="handleCancel"
>
<a-spin :spinning="confirmLoading">
<a-descriptions title="" bordered>
<a-descriptions-item label="标题" :span="2">
{{ form.title }}
</a-descriptions-item>
<a-descriptions-item label="交易金额(元)" :span="2">
{{ form.amount ? (form.amount / 100).toFixed(2) : '无' }}
</a-descriptions-item>
<a-descriptions-item label="本地交易号" :span="4">
{{ form.tradeNo }}
</a-descriptions-item>
<a-descriptions-item label="商户交易号" :span="4">
{{ form.bizTradeNo }}
</a-descriptions-item>
<a-descriptions-item label="通道交易号" :span="4">
{{ form.outTradeNo || '无' }}
</a-descriptions-item>
<a-descriptions-item label="流水类型" :span="2">
<a-tag>{{ dictConvert('TradeFlowRecordType', form.type) }}</a-tag>
</a-descriptions-item>
<a-descriptions-item label="交易通道" :span="2">
<a-tag> {{ dictConvert('PayChannel', form.channel) }}</a-tag>
</a-descriptions-item>
<a-descriptions-item label="同步时间" :span="2">
{{ form.createTime }}
</a-descriptions-item>
</a-descriptions>
</a-spin>
<template #footer>
<a-button key="cancel" @click="handleCancel">取消</a-button>
</template>
</basic-modal>
</template>
<script lang="ts" setup>
import { $ref } from 'vue/macros'
import useFormEdit from '/@/hooks/bootx/useFormEdit'
import { get, TradeFlowRecord } from './TradeFlowRecord.api'
import { BasicModal } from '/@/components/Modal'
import { useDict } from '/@/hooks/bootx/useDict'
const { handleCancel, confirmLoading, visible, showable } = useFormEdit()
const { dictConvert } = useDict()
// 表单
let form = $ref<TradeFlowRecord>({})
// 入口
function init(id) {
visible.value = true
confirmLoading.value = true
get(id).then(({ data }) => {
form = data
confirmLoading.value = false
})
}
defineExpose({
init,
})
</script>
<style lang="less" scoped>
/deep/ .ant-descriptions-item-label {
width: 170px;
}
</style>

View File

@@ -0,0 +1,160 @@
<template>
<div>
<div class="m-3 p-3 pt-5 bg-white">
<b-query :query-params="model.queryParam" :default-item-count="3" :fields="fields" @query="queryPage" @reset="resetQueryParams" />
</div>
<div class="m-3 p-3 bg-white">
<vxe-toolbar ref="xToolbar" custom :refresh="{ queryMethod: queryPage }" />
<vxe-table row-id="id" ref="xTable" :data="pagination.records" :loading="loading">
<vxe-column type="seq" title="序号" width="60" />
<vxe-column field="title" title="标题" :min-width="220" />
<vxe-column field="amount" title="金额(元)" :min-width="120" sortable>
<template #default="{ row }"> {{ row.amount ? (row.amount / 100).toFixed(2) : 0 }} </template>
</vxe-column>
<vxe-column field="type" title="流水类型" :min-width="120">
<template #default="{ row }">
<a-tag>{{ dictConvert('TradeFlowRecordType', row.type) }}</a-tag>
</template>
</vxe-column>
<vxe-column field="channel" title="交易通道" :min-width="100">
<template #default="{ row }">
<a-tag>{{ dictConvert('AsyncPayChannel', row.channel) }}</a-tag>
</template>
</vxe-column>
<vxe-column field="tradeNo" title="本地交易号" :min-width="220">
<template #default="{ row }">
<a @click="showOrder(row)">
{{ row.tradeNo }}
</a>
</template>
</vxe-column>
<vxe-column field="bizTradeNo" title="商户交易号" :min-width="220" />
<vxe-column field="outTradeNo" title="通道交易号" :min-width="220" />
<vxe-column field="createTime" title="时间" :min-width="160" sortable />
<vxe-column fixed="right" :min-width="60" :showOverflow="false" title="操作">
<template #default="{ row }">
<span>
<a-link @click="show(row)">查看</a-link>
</span>
</template>
</vxe-column>
</vxe-table>
<vxe-pager
size="medium"
:loading="loading"
:current-page="pagination.current"
:page-size="pagination.size"
:total="pagination.total"
@page-change="handleTableChange"
/>
</div>
<trade-flow-record-info ref="tradeFlowRecordInfo" />
<pay-order-info ref="payOrderInfo" />
<refund-order-info ref="refundOrderInfo" />
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted } from 'vue'
import { $ref } from 'vue/macros'
import { page } from './TradeFlowRecord.api'
import useTablePage from '/@/hooks/bootx/useTablePage'
import { VxeTableInstance, VxeToolbarInstance } from 'vxe-table'
import BQuery from '/@/components/Bootx/Query/BQuery.vue'
import { useMessage } from '/@/hooks/web/useMessage'
import { LIST, QueryField, STRING } from '/@/components/Bootx/Query/Query'
import { useDict } from '/@/hooks/bootx/useDict'
import { LabeledValue } from 'ant-design-vue/lib/select'
import PayOrderInfo from '/@/views/payment/order/pay/PayOrderInfo.vue'
import RefundOrderInfo from '/@/views/payment/order/refund/RefundOrderInfo.vue'
import ALink from '/@/components/Link/Link.vue'
import TradeFlowRecordInfo from './TradeFlowRecordInfo.vue'
// 使用hooks
const { handleTableChange, pageQueryResHandel, resetQueryParams, pagination, pages, model, loading } = useTablePage(queryPage)
const { notification, createMessage, createConfirm } = useMessage()
const { dictConvert, dictDropDown } = useDict()
let payChannelList = $ref<LabeledValue[]>([])
let tradeFlowRecordTypeList = $ref<LabeledValue[]>([])
// 查询条件
const fields = computed(() => {
return [
{ field: 'title', type: STRING, name: '订单标题', placeholder: '请输入订单标题' },
{ field: 'tradeNo', type: STRING, name: '本地交易号', placeholder: '请输入本地交易号' },
{ field: 'bizTradeNo', type: STRING, name: '商户交易号', placeholder: '请输入商户交易号' },
{ field: 'outTradeNo', type: STRING, name: '通道交易号', placeholder: '请输入通道交易号' },
{
field: 'type',
type: LIST,
name: '流水类型',
placeholder: '请选择流水类型',
selectList: tradeFlowRecordTypeList,
},
{
field: 'channel',
type: LIST,
name: '交易通道',
placeholder: '请选择交易通道',
selectList: payChannelList,
},
] as QueryField[]
})
const xTable = $ref<VxeTableInstance>()
const xToolbar = $ref<VxeToolbarInstance>()
const payOrderInfo = $ref<any>()
const refundOrderInfo = $ref<any>()
const tradeFlowRecordInfo = $ref<any>()
onMounted(() => {
init()
vxeBind()
queryPage()
})
function vxeBind() {
xTable?.connect(xToolbar as VxeToolbarInstance)
}
/**
* 初始化
*/
async function init() {
tradeFlowRecordTypeList = await dictDropDown('TradeFlowRecordType')
payChannelList = await dictDropDown('PayChannel')
}
/**
* 分页查询
*/
function queryPage() {
loading.value = true
page({
...model.queryParam,
...pages,
}).then(({ data }) => {
pageQueryResHandel(data)
})
return Promise.resolve()
}
/**
* 查看
*/
function show(record) {
tradeFlowRecordInfo.init(record.id)
}
/**
* 查看支付单信息
*/
function showOrder(record) {
if (record.type === 'pay') {
payOrderInfo.init(record.tradeNo)
} else if (record.type === 'refund') {
refundOrderInfo.init(record.tradeNo)
}
}
</script>
<style lang="less" scoped></style>

View File

@@ -27,7 +27,8 @@
</a-descriptions-item>
<a-descriptions-item label="同步结果" :span="2">
<a-tag v-if="form.syncType === 'pay'">{{ dictConvert('PaySyncStatus', form.outTradeStatus) }}</a-tag>
<a-tag v-else>{{ dictConvert('RefundSyncStatus', form.outTradeStatus) }}</a-tag>
<a-tag v-else-if="form.syncType === 'refund'">{{ dictConvert('RefundSyncStatus', form.outTradeStatus) }}</a-tag>
<a-tag v-else></a-tag>
</a-descriptions-item>
<a-descriptions-item label="修复单号" :span="2">
<a-tag v-if="form.repair" color="green"> {{ form.repairNo }} </a-tag>

View File

@@ -15,7 +15,7 @@
</template>
</vxe-column>
<vxe-column field="bizTradeNo" title="商户交易号" :min-width="220" />
<vxe-column field="channel" title="同步类型" :min-width="60">
<vxe-column field="channel" title="同步类型" :min-width="120">
<template #default="{ row }">
<a-tag>{{ dictConvert('PaymentType', row.syncType) }}</a-tag>
</template>
@@ -28,7 +28,8 @@
<vxe-column field="status" title="同步结果" :min-width="100">
<template #default="{ row }">
<a-tag v-if="row.syncType === 'pay'">{{ dictConvert('PaySyncStatus', row.outTradeStatus) }}</a-tag>
<a-tag v-else>{{ dictConvert('RefundSyncStatus', row.outTradeStatus) }}</a-tag>
<a-tag v-else-if="row.syncType === 'refund'">{{ dictConvert('RefundSyncStatus', row.outTradeStatus) }}</a-tag>
<a-tag v-else></a-tag>
</template>
</vxe-column>
<vxe-column field="repairOrder" title="是否修复" width="170">
@@ -37,7 +38,7 @@
<a-tag v-else>无需修复</a-tag>
</template>
</vxe-column>
<vxe-column field="errorMsg" title="错误消息" :min-width="160"/>
<vxe-column field="errorMsg" title="错误消息" :min-width="160" />
<vxe-column field="createTime" title="同步时间" :min-width="160" />
<vxe-column fixed="right" :min-width="60" :showOverflow="false" title="操作">
<template #default="{ row }">
@@ -57,9 +58,10 @@
/>
</div>
<pay-sync-record-info ref="paySyncRecordInfo" />
<pay-repair-record-info ref="payRepairRecordInfo" />
<pay-order-info ref="payOrderInfo" />
<refund-order-info ref="refundOrderInfo" />
<pay-repair-record-info ref="payRepairRecordInfo" />
<allocation-order-info ref="allocationOrderInfo" />
</div>
</template>
@@ -78,6 +80,8 @@
import PayOrderInfo from '/@/views/payment/order/pay/PayOrderInfo.vue'
import PayRepairRecordInfo from '/@/views/payment/record/repair/PayRepairRecordInfo.vue'
import RefundOrderInfo from '/@/views/payment/order/refund/RefundOrderInfo.vue'
import AllocationOrderInfo from '/@/views/payment/allocation/order/AllocationOrderInfo.vue'
import ALink from '/@/components/Link/Link.vue'
// 使用hooks
const { handleTableChange, pageQueryResHandel, resetQueryParams, pagination, pages, model, loading } = useTablePage(queryPage)
@@ -93,7 +97,7 @@
return [
{ field: 'tradeNo', type: STRING, name: '本地交易号', placeholder: '请输入本地交易号' },
{ field: 'bizTradeNo', type: STRING, name: '商户交易号', placeholder: '请输入商户交易号' },
{ field: 'bizTradeNo', type: STRING, name: '通道交易号', placeholder: '请输入通道交易号' },
{ field: 'outTradeNo', type: STRING, name: '通道交易号', placeholder: '请输入通道交易号' },
{
field: 'syncType',
type: LIST,
@@ -124,6 +128,7 @@
const payOrderInfo = $ref<any>()
const refundOrderInfo = $ref<any>()
const payRepairRecordInfo = $ref<any>()
const allocationOrderInfo = $ref<any>()
onMounted(() => {
init()
@@ -169,8 +174,10 @@
function showOrder(record) {
if (record.syncType === 'pay') {
payOrderInfo.init(record.tradeNo)
} else {
} else if (record.syncType === 'refund') {
refundOrderInfo.init(record.tradeNo)
} else {
allocationOrderInfo.init(record.tradeNo)
}
}
</script>