mirror of
				https://gitee.com/hhyykk/ipms-sjy-ui.git
				synced 2025-10-30 09:48:44 +08:00 
			
		
		
		
	!116 【重构】Vue3 管理后台:[支付管理 -> 应用信息][支付管理 -> 支付订单][支付管理 -> 退款订单] 使用 Element Plus 原生实现
Merge pull request !116 from 东方白/dev
This commit is contained in:
		| @@ -114,6 +114,10 @@ export const PayChannelEnum = { | ||||
|   ALIPAY_QR: { | ||||
|     code: 'alipay_qr', | ||||
|     name: '支付宝扫码支付' | ||||
|   }, | ||||
|   ALIPAY_BAR: { | ||||
|     code: 'alipay_bar', | ||||
|     name: '支付宝条码支付' | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										158
									
								
								src/views/pay/app/AppForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								src/views/pay/app/AppForm.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,158 @@ | ||||
| <template> | ||||
|   <Dialog :title="dialogTitle" v-model="dialogVisible" width="50%"> | ||||
|     <el-form | ||||
|       ref="formRef" | ||||
|       :model="formData" | ||||
|       :rules="formRules" | ||||
|       label-width="160px" | ||||
|       v-loading="formLoading" | ||||
|     > | ||||
|       <el-form-item label="应用名" prop="name"> | ||||
|         <el-input v-model="formData.name" placeholder="请输入应用名" /> | ||||
|       </el-form-item> | ||||
|  | ||||
|       <el-form-item label="所属商户" prop="merchantId"> | ||||
|         <el-select | ||||
|           v-model="formData.merchantId" | ||||
|           filterable | ||||
|           remote | ||||
|           reserve-keyword | ||||
|           placeholder="请选择所属商户" | ||||
|           :remote-method="handleGetMerchantListByName" | ||||
|           :loading="formLoading" | ||||
|         > | ||||
|           <el-option | ||||
|             v-for="item in merchantList" | ||||
|             :key="item.id" | ||||
|             :label="item.name" | ||||
|             :value="item.id" | ||||
|           /> | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="开启状态" prop="status"> | ||||
|         <el-radio-group v-model="formData.status"> | ||||
|           <el-radio | ||||
|             v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" | ||||
|             :key="dict.value" | ||||
|             :label="dict.value" | ||||
|           > | ||||
|             {{ dict.label }} | ||||
|           </el-radio> | ||||
|         </el-radio-group> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="支付结果的回调地址" prop="payNotifyUrl"> | ||||
|         <el-input v-model="formData.payNotifyUrl" placeholder="请输入支付结果的回调地址" /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="退款结果的回调地址" prop="refundNotifyUrl"> | ||||
|         <el-input v-model="formData.refundNotifyUrl" placeholder="请输入退款结果的回调地址" /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="备注" prop="remark"> | ||||
|         <el-input v-model="formData.remark" placeholder="请输入备注" /> | ||||
|       </el-form-item> | ||||
|     </el-form> | ||||
|     <template #footer> | ||||
|       <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> | ||||
|       <el-button @click="dialogVisible = false">取 消</el-button> | ||||
|     </template> | ||||
|   </Dialog> | ||||
| </template> | ||||
| <script setup lang="ts"> | ||||
| import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' | ||||
| import * as AppApi from '@/api/pay/app' | ||||
| import * as MerchantApi from '@/api/pay/merchant' | ||||
| import { CommonStatusEnum } from '@/utils/constants' | ||||
|  | ||||
| const { t } = useI18n() // 国际化 | ||||
| const message = useMessage() // 消息弹窗 | ||||
| const dialogVisible = ref(false) // 弹窗的是否展示 | ||||
| const dialogTitle = ref('') // 弹窗的标题 | ||||
| const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 | ||||
| const formType = ref('') // 表单的类型:create - 新增;update - 修改 | ||||
| const formData = ref({ | ||||
|   id: undefined, | ||||
|   name: undefined, | ||||
|   packageId: undefined, | ||||
|   contactName: undefined, | ||||
|   contactMobile: undefined, | ||||
|   accountCount: undefined, | ||||
|   expireTime: undefined, | ||||
|   domain: undefined, | ||||
|   status: CommonStatusEnum.ENABLE | ||||
| }) | ||||
| const formRules = reactive({ | ||||
|   name: [{ required: true, message: '应用名不能为空', trigger: 'blur' }], | ||||
|   status: [{ required: true, message: '开启状态不能为空', trigger: 'blur' }], | ||||
|   payNotifyUrl: [{ required: true, message: '支付结果的回调地址不能为空', trigger: 'blur' }], | ||||
|   refundNotifyUrl: [{ required: true, message: '退款结果的回调地址不能为空', trigger: 'blur' }], | ||||
|   merchantId: [{ required: true, message: '商户编号不能为空', trigger: 'blur' }] | ||||
| }) | ||||
| const formRef = ref() // 表单 Ref | ||||
| const merchantList = ref([]) // 商户列表 | ||||
|  | ||||
| /** 打开弹窗 */ | ||||
| const open = async (type: string, id?: number) => { | ||||
|   dialogVisible.value = true | ||||
|   dialogTitle.value = t('action.' + type) | ||||
|   formType.value = type | ||||
|   resetForm() | ||||
|   // 修改时,设置数据 | ||||
|   if (id) { | ||||
|     formLoading.value = true | ||||
|     try { | ||||
|       formData.value = await AppApi.getApp(id) | ||||
|     } finally { | ||||
|       formLoading.value = false | ||||
|     } | ||||
|   } | ||||
|   await handleGetMerchantListByName(null) | ||||
| } | ||||
| defineExpose({ open }) // 提供 open 方法,用于打开弹窗 | ||||
|  | ||||
| /** 提交表单 */ | ||||
| const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 | ||||
| const submitForm = async () => { | ||||
|   // 校验表单 | ||||
|   if (!formRef) return | ||||
|   const valid = await formRef.value.validate() | ||||
|   if (!valid) return | ||||
|   // 提交请求 | ||||
|   formLoading.value = true | ||||
|   try { | ||||
|     const data = formData.value as unknown as AppApi.AppVO | ||||
|     if (formType.value === 'create') { | ||||
|       await AppApi.createApp(data) | ||||
|       message.success(t('common.createSuccess')) | ||||
|     } else { | ||||
|       await AppApi.updateApp(data) | ||||
|       message.success(t('common.updateSuccess')) | ||||
|     } | ||||
|     dialogVisible.value = false | ||||
|     // 发送操作成功的事件 | ||||
|     emit('success') | ||||
|   } finally { | ||||
|     formLoading.value = false | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 根据商户名称模糊匹配商户信息 | ||||
|  * @param name 商户名称 | ||||
|  */ | ||||
| const handleGetMerchantListByName = async (name) => { | ||||
|   merchantList.value = await MerchantApi.getMerchantListByName(name) | ||||
| } | ||||
|  | ||||
| /** 重置表单 */ | ||||
| const resetForm = () => { | ||||
|   formData.value = { | ||||
|     id: undefined, | ||||
|     name: undefined, | ||||
|     status: CommonStatusEnum.ENABLE, | ||||
|     remark: undefined, | ||||
|     payNotifyUrl: undefined, | ||||
|     refundNotifyUrl: undefined, | ||||
|     merchantId: undefined | ||||
|   } | ||||
|   formRef.value?.resetFields() | ||||
| } | ||||
| </script> | ||||
| @@ -1,71 +0,0 @@ | ||||
| import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas' | ||||
| const { t } = useI18n() // 国际化 | ||||
|  | ||||
| // 表单校验 | ||||
| export const rules = reactive({ | ||||
|   name: [required], | ||||
|   status: [required], | ||||
|   payNotifyUrl: [required], | ||||
|   refundNotifyUrl: [required], | ||||
|   merchantId: [required] | ||||
| }) | ||||
|  | ||||
| // CrudSchema | ||||
| const crudSchemas = reactive<VxeCrudSchema>({ | ||||
|   primaryKey: 'id', | ||||
|   primaryType: 'seq', | ||||
|   primaryTitle: '编号', | ||||
|   action: true, | ||||
|   columns: [ | ||||
|     { | ||||
|       title: '应用名', | ||||
|       field: 'name', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '商户名称', | ||||
|       field: 'payMerchant', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: t('common.status'), | ||||
|       field: 'status', | ||||
|       dictType: DICT_TYPE.COMMON_STATUS, | ||||
|       dictClass: 'number', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       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 } = useVxeCrudSchemas(crudSchemas) | ||||
| @@ -1,155 +1,475 @@ | ||||
| <template> | ||||
|   <!-- 搜索 --> | ||||
|   <ContentWrap> | ||||
|     <!-- 列表 --> | ||||
|     <XTable @register="registerTable"> | ||||
|       <template #toolbar_buttons> | ||||
|         <!-- 操作:新增 --> | ||||
|         <XButton | ||||
|     <el-form | ||||
|       class="-mb-15px" | ||||
|       :model="queryParams" | ||||
|       ref="queryFormRef" | ||||
|       :inline="true" | ||||
|       label-width="68px" | ||||
|     > | ||||
|       <el-form-item label="应用名" prop="name"> | ||||
|         <el-input | ||||
|           v-model="queryParams.name" | ||||
|           placeholder="请输入应用名" | ||||
|           clearable | ||||
|           @keyup.enter="handleQuery" | ||||
|           class="!w-240px" | ||||
|         /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="商户名称" prop="contactName"> | ||||
|         <el-input | ||||
|           v-model="queryParams.contactName" | ||||
|           placeholder="请输入商户名称" | ||||
|           clearable | ||||
|           @keyup.enter="handleQuery" | ||||
|           class="!w-240px" | ||||
|         /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="开启状态" prop="status"> | ||||
|         <el-select | ||||
|           v-model="queryParams.status" | ||||
|           placeholder="请选择开启状态" | ||||
|           clearable | ||||
|           class="!w-240px" | ||||
|         > | ||||
|           <el-option | ||||
|             v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" | ||||
|             :key="dict.value" | ||||
|             :label="dict.label" | ||||
|             :value="dict.value" | ||||
|           /> | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="创建时间" prop="createTime"> | ||||
|         <el-date-picker | ||||
|           v-model="queryParams.createTime" | ||||
|           value-format="YYYY-MM-DD HH:mm:ss" | ||||
|           type="daterange" | ||||
|           start-placeholder="开始日期" | ||||
|           end-placeholder="结束日期" | ||||
|           :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" | ||||
|           class="!w-240px" | ||||
|         /> | ||||
|       </el-form-item> | ||||
|  | ||||
|       <el-form-item> | ||||
|         <el-button @click="handleQuery"> | ||||
|           <Icon icon="ep:search" class="mr-5px" /> | ||||
|           搜索 | ||||
|         </el-button> | ||||
|         <el-button @click="resetQuery"> | ||||
|           <Icon icon="ep:refresh" class="mr-5px" /> | ||||
|           重置 | ||||
|         </el-button> | ||||
|         <el-button | ||||
|           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="exportList('应用信息.xls')" | ||||
|         /> | ||||
|       </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="deleteData(row.id)" | ||||
|         /> | ||||
|       </template> | ||||
|     </XTable> | ||||
|           plain | ||||
|           @click="openForm('create')" | ||||
|           v-hasPermi="['system:tenant:create']" | ||||
|         > | ||||
|           <Icon icon="ep:plus" class="mr-5px" /> | ||||
|           新增 | ||||
|         </el-button> | ||||
|         <el-button | ||||
|           type="success" | ||||
|           plain | ||||
|           @click="handleExport" | ||||
|           :loading="exportLoading" | ||||
|           v-hasPermi="['system:tenant:export']" | ||||
|         > | ||||
|           <Icon icon="ep:download" class="mr-5px" /> | ||||
|           导出 | ||||
|         </el-button> | ||||
|       </el-form-item> | ||||
|     </el-form> | ||||
|   </ContentWrap> | ||||
|  | ||||
|   <XModal v-model="dialogVisible" :title="dialogTitle"> | ||||
|     <!-- 对话框(添加 / 修改) --> | ||||
|     <Form | ||||
|       v-if="['create', 'update'].includes(actionType)" | ||||
|       :schema="allSchemas.formSchema" | ||||
|       :rules="rules" | ||||
|       ref="formRef" | ||||
|   <!-- 列表 --> | ||||
|   <ContentWrap> | ||||
|     <el-table v-loading="loading" :data="list"> | ||||
|       <el-table-column label="应用编号" align="center" prop="id" /> | ||||
|       <el-table-column label="应用名" align="center" prop="name" /> | ||||
|       <el-table-column label="开启状态" align="center" prop="status"> | ||||
|         <template #default="scope"> | ||||
|           <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|       <el-table-column label="商户名称" align="center" prop="payMerchant.name" /> | ||||
|       <el-table-column label="支付宝配置" align="center"> | ||||
|         <el-table-column :label="payChannelEnum.ALIPAY_APP.name" align="center"> | ||||
|           <template #default="scope"> | ||||
|             <el-button | ||||
|               type="success" | ||||
|               v-if="judgeChannelExist(scope.row.channelCodes, payChannelEnum.ALIPAY_APP.code)" | ||||
|               @click=" | ||||
|                 handleUpdateChannel(scope.row, payChannelEnum.ALIPAY_APP.code, payType.ALIPAY) | ||||
|               " | ||||
|               circle | ||||
|             > | ||||
|               <Icon icon="ep:check" /> | ||||
|             </el-button> | ||||
|             <el-button | ||||
|               v-else | ||||
|               type="danger" | ||||
|               circle | ||||
|               @click=" | ||||
|                 handleCreateChannel(scope.row, payChannelEnum.ALIPAY_APP.code, payType.ALIPAY) | ||||
|               " | ||||
|             > | ||||
|               <Icon icon="ep:close" /> | ||||
|             </el-button> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column :label="payChannelEnum.ALIPAY_PC.name" align="center"> | ||||
|           <template #default="scope"> | ||||
|             <el-button | ||||
|               type="success" | ||||
|               circle | ||||
|               v-if="judgeChannelExist(scope.row.channelCodes, payChannelEnum.ALIPAY_PC.code)" | ||||
|               @click="handleUpdateChannel(scope.row, payChannelEnum.ALIPAY_PC.code, payType.ALIPAY)" | ||||
|             > | ||||
|               <Icon icon="ep:check" /> | ||||
|             </el-button> | ||||
|             <el-button | ||||
|               v-else | ||||
|               type="danger" | ||||
|               circle | ||||
|               @click="handleCreateChannel(scope.row, payChannelEnum.ALIPAY_PC.code, payType.ALIPAY)" | ||||
|             > | ||||
|               <Icon icon="ep:close" /> | ||||
|             </el-button> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column :label="payChannelEnum.ALIPAY_WAP.name" align="center"> | ||||
|           <template #default="scope"> | ||||
|             <el-button | ||||
|               type="success" | ||||
|               circle | ||||
|               v-if="judgeChannelExist(scope.row.channelCodes, payChannelEnum.ALIPAY_WAP.code)" | ||||
|               @click=" | ||||
|                 handleUpdateChannel(scope.row, payChannelEnum.ALIPAY_WAP.code, payType.ALIPAY) | ||||
|               " | ||||
|             > | ||||
|               <Icon icon="ep:check" /> | ||||
|             </el-button> | ||||
|             <el-button | ||||
|               v-else | ||||
|               type="danger" | ||||
|               circle | ||||
|               @click=" | ||||
|                 handleCreateChannel(scope.row, payChannelEnum.ALIPAY_WAP.code, payType.ALIPAY) | ||||
|               " | ||||
|             > | ||||
|               <Icon icon="ep:close" /> | ||||
|             </el-button> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column :label="payChannelEnum.ALIPAY_QR.name" align="center"> | ||||
|           <template #default="scope"> | ||||
|             <el-button | ||||
|               type="success" | ||||
|               circle | ||||
|               v-if="judgeChannelExist(scope.row.channelCodes, payChannelEnum.ALIPAY_QR.code)" | ||||
|               @click="handleUpdateChannel(scope.row, payChannelEnum.ALIPAY_QR.code, payType.ALIPAY)" | ||||
|             > | ||||
|               <Icon icon="ep:check" /> | ||||
|             </el-button> | ||||
|             <el-button | ||||
|               v-else | ||||
|               type="danger" | ||||
|               circle | ||||
|               @click="handleCreateChannel(scope.row, payChannelEnum.ALIPAY_QR.code, payType.ALIPAY)" | ||||
|             > | ||||
|               <Icon icon="ep:close" /> | ||||
|             </el-button> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column :label="payChannelEnum.ALIPAY_BAR.name" align="center"> | ||||
|           <template #default="scope"> | ||||
|             <el-button | ||||
|               type="success" | ||||
|               circle | ||||
|               v-if="judgeChannelExist(scope.row.channelCodes, payChannelEnum.ALIPAY_BAR.code)" | ||||
|               @click=" | ||||
|                 handleUpdateChannel(scope.row, payChannelEnum.ALIPAY_BAR.code, payType.ALIPAY) | ||||
|               " | ||||
|             > | ||||
|               <Icon icon="ep:check" /> | ||||
|             </el-button> | ||||
|             <el-button | ||||
|               v-else | ||||
|               type="danger" | ||||
|               circle | ||||
|               @click=" | ||||
|                 handleCreateChannel(scope.row, payChannelEnum.ALIPAY_BAR.code, payType.ALIPAY) | ||||
|               " | ||||
|             > | ||||
|               <Icon icon="ep:close" /> | ||||
|             </el-button> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table-column> | ||||
|       <el-table-column label="微信配置" align="center"> | ||||
|         <el-table-column :label="payChannelEnum.WX_LITE.name" align="center"> | ||||
|           <template #default="scope"> | ||||
|             <el-button | ||||
|               type="success" | ||||
|               circle | ||||
|               v-if="judgeChannelExist(scope.row.channelCodes, payChannelEnum.WX_LITE.code)" | ||||
|               @click="handleUpdateChannel(scope.row, payChannelEnum.WX_LITE.code, payType.WECHAT)" | ||||
|             > | ||||
|               <Icon icon="ep:check" /> | ||||
|             </el-button> | ||||
|             <el-button | ||||
|               v-else | ||||
|               type="danger" | ||||
|               circle | ||||
|               @click="handleCreateChannel(scope.row, payChannelEnum.WX_LITE.code, payType.WECHAT)" | ||||
|             > | ||||
|               <Icon icon="ep:close" /> | ||||
|             </el-button> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column :label="payChannelEnum.WX_PUB.name" align="center"> | ||||
|           <template #default="scope"> | ||||
|             <el-button | ||||
|               type="success" | ||||
|               circle | ||||
|               v-if="judgeChannelExist(scope.row.channelCodes, payChannelEnum.WX_PUB.code)" | ||||
|               @click="handleUpdateChannel(scope.row, payChannelEnum.WX_PUB.code, payType.WECHAT)" | ||||
|             > | ||||
|               <Icon icon="ep:check" /> | ||||
|             </el-button> | ||||
|             <el-button | ||||
|               v-else | ||||
|               type="danger" | ||||
|               circle | ||||
|               @click="handleCreateChannel(scope.row, payChannelEnum.WX_PUB.code, payType.WECHAT)" | ||||
|             > | ||||
|               <Icon icon="ep:close" /> | ||||
|             </el-button> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column :label="payChannelEnum.WX_APP.name" align="center"> | ||||
|           <template #default="scope"> | ||||
|             <el-button | ||||
|               type="success" | ||||
|               circle | ||||
|               v-if="judgeChannelExist(scope.row.channelCodes, payChannelEnum.WX_APP.code)" | ||||
|               @click="handleUpdateChannel(scope.row, payChannelEnum.WX_APP.code, payType.WECHAT)" | ||||
|             > | ||||
|               <Icon icon="ep:check" /> | ||||
|             </el-button> | ||||
|             <el-button | ||||
|               v-else | ||||
|               type="danger" | ||||
|               circle | ||||
|               @click="handleCreateChannel(scope.row, payChannelEnum.WX_APP.code, payType.WECHAT)" | ||||
|             > | ||||
|               <Icon icon="ep:close" /> | ||||
|             </el-button> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table-column> | ||||
|       <el-table-column | ||||
|         label="创建时间" | ||||
|         align="center" | ||||
|         prop="createTime" | ||||
|         width="180" | ||||
|         :formatter="dateFormatter" | ||||
|       /> | ||||
|     <!-- 对话框(详情) --> | ||||
|     <Descriptions | ||||
|       v-if="actionType === 'detail'" | ||||
|       :schema="allSchemas.detailSchema" | ||||
|       :data="detailData" | ||||
|     /> | ||||
|     <!-- 操作按钮 --> | ||||
|     <template #footer> | ||||
|       <!-- 按钮:保存 --> | ||||
|       <XButton | ||||
|         v-if="['create', 'update'].includes(actionType)" | ||||
|       <el-table-column label="操作" align="center" min-width="110" fixed="right"> | ||||
|         <template #default="scope"> | ||||
|           <el-button | ||||
|             link | ||||
|             type="primary" | ||||
|         :title="t('action.save')" | ||||
|         :loading="actionLoading" | ||||
|         @click="submitForm()" | ||||
|             @click="openForm('update', scope.row.id)" | ||||
|             v-hasPermi="['system:tenant:update']" | ||||
|           > | ||||
|             编辑 | ||||
|           </el-button> | ||||
|           <el-button | ||||
|             link | ||||
|             type="danger" | ||||
|             @click="handleDelete(scope.row.id)" | ||||
|             v-hasPermi="['system:tenant:delete']" | ||||
|           > | ||||
|             删除 | ||||
|           </el-button> | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|     </el-table> | ||||
|     <!-- 分页 --> | ||||
|     <Pagination | ||||
|       :total="total" | ||||
|       v-model:page="queryParams.pageNo" | ||||
|       v-model:limit="queryParams.pageSize" | ||||
|       @pagination="getList" | ||||
|     /> | ||||
|       <!-- 按钮:关闭 --> | ||||
|       <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" /> | ||||
|   </ContentWrap> | ||||
|  | ||||
|   <!-- 表单弹窗:添加/修改 --> | ||||
|   <AppForm ref="formRef" @success="getList" /> | ||||
| </template> | ||||
|   </XModal> | ||||
| </template> | ||||
| <script setup lang="ts" name="PayApp"> | ||||
| import type { FormExpose } from '@/components/Form' | ||||
| import { rules, allSchemas } from './app.data' | ||||
| <script setup lang="ts" name="App"> | ||||
| import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' | ||||
| import download from '@/utils/download' | ||||
| import * as AppApi from '@/api/pay/app' | ||||
| import ContentWrap from '@/components/ContentWrap/src/ContentWrap.vue' | ||||
| import { dateFormatter } from '@/utils/formatTime' | ||||
| import AppForm from '@/views/pay/app/AppForm.vue' | ||||
| import { PayChannelEnum as payChannelEnum, PayType } from '@/utils/constants' | ||||
|  | ||||
| const { t } = useI18n() // 国际化 | ||||
| const message = useMessage() // 消息弹窗 | ||||
| const { t } = useI18n() // 国际化 | ||||
|  | ||||
| // 列表相关的变量 | ||||
| const [registerTable, { reload, deleteData, exportList }] = useXTable({ | ||||
|   allSchemas: allSchemas, | ||||
|   getListApi: AppApi.getAppPage, | ||||
|   deleteApi: AppApi.deleteApp, | ||||
|   exportListApi: AppApi.exportApp | ||||
| const loading = ref(true) // 列表的加载中 | ||||
| const total = ref(0) // 列表的总页数 | ||||
| const list = ref([]) // 列表的数据 | ||||
| const queryParams = reactive({ | ||||
|   pageNo: 1, | ||||
|   pageSize: 10, | ||||
|   name: undefined, | ||||
|   status: undefined, | ||||
|   remark: undefined, | ||||
|   payNotifyUrl: undefined, | ||||
|   refundNotifyUrl: undefined, | ||||
|   merchantName: undefined, | ||||
|   createTime: [] | ||||
| }) | ||||
|  | ||||
| // ========== CRUD 相关 ========== | ||||
| const actionLoading = ref(false) // 遮罩层 | ||||
| const actionType = ref('') // 操作按钮的类型 | ||||
| const dialogVisible = ref(false) // 是否显示弹出层 | ||||
| const dialogTitle = ref('edit') // 弹出层标题 | ||||
| const formRef = ref<FormExpose>() // 表单 Ref | ||||
| const detailData = ref() // 详情 Ref | ||||
|  | ||||
| // 设置标题 | ||||
| const setDialogTile = (type: string) => { | ||||
|   dialogTitle.value = t('action.' + type) | ||||
|   actionType.value = type | ||||
|   dialogVisible.value = true | ||||
| const queryFormRef = ref() // 搜索的表单 | ||||
| const exportLoading = ref(false) // 导出的加载中 | ||||
| const channelParam = reactive({ | ||||
|   loading: false, | ||||
|   // 是否修改 | ||||
|   edit: false, | ||||
|   // 微信是否显示 | ||||
|   wechatOpen: false, | ||||
|   // 支付宝是否显示 | ||||
|   aliPayOpen: false, | ||||
|   // 应用ID | ||||
|   appId: null, | ||||
|   // 渠道编码 | ||||
|   payCode: null, | ||||
|   // 商户对象 | ||||
|   payMerchant: { | ||||
|     // 编号 | ||||
|     id: null, | ||||
|     // 名称 | ||||
|     name: null | ||||
|   } | ||||
| }) // 微信组件传参参数 | ||||
|  | ||||
| // 新增操作 | ||||
| const handleCreate = () => { | ||||
|   setDialogTile('create') | ||||
| } | ||||
|  | ||||
| // 修改操作 | ||||
| const handleUpdate = async (rowId: number) => { | ||||
|   setDialogTile('update') | ||||
|   // 设置数据 | ||||
|   const res = await AppApi.getApp(rowId) | ||||
|   unref(formRef)?.setValues(res) | ||||
| } | ||||
|  | ||||
| // 详情操作 | ||||
| const handleDetail = async (rowId: number) => { | ||||
|   setDialogTile('detail') | ||||
|   const res = await AppApi.getApp(rowId) | ||||
|   detailData.value = res | ||||
| } | ||||
|  | ||||
| // 提交按钮 | ||||
| const submitForm = async () => { | ||||
|   const elForm = unref(formRef)?.getElFormRef() | ||||
|   if (!elForm) return | ||||
|   elForm.validate(async (valid) => { | ||||
|     if (valid) { | ||||
|       actionLoading.value = true | ||||
|       // 提交请求 | ||||
| /** 查询列表 */ | ||||
| const getList = async () => { | ||||
|   loading.value = true | ||||
|   try { | ||||
|         const data = unref(formRef)?.formModel as AppApi.AppVO | ||||
|         if (actionType.value === 'create') { | ||||
|           await AppApi.createApp(data) | ||||
|           message.success(t('common.createSuccess')) | ||||
|         } else { | ||||
|           await AppApi.updateApp(data) | ||||
|           message.success(t('common.updateSuccess')) | ||||
|         } | ||||
|         dialogVisible.value = false | ||||
|     const data = await AppApi.getAppPage(queryParams) | ||||
|     list.value = data.list | ||||
|     total.value = data.total | ||||
|   } finally { | ||||
|         actionLoading.value = false | ||||
|     loading.value = false | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   queryParams.pageNo = 1 | ||||
|   getList() | ||||
| } | ||||
|  | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value.resetFields() | ||||
|   handleQuery() | ||||
| } | ||||
|  | ||||
| /** 添加/修改操作 */ | ||||
| const formRef = ref() | ||||
| const openForm = (type: string, id?: number) => { | ||||
|   formRef.value.open(type, id) | ||||
| } | ||||
|  | ||||
| /** 删除按钮操作 */ | ||||
| const handleDelete = async (id: number) => { | ||||
|   try { | ||||
|     // 删除的二次确认 | ||||
|     await message.delConfirm() | ||||
|     // 发起删除 | ||||
|     await AppApi.deleteApp(id) | ||||
|     message.success(t('common.delSuccess')) | ||||
|     // 刷新列表 | ||||
|         await reload() | ||||
|     await getList() | ||||
|   } catch {} | ||||
| } | ||||
|  | ||||
| /** 导出按钮操作 */ | ||||
| const handleExport = async () => { | ||||
|   try { | ||||
|     // 导出的二次确认 | ||||
|     await message.exportConfirm() | ||||
|     // 发起导出 | ||||
|     exportLoading.value = true | ||||
|     const data = await AppApi.exportApp(queryParams) | ||||
|     download.excel(data, '支付应用信息.xls') | ||||
|   } catch { | ||||
|   } finally { | ||||
|     exportLoading.value = false | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 根据渠道编码判断渠道列表中是否存在 | ||||
|  * @param channels 渠道列表 | ||||
|  * @param channelCode 渠道编码 | ||||
|  */ | ||||
| const judgeChannelExist = (channels, channelCode) => { | ||||
|   if (!channels) { | ||||
|     return false | ||||
|   } | ||||
|   return channels.indexOf(channelCode) !== -1 | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 修改支付渠道信息 | ||||
|  * @param row 行记录 | ||||
|  * @param payCode 支付编码 | ||||
|  * @param type 支付类型 | ||||
|  */ | ||||
| const handleUpdateChannel = async (row, payCode, type) => { | ||||
|   await settingChannelParam(row, payCode, type) | ||||
|   channelParam.edit = true | ||||
|   channelParam.loading = true | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 新增支付渠道信息 | ||||
|  */ | ||||
| const handleCreateChannel = async (row, payCode, type) => { | ||||
|   await settingChannelParam(row, payCode, type) | ||||
|   channelParam.edit = false | ||||
|   channelParam.loading = false | ||||
| } | ||||
|  | ||||
| const settingChannelParam = async (row, payCode, type) => { | ||||
|   if (type === PayType.WECHAT) { | ||||
|     channelParam.wechatOpen = true | ||||
|     channelParam.aliPayOpen = false | ||||
|   } | ||||
|   if (type === PayType.ALIPAY) { | ||||
|     channelParam.aliPayOpen = true | ||||
|     channelParam.wechatOpen = false | ||||
|   } | ||||
|   channelParam.edit = false | ||||
|   channelParam.loading = false | ||||
|   channelParam.appId = row.id | ||||
|   channelParam.payCode = payCode | ||||
|   channelParam.payMerchant = row.payMerchant | ||||
| } | ||||
|  | ||||
| /** 初始化 **/ | ||||
| onMounted(async () => { | ||||
|   await getList() | ||||
| }) | ||||
| } | ||||
| </script> | ||||
|   | ||||
| @@ -1,79 +1,359 @@ | ||||
| <template> | ||||
|   <ContentWrap> | ||||
|     <!-- 列表 --> | ||||
|     <XTable @register="registerTable"> | ||||
|       <template #toolbar_buttons> | ||||
|         <!-- 操作:新增 --> | ||||
|         <XButton | ||||
|           type="primary" | ||||
|           preIcon="ep:zoom-in" | ||||
|           :title="t('action.add')" | ||||
|           v-hasPermi="['pay:order:create']" | ||||
|           @click="handleCreate()" | ||||
|     <el-form | ||||
|       class="-mb-15px" | ||||
|       :model="queryParams" | ||||
|       ref="queryFormRef" | ||||
|       :inline="true" | ||||
|       label-width="120px" | ||||
|     > | ||||
|       <el-form-item label="所属商户" prop="merchantId"> | ||||
|         <el-select | ||||
|           v-model="queryParams.merchantId" | ||||
|           clearable | ||||
|           @clear=" | ||||
|             () => { | ||||
|               queryParams.merchantId = null | ||||
|             } | ||||
|           " | ||||
|           filterable | ||||
|           remote | ||||
|           reserve-keyword | ||||
|           placeholder="请选择所属商户" | ||||
|           @change="handleGetAppListByMerchantId" | ||||
|           :remote-method="handleGetMerchantListByName" | ||||
|           :loading="merchantLoading" | ||||
|         > | ||||
|           <el-option | ||||
|             v-for="item in merchantList" | ||||
|             :key="item.id" | ||||
|             :label="item.name" | ||||
|             :value="item.id" | ||||
|           /> | ||||
|         <!-- 操作:导出 --> | ||||
|         <XButton | ||||
|           type="warning" | ||||
|           preIcon="ep:download" | ||||
|           :title="t('action.export')" | ||||
|           v-hasPermi="['pay:order:export']" | ||||
|           @click="exportList('订单数据.xls')" | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="应用编号" prop="appId"> | ||||
|         <el-select clearable v-model="queryParams.appId" filterable placeholder="请选择应用信息"> | ||||
|           <el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" /> | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="渠道编码" prop="channelCode"> | ||||
|         <el-select | ||||
|           v-model="queryParams.channelCode" | ||||
|           placeholder="请输入渠道编码" | ||||
|           clearable | ||||
|           @clear=" | ||||
|             () => { | ||||
|               queryParams.channelCode = null | ||||
|             } | ||||
|           " | ||||
|         > | ||||
|           <el-option | ||||
|             v-for="dict in getDictOptions(DICT_TYPE.PAY_CHANNEL_CODE_TYPE)" | ||||
|             :key="dict.value" | ||||
|             :label="dict.label" | ||||
|             :value="dict.value" | ||||
|           /> | ||||
|       </template> | ||||
|       <template #actionbtns_default="{ row }"> | ||||
|         <!-- 操作:详情 --> | ||||
|         <XTextButton | ||||
|           preIcon="ep:view" | ||||
|           :title="t('action.detail')" | ||||
|           v-hasPermi="['pay:order:query']" | ||||
|           @click="handleDetail(row.id)" | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="商户订单编号" prop="merchantOrderId"> | ||||
|         <el-input | ||||
|           v-model="queryParams.merchantOrderId" | ||||
|           placeholder="请输入商户订单编号" | ||||
|           clearable | ||||
|           @keyup.enter="handleQuery" | ||||
|         /> | ||||
|       </template> | ||||
|     </XTable> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="渠道订单号" prop="channelOrderNo"> | ||||
|         <el-input | ||||
|           v-model="queryParams.channelOrderNo" | ||||
|           placeholder="请输入渠道订单号" | ||||
|           clearable | ||||
|           @keyup.enter="handleQuery" | ||||
|         /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="支付状态" prop="status"> | ||||
|         <el-select v-model="queryParams.status" placeholder="请选择支付状态" clearable size="small"> | ||||
|           <el-option | ||||
|             v-for="dict in getDictOptions(DICT_TYPE.PAY_ORDER_STATUS)" | ||||
|             :key="parseInt(dict.value)" | ||||
|             :label="dict.label" | ||||
|             :value="parseInt(dict.value)" | ||||
|           /> | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="退款状态" prop="refundStatus"> | ||||
|         <el-select v-model="queryParams.refundStatus" placeholder="请选择退款状态" clearable> | ||||
|           <el-option | ||||
|             v-for="dict in getDictOptions(DICT_TYPE.PAY_ORDER_REFUND_STATUS)" | ||||
|             :key="parseInt(dict.value)" | ||||
|             :label="dict.label" | ||||
|             :value="parseInt(dict.value)" | ||||
|           /> | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="回调商户状态" prop="notifyStatus"> | ||||
|         <el-select | ||||
|           v-model="queryParams.notifyStatus" | ||||
|           placeholder="请选择订单回调商户状态" | ||||
|           clearable | ||||
|         > | ||||
|           <el-option | ||||
|             v-for="dict in getDictOptions(DICT_TYPE.PAY_ORDER_NOTIFY_STATUS)" | ||||
|             :key="parseInt(dict.value)" | ||||
|             :label="dict.label" | ||||
|             :value="parseInt(dict.value)" | ||||
|           /> | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="创建时间" prop="createTime"> | ||||
|         <el-date-picker | ||||
|           v-model="queryParams.createTime" | ||||
|           value-format="YYYY-MM-DD HH:mm:ss" | ||||
|           type="daterange" | ||||
|           start-placeholder="开始日期" | ||||
|           end-placeholder="结束日期" | ||||
|           :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" | ||||
|           class="!w-240px" | ||||
|         /> | ||||
|       </el-form-item> | ||||
|       <el-form-item> | ||||
|         <el-button @click="handleQuery"> | ||||
|           <Icon icon="ep:search" class="mr-5px" /> | ||||
|           搜索 | ||||
|         </el-button> | ||||
|         <el-button @click="resetQuery"> | ||||
|           <Icon icon="ep:refresh" class="mr-5px" /> | ||||
|           重置 | ||||
|         </el-button> | ||||
|         <el-button | ||||
|           type="success" | ||||
|           plain | ||||
|           @click="handleExport" | ||||
|           :loading="exportLoading" | ||||
|           v-hasPermi="['system:tenant:export']" | ||||
|         > | ||||
|           <Icon icon="ep:download" class="mr-5px" /> | ||||
|           导出 | ||||
|         </el-button> | ||||
|       </el-form-item> | ||||
|     </el-form> | ||||
|   </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" /> | ||||
|   <content-wrap> | ||||
|     <el-table v-loading="loading" :data="list"> | ||||
|       <el-table-column label="订单编号" align="center" prop="id" /> | ||||
|       <el-table-column label="商户名称" align="center" prop="merchantName" width="120" /> | ||||
|       <el-table-column label="应用名称" align="center" prop="appName" width="120" /> | ||||
|       <el-table-column label="渠道名称" align="center" prop="channelCodeName" width="120" /> | ||||
|       <el-table-column label="渠道订单号" align="center" prop="merchantOrderId" width="120" /> | ||||
|       <el-table-column label="商品标题" align="center" prop="subject" width="250" /> | ||||
|       <el-table-column label="商品描述" align="center" prop="body" width="250" /> | ||||
|       <el-table-column label="异步通知地址" align="center" prop="notifyUrl" width="250" /> | ||||
|       <el-table-column label="回调状态" align="center" prop="notifyStatus"> | ||||
|         <template #default="scope"> | ||||
|           <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> | ||||
|         </template> | ||||
|   </XModal> | ||||
|       </el-table-column> | ||||
|       <el-table-column label="支付订单" align="left"> | ||||
|         <template #default="scope"> | ||||
|           <p class="order-font"> | ||||
|             <el-tag size="small">商户</el-tag> | ||||
|             {{ scope.row.merchantOrderId }} | ||||
|           </p> | ||||
|           <p class="order-font"> | ||||
|             <el-tag size="small" type="warning">支付</el-tag> | ||||
|             {{ scope.row.channelOrderNo }} | ||||
|           </p> | ||||
|         </template> | ||||
| <script setup lang="ts" name="PayOrder"> | ||||
| import { allSchemas } from './order.data' | ||||
|       </el-table-column> | ||||
|       <el-table-column label="支付金额" align="center" prop="amount"> | ||||
|         <template #default="scope"> | ||||
|           ¥{{ parseFloat(scope.row.amount / 100).toFixed(2) }} | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|       <el-table-column label="手续金额" align="center" prop="channelFeeAmount"> | ||||
|         <template #default="scope"> | ||||
|           ¥{{ parseFloat(scope.row.channelFeeAmount / 100).toFixed(2) }} | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|       <el-table-column label="退款金额" align="center" prop="refundAmount"> | ||||
|         <template #default="scope"> | ||||
|           ¥{{ parseFloat(scope.row.refundAmount / 100).toFixed(2) }} | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|       <el-table-column label="支付状态" align="center" prop="status"> | ||||
|         <template #default="scope"> | ||||
|           <dict-tag :type="DICT_TYPE.PAY_ORDER_STATUS" :value="scope.row.status" /> | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|       <el-table-column label="回调状态" align="center" prop="notifyStatus"> | ||||
|         <template #default="scope"> | ||||
|           <dict-tag :type="DICT_TYPE.PAY_ORDER_NOTIFY_STATUS" :value="scope.row.notifyStatus" /> | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|       <el-table-column | ||||
|         label="创建时间" | ||||
|         align="center" | ||||
|         prop="createTime" | ||||
|         width="100" | ||||
|         :formatter="dateFormatter" | ||||
|       /> | ||||
|       <el-table-column | ||||
|         label="支付时间" | ||||
|         align="center" | ||||
|         prop="successTime" | ||||
|         width="100" | ||||
|         :formatter="dateFormatter" | ||||
|       /> | ||||
|       <el-table-column | ||||
|         label="操作" | ||||
|         align="center" | ||||
|         fixed="right" | ||||
|         class-name="small-padding fixed-width" | ||||
|       > | ||||
|         <template #default="scope"> | ||||
|           <el-button | ||||
|             size="small" | ||||
|             type="text" | ||||
|             icon="el-icon-search" | ||||
|             @click="openForm(scope.row.id)" | ||||
|             v-hasPermi="['pay:order:query']" | ||||
|             >查看详情 | ||||
|           </el-button> | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|     </el-table> | ||||
|     <!-- 分页组件 --> | ||||
|     <!-- 分页 --> | ||||
|     <Pagination | ||||
|       :total="total" | ||||
|       v-model:page="queryParams.pageNo" | ||||
|       v-model:limit="queryParams.pageSize" | ||||
|       @pagination="getList" | ||||
|     /> | ||||
|   </content-wrap> | ||||
|  | ||||
|   <!-- 表单弹窗:预览 --> | ||||
|   <OrderForm ref="formRef" @success="getList" /> | ||||
| </template> | ||||
| <script setup lang="ts" name="Order"> | ||||
| import { DICT_TYPE, getDictOptions } from '@/utils/dict' | ||||
| import ContentWrap from '@/components/ContentWrap/src/ContentWrap.vue' | ||||
| import * as MerchantApi from '@/api/pay/merchant' | ||||
| import * as OrderApi from '@/api/pay/order' | ||||
| import download from '@/utils/download' | ||||
| import * as AppApi from '@/api/pay/app' | ||||
| import { dateFormatter } from '@/utils/formatTime' | ||||
| import OrderForm from '@/views/pay/order/orderForm.vue' | ||||
|  | ||||
| const { t } = useI18n() // 国际化 | ||||
| // 列表相关的变量 | ||||
| const [registerTable, { exportList }] = useXTable({ | ||||
|   allSchemas: allSchemas, | ||||
|   getListApi: OrderApi.getOrderPage, | ||||
|   exportListApi: OrderApi.exportOrder | ||||
| const message = useMessage() // 消息弹窗 | ||||
|  | ||||
| // const { t } = useI18n() // 国际化 | ||||
| const queryFormRef = ref() // 搜索的表单 | ||||
| const merchantList = ref([]) // 商户列表 | ||||
| const merchantLoading = ref(false) // 商户加载遮罩层 | ||||
| const appList = ref([]) // 支付应用列表集合 | ||||
| const loading = ref(false) // 列表的加载中 | ||||
| const exportLoading = ref(false) // 导出等待 | ||||
| const total = ref(0) // 列表的总页数 | ||||
| const list = ref([]) // 列表的数据 | ||||
| const queryParams = reactive({ | ||||
|   pageNo: 1, | ||||
|   pageSize: 10, | ||||
|   merchantId: undefined, | ||||
|   appId: undefined, | ||||
|   channelId: undefined, | ||||
|   channelCode: undefined, | ||||
|   merchantOrderId: undefined, | ||||
|   subject: undefined, | ||||
|   body: undefined, | ||||
|   notifyUrl: undefined, | ||||
|   notifyStatus: undefined, | ||||
|   amount: undefined, | ||||
|   channelFeeRate: undefined, | ||||
|   channelFeeAmount: undefined, | ||||
|   status: undefined, | ||||
|   userIp: undefined, | ||||
|   successExtensionId: undefined, | ||||
|   refundStatus: undefined, | ||||
|   refundTimes: undefined, | ||||
|   refundAmount: undefined, | ||||
|   channelUserId: undefined, | ||||
|   channelOrderNo: undefined, | ||||
|   expireTime: [], | ||||
|   successTime: [], | ||||
|   notifyTime: [], | ||||
|   createTime: [] | ||||
| }) | ||||
| // ========== CRUD 相关 ========== | ||||
| const actionLoading = ref(false) // 遮罩层 | ||||
| const actionType = ref('') // 操作按钮的类型 | ||||
| const dialogVisible = ref(false) // 是否显示弹出层 | ||||
| const dialogTitle = ref('edit') // 弹出层标题 | ||||
| const detailData = ref() // 详情 Ref | ||||
| // 设置标题 | ||||
| const setDialogTile = (type: string) => { | ||||
|   dialogTitle.value = t('action.' + type) | ||||
|   actionType.value = type | ||||
|   dialogVisible.value = true | ||||
|  | ||||
| /** | ||||
|  * 根据商户名称模糊匹配商户信息 | ||||
|  * @param name 商户名称 | ||||
|  */ | ||||
| const handleGetMerchantListByName = async (name) => { | ||||
|   merchantList.value = await MerchantApi.getMerchantListByName(name) | ||||
| } | ||||
|  | ||||
| // 新增操作 | ||||
| const handleCreate = () => { | ||||
|   setDialogTile('create') | ||||
| /** | ||||
|  * 根据商户 ID 查询支付应用信息 | ||||
|  */ | ||||
| const handleGetAppListByMerchantId = () => { | ||||
|   queryParams.appId = undefined | ||||
|   if (queryParams.merchantId) { | ||||
|     AppApi.getAppListByMerchantId(queryParams.merchantId).then((response) => { | ||||
|       appList.value = response.data | ||||
|     }) | ||||
|   } | ||||
| } | ||||
|  | ||||
| // 详情操作 | ||||
| const handleDetail = async (rowId: number) => { | ||||
|   setDialogTile('detail') | ||||
|   const res = await OrderApi.getOrder(rowId) | ||||
|   detailData.value = res | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   queryParams.pageNo = 1 | ||||
|   getList() | ||||
| } | ||||
|  | ||||
| /** 查询列表 */ | ||||
| const getList = async () => { | ||||
|   loading.value = true | ||||
|   try { | ||||
|     const data = await OrderApi.getOrderPage(queryParams) | ||||
|     list.value = data.list | ||||
|     total.value = data.total | ||||
|   } finally { | ||||
|     loading.value = false | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value.resetFields() | ||||
|   handleQuery() | ||||
| } | ||||
|  | ||||
| /** 导出按钮操作 */ | ||||
| const handleExport = async () => { | ||||
|   // 处理查询参数 | ||||
|   // 导出的二次确认 | ||||
|   await message.exportConfirm() | ||||
|   // 发起导出 | ||||
|   exportLoading.value = true | ||||
|   const data = await OrderApi.exportOrder(queryParams) | ||||
|   download.excel(data, '支付订单.xls') | ||||
| } | ||||
| /** 预览详情 */ | ||||
| const formRef = ref() | ||||
| const openForm = (id?: number) => { | ||||
|   formRef.value.open(id) | ||||
| } | ||||
| /** 初始化 **/ | ||||
| onMounted(async () => { | ||||
|   await getList() | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <style> | ||||
| .order-font { | ||||
|   font-size: 12px; | ||||
|   padding: 2px 0; | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -1,152 +0,0 @@ | ||||
| import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas' | ||||
| const { t } = useI18n() // 国际化 | ||||
|  | ||||
| // 表单校验 | ||||
| export const rules = reactive({ | ||||
|   merchantId: [required], | ||||
|   appId: [required], | ||||
|   merchantOrderId: [required], | ||||
|   subject: [required], | ||||
|   body: [required], | ||||
|   notifyUrl: [required], | ||||
|   notifyStatus: [required], | ||||
|   amount: [required], | ||||
|   status: [required], | ||||
|   userIp: [required], | ||||
|   expireTime: [required], | ||||
|   refundStatus: [required], | ||||
|   refundTimes: [required], | ||||
|   refundAmount: [required] | ||||
| }) | ||||
| // CrudSchema | ||||
| const crudSchemas = reactive<VxeCrudSchema>({ | ||||
|   primaryKey: 'id', | ||||
|   primaryType: 'seq', | ||||
|   primaryTitle: '岗位编号', | ||||
|   action: true, | ||||
|   columns: [ | ||||
|     { | ||||
|       title: '商户编号', | ||||
|       field: 'merchantId', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '应用编号', | ||||
|       field: 'appId', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '渠道编号', | ||||
|       field: 'channelId' | ||||
|     }, | ||||
|     { | ||||
|       title: '渠道编码', | ||||
|       field: 'channelCode', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '渠道订单号', | ||||
|       field: 'merchantOrderId', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '商品标题', | ||||
|       field: 'subject' | ||||
|     }, | ||||
|     { | ||||
|       title: '商品描述', | ||||
|       field: 'body' | ||||
|     }, | ||||
|     { | ||||
|       title: '异步通知地址', | ||||
|       field: 'notifyUrl' | ||||
|     }, | ||||
|     { | ||||
|       title: '回调状态', | ||||
|       field: 'notifyStatus', | ||||
|       dictType: DICT_TYPE.PAY_ORDER_NOTIFY_STATUS, | ||||
|       dictClass: 'number' | ||||
|     }, | ||||
|     { | ||||
|       title: '支付金额', | ||||
|       field: 'amount', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '渠道手续费', | ||||
|       field: 'channelFeeRate', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '渠道手续金额', | ||||
|       field: 'channelFeeAmount', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '支付状态', | ||||
|       field: 'status', | ||||
|       dictType: DICT_TYPE.PAY_ORDER_STATUS, | ||||
|       dictClass: 'number', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '用户 IP', | ||||
|       field: 'userIp' | ||||
|     }, | ||||
|     { | ||||
|       title: '订单失效时间', | ||||
|       field: 'expireTime', | ||||
|       formatter: 'formatDate' | ||||
|     }, | ||||
|     { | ||||
|       title: '支付时间', | ||||
|       field: 'successTime', | ||||
|       formatter: 'formatDate' | ||||
|     }, | ||||
|     { | ||||
|       title: '支付通知时间', | ||||
|       field: 'notifyTime', | ||||
|       formatter: 'formatDate' | ||||
|     }, | ||||
|     { | ||||
|       title: '拓展编号', | ||||
|       field: 'successExtensionId' | ||||
|     }, | ||||
|     { | ||||
|       title: '退款状态', | ||||
|       field: 'refundStatus', | ||||
|       dictType: DICT_TYPE.PAY_ORDER_REFUND_STATUS, | ||||
|       dictClass: 'number', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '退款次数', | ||||
|       field: 'refundTimes' | ||||
|     }, | ||||
|     { | ||||
|       title: '退款总金额', | ||||
|       field: 'refundAmount' | ||||
|     }, | ||||
|     { | ||||
|       title: '渠道用户编号', | ||||
|       field: 'channelUserId' | ||||
|     }, | ||||
|     { | ||||
|       title: '渠道订单号', | ||||
|       field: 'channelOrderNo' | ||||
|     }, | ||||
|     { | ||||
|       title: t('common.createTime'), | ||||
|       field: 'createTime', | ||||
|       formatter: 'formatDate', | ||||
|       isForm: false, | ||||
|       search: { | ||||
|         show: true, | ||||
|         itemRender: { | ||||
|           name: 'XDataTimePicker' | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   ] | ||||
| }) | ||||
| export const { allSchemas } = useVxeCrudSchemas(crudSchemas) | ||||
							
								
								
									
										152
									
								
								src/views/pay/order/orderForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								src/views/pay/order/orderForm.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | ||||
| <template> | ||||
|   <Dialog :title="dialogTitle" v-model="dialogVisible" width="50%"> | ||||
|     <el-descriptions :column="2" label-class-name="desc-label"> | ||||
|       <el-descriptions-item label="商户名称">{{ orderDetail.merchantName }}</el-descriptions-item> | ||||
|       <el-descriptions-item label="应用名称">{{ orderDetail.appName }}</el-descriptions-item> | ||||
|       <el-descriptions-item label="商品名称">{{ orderDetail.subject }}</el-descriptions-item> | ||||
|     </el-descriptions> | ||||
|     <el-divider /> | ||||
|     <el-descriptions :column="2" label-class-name="desc-label"> | ||||
|       <el-descriptions-item label="商户订单号"> | ||||
|         <el-tag size="small">{{ orderDetail.merchantOrderId }}</el-tag> | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="渠道订单号"> | ||||
|         <el-tag class="tag-purple" size="small">{{ orderDetail.channelOrderNo }}</el-tag> | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="支付订单号"> | ||||
|         <el-tag v-if="orderDetail.payOrderExtension.no !== ''" class="tag-pink" size="small"> | ||||
|           {{ orderDetail.payOrderExtension.no }} | ||||
|         </el-tag> | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="金额"> | ||||
|         <el-tag type="success" size="small">{{ parseFloat(orderDetail.amount / 100, 2) }}</el-tag> | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="手续费"> | ||||
|         <el-tag type="warning" size="small" | ||||
|           >{{ parseFloat(orderDetail.channelFeeAmount / 100, 2) }} | ||||
|         </el-tag> | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="手续费比例"> | ||||
|         {{ parseFloat(orderDetail.channelFeeRate / 100, 2) }}% | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="支付状态"> | ||||
|         <dict-tag :type="DICT_TYPE.PAY_ORDER_STATUS" :value="orderDetail.status" /> | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="回调状态"> | ||||
|         <dict-tag :type="DICT_TYPE.PAY_ORDER_NOTIFY_STATUS" :value="orderDetail.notifyStatus" /> | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="回调地址">{{ orderDetail.notifyUrl }}</el-descriptions-item> | ||||
|       <el-descriptions-item label="创建时间" :formatter="dateFormatter"> | ||||
|         {{ formatDate(orderDetail.createTime) }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="支付时间" :formatter="dateFormatter"> | ||||
|         {{ formatDate(orderDetail.successTime) }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="失效时间" :formatter="dateFormatter"> | ||||
|         {{ formatDate(orderDetail.expireTime) }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="通知时间" :formatter="dateFormatter"> | ||||
|         {{ formatDate(orderDetail.notifyTime) }} | ||||
|       </el-descriptions-item> | ||||
|     </el-descriptions> | ||||
|     <el-divider /> | ||||
|     <el-descriptions :column="2" label-class-name="desc-label"> | ||||
|       <el-descriptions-item label="支付渠道" | ||||
|         >{{ orderDetail.channelCodeName }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="支付IP">{{ orderDetail.userIp }}</el-descriptions-item> | ||||
|       <el-descriptions-item label="退款状态"> | ||||
|         <dict-tag :type="DICT_TYPE.PAY_ORDER_REFUND_STATUS" :value="orderDetail.refundStatus" /> | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="退款次数">{{ orderDetail.refundTimes }}</el-descriptions-item> | ||||
|       <el-descriptions-item label="退款金额"> | ||||
|         <el-tag type="warning"> | ||||
|           {{ parseFloat(orderDetail.refundAmount / 100, 2) }} | ||||
|         </el-tag> | ||||
|       </el-descriptions-item> | ||||
|     </el-descriptions> | ||||
|     <el-divider /> | ||||
|     <el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border> | ||||
|       <el-descriptions-item label="商品描述"> | ||||
|         {{ orderDetail.body }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="支付通道异步回调内容"> | ||||
|         {{ orderDetail.payOrderExtension.channelNotifyData }} | ||||
|       </el-descriptions-item> | ||||
|     </el-descriptions> | ||||
|   </Dialog> | ||||
| </template> | ||||
| <script setup lang="ts" name="orderForm"> | ||||
| import { DICT_TYPE } from '@/utils/dict' | ||||
| import * as OrderApi from '@/api/pay/order' | ||||
| import { dateFormatter, formatDate } from '@/utils/formatTime' | ||||
|  | ||||
| const { t } = useI18n() // 国际化 | ||||
| // const message = useMessage() // 消息弹窗 | ||||
| const dialogVisible = ref(false) // 弹窗的是否展示 | ||||
| const dialogTitle = ref('订单详情') // 弹窗的标题 | ||||
| const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 | ||||
| const defaultOrderDetail = { | ||||
|   merchantName: '', | ||||
|   appName: '', | ||||
|   channelCodeName: '', | ||||
|   subject: '', | ||||
|   merchantOrderId: null, | ||||
|   channelOrderNo: '', | ||||
|   body: '', | ||||
|   amount: null, | ||||
|   channelFeeRate: null, | ||||
|   channelFeeAmount: null, | ||||
|   userIp: '', | ||||
|   status: null, | ||||
|   notifyUrl: '', | ||||
|   notifyStatus: null, | ||||
|   refundStatus: null, | ||||
|   refundTimes: '', | ||||
|   refundAmount: null, | ||||
|   createTime: '', | ||||
|   successTime: '', | ||||
|   notifyTime: '', | ||||
|   expireTime: '', | ||||
|   payOrderExtension: { | ||||
|     channelNotifyData: '', | ||||
|     no: '' | ||||
|   } | ||||
| } | ||||
| const orderDetail = ref(JSON.parse(JSON.stringify(defaultOrderDetail))) | ||||
|  | ||||
| /** 打开弹窗 */ | ||||
| const open = async (id?: number) => { | ||||
|   dialogVisible.value = true | ||||
|   dialogTitle.value = t('action.preview') | ||||
|   // 修改时,设置数据 | ||||
|   if (id) { | ||||
|     formLoading.value = true | ||||
|     try { | ||||
|       orderDetail.value = await OrderApi.getOrderDetail(id) | ||||
|       if (orderDetail.value.payOrderExtension === null) { | ||||
|         orderDetail.value.payOrderExtension = Object.assign( | ||||
|           defaultOrderDetail.payOrderExtension, | ||||
|           {} | ||||
|         ) | ||||
|       } | ||||
|     } finally { | ||||
|       formLoading.value = false | ||||
|     } | ||||
|   } | ||||
| } | ||||
| defineExpose({ open }) // 提供 open 方法,用于打开弹窗 | ||||
| </script> | ||||
| <style> | ||||
| .tag-purple { | ||||
|   color: #722ed1; | ||||
|   background: #f9f0ff; | ||||
|   border-color: #d3adf7; | ||||
| } | ||||
|  | ||||
| .tag-pink { | ||||
|   color: #eb2f96; | ||||
|   background: #fff0f6; | ||||
|   border-color: #ffadd2; | ||||
| } | ||||
| </style> | ||||
| @@ -1,59 +1,359 @@ | ||||
| <template> | ||||
|   <ContentWrap> | ||||
|     <!-- 列表 --> | ||||
|     <XTable @register="registerTable"> | ||||
|       <template #toolbar_buttons> | ||||
|         <!-- 操作:导出 --> | ||||
|         <XButton | ||||
|           type="warning" | ||||
|           preIcon="ep:download" | ||||
|           :title="t('action.export')" | ||||
|           v-hasPermi="['pay:refund:export']" | ||||
|           @click="exportList('退款订单.xls')" | ||||
|     <!-- 搜索工作栏 --> | ||||
|     <el-form | ||||
|       :model="queryParams" | ||||
|       ref="queryFormRef" | ||||
|       size="small" | ||||
|       :inline="true" | ||||
|       label-width="120px" | ||||
|     > | ||||
|       <el-form-item label="所属商户" prop="merchantId"> | ||||
|         <el-select | ||||
|           v-model="queryParams.merchantId" | ||||
|           clearable | ||||
|           @clear=" | ||||
|             () => { | ||||
|               queryParams.merchantId = null | ||||
|             } | ||||
|           " | ||||
|           filterable | ||||
|           remote | ||||
|           reserve-keyword | ||||
|           placeholder="请选择所属商户" | ||||
|           @change="handleGetAppListByMerchantId" | ||||
|           :remote-method="handleGetMerchantListByName" | ||||
|           :loading="merchantLoading" | ||||
|         > | ||||
|           <el-option | ||||
|             v-for="item in merchantList" | ||||
|             :key="item.id" | ||||
|             :label="item.name" | ||||
|             :value="item.id" | ||||
|           /> | ||||
|       </template> | ||||
|       <template #actionbtns_default="{ row }"> | ||||
|         <!-- 操作:详情 --> | ||||
|         <XTextButton | ||||
|           preIcon="ep:view" | ||||
|           :title="t('action.detail')" | ||||
|           v-hasPermi="['pay:refund:query']" | ||||
|           @click="handleDetail(row.id)" | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="应用编号" prop="appId"> | ||||
|         <el-select clearable v-model="queryParams.appId" filterable placeholder="请选择应用信息"> | ||||
|           <el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" /> | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="渠道编码" prop="channelCode"> | ||||
|         <el-select | ||||
|           v-model="queryParams.channelCode" | ||||
|           placeholder="请输入渠道编码" | ||||
|           clearable | ||||
|           @clear=" | ||||
|             () => { | ||||
|               queryParams.channelCode = null | ||||
|             } | ||||
|           " | ||||
|         > | ||||
|           <el-option | ||||
|             v-for="dict in getDictOptions(DICT_TYPE.PAY_CHANNEL_CODE_TYPE)" | ||||
|             :key="dict.value" | ||||
|             :label="dict.label" | ||||
|             :value="dict.value" | ||||
|           /> | ||||
|       </template> | ||||
|     </XTable> | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="退款类型" prop="type"> | ||||
|         <el-select v-model="queryParams.type" placeholder="请选择退款类型" clearable> | ||||
|           <el-option | ||||
|             v-for="dict in getDictOptions(DICT_TYPE.PAY_REFUND_ORDER_TYPE)" | ||||
|             :key="parseInt(dict.value)" | ||||
|             :label="dict.label" | ||||
|             :value="parseInt(dict.value)" | ||||
|           /> | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="商户退款订单号" prop="merchantRefundNo"> | ||||
|         <el-input | ||||
|           v-model="queryParams.merchantRefundNo" | ||||
|           placeholder="请输入商户退款订单号" | ||||
|           clearable | ||||
|           @keyup.enter="handleQuery" | ||||
|         /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="退款状态" prop="status"> | ||||
|         <el-select v-model="queryParams.status" placeholder="请选择退款状态" clearable> | ||||
|           <el-option | ||||
|             v-for="dict in getDictOptions(DICT_TYPE.PAY_REFUND_ORDER_STATUS)" | ||||
|             :key="parseInt(dict.value)" | ||||
|             :label="dict.label" | ||||
|             :value="parseInt(dict.value)" | ||||
|           /> | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="退款回调状态" prop="notifyStatus"> | ||||
|         <el-select | ||||
|           v-model="queryParams.notifyStatus" | ||||
|           placeholder="请选择通知商户退款结果的回调状态" | ||||
|           clearable | ||||
|         > | ||||
|           <el-option | ||||
|             v-for="dict in getDictOptions(DICT_TYPE.PAY_ORDER_NOTIFY_STATUS)" | ||||
|             :key="parseInt(dict.value)" | ||||
|             :label="dict.label" | ||||
|             :value="parseInt(dict.value)" | ||||
|           /> | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="创建时间" prop="createTime"> | ||||
|         <el-date-picker | ||||
|           v-model="queryParams.createTime" | ||||
|           value-format="YYYY-MM-DD HH:mm:ss" | ||||
|           type="daterange" | ||||
|           start-placeholder="开始日期" | ||||
|           end-placeholder="结束日期" | ||||
|           :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" | ||||
|           class="!w-240px" | ||||
|         /> | ||||
|       </el-form-item> | ||||
|       <el-form-item> | ||||
|         <el-button @click="handleQuery"> | ||||
|           <Icon icon="ep:search" class="mr-5px" /> | ||||
|           搜索 | ||||
|         </el-button> | ||||
|         <el-button @click="resetQuery"> | ||||
|           <Icon icon="ep:refresh" class="mr-5px" /> | ||||
|           重置 | ||||
|         </el-button> | ||||
|         <el-button | ||||
|           type="success" | ||||
|           plain | ||||
|           @click="handleExport" | ||||
|           :loading="exportLoading" | ||||
|           v-hasPermi="['system:tenant:export']" | ||||
|         > | ||||
|           <Icon icon="ep:download" class="mr-5px" /> | ||||
|           导出 | ||||
|         </el-button> | ||||
|       </el-form-item> | ||||
|     </el-form> | ||||
|   </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> | ||||
|   <el-table v-loading="loading" :data="list"> | ||||
|     <el-table-column label="编号" align="center" prop="id" /> | ||||
|     <el-table-column label="商户名称" align="center" prop="merchantName" width="120" /> | ||||
|     <el-table-column label="应用名称" align="center" prop="appName" width="120" /> | ||||
|     <el-table-column label="渠道名称" align="center" prop="channelCodeName" width="120" /> | ||||
|     <el-table-column label="交易订单号" align="center" prop="tradeNo" width="140" /> | ||||
|     <el-table-column label="商户订单编号" align="center" prop="merchantOrderId" width="140" /> | ||||
|     <el-table-column label="商户订单号" align="left" width="230"> | ||||
|       <template #default="scope"> | ||||
|         <p class="order-font"> | ||||
|           <el-tag size="small">退款</el-tag> | ||||
|           {{ scope.row.merchantRefundNo }} | ||||
|         </p> | ||||
|         <p class="order-font"> | ||||
|           <el-tag type="success">交易</el-tag> | ||||
|           {{ scope.row.merchantOrderId }} | ||||
|         </p> | ||||
|       </template> | ||||
|   </XModal> | ||||
|     </el-table-column> | ||||
|     <el-table-column label="支付订单号" align="center" prop="merchantRefundNo" width="250"> | ||||
|       <template #default="scope"> | ||||
|         <p class="order-font"> | ||||
|           <el-tag size="small">交易</el-tag> | ||||
|           {{ scope.row.tradeNo }} | ||||
|         </p> | ||||
|         <p class="order-font"> | ||||
|           <el-tag size="small" type="warning">渠道</el-tag> | ||||
|           {{ scope.row.channelOrderNo }} | ||||
|         </p> | ||||
|       </template> | ||||
| <script setup lang="ts" name="PayRefund"> | ||||
| import { allSchemas } from './refund.data' | ||||
|     </el-table-column> | ||||
|     <el-table-column label="支付金额(元)" align="center" prop="payAmount" width="100"> | ||||
|       <template #default="scope"> | ||||
|         ¥{{ parseFloat(scope.row.payAmount / 100).toFixed(2) }} | ||||
|       </template> | ||||
|     </el-table-column> | ||||
|     <el-table-column label="退款金额(元)" align="center" prop="refundAmount" width="100"> | ||||
|       <template #default="scope"> | ||||
|         ¥{{ parseFloat(scope.row.refundAmount / 100).toFixed(2) }} | ||||
|       </template> | ||||
|     </el-table-column> | ||||
|     <el-table-column label="退款类型" align="center" prop="type" width="80"> | ||||
|       <template #default="scope"> | ||||
|         <dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_TYPE" :value="scope.row.type" /> | ||||
|       </template> | ||||
|     </el-table-column> | ||||
|     <el-table-column label="退款状态" align="center" prop="status"> | ||||
|       <template #default="scope"> | ||||
|         <dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_STATUS" :value="scope.row.status" /> | ||||
|       </template> | ||||
|     </el-table-column> | ||||
|     <el-table-column label="回调状态" align="center" prop="notifyStatus"> | ||||
|       <template #default="scope"> | ||||
|         <dict-tag :type="DICT_TYPE.PAY_ORDER_NOTIFY_STATUS" :value="scope.row.notifyStatus" /> | ||||
|       </template> | ||||
|     </el-table-column> | ||||
|     <el-table-column | ||||
|       label="退款原因" | ||||
|       align="center" | ||||
|       prop="reason" | ||||
|       width="140" | ||||
|       :show-overflow-tooltip="true" | ||||
|     /> | ||||
|     <el-table-column | ||||
|       label="创建时间" | ||||
|       align="center" | ||||
|       prop="createTime" | ||||
|       width="100" | ||||
|       :formatter="dateFormatter" | ||||
|     /> | ||||
|     <el-table-column | ||||
|       label="退款成功时间" | ||||
|       align="center" | ||||
|       prop="successTime" | ||||
|       width="100" | ||||
|       :formatter="dateFormatter" | ||||
|     /> | ||||
|     <el-table-column | ||||
|       label="操作" | ||||
|       align="center" | ||||
|       fixed="right" | ||||
|       class-name="small-padding fixed-width" | ||||
|     > | ||||
|       <template #default="scope"> | ||||
|         <el-button | ||||
|           size="small" | ||||
|           type="text" | ||||
|           icon="el-icon-search" | ||||
|           @click="openForm(scope.row.id)" | ||||
|           v-hasPermi="['pay:order:query']" | ||||
|           >查看详情 | ||||
|         </el-button> | ||||
|       </template> | ||||
|     </el-table-column> | ||||
|   </el-table> | ||||
|   <content-wrap> | ||||
|     <!-- 分页 --> | ||||
|     <Pagination | ||||
|       :total="total" | ||||
|       v-model:page="queryParams.pageNo" | ||||
|       v-model:limit="queryParams.pageSize" | ||||
|       @pagination="getList" | ||||
|     /> | ||||
|   </content-wrap> | ||||
|   <!-- 表单弹窗:预览 --> | ||||
|   <RefundForm ref="formRef" @success="getList" /> | ||||
| </template> | ||||
| <script setup lang="ts" name="Refund"> | ||||
| import * as AppApi from '@/api/pay/app' | ||||
| import * as MerchantApi from '@/api/pay/merchant' | ||||
| import * as RefundApi from '@/api/pay/refund' | ||||
| import { DICT_TYPE, getDictOptions } from '@/utils/dict' | ||||
| import download from '@/utils/download' | ||||
| import { dateFormatter } from '@/utils/formatTime' | ||||
| import RefundForm from '@/views/pay/refund/refundForm.vue' | ||||
|  | ||||
| const { t } = useI18n() // 国际化 | ||||
|  | ||||
| // 列表相关的变量 | ||||
| const [registerTable, { exportList }] = useXTable({ | ||||
|   allSchemas: allSchemas, | ||||
|   getListApi: RefundApi.getRefundPage, | ||||
|   exportListApi: RefundApi.exportRefund | ||||
| const merchantLoading = ref(false) // 商户加载遮罩层 | ||||
| const message = useMessage() // 消息弹窗 | ||||
| const appList = ref([]) // 支付应用列表集合 | ||||
| const merchantList = ref([]) // 商户列表 | ||||
| const exportLoading = ref(false) // 导出等待 | ||||
| const loading = ref(false) // 列表遮罩层 | ||||
| const total = ref(0) // 列表的总页数 | ||||
| const list = ref([]) // 列表的数据 | ||||
| const queryFormRef = ref() // 搜索的表单 | ||||
| const queryParams = reactive({ | ||||
|   pageNo: 1, | ||||
|   pageSize: 10, | ||||
|   merchantId: undefined, | ||||
|   appId: undefined, | ||||
|   channelId: undefined, | ||||
|   channelCode: undefined, | ||||
|   orderId: undefined, | ||||
|   tradeNo: undefined, | ||||
|   merchantOrderId: undefined, | ||||
|   merchantRefundNo: undefined, | ||||
|   notifyUrl: undefined, | ||||
|   notifyStatus: undefined, | ||||
|   status: undefined, | ||||
|   type: undefined, | ||||
|   payAmount: undefined, | ||||
|   refundAmount: undefined, | ||||
|   reason: undefined, | ||||
|   userIp: undefined, | ||||
|   channelOrderNo: undefined, | ||||
|   channelRefundNo: undefined, | ||||
|   channelErrorCode: undefined, | ||||
|   channelErrorMsg: undefined, | ||||
|   channelExtras: undefined, | ||||
|   expireTime: [], | ||||
|   successTime: [], | ||||
|   notifyTime: [], | ||||
|   createTime: [] | ||||
| }) | ||||
|  | ||||
| // ========== CRUD 相关 ========== | ||||
| const dialogVisible = ref(false) // 是否显示弹出层 | ||||
| const detailData = ref() // 详情 Ref | ||||
|  | ||||
| // 详情操作 | ||||
| const handleDetail = async (rowId: number) => { | ||||
|   // 设置数据 | ||||
|   detailData.value = RefundApi.getRefund(rowId) | ||||
|   dialogVisible.value = true | ||||
| /** | ||||
|  * 根据商户 ID 查询支付应用信息 | ||||
|  */ | ||||
| const handleGetAppListByMerchantId = () => { | ||||
|   queryParams.appId = undefined | ||||
|   if (queryParams.merchantId) { | ||||
|     AppApi.getAppListByMerchantId(queryParams.merchantId).then((response) => { | ||||
|       appList.value = response.data | ||||
|     }) | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 根据商户名称模糊匹配商户信息 | ||||
|  * @param name 商户名称 | ||||
|  */ | ||||
| const handleGetMerchantListByName = async (name) => { | ||||
|   merchantList.value = await MerchantApi.getMerchantListByName(name) | ||||
| } | ||||
|  | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   queryParams.pageNo = 1 | ||||
|   getList() | ||||
| } | ||||
|  | ||||
| /** 查询列表 */ | ||||
| const getList = async () => { | ||||
|   loading.value = true | ||||
|   try { | ||||
|     const data = await RefundApi.getRefundPage(queryParams) | ||||
|     list.value = data.list | ||||
|     total.value = data.total | ||||
|   } finally { | ||||
|     loading.value = false | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value.resetFields() | ||||
|   handleQuery() | ||||
| } | ||||
|  | ||||
| /** 导出按钮操作 */ | ||||
| const handleExport = async () => { | ||||
|   // 导出的二次确认 | ||||
|   await message.exportConfirm() | ||||
|   // 发起导出 | ||||
|   exportLoading.value = true | ||||
|   const data = await RefundApi.exportRefund(queryParams) | ||||
|   download.excel(data, '退款订单.xls') | ||||
| } | ||||
| /** 预览详情 */ | ||||
| const formRef = ref() | ||||
| const openForm = (id?: number) => { | ||||
|   formRef.value.open(id) | ||||
| } | ||||
| /** 初始化 **/ | ||||
| onMounted(async () => { | ||||
|   await getList() | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <style> | ||||
| .order-font { | ||||
|   font-size: 12px; | ||||
|   padding: 2px 0; | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -1,173 +0,0 @@ | ||||
| import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas' | ||||
| const { t } = useI18n() // 国际化 | ||||
|  | ||||
| // CrudSchema | ||||
| const crudSchemas = reactive<VxeCrudSchema>({ | ||||
|   primaryKey: 'id', | ||||
|   primaryType: 'seq', | ||||
|   primaryTitle: '序号', | ||||
|   action: true, | ||||
|   columns: [ | ||||
|     { | ||||
|       title: '商户编号', | ||||
|       field: 'merchantId', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '应用编号', | ||||
|       field: 'appId', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '渠道编号', | ||||
|       field: 'channelId', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '渠道编码', | ||||
|       field: 'channelCode', | ||||
|       dictType: DICT_TYPE.PAY_CHANNEL_CODE_TYPE, | ||||
|       dictClass: 'number', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '支付订单编号', | ||||
|       field: 'orderId', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '交易订单号', | ||||
|       field: 'tradeNo', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '商户订单号', | ||||
|       field: 'merchantOrderId', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '商户退款单号', | ||||
|       field: 'merchantRefundNo', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '回调地址', | ||||
|       field: 'notifyUrl', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '回调状态', | ||||
|       field: 'notifyStatus', | ||||
|       dictType: DICT_TYPE.PAY_ORDER_NOTIFY_STATUS, | ||||
|       dictClass: 'number', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '退款类型', | ||||
|       field: 'type', | ||||
|       dictType: DICT_TYPE.PAY_REFUND_ORDER_TYPE, | ||||
|       dictClass: 'number', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: t('common.status'), | ||||
|       field: 'status', | ||||
|       dictType: DICT_TYPE.PAY_REFUND_ORDER_STATUS, | ||||
|       dictClass: 'number', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '支付金额', | ||||
|       field: 'payAmount', | ||||
|       formatter: 'formatAmount', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '退款金额', | ||||
|       field: 'refundAmount', | ||||
|       formatter: 'formatAmount', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: '退款原因', | ||||
|       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' | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   ] | ||||
| }) | ||||
| export const { allSchemas } = useVxeCrudSchemas(crudSchemas) | ||||
							
								
								
									
										154
									
								
								src/views/pay/refund/refundForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								src/views/pay/refund/refundForm.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
| <template> | ||||
|   <Dialog :title="dialogTitle" v-model="dialogVisible" width="50%"> | ||||
|     <el-descriptions :column="2" label-class-name="desc-label"> | ||||
|       <el-descriptions-item label="商户名称">{{ refundDetail.merchantName }}</el-descriptions-item> | ||||
|       <el-descriptions-item label="应用名称">{{ refundDetail.appName }}</el-descriptions-item> | ||||
|       <el-descriptions-item label="商品名称">{{ refundDetail.subject }}</el-descriptions-item> | ||||
|     </el-descriptions> | ||||
|     <el-divider /> | ||||
|     <el-descriptions :column="2" label-class-name="desc-label"> | ||||
|       <el-descriptions-item label="商户退款单号"> | ||||
|         <el-tag size="small">{{ refundDetail.merchantRefundNo }}</el-tag> | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="商户订单号" | ||||
|         >{{ refundDetail.merchantOrderId }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="交易订单号">{{ refundDetail.tradeNo }}</el-descriptions-item> | ||||
|     </el-descriptions> | ||||
|     <el-divider /> | ||||
|     <el-descriptions :column="2" label-class-name="desc-label"> | ||||
|       <el-descriptions-item label="支付金额"> | ||||
|         {{ parseFloat(refundDetail.payAmount / 100).toFixed(2) }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="退款金额" size="small"> | ||||
|         <el-tag class="tag-purple" size="small"> | ||||
|           {{ parseFloat(refundDetail.refundAmount / 100).toFixed(2) }} | ||||
|         </el-tag> | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="退款类型"> | ||||
|         <dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_TYPE" :value="refundDetail.type" /> | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="退款状态"> | ||||
|         <dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_STATUS" :value="refundDetail.status" /> | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="创建时间" | ||||
|         >{{ formatDate(refundDetail.createTime) }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="退款成功时间" | ||||
|         >{{ formatDate(refundDetail.successTime) }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="退款失效时间" | ||||
|         >{{ formatDate(refundDetail.expireTime) }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="更新时间" | ||||
|         >{{ formatDate(refundDetail.updateTime) }} | ||||
|       </el-descriptions-item> | ||||
|     </el-descriptions> | ||||
|     <el-divider /> | ||||
|     <el-descriptions :column="2" label-class-name="desc-label"> | ||||
|       <el-descriptions-item label="支付渠道"> | ||||
|         {{ refundDetail.channelCodeName }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="支付IP" size="small"> | ||||
|         {{ refundDetail.userIp }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="回调地址">{{ refundDetail.notifyUrl }}</el-descriptions-item> | ||||
|       <el-descriptions-item label="回调状态"> | ||||
|         <dict-tag :type="DICT_TYPE.PAY_ORDER_NOTIFY_STATUS" :value="refundDetail.notifyStatus" /> | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="回调时间" | ||||
|         >{{ formatDate(refundDetail.notifyTime) }} | ||||
|       </el-descriptions-item> | ||||
|     </el-descriptions> | ||||
|     <el-divider /> | ||||
|     <el-descriptions :column="2" label-class-name="desc-label"> | ||||
|       <el-descriptions-item label="渠道订单号" | ||||
|         >{{ refundDetail.channelOrderNo }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="渠道退款单号" | ||||
|         >{{ refundDetail.channelRefundNo }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="渠道错误码" | ||||
|         >{{ refundDetail.channelErrorCode }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="渠道错误码描述" | ||||
|         >{{ refundDetail.channelErrorMsg }} | ||||
|       </el-descriptions-item> | ||||
|     </el-descriptions> | ||||
|     <br /> | ||||
|     <el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border> | ||||
|       <el-descriptions-item label="渠道额外参数" | ||||
|         >{{ refundDetail.channelExtras }} | ||||
|       </el-descriptions-item> | ||||
|       <el-descriptions-item label="退款原因">{{ refundDetail.reason }}</el-descriptions-item> | ||||
|     </el-descriptions> | ||||
|   </Dialog> | ||||
| </template> | ||||
| <script setup lang="ts" name="refundForm"> | ||||
| import { DICT_TYPE } from '@/utils/dict' | ||||
| import * as RefundApi from '@/api/pay/refund' | ||||
| import { formatDate } from '@/utils/formatTime' | ||||
|  | ||||
| const { t } = useI18n() // 国际化 | ||||
| // const message = useMessage() // 消息弹窗 | ||||
| const dialogVisible = ref(false) // 弹窗的是否展示 | ||||
| const dialogTitle = ref('退款订单详情') // 弹窗的标题 | ||||
| const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 | ||||
| const defaultrefundDetail = { | ||||
|   id: null, | ||||
|   appId: null, | ||||
|   appName: '', | ||||
|   channelCode: '', | ||||
|   channelCodeName: '', | ||||
|   channelErrorCode: '', | ||||
|   channelErrorMsg: '', | ||||
|   channelExtras: '', | ||||
|   channelId: null, | ||||
|   channelOrderNo: '', | ||||
|   channelRefundNo: '', | ||||
|   createTime: null, | ||||
|   expireTime: null, | ||||
|   merchantId: null, | ||||
|   merchantName: '', | ||||
|   merchantOrderId: '', | ||||
|   merchantRefundNo: '', | ||||
|   notifyStatus: null, | ||||
|   notifyTime: null, | ||||
|   notifyUrl: '', | ||||
|   orderId: null, | ||||
|   payAmount: null, | ||||
|   reason: '', | ||||
|   refundAmount: null, | ||||
|   status: null, | ||||
|   subject: '', | ||||
|   successTime: null, | ||||
|   tradeNo: '', | ||||
|   type: null, | ||||
|   userIp: '' | ||||
| } | ||||
| const refundDetail = ref(JSON.parse(JSON.stringify(defaultrefundDetail))) | ||||
|  | ||||
| /** 打开弹窗 */ | ||||
| const open = async (id?: number) => { | ||||
|   dialogVisible.value = true | ||||
|   dialogTitle.value = t('action.preview') | ||||
|   // 修改时,设置数据 | ||||
|   if (id) { | ||||
|     formLoading.value = true | ||||
|     try { | ||||
|       refundDetail.value = await RefundApi.getRefundApi(id) | ||||
|     } finally { | ||||
|       formLoading.value = false | ||||
|     } | ||||
|   } | ||||
| } | ||||
| defineExpose({ open }) // 提供 open 方法,用于打开弹窗 | ||||
| </script> | ||||
|  | ||||
| <style> | ||||
| .tag-purple { | ||||
|   color: #722ed1; | ||||
|   background: #f9f0ff; | ||||
|   border-color: #d3adf7; | ||||
| } | ||||
| </style> | ||||
		Reference in New Issue
	
	Block a user
	 芋道源码
					芋道源码