refactor: pay

plp
xingyu4j 3 years ago
parent 24439b70ea
commit cbc7b9dfc0

@ -1,8 +1,44 @@
import request from '@/config/axios' import request from '@/config/axios'
import type { AppVO } from './types'
export interface AppVO {
id: number
name: string
status: number
remark: string
payNotifyUrl: string
refundNotifyUrl: string
merchantId: number
merchantName: string
createTime: Date
}
export interface AppPageReqVO extends PageParam {
name?: string
status?: number
remark?: string
payNotifyUrl?: string
refundNotifyUrl?: string
merchantName?: string
createTime?: Date[]
}
export interface AppExportReqVO {
name?: string
status?: number
remark?: string
payNotifyUrl?: string
refundNotifyUrl?: string
merchantName?: string
createTime?: Date[]
}
export interface AppUpdateStatusReqVO {
id: number
status: number
}
// 查询列表支付应用 // 查询列表支付应用
export const getAppPageApi = (params) => { export const getAppPageApi = (params: AppPageReqVO) => {
return request.get({ url: '/pay/app/page', params }) return request.get({ url: '/pay/app/page', params })
} }
@ -22,11 +58,7 @@ export const updateAppApi = (data: AppVO) => {
} }
// 支付应用信息状态修改 // 支付应用信息状态修改
export const changeAppStatusApi = (id: number, status: number) => { export const changeAppStatusApi = (data: AppUpdateStatusReqVO) => {
const data = {
id,
status
}
return request.put({ url: '/pay/app/update-status', data: data }) return request.put({ url: '/pay/app/update-status', data: data })
} }
@ -36,7 +68,7 @@ export const deleteAppApi = (id: number) => {
} }
// 导出支付应用 // 导出支付应用
export const exportAppApi = (params) => { export const exportAppApi = (params: AppExportReqVO) => {
return request.download({ url: '/pay/app/export-excel', params }) return request.download({ url: '/pay/app/export-excel', params })
} }

@ -1,11 +0,0 @@
export type AppVO = {
id: number
name: string
status: number
remark: string
payNotifyUrl: string
refundNotifyUrl: string
merchantName: string
merchantId: number
createTime: string
}

@ -1,8 +1,41 @@
import request from '@/config/axios' import request from '@/config/axios'
import type { ChannelVO } from './types'
export interface ChannelVO {
id: number
code: string
config: string
status: number
remark: string
feeRate: number
merchantId: number
appId: number
createTime: Date
}
export interface ChannelPageReqVO extends PageParam {
code?: string
status?: number
remark?: string
feeRate?: number
merchantId?: number
appId?: number
config?: string
createTime?: Date[]
}
export interface ChannelExportReqVO {
code?: string
status?: number
remark?: string
feeRate?: number
merchantId?: number
appId?: number
config?: string
createTime?: Date[]
}
// 查询列表支付渠道 // 查询列表支付渠道
export const getChannelPageApi = (params) => { export const getChannelPageApi = (params: ChannelPageReqVO) => {
return request.get({ url: '/pay/channel/page', params }) return request.get({ url: '/pay/channel/page', params })
} }
@ -32,6 +65,6 @@ export const deleteChannelApi = (id: number) => {
} }
// 导出支付渠道 // 导出支付渠道
export const exportChannelApi = (params) => { export const exportChannelApi = (params: ChannelExportReqVO) => {
return request.download({ url: '/pay/channel/export-excel', params }) return request.download({ url: '/pay/channel/export-excel', params })
} }

@ -1,11 +0,0 @@
export type ChannelVO = {
id: number
code: string
config: string
status: number
remark: string
feeRate: number
merchantId: number
appId: number
createTime: string
}

@ -1,8 +1,35 @@
import request from '@/config/axios' import request from '@/config/axios'
import type { MerchantVO } from './types'
export interface MerchantVO {
id: number
no: string
name: string
shortName: string
status: number
remark: string
createTime: Date
}
export interface MerchantPageReqVO extends PageParam {
no?: string
name?: string
shortName?: string
status?: number
remark?: string
createTime?: Date[]
}
export interface MerchantExportReqVO {
no?: string
name?: string
shortName?: string
status?: number
remark?: string
createTime?: Date[]
}
// 查询列表支付商户 // 查询列表支付商户
export const getMerchantPageApi = (params) => { export const getMerchantPageApi = (params: MerchantPageReqVO) => {
return request.get({ url: '/pay/merchant/page', params }) return request.get({ url: '/pay/merchant/page', params })
} }
@ -37,7 +64,7 @@ export const deleteMerchantApi = (id: number) => {
} }
// 导出支付商户 // 导出支付商户
export const exportMerchantApi = (params) => { export const exportMerchantApi = (params: MerchantExportReqVO) => {
return request.download({ url: '/pay/merchant/export-excel', params }) return request.download({ url: '/pay/merchant/export-excel', params })
} }
// 支付商户状态修改 // 支付商户状态修改

@ -1,9 +0,0 @@
export type MerchantVO = {
id: number
no: string
name: string
shortName: string
status: number
remark: string
createTime: string
}

@ -1,8 +1,85 @@
import request from '@/config/axios' import request from '@/config/axios'
import type { OrderVO } from './types'
export interface OrderVO {
id: number
merchantId: number
appId: number
channelId: number
channelCode: string
merchantOrderId: string
subject: string
body: string
notifyUrl: string
notifyStatus: number
amount: number
channelFeeRate: number
channelFeeAmount: number
status: number
userIp: string
expireTime: Date
successTime: Date
notifyTime: Date
successExtensionId: number
refundStatus: number
refundTimes: number
refundAmount: number
channelUserId: string
channelOrderNo: string
createTime: Date
}
export interface OrderPageReqVO extends PageParam {
merchantId?: number
appId?: number
channelId?: number
channelCode?: string
merchantOrderId?: string
subject?: string
body?: string
notifyUrl?: string
notifyStatus?: number
amount?: number
channelFeeRate?: number
channelFeeAmount?: number
status?: number
expireTime?: Date[]
successTime?: Date[]
notifyTime?: Date[]
successExtensionId?: number
refundStatus?: number
refundTimes?: number
channelUserId?: string
channelOrderNo?: string
createTime?: Date[]
}
export interface OrderExportReqVO {
merchantId?: number
appId?: number
channelId?: number
channelCode?: string
merchantOrderId?: string
subject?: string
body?: string
notifyUrl?: string
notifyStatus?: number
amount?: number
channelFeeRate?: number
channelFeeAmount?: number
status?: number
expireTime?: Date[]
successTime?: Date[]
notifyTime?: Date[]
successExtensionId?: number
refundStatus?: number
refundTimes?: number
channelUserId?: string
channelOrderNo?: string
createTime?: Date[]
}
// 查询列表支付订单 // 查询列表支付订单
export const getOrderPageApi = async (params) => { export const getOrderPageApi = async (params: OrderPageReqVO) => {
return await request.get({ url: '/pay/order/page', params }) return await request.get({ url: '/pay/order/page', params })
} }
@ -27,6 +104,6 @@ export const deleteOrderApi = async (id: number) => {
} }
// 导出支付订单 // 导出支付订单
export const exportOrderApi = async (params) => { export const exportOrderApi = async (params: OrderExportReqVO) => {
return await request.download({ url: '/pay/order/export-excel', params }) return await request.download({ url: '/pay/order/export-excel', params })
} }

@ -1,26 +0,0 @@
export type OrderVO = {
id: number
merchantId: number
appId: number
channelId: number
channelCode: string
merchantOrderId: string
subject: string
body: string
notifyUrl: string
notifyStatus: number
amount: number
channelFeeRate: number
channelFeeAmount: number
status: number
userIp: string
expireTime: string
successTime: string
notifyTime: string
successExtensionId: number
refundStatus: number
refundTimes: number
refundAmount: number
channelUserId: string
channelOrderNo: string
}

@ -1,8 +1,92 @@
import request from '@/config/axios' import request from '@/config/axios'
import type { RefundVO } from './types'
export interface RefundVO {
id: number
merchantId: number
appId: number
channelId: number
channelCode: string
orderId: string
tradeNo: string
merchantOrderId: string
merchantRefundNo: string
notifyUrl: string
notifyStatus: number
status: number
type: number
payAmount: number
refundAmount: number
reason: string
userIp: string
channelOrderNo: string
channelRefundNo: string
channelErrorCode: string
channelErrorMsg: string
channelExtras: string
expireTime: Date
successTime: Date
notifyTime: Date
createTime: Date
}
export interface RefundPageReqVO extends PageParam {
merchantId?: number
appId?: number
channelId?: number
channelCode?: string
orderId?: string
tradeNo?: string
merchantOrderId?: string
merchantRefundNo?: string
notifyUrl?: string
notifyStatus?: number
status?: number
type?: number
payAmount?: number
refundAmount?: number
reason?: string
userIp?: string
channelOrderNo?: string
channelRefundNo?: string
channelErrorCode?: string
channelErrorMsg?: string
channelExtras?: string
expireTime?: Date[]
successTime?: Date[]
notifyTime?: Date[]
createTime?: Date[]
}
export interface PayRefundExportReqVO {
merchantId?: number
appId?: number
channelId?: number
channelCode?: string
orderId?: string
tradeNo?: string
merchantOrderId?: string
merchantRefundNo?: string
notifyUrl?: string
notifyStatus?: number
status?: number
type?: number
payAmount?: number
refundAmount?: number
reason?: string
userIp?: string
channelOrderNo?: string
channelRefundNo?: string
channelErrorCode?: string
channelErrorMsg?: string
channelExtras?: string
expireTime?: Date[]
successTime?: Date[]
notifyTime?: Date[]
createTime?: Date[]
}
// 查询列表退款订单 // 查询列表退款订单
export const getRefundPageApi = (params) => { export const getRefundPageApi = (params: RefundPageReqVO) => {
return request.get({ url: '/pay/refund/page', params }) return request.get({ url: '/pay/refund/page', params })
} }
@ -27,6 +111,6 @@ export const deleteRefundApi = (id: number) => {
} }
// 导出退款订单 // 导出退款订单
export const exportRefundApi = (params) => { export const exportRefundApi = (params: PayRefundExportReqVO) => {
return request.download({ url: '/pay/refund/export-excel', params }) return request.download({ url: '/pay/refund/export-excel', params })
} }

@ -1,26 +0,0 @@
export type RefundVO = {
id: number
merchantId: number
appId: number
channelId: number
channelCode: string
merchantOrderId: string
subject: string
body: string
notifyUrl: string
notifyStatus: number
amount: number
channelFeeRate: number
channelFeeAmount: number
status: number
userIp: string
expireTime: string
successTime: string
notifyTime: string
successExtensionId: number
refundStatus: number
refundTimes: number
refundAmount: number
channelUserId: string
channelOrderNo: string
}

@ -121,18 +121,8 @@ const filterSearchSchema = (crudSchema: VxeCrudSchema): VxeFormItemProps[] => {
if (schemaItem?.isSearch || schemaItem.search?.show) { if (schemaItem?.isSearch || schemaItem.search?.show) {
let itemRenderName = schemaItem?.search?.itemRender?.name || '$input' let itemRenderName = schemaItem?.search?.itemRender?.name || '$input'
const options: any[] = [] const options: any[] = []
let itemRender: FormItemRenderOptions let itemRender: FormItemRenderOptions = {}
if (schemaItem.search?.itemRender) {
itemRender = schemaItem.search.itemRender
} else {
itemRender = {
name: itemRenderName,
props:
itemRenderName == '$input'
? { placeholder: t('common.inputText') }
: { placeholder: t('common.selectText') }
}
}
if (schemaItem.dictType) { if (schemaItem.dictType) {
const allOptions = { label: '全部', value: '' } const allOptions = { label: '全部', value: '' }
options.push(allOptions) options.push(allOptions)
@ -146,8 +136,19 @@ const filterSearchSchema = (crudSchema: VxeCrudSchema): VxeFormItemProps[] => {
options: options, options: options,
props: { placeholder: t('common.selectText') } props: { placeholder: t('common.selectText') }
} }
} else {
if (schemaItem.search?.itemRender) {
itemRender = schemaItem.search.itemRender
} else {
itemRender = {
name: itemRenderName,
props:
itemRenderName == '$input'
? { placeholder: t('common.inputText') }
: { placeholder: t('common.selectText') }
}
}
} }
const searchSchemaItem = { const searchSchemaItem = {
// 默认为 input // 默认为 input
folding: searchSchema.length > spanLength - 1, folding: searchSchema.length > spanLength - 1,
@ -156,7 +157,6 @@ const filterSearchSchema = (crudSchema: VxeCrudSchema): VxeFormItemProps[] => {
title: schemaItem.search?.title || schemaItem.title, title: schemaItem.search?.title || schemaItem.title,
span: span span: span
} }
searchSchema.push(searchSchemaItem) searchSchema.push(searchSchemaItem)
} }
}) })

@ -1,8 +1,8 @@
import { reactive } from 'vue' import { reactive } from 'vue'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { required } from '@/utils/formRules' import { required } from '@/utils/formRules'
import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'
import { DICT_TYPE } from '@/utils/dict' import { DICT_TYPE } from '@/utils/dict'
import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas'
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
// 表单校验 // 表单校验
@ -15,67 +15,61 @@ export const rules = reactive({
}) })
// CrudSchema // CrudSchema
const crudSchemas = reactive<CrudSchema[]>([ const crudSchemas = reactive<VxeCrudSchema>({
{ primaryKey: 'id',
label: t('common.index'), primaryType: 'seq',
field: 'id', primaryTitle: '编号',
type: 'index', action: true,
form: { columns: [
show: false {
title: '应用名',
field: 'name',
isSearch: true
}, },
detail: { {
show: false title: '商户名称',
} field: 'payMerchant',
}, isSearch: true
{
label: '应用名',
field: 'name',
search: {
show: true
}
},
{
label: '商户名称',
field: 'payMerchant',
search: {
show: true
}
},
{
label: t('common.status'),
field: 'status',
dictType: DICT_TYPE.COMMON_STATUS,
dictClass: 'number',
search: {
show: true
}
},
{
label: t('common.createTime'),
field: 'createTime',
form: {
show: false
}, },
search: { {
show: true, title: t('common.status'),
component: 'DatePicker', field: 'status',
componentProps: { dictType: DICT_TYPE.COMMON_STATUS,
type: 'datetimerange', dictClass: 'number',
valueFormat: 'YYYY-MM-DD HH:mm:ss', isSearch: true
defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]
}
}
},
{
label: t('table.action'),
field: 'action',
width: '240px',
form: {
show: false
}, },
detail: { {
show: false title: '支付结果的回调地址',
field: 'payNotifyUrl',
isSearch: true
},
{
title: '退款结果的回调地址',
field: 'refundNotifyUrl',
isSearch: true
},
{
title: '商户名称',
field: 'merchantName',
isSearch: true
},
{
title: '备注',
field: 'remark',
isTable: false,
isSearch: true
},
{
title: t('common.createTime'),
field: 'createTime',
isForm: false,
search: {
show: true,
itemRender: {
name: 'XDataTimePicker'
}
}
} }
} ]
]) })
export const { allSchemas } = useCrudSchemas(crudSchemas) export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

@ -1,23 +1,101 @@
<template>
<ContentWrap>
<!-- 列表 -->
<vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar">
<template #toolbar_buttons>
<!-- 操作新增 -->
<XButton
type="primary"
preIcon="ep:zoom-in"
:title="t('action.add')"
v-hasPermi="['pay:app:create']"
@click="handleCreate()"
/>
<!-- 操作导出 -->
<XButton
type="warning"
preIcon="ep:download"
:title="t('action.export')"
v-hasPermi="['pay:app:export']"
@click="handleExport()"
/>
</template>
<template #actionbtns_default="{ row }">
<!-- 操作修改 -->
<XTextButton
preIcon="ep:edit"
:title="t('action.edit')"
v-hasPermi="['pay:app:update']"
@click="handleUpdate(row.id)"
/>
<!-- 操作详情 -->
<XTextButton
preIcon="ep:view"
:title="t('action.detail')"
v-hasPermi="['pay:app:query']"
@click="handleDetail(row.id)"
/>
<!-- 操作删除 -->
<XTextButton
preIcon="ep:delete"
:title="t('action.del')"
v-hasPermi="['pay:app:delete']"
@click="handleDelete(row.id)"
/>
</template>
</vxe-grid>
</ContentWrap>
<XModal v-model="dialogVisible" :title="dialogTitle">
<!-- 对话框(添加 / 修改) -->
<Form
v-if="['create', 'update'].includes(actionType)"
:schema="allSchemas.formSchema"
:rules="rules"
ref="formRef"
/>
<!-- 对话框(详情) -->
<Descriptions
v-if="actionType === 'detail'"
:schema="allSchemas.detailSchema"
:data="detailData"
/>
<!-- 操作按钮 -->
<template #footer>
<!-- 按钮保存 -->
<XButton
v-if="['create', 'update'].includes(actionType)"
type="primary"
:title="t('action.save')"
:loading="actionLoading"
@click="submitForm()"
/>
<!-- 按钮关闭 -->
<XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
</template>
</XModal>
</template>
<script setup lang="ts" name="App"> <script setup lang="ts" name="App">
import { ref, unref } from 'vue' import { ref, unref } from 'vue'
import dayjs from 'dayjs'
import { ElMessage } from 'element-plus'
import { DICT_TYPE } from '@/utils/dict'
import { useTable } from '@/hooks/web/useTable'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { useMessage } from '@/hooks/web/useMessage'
import { useVxeGrid } from '@/hooks/web/useVxeGrid'
import { VxeGridInstance } from 'vxe-table'
import { FormExpose } from '@/components/Form' import { FormExpose } from '@/components/Form'
import type { AppVO } from '@/api/pay/app/types'
import { rules, allSchemas } from './app.data' import { rules, allSchemas } from './app.data'
import * as AppApi from '@/api/pay/app' import * as AppApi from '@/api/pay/app'
const { t } = useI18n() // const { t } = useI18n() //
const message = useMessage() //
// ========== ========== //
const { register, tableObject, methods } = useTable<AppVO>({ const xGrid = ref<VxeGridInstance>() // Grid Ref
const { gridOptions, getList, deleteData, exportList } = useVxeGrid<AppApi.AppVO>({
allSchemas: allSchemas,
getListApi: AppApi.getAppPageApi, getListApi: AppApi.getAppPageApi,
delListApi: AppApi.deleteAppApi, deleteApi: AppApi.deleteAppApi,
exportListApi: AppApi.exportAppApi exportListApi: AppApi.exportAppApi
}) })
const { getList, setSearchParams, delList, exportList } = methods
// ========== CRUD ========== // ========== CRUD ==========
const actionLoading = ref(false) // const actionLoading = ref(false) //
@ -25,6 +103,7 @@ const actionType = ref('') // 操作按钮的类型
const dialogVisible = ref(false) // const dialogVisible = ref(false) //
const dialogTitle = ref('edit') // const dialogTitle = ref('edit') //
const formRef = ref<FormExpose>() // Ref const formRef = ref<FormExpose>() // Ref
const detailData = ref() // Ref
// //
const setDialogTile = (type: string) => { const setDialogTile = (type: string) => {
@ -38,14 +117,31 @@ const handleCreate = () => {
setDialogTile('create') setDialogTile('create')
} }
//
const handleExport = async () => {
await exportList(xGrid, '应用信息.xls')
}
// //
const handleUpdate = async (row: AppVO) => { const handleUpdate = async (rowId: number) => {
setDialogTile('update') setDialogTile('update')
// //
const res = await AppApi.getAppApi(row.id) const res = await AppApi.getAppApi(rowId)
unref(formRef)?.setValues(res) unref(formRef)?.setValues(res)
} }
//
const handleDetail = async (rowId: number) => {
setDialogTile('detail')
const res = await AppApi.getAppApi(rowId)
detailData.value = res
}
//
const handleDelete = async (rowId: number) => {
await deleteData(xGrid, rowId)
}
// //
const submitForm = async () => { const submitForm = async () => {
const elForm = unref(formRef)?.getElFormRef() const elForm = unref(formRef)?.getElFormRef()
@ -55,132 +151,21 @@ const submitForm = async () => {
actionLoading.value = true actionLoading.value = true
// //
try { try {
const data = unref(formRef)?.formModel as AppVO const data = unref(formRef)?.formModel as AppApi.AppVO
if (actionType.value === 'create') { if (actionType.value === 'create') {
await AppApi.createAppApi(data) await AppApi.createAppApi(data)
ElMessage.success(t('common.createSuccess')) message.success(t('common.createSuccess'))
} else { } else {
await AppApi.updateAppApi(data) await AppApi.updateAppApi(data)
ElMessage.success(t('common.updateSuccess')) message.success(t('common.updateSuccess'))
} }
//
dialogVisible.value = false dialogVisible.value = false
await getList()
} finally { } finally {
actionLoading.value = false actionLoading.value = false
//
await getList(xGrid)
} }
} }
}) })
} }
// ========== ==========
const detailRef = ref() // Ref
//
const handleDetail = async (row: AppVO) => {
//
detailRef.value = row
setDialogTile('detail')
}
// ========== ==========
getList()
</script> </script>
<template>
<!-- 搜索工作区 -->
<ContentWrap>
<Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
</ContentWrap>
<ContentWrap>
<!-- 操作工具栏 -->
<div class="mb-10px">
<el-button type="primary" v-hasPermi="['system:post:create']" @click="handleCreate">
<Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}
</el-button>
<el-button
type="warning"
v-hasPermi="['system:post:export']"
:loading="tableObject.exportLoading"
@click="exportList('应用数据.xls')"
>
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
</div>
<!-- 列表 -->
<Table
:columns="allSchemas.tableColumns"
:selection="false"
:data="tableObject.tableList"
:loading="tableObject.loading"
:pagination="{
total: tableObject.total
}"
v-model:pageSize="tableObject.pageSize"
v-model:currentPage="tableObject.currentPage"
@register="register"
>
<template #status="{ row }">
<DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
</template>
<template #createTime="{ row }">
<span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
</template>
<template #action="{ row }">
<el-button
link
type="primary"
v-hasPermi="['system:post:update']"
@click="handleUpdate(row)"
>
<Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
</el-button>
<el-button
link
type="primary"
v-hasPermi="['system:post:update']"
@click="handleDetail(row)"
>
<Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }}
</el-button>
<el-button
link
type="primary"
v-hasPermi="['system:post:delete']"
@click="delList(row.id, false)"
>
<Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
</el-button>
</template>
</Table>
</ContentWrap>
<XModal v-model="dialogVisible" :title="dialogTitle">
<!-- 对话框(添加 / 修改) -->
<Form
v-if="['create', 'update'].includes(actionType)"
:schema="allSchemas.formSchema"
:rules="rules"
ref="formRef"
/>
<!-- 对话框(详情) -->
<Descriptions
v-if="actionType === 'detail'"
:schema="allSchemas.detailSchema"
:data="detailRef"
/>
<!-- 操作按钮 -->
<template #footer>
<!-- 按钮保存 -->
<XButton
v-if="['create', 'update'].includes(actionType)"
type="primary"
:title="t('action.save')"
:loading="actionLoading"
@click="submitForm()"
/>
<!-- 按钮关闭 -->
<XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
</template>
</XModal>
</template>

@ -1,23 +1,99 @@
<template>
<ContentWrap>
<!-- 列表 -->
<vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar">
<template #toolbar_buttons>
<!-- 操作新增 -->
<XButton
type="primary"
preIcon="ep:zoom-in"
:title="t('action.add')"
v-hasPermi="['pay:merchant:create']"
@click="handleCreate()"
/>
<!-- 操作导出 -->
<XButton
type="warning"
preIcon="ep:download"
:title="t('action.export')"
v-hasPermi="['pay:merchant:export']"
@click="handleExport()"
/>
</template>
<template #actionbtns_default="{ row }">
<!-- 操作修改 -->
<XTextButton
preIcon="ep:edit"
:title="t('action.edit')"
v-hasPermi="['pay:merchant:update']"
@click="handleUpdate(row.id)"
/>
<!-- 操作详情 -->
<XTextButton
preIcon="ep:view"
:title="t('action.detail')"
v-hasPermi="['pay:merchant:query']"
@click="handleDetail(row.id)"
/>
<!-- 操作删除 -->
<XTextButton
preIcon="ep:delete"
:title="t('action.del')"
v-hasPermi="['pay:merchant:delete']"
@click="handleDelete(row.id)"
/>
</template>
</vxe-grid>
</ContentWrap>
<XModal v-model="dialogVisible" :title="dialogTitle">
<!-- 对话框(添加 / 修改) -->
<Form
v-if="['create', 'update'].includes(actionType)"
:schema="allSchemas.formSchema"
:rules="rules"
ref="formRef"
/>
<!-- 对话框(详情) -->
<Descriptions
v-if="actionType === 'detail'"
:schema="allSchemas.detailSchema"
:data="detailData"
/>
<!-- 操作按钮 -->
<template #footer>
<!-- 按钮保存 -->
<XButton
v-if="['create', 'update'].includes(actionType)"
type="primary"
:title="t('action.save')"
:loading="actionLoading"
@click="submitForm()"
/>
<!-- 按钮关闭 -->
<XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
</template>
</XModal>
</template>
<script setup lang="ts" name="Merchant"> <script setup lang="ts" name="Merchant">
import { ref, unref } from 'vue' import { ref, unref } from 'vue'
import dayjs from 'dayjs'
import { ElMessage } from 'element-plus'
import { DICT_TYPE } from '@/utils/dict'
import { useTable } from '@/hooks/web/useTable'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { useMessage } from '@/hooks/web/useMessage'
import { useVxeGrid } from '@/hooks/web/useVxeGrid'
import { VxeGridInstance } from 'vxe-table'
import { FormExpose } from '@/components/Form' import { FormExpose } from '@/components/Form'
import type { MerchantVO } from '@/api/pay/merchant/types'
import { rules, allSchemas } from './merchant.data' import { rules, allSchemas } from './merchant.data'
import * as MerchantApi from '@/api/pay/merchant' import * as MerchantApi from '@/api/pay/merchant'
const { t } = useI18n() //
// ========== ========== const { t } = useI18n() //
const { register, tableObject, methods } = useTable<MerchantVO>({ const message = useMessage() //
//
const xGrid = ref<VxeGridInstance>() // Grid Ref
const { gridOptions, getList, deleteData, exportList } = useVxeGrid<MerchantApi.MerchantVO>({
allSchemas: allSchemas,
getListApi: MerchantApi.getMerchantPageApi, getListApi: MerchantApi.getMerchantPageApi,
delListApi: MerchantApi.deleteMerchantApi, deleteApi: MerchantApi.deleteMerchantApi,
exportListApi: MerchantApi.exportMerchantApi exportListApi: MerchantApi.exportMerchantApi
}) })
const { getList, setSearchParams, delList, exportList } = methods
// ========== CRUD ========== // ========== CRUD ==========
const actionLoading = ref(false) // const actionLoading = ref(false) //
@ -25,6 +101,7 @@ const actionType = ref('') // 操作按钮的类型
const dialogVisible = ref(false) // const dialogVisible = ref(false) //
const dialogTitle = ref('edit') // const dialogTitle = ref('edit') //
const formRef = ref<FormExpose>() // Ref const formRef = ref<FormExpose>() // Ref
const detailData = ref() // Ref
// //
const setDialogTile = (type: string) => { const setDialogTile = (type: string) => {
@ -38,14 +115,31 @@ const handleCreate = () => {
setDialogTile('create') setDialogTile('create')
} }
//
const handleExport = async () => {
await exportList(xGrid, '商户列表.xls')
}
// //
const handleUpdate = async (row: MerchantVO) => { const handleUpdate = async (rowId: number) => {
setDialogTile('update') setDialogTile('update')
// //
const res = await MerchantApi.getMerchantApi(row.id) const res = await MerchantApi.getMerchantApi(rowId)
unref(formRef)?.setValues(res) unref(formRef)?.setValues(res)
} }
//
const handleDetail = async (rowId: number) => {
setDialogTile('detail')
const res = await MerchantApi.getMerchantApi(rowId)
detailData.value = res
}
//
const handleDelete = async (rowId: number) => {
await deleteData(xGrid, rowId)
}
// //
const submitForm = async () => { const submitForm = async () => {
const elForm = unref(formRef)?.getElFormRef() const elForm = unref(formRef)?.getElFormRef()
@ -55,132 +149,21 @@ const submitForm = async () => {
actionLoading.value = true actionLoading.value = true
// //
try { try {
const data = unref(formRef)?.formModel as MerchantVO const data = unref(formRef)?.formModel as MerchantApi.MerchantVO
if (actionType.value === 'create') { if (actionType.value === 'create') {
await MerchantApi.createMerchantApi(data) await MerchantApi.createMerchantApi(data)
ElMessage.success(t('common.createSuccess')) message.success(t('common.createSuccess'))
} else { } else {
await MerchantApi.updateMerchantApi(data) await MerchantApi.updateMerchantApi(data)
ElMessage.success(t('common.updateSuccess')) message.success(t('common.updateSuccess'))
} }
//
dialogVisible.value = false dialogVisible.value = false
await getList()
} finally { } finally {
actionLoading.value = false actionLoading.value = false
//
await getList(xGrid)
} }
} }
}) })
} }
// ========== ==========
const detailRef = ref() // Ref
//
const handleDetail = async (row: MerchantVO) => {
//
detailRef.value = row
setDialogTile('detail')
}
// ========== ==========
getList()
</script> </script>
<template>
<!-- 搜索工作区 -->
<ContentWrap>
<Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
</ContentWrap>
<ContentWrap>
<!-- 操作工具栏 -->
<div class="mb-10px">
<el-button type="primary" v-hasPermi="['system:post:create']" @click="handleCreate">
<Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}
</el-button>
<el-button
type="warning"
v-hasPermi="['system:post:export']"
:loading="tableObject.exportLoading"
@click="exportList('商户数据.xls')"
>
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
</div>
<!-- 列表 -->
<Table
:columns="allSchemas.tableColumns"
:selection="false"
:data="tableObject.tableList"
:loading="tableObject.loading"
:pagination="{
total: tableObject.total
}"
v-model:pageSize="tableObject.pageSize"
v-model:currentPage="tableObject.currentPage"
@register="register"
>
<template #status="{ row }">
<DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
</template>
<template #createTime="{ row }">
<span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
</template>
<template #action="{ row }">
<el-button
link
type="primary"
v-hasPermi="['system:post:update']"
@click="handleUpdate(row)"
>
<Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
</el-button>
<el-button
link
type="primary"
v-hasPermi="['system:post:update']"
@click="handleDetail(row)"
>
<Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }}
</el-button>
<el-button
link
type="primary"
v-hasPermi="['system:post:delete']"
@click="delList(row.id, false)"
>
<Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
</el-button>
</template>
</Table>
</ContentWrap>
<XModal v-model="dialogVisible" :title="dialogTitle">
<!-- 对话框(添加 / 修改) -->
<Form
v-if="['create', 'update'].includes(actionType)"
:schema="allSchemas.formSchema"
:rules="rules"
ref="formRef"
/>
<!-- 对话框(详情) -->
<Descriptions
v-if="actionType === 'detail'"
:schema="allSchemas.detailSchema"
:data="detailRef"
/>
<!-- 操作按钮 -->
<template #footer>
<!-- 按钮保存 -->
<XButton
v-if="['create', 'update'].includes(actionType)"
type="primary"
:title="t('action.save')"
:loading="actionLoading"
@click="submitForm()"
/>
<!-- 按钮关闭 -->
<XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
</template>
</XModal>
</template>

@ -1,8 +1,8 @@
import { reactive } from 'vue' import { reactive } from 'vue'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { required } from '@/utils/formRules' import { required } from '@/utils/formRules'
import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'
import { DICT_TYPE } from '@/utils/dict' import { DICT_TYPE } from '@/utils/dict'
import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas'
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
// 表单校验 // 表单校验
@ -14,91 +14,61 @@ export const rules = reactive({
}) })
// CrudSchema // CrudSchema
const crudSchemas = reactive<CrudSchema[]>([ const crudSchemas = reactive<VxeCrudSchema>({
{ primaryKey: 'id',
label: t('common.index'), primaryType: 'seq',
field: 'id', primaryTitle: '商户编号',
type: 'index', action: true,
form: { columns: [
show: false {
title: '商户号',
field: 'no',
isSearch: true
}, },
detail: { {
show: false title: '商户全称',
} field: 'code',
}, isSearch: true
{
label: '商户号',
field: 'no',
search: {
show: true
}
},
{
label: '商户全称',
field: 'code',
search: {
show: true
}
},
{
label: '商户简称',
field: 'shortName',
search: {
show: true
}
},
{
label: t('common.status'),
field: 'status',
dictType: DICT_TYPE.COMMON_STATUS,
dictClass: 'number',
search: {
show: true
}
},
{
label: t('form.remark'),
field: 'remark',
form: {
component: 'Input',
componentProps: {
type: 'textarea',
rows: 4
},
colProps: {
span: 24
}
}, },
table: { {
show: false title: '商户简称',
} field: 'shortName',
}, isSearch: true
{ },
label: t('common.createTime'), {
field: 'createTime', title: t('common.status'),
form: { field: 'status',
show: false dictType: DICT_TYPE.COMMON_STATUS,
dictClass: 'number',
isSearch: true
}, },
search: { {
show: true, title: t('form.remark'),
component: 'DatePicker', field: 'remark',
componentProps: { isTable: false,
type: 'datetimerange', form: {
valueFormat: 'YYYY-MM-DD HH:mm:ss', component: 'Input',
defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)] componentProps: {
type: 'textarea',
rows: 4
},
colProps: {
span: 24
}
} }
}
},
{
label: t('table.action'),
field: 'action',
width: '240px',
form: {
show: false
}, },
detail: { {
show: false title: t('common.createTime'),
field: 'createTime',
formatter: 'formatDate',
isForm: false,
search: {
show: true,
itemRender: {
name: 'XDataTimePicker'
}
}
} }
} ]
]) })
export const { allSchemas } = useCrudSchemas(crudSchemas) export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

@ -1,28 +1,68 @@
<template>
<ContentWrap>
<!-- 列表 -->
<vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar">
<template #toolbar_buttons>
<!-- 操作新增 -->
<XButton
type="primary"
preIcon="ep:zoom-in"
:title="t('action.add')"
v-hasPermi="['pay:order:create']"
@click="handleCreate()"
/>
<!-- 操作导出 -->
<XButton
type="warning"
preIcon="ep:download"
:title="t('action.export')"
v-hasPermi="['pay:order:export']"
@click="handleExport()"
/>
</template>
<template #actionbtns_default="{ row }">
<!-- 操作详情 -->
<XTextButton
preIcon="ep:view"
:title="t('action.detail')"
v-hasPermi="['pay:order:query']"
@click="handleDetail(row.id)"
/>
</template>
</vxe-grid>
</ContentWrap>
<XModal v-model="dialogVisible" :title="dialogTitle">
<!-- 对话框(详情) -->
<Descriptions :schema="allSchemas.detailSchema" :data="detailData" />
<!-- 操作按钮 -->
<template #footer>
<!-- 按钮关闭 -->
<XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
</template>
</XModal>
</template>
<script setup lang="ts" name="Order"> <script setup lang="ts" name="Order">
import { ref, unref } from 'vue' import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { DICT_TYPE } from '@/utils/dict'
import { useTable } from '@/hooks/web/useTable'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { FormExpose } from '@/components/Form' import { useVxeGrid } from '@/hooks/web/useVxeGrid'
import type { OrderVO } from '@/api/pay/order/types' import { VxeGridInstance } from 'vxe-table'
import { rules, allSchemas } from './order.data' import { allSchemas } from './order.data'
import * as OrderApi from '@/api/pay/order' import * as OrderApi from '@/api/pay/order'
const { t } = useI18n() // const { t } = useI18n() //
// ========== ========== //
const { register, tableObject, methods } = useTable<OrderVO>({ const xGrid = ref<VxeGridInstance>() // Grid Ref
const { gridOptions, exportList } = useVxeGrid<OrderApi.OrderVO>({
allSchemas: allSchemas,
getListApi: OrderApi.getOrderPageApi, getListApi: OrderApi.getOrderPageApi,
delListApi: OrderApi.deleteOrderApi,
exportListApi: OrderApi.exportOrderApi exportListApi: OrderApi.exportOrderApi
}) })
const { getList, setSearchParams, delList, exportList } = methods
// ========== CRUD ========== // ========== CRUD ==========
const actionLoading = ref(false) // const actionLoading = ref(false) //
const actionType = ref('') // const actionType = ref('') //
const dialogVisible = ref(false) // const dialogVisible = ref(false) //
const dialogTitle = ref('edit') // const dialogTitle = ref('edit') //
const formRef = ref<FormExpose>() // Ref const detailData = ref() // Ref
// //
const setDialogTile = (type: string) => { const setDialogTile = (type: string) => {
dialogTitle.value = t('action.' + type) dialogTitle.value = t('action.' + type)
@ -34,137 +74,15 @@ const setDialogTile = (type: string) => {
const handleCreate = () => { const handleCreate = () => {
setDialogTile('create') setDialogTile('create')
} }
//
// const handleExport = async () => {
const handleUpdate = async (row: OrderVO) => { await exportList(xGrid, '订单数据.xls')
setDialogTile('update')
//
const res = await OrderApi.getOrderApi(row.id)
unref(formRef)?.setValues(res)
}
//
const submitForm = async () => {
const elForm = unref(formRef)?.getElFormRef()
if (!elForm) return
elForm.validate(async (valid) => {
if (valid) {
actionLoading.value = true
//
try {
const data = unref(formRef)?.formModel as OrderVO
if (actionType.value === 'create') {
await OrderApi.createOrderApi(data)
ElMessage.success(t('common.createSuccess'))
} else {
await OrderApi.updateOrderApi(data)
ElMessage.success(t('common.updateSuccess'))
}
//
dialogVisible.value = false
await getList()
} finally {
actionLoading.value = false
}
}
})
} }
// ========== ==========
const detailRef = ref() // Ref
// //
const handleDetail = async (row: OrderVO) => { const handleDetail = async (rowId: number) => {
setDialogTile('detail') setDialogTile('detail')
// const res = await OrderApi.getOrderApi(rowId)
const res = await OrderApi.getOrderApi(row.id as number) detailData.value = res
detailRef.value = res
} }
// ========== ==========
getList()
</script> </script>
<template>
<!-- 搜索工作区 -->
<ContentWrap>
<Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
</ContentWrap>
<ContentWrap>
<!-- 操作工具栏 -->
<div class="mb-10px">
<el-button type="primary" v-hasPermi="['pay:order:create']" @click="handleCreate">
<Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}
</el-button>
<el-button
type="warning"
v-hasPermi="['pay:order:export']"
:loading="tableObject.exportLoading"
@click="exportList('订单数据.xls')"
>
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
</div>
<!-- 列表 -->
<Table
:columns="allSchemas.tableColumns"
:selection="false"
:data="tableObject.tableList"
:loading="tableObject.loading"
:pagination="{
total: tableObject.total
}"
v-model:pageSize="tableObject.pageSize"
v-model:currentPage="tableObject.currentPage"
@register="register"
>
<template #status="{ row }">
<DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
</template>
<template #action="{ row }">
<el-button link type="primary" v-hasPermi="['pay:order:update']" @click="handleUpdate(row)">
<Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
</el-button>
<el-button link type="primary" v-hasPermi="['pay:order:update']" @click="handleDetail(row)">
<Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }}
</el-button>
<el-button
link
type="primary"
v-hasPermi="['pay:order:delete']"
@click="delList(row.id, false)"
>
<Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
</el-button>
</template>
</Table>
</ContentWrap>
<XModal v-model="dialogVisible" :title="dialogTitle">
<!-- 对话框(添加 / 修改) -->
<Form
v-if="['create', 'update'].includes(actionType)"
:schema="allSchemas.formSchema"
:rules="rules"
ref="formRef"
/>
<!-- 对话框(详情) -->
<Descriptions
v-if="actionType === 'detail'"
:schema="allSchemas.detailSchema"
:data="detailRef"
/>
<!-- 操作按钮 -->
<template #footer>
<!-- 按钮保存 -->
<XButton
v-if="['create', 'update'].includes(actionType)"
type="primary"
:title="t('action.save')"
:loading="actionLoading"
@click="submitForm()"
/>
<!-- 按钮关闭 -->
<XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
</template>
</XModal>
</template>

@ -1,8 +1,8 @@
import { reactive } from 'vue' import { reactive } from 'vue'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { required } from '@/utils/formRules' import { required } from '@/utils/formRules'
import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'
import { DICT_TYPE } from '@/utils/dict' import { DICT_TYPE } from '@/utils/dict'
import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas'
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
// 表单校验 // 表单校验
@ -23,166 +23,134 @@ export const rules = reactive({
refundAmount: [required] refundAmount: [required]
}) })
// CrudSchema // CrudSchema
const crudSchemas = reactive<CrudSchema[]>([ const crudSchemas = reactive<VxeCrudSchema>({
{ primaryKey: 'id',
label: t('common.index'), primaryType: 'seq',
field: 'id', primaryTitle: '岗位编号',
type: 'index', action: true,
form: { columns: [
show: false {
}, title: '商户编号',
detail: { field: 'merchantId',
show: false isSearch: true
} },
}, {
{ title: '应用编号',
label: '商户编号', field: 'appId',
field: 'merchantId', isSearch: true
search: { },
show: true {
} title: '渠道编号',
}, field: 'channelId'
{ },
label: '应用编号', {
field: 'appId', title: '渠道编码',
search: { field: 'channelCode',
show: true isSearch: true
} },
}, {
{ title: '渠道订单号',
label: '渠道编号', field: 'merchantOrderId',
field: 'channelId' isSearch: true
}, },
{ {
label: '渠道编码', title: '商品标题',
field: 'channelCode', field: 'subject'
search: { },
show: true {
} title: '商品描述',
}, field: 'body'
{ },
label: '渠道订单号', {
field: 'merchantOrderId', title: '异步通知地址',
search: { field: 'notifyUrl'
show: true },
} {
}, title: '回调状态',
{ field: 'notifyStatus',
label: '商品标题', dictType: DICT_TYPE.PAY_ORDER_NOTIFY_STATUS,
field: 'subject' dictClass: 'number'
}, },
{ {
label: '商品描述', title: '支付金额',
field: 'body' field: 'amount',
}, isSearch: true
{ },
label: '异步通知地址', {
field: 'notifyUrl' title: '渠道手续费',
}, field: 'channelFeeRate',
{ isSearch: true
label: '回调商户状态', },
field: 'notifyStatus', {
dictType: DICT_TYPE.PAY_ORDER_NOTIFY_STATUS, title: '渠道手续金额',
dictClass: 'number' field: 'channelFeeAmount',
}, isSearch: true
{ },
label: '支付金额', {
field: 'amount', title: '支付状态',
search: { field: 'status',
show: true dictType: DICT_TYPE.PAY_ORDER_STATUS,
} dictClass: 'number',
}, isSearch: true
{ },
label: '渠道手续费', {
field: 'channelFeeRate', title: '用户 IP',
search: { field: 'userIp'
show: true },
} {
}, title: '订单失效时间',
{ field: 'expireTime',
label: '渠道手续金额', formatter: 'formatDate'
field: 'channelFeeAmount', },
search: { {
show: true title: '支付时间',
} field: 'successTime',
}, formatter: 'formatDate'
{ },
label: '支付状态', {
field: 'status', title: '支付通知时间',
dictType: DICT_TYPE.PAY_ORDER_STATUS, field: 'notifyTime',
dictClass: 'number', formatter: 'formatDate'
search: { },
show: true {
} title: '拓展编号',
}, field: 'successExtensionId'
{ },
label: '用户 IP', {
field: 'userIp' title: '退款状态',
}, field: 'refundStatus',
{ dictType: DICT_TYPE.PAY_ORDER_REFUND_STATUS,
label: '订单失效时间', dictClass: 'number',
field: 'expireTime' isSearch: true
}, },
{ {
label: '订单支付成功时间', title: '退款次数',
field: 'successTime' field: 'refundTimes'
}, },
{ {
label: '订单支付通知时间', title: '退款总金额',
field: 'notifyTime' field: 'refundAmount'
}, },
{ {
label: '支付成功的订单拓展单编号', title: '渠道用户编号',
field: 'successExtensionId' field: 'channelUserId'
}, },
{ {
label: '退款状态', title: '渠道订单号',
field: 'refundStatus', field: 'channelOrderNo'
dictType: DICT_TYPE.PAY_ORDER_REFUND_STATUS, },
dictClass: 'number', {
search: { title: t('common.createTime'),
show: true field: 'createTime',
} formatter: 'formatDate',
}, isForm: false,
{ search: {
label: '退款次数', show: true,
field: 'refundTimes' itemRender: {
}, name: 'XDataTimePicker'
{ }
label: '退款总金额',
field: 'refundAmount'
},
{
label: '渠道用户编号',
field: 'channelUserId'
},
{
label: '渠道订单号',
field: 'channelOrderNo'
},
{
label: t('common.createTime'),
field: 'createTime',
form: {
show: false
},
search: {
show: true,
component: 'DatePicker',
componentProps: {
type: 'datetimerange',
valueFormat: 'YYYY-MM-DD HH:mm:ss',
defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]
} }
} }
}, ]
{ })
label: t('table.action'), export const { allSchemas } = useVxeCrudSchemas(crudSchemas)
field: 'action',
width: '270px',
form: {
show: false
}
}
])
export const { allSchemas } = useCrudSchemas(crudSchemas)

@ -1,104 +1,69 @@
<template>
<ContentWrap>
<!-- 列表 -->
<vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar">
<template #toolbar_buttons>
<!-- 操作导出 -->
<XButton
type="warning"
preIcon="ep:download"
:title="t('action.export')"
v-hasPermi="['pay:refund:export']"
@click="handleExport()"
/>
</template>
<template #actionbtns_default="{ row }">
<!-- 操作详情 -->
<XTextButton
preIcon="ep:view"
:title="t('action.detail')"
v-hasPermi="['pay:refund:query']"
@click="handleDetail(row.id)"
/>
</template>
</vxe-grid>
</ContentWrap>
<XModal v-model="dialogVisible" :title="t('action.detail')">
<!-- 对话框(详情) -->
<Descriptions :schema="allSchemas.detailSchema" :data="detailData" />
<!-- 操作按钮 -->
<template #footer>
<el-button @click="dialogVisible = false">{{ t('dialog.close') }}</el-button>
</template>
</XModal>
</template>
<script setup lang="ts" name="Refund"> <script setup lang="ts" name="Refund">
import { ref } from 'vue' import { ref } from 'vue'
import dayjs from 'dayjs'
import { DICT_TYPE } from '@/utils/dict'
import { useTable } from '@/hooks/web/useTable'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import type { RefundVO } from '@/api/pay/refund/types' import { useVxeGrid } from '@/hooks/web/useVxeGrid'
import { VxeGridInstance } from 'vxe-table'
import { allSchemas } from './refund.data' import { allSchemas } from './refund.data'
import * as RefundApi from '@/api/pay/refund' import * as RefundApi from '@/api/pay/refund'
const { t } = useI18n() // const { t } = useI18n() //
// ========== ========== //
const { register, tableObject, methods } = useTable<RefundVO>({ const xGrid = ref<VxeGridInstance>() // Grid Ref
const { gridOptions, exportList } = useVxeGrid<RefundApi.RefundVO>({
allSchemas: allSchemas,
getListApi: RefundApi.getRefundPageApi, getListApi: RefundApi.getRefundPageApi,
delListApi: RefundApi.deleteRefundApi,
exportListApi: RefundApi.exportRefundApi exportListApi: RefundApi.exportRefundApi
}) })
const { getList, setSearchParams, delList, exportList } = methods
//
const handleExport = async () => {
await exportList(xGrid, '退款订单.xls')
}
// ========== CRUD ========== // ========== CRUD ==========
const dialogVisible = ref(false) // const dialogVisible = ref(false) //
const dialogTitle = ref('edit') // const detailData = ref() // Ref
// ========== ==========
const detailRef = ref() // Ref
// //
const handleDetail = async (row: RefundVO) => { const handleDetail = async (rowId: number) => {
// //
detailRef.value = RefundApi.getRefundApi(row.id) detailData.value = RefundApi.getRefundApi(rowId)
dialogTitle.value = t('action.detail')
dialogVisible.value = true dialogVisible.value = true
} }
// ========== ==========
getList()
</script> </script>
<template>
<!-- 搜索工作区 -->
<ContentWrap>
<Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
</ContentWrap>
<ContentWrap>
<!-- 操作工具栏 -->
<div class="mb-10px">
<el-button
type="warning"
v-hasPermi="['system:post:export']"
:loading="tableObject.exportLoading"
@click="exportList('退款订单.xls')"
>
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
</div>
<!-- 列表 -->
<Table
:columns="allSchemas.tableColumns"
:selection="false"
:data="tableObject.tableList"
:loading="tableObject.loading"
:pagination="{
total: tableObject.total
}"
v-model:pageSize="tableObject.pageSize"
v-model:currentPage="tableObject.currentPage"
@register="register"
>
<template #status="{ row }">
<DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
</template>
<template #createTime="{ row }">
<span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
</template>
<template #action="{ row }">
<el-button
link
type="primary"
v-hasPermi="['system:post:update']"
@click="handleDetail(row)"
>
<Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }}
</el-button>
<el-button
link
type="primary"
v-hasPermi="['system:post:delete']"
@click="delList(row.id, false)"
>
<Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
</el-button>
</template>
</Table>
</ContentWrap>
<XModal v-model="dialogVisible" :title="dialogTitle">
<!-- 对话框(详情) -->
<Descriptions :schema="allSchemas.detailSchema" :data="detailRef" />
<!-- 操作按钮 -->
<template #footer>
<el-button @click="dialogVisible = false">{{ t('dialog.close') }}</el-button>
</template>
</XModal>
</template>

@ -1,112 +1,176 @@
import { reactive } from 'vue' import { reactive } from 'vue'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'
import { DICT_TYPE } from '@/utils/dict' import { DICT_TYPE } from '@/utils/dict'
import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas'
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
// CrudSchema // CrudSchema
const crudSchemas = reactive<CrudSchema[]>([ const crudSchemas = reactive<VxeCrudSchema>({
{ primaryKey: 'id',
label: t('common.index'), primaryType: 'seq',
field: 'id', primaryTitle: '序号',
type: 'index', action: true,
form: { columns: [
show: false {
}, title: '商户编号',
detail: { field: 'merchantId',
show: false isSearch: true
} },
}, {
{ title: '应用编号',
label: '应用编号', field: 'appId',
field: 'appId', isSearch: true
search: { },
show: true {
} title: '渠道编号',
}, field: 'channelId',
{ isSearch: true
label: '商户名称', },
field: 'merchantName' {
}, title: '渠道编码',
{ field: 'channelCode',
label: '应用名称', dictType: DICT_TYPE.PAY_CHANNEL_CODE_TYPE,
field: 'appName' dictClass: 'number',
}, isSearch: true
{ },
label: '商品名称', {
field: 'subject' title: '支付订单编号',
}, field: 'orderId',
{ isSearch: true
label: '商户退款单号', },
field: 'merchantRefundNo' {
}, title: '交易订单号',
{ field: 'tradeNo',
label: '商户订单号', isSearch: true
field: 'merchantOrderId' },
}, {
{ title: '商户订单号',
label: '交易订单号', field: 'merchantOrderId',
field: 'tradeNo' isSearch: true
}, },
{ {
label: '支付金额', title: '商户退款单号',
field: 'payAmount' field: 'merchantRefundNo',
}, isSearch: true
{ },
label: '退款金额', {
field: 'refundAmount' title: '回调地址',
}, field: 'notifyUrl',
{ isSearch: true
label: '渠道编码', },
field: 'channelCode', {
search: { title: '回调状态',
show: true field: 'notifyStatus',
} dictType: DICT_TYPE.PAY_ORDER_NOTIFY_STATUS,
}, dictClass: 'number',
{ isSearch: true
label: '退款类型', },
field: 'type', {
dictType: DICT_TYPE.PAY_REFUND_ORDER_TYPE, title: '退款类型',
dictClass: 'number', field: 'type',
search: { dictType: DICT_TYPE.PAY_REFUND_ORDER_TYPE,
show: true dictClass: 'number',
} isSearch: true
}, },
{ {
label: t('common.status'), title: t('common.status'),
field: 'status', field: 'status',
dictType: DICT_TYPE.PAY_REFUND_ORDER_STATUS, dictType: DICT_TYPE.PAY_REFUND_ORDER_STATUS,
dictClass: 'number', dictClass: 'number',
search: { isSearch: true
show: true },
} {
}, title: '支付金额',
{ field: 'payAmount',
label: t('common.createTime'), formatter: 'formatAmount',
field: 'createTime', isSearch: true
form: { },
show: false {
}, title: '退款金额',
search: { field: 'refundAmount',
show: true, formatter: 'formatAmount',
component: 'DatePicker', isSearch: true
componentProps: { },
type: 'datetimerange', {
valueFormat: 'YYYY-MM-DD HH:mm:ss', title: '退款原因',
defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)] field: 'reason',
isSearch: true
},
{
title: '用户IP',
field: 'userIp',
isSearch: true
},
{
title: '渠道订单号',
field: 'channelOrderNo',
isSearch: true
},
{
title: '渠道退款单号',
field: 'channelRefundNo',
isSearch: true
},
{
title: '渠道调用报错时',
field: 'channelErrorCode'
},
{
title: '渠道调用报错时',
field: 'channelErrorMsg'
},
{
title: '支付渠道的额外参数',
field: 'channelExtras'
},
{
title: '退款失效时间',
field: 'expireTime',
formatter: 'formatDate',
isForm: false,
search: {
show: true,
itemRender: {
name: 'XDataTimePicker'
}
}
},
{
title: '退款成功时间',
field: 'successTime',
formatter: 'formatDate',
isForm: false,
search: {
show: true,
itemRender: {
name: 'XDataTimePicker'
}
}
},
{
title: '退款通知时间',
field: 'notifyTime',
formatter: 'formatDate',
isForm: false,
search: {
show: true,
itemRender: {
name: 'XDataTimePicker'
}
}
},
{
title: t('common.createTime'),
field: 'createTime',
formatter: 'formatDate',
isForm: false,
search: {
show: true,
itemRender: {
name: 'XDataTimePicker'
}
} }
} }
}, ]
{ })
label: t('table.action'), export const { allSchemas } = useVxeCrudSchemas(crudSchemas)
field: 'action',
width: '240px',
form: {
show: false
},
detail: {
show: false
}
}
])
export const { allSchemas } = useCrudSchemas(crudSchemas)

Loading…
Cancel
Save