18 changed files with 431 additions and 5 deletions
			
			
		| After Width: | Height: | Size: 1.6 KiB | 
| After Width: | Height: | Size: 3.9 KiB | 
| After Width: | Height: | Size: 1.7 KiB | 
| After Width: | Height: | Size: 1.0 KiB | 
| @ -0,0 +1,43 @@ | |||||||
|  | <template> | ||||||
|  |   <BasicModal v-bind="$attrs" @register="registerModal" title="发起订单" @ok="handleSubmit"> | ||||||
|  |     <BasicForm @register="registerForm" /> | ||||||
|  |   </BasicModal> | ||||||
|  | </template> | ||||||
|  | <script lang="ts" setup name="PayDemoModal"> | ||||||
|  | import { useI18n } from '@/hooks/web/useI18n' | ||||||
|  | import { useMessage } from '@/hooks/web/useMessage' | ||||||
|  | import { BasicForm, useForm } from '@/components/Form' | ||||||
|  | import { BasicModal, useModalInner } from '@/components/Modal' | ||||||
|  | import { formSchema } from './demo.data' | ||||||
|  | import { createDemoOrder } from '@/api/pay/demo' | ||||||
|  | 
 | ||||||
|  | const { t } = useI18n() | ||||||
|  | const { createMessage } = useMessage() | ||||||
|  | const emit = defineEmits(['success', 'register']) | ||||||
|  | 
 | ||||||
|  | const [registerForm, { resetFields, validate }] = useForm({ | ||||||
|  |   labelWidth: 120, | ||||||
|  |   baseColProps: { span: 24 }, | ||||||
|  |   schemas: formSchema, | ||||||
|  |   showActionButtonGroup: false, | ||||||
|  |   actionColOptions: { span: 23 } | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | const [registerModal, { setModalProps, closeModal }] = useModalInner(async () => { | ||||||
|  |   resetFields() | ||||||
|  |   setModalProps({ confirmLoading: false }) | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | async function handleSubmit() { | ||||||
|  |   try { | ||||||
|  |     const values = await validate() | ||||||
|  |     setModalProps({ confirmLoading: true }) | ||||||
|  |     await createDemoOrder(values) | ||||||
|  |     closeModal() | ||||||
|  |     emit('success') | ||||||
|  |     createMessage.success(t('common.saveSuccessText')) | ||||||
|  |   } finally { | ||||||
|  |     setModalProps({ confirmLoading: false }) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
| @ -0,0 +1,110 @@ | |||||||
|  | import { BasicColumn, FormSchema, useRender } from '@/components/Table' | ||||||
|  | import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' | ||||||
|  | 
 | ||||||
|  | export const columns: BasicColumn[] = [ | ||||||
|  |   { | ||||||
|  |     title: '订单编号', | ||||||
|  |     dataIndex: 'id', | ||||||
|  |     width: 100 | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     title: '用户编号', | ||||||
|  |     dataIndex: 'userId', | ||||||
|  |     width: 100 | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     title: '商品名字', | ||||||
|  |     dataIndex: 'spuName', | ||||||
|  |     width: 100 | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     title: '支付价格', | ||||||
|  |     dataIndex: 'price', | ||||||
|  |     width: 100, | ||||||
|  |     customRender: ({ text }) => { | ||||||
|  |       return useRender.renderTag('¥' + (text / 100.0).toFixed(2)) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     title: '退款金额', | ||||||
|  |     dataIndex: 'refundPrice', | ||||||
|  |     width: 100, | ||||||
|  |     customRender: ({ text }) => { | ||||||
|  |       return useRender.renderTag('¥' + (text / 100.0).toFixed(2)) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     title: '支付单号', | ||||||
|  |     dataIndex: 'payOrderId', | ||||||
|  |     width: 100 | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     title: '创建时间', | ||||||
|  |     dataIndex: 'createTime', | ||||||
|  |     width: 180, | ||||||
|  |     customRender: ({ text }) => { | ||||||
|  |       return useRender.renderDate(text) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     title: '是否支付', | ||||||
|  |     dataIndex: 'payed', | ||||||
|  |     width: 100, | ||||||
|  |     customRender: ({ text }) => { | ||||||
|  |       return useRender.renderDict(text, DICT_TYPE.INFRA_BOOLEAN_STRING) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     title: '支付时间', | ||||||
|  |     dataIndex: 'payTime', | ||||||
|  |     width: 180, | ||||||
|  |     customRender: ({ text }) => { | ||||||
|  |       return useRender.renderDate(text) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     title: '退款时间', | ||||||
|  |     dataIndex: 'refundTime', | ||||||
|  |     width: 180, | ||||||
|  |     customRender: ({ text }) => { | ||||||
|  |       return useRender.renderDate(text) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | export const searchFormSchema: FormSchema[] = [ | ||||||
|  |   { | ||||||
|  |     label: '支付单号', | ||||||
|  |     field: 'payOrderId', | ||||||
|  |     component: 'Input', | ||||||
|  |     colProps: { span: 8 } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '是否支付', | ||||||
|  |     field: 'payed', | ||||||
|  |     component: 'Select', | ||||||
|  |     componentProps: { | ||||||
|  |       options: getIntDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING) | ||||||
|  |     }, | ||||||
|  |     colProps: { span: 8 } | ||||||
|  |   } | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | export const formSchema: FormSchema[] = [ | ||||||
|  |   { | ||||||
|  |     label: '商品', | ||||||
|  |     field: 'spuId', | ||||||
|  |     component: 'Select', | ||||||
|  |     defaultValue: 0, | ||||||
|  |     required: true, | ||||||
|  |     componentProps: { | ||||||
|  |       options: [ | ||||||
|  |         { value: 1, label: '华为手机', price: 1 }, | ||||||
|  |         { value: 2, label: '小米电视', price: 10 }, | ||||||
|  |         { value: 3, label: '苹果手表', price: 100 }, | ||||||
|  |         { value: 4, label: '华硕笔记本', price: 1000 }, | ||||||
|  |         { value: 5, label: '蔚来汽车', price: 200000 } | ||||||
|  |       ] | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | ] | ||||||
| @ -1,3 +1,74 @@ | |||||||
| <template> | <template> | ||||||
|   <div>开发中</div> |   <div> | ||||||
|  |     <BasicTable @register="registerTable"> | ||||||
|  |       <template #toolbar> | ||||||
|  |         <a-button type="primary" v-auth="['pay:app:create']" :preIcon="IconEnum.ADD" @click="handleAdd"> 发起订单 </a-button> | ||||||
|       </template> |       </template> | ||||||
|  |       <template #bodyCell="{ column, record }"> | ||||||
|  |         <template v-if="column.key === 'action'"> | ||||||
|  |           <TableAction | ||||||
|  |             :actions="[ | ||||||
|  |               { icon: IconEnum.EDIT, label: '前往支付', onClick: handlePay.bind(null, record) }, | ||||||
|  |               { icon: IconEnum.DELETE, color: 'error', label: '发起退款', onClick: handleRefund.bind(null, record) } | ||||||
|  |             ]" | ||||||
|  |           /> | ||||||
|  |         </template> | ||||||
|  |       </template> | ||||||
|  |     </BasicTable> | ||||||
|  |     <DemoModal @register="registerModal" @success="reload()" /> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | <script lang="ts" setup name="PayDemo"> | ||||||
|  | import { useGo } from '@/hooks/web/usePage' | ||||||
|  | import { useI18n } from '@/hooks/web/useI18n' | ||||||
|  | import { useMessage } from '@/hooks/web/useMessage' | ||||||
|  | import { useModal } from '@/components/Modal' | ||||||
|  | import DemoModal from './DemoModal.vue' | ||||||
|  | import { IconEnum } from '@/enums/appEnum' | ||||||
|  | import { BasicTable, useTable, TableAction } from '@/components/Table' | ||||||
|  | import { getDemoOrderPage, refundDemoOrder } from '@/api/pay/demo' | ||||||
|  | import { columns, searchFormSchema } from './demo.data' | ||||||
|  | 
 | ||||||
|  | const go = useGo() | ||||||
|  | const { t } = useI18n() | ||||||
|  | const { createConfirm, createMessage } = useMessage() | ||||||
|  | const [registerModal, { openModal }] = useModal() | ||||||
|  | 
 | ||||||
|  | const [registerTable, { reload }] = useTable({ | ||||||
|  |   title: '接入示例列表', | ||||||
|  |   api: getDemoOrderPage, | ||||||
|  |   columns, | ||||||
|  |   formConfig: { labelWidth: 120, schemas: searchFormSchema }, | ||||||
|  |   useSearchForm: true, | ||||||
|  |   showTableSetting: true, | ||||||
|  |   actionColumn: { | ||||||
|  |     width: 180, | ||||||
|  |     title: t('common.action'), | ||||||
|  |     dataIndex: 'action', | ||||||
|  |     fixed: 'right' | ||||||
|  |   } | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | function handleAdd() { | ||||||
|  |   openModal(true) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 支付按钮操作 */ | ||||||
|  | function handlePay(record: Recordable) { | ||||||
|  |   go('/cashRegister/submit?id=' + record.id) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 退款按钮操作 */ | ||||||
|  | async function handleRefund(record: Recordable) { | ||||||
|  |   createConfirm({ | ||||||
|  |     title: '退款', | ||||||
|  |     iconType: 'warning', | ||||||
|  |     content: '是否确认退款编号为"' + record.id + '"的示例订单?', | ||||||
|  |     async onOk() { | ||||||
|  |       await refundDemoOrder(record.id) | ||||||
|  |       createMessage.success(t('common.successText')) | ||||||
|  |       reload() | ||||||
|  |     } | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | |||||||
| @ -0,0 +1,121 @@ | |||||||
|  | <template> | ||||||
|  |   <div> | ||||||
|  |     <Card> | ||||||
|  |       <Description :bordered="false" :column="3" :data="orderData" :schema="descSchema" /> | ||||||
|  |     </Card> | ||||||
|  |     <Card class="mt-4 justify-center"> | ||||||
|  |       <List :grid="{ column: 8 }" header="选择支付宝支付" :data-source="aliPayChannels"> | ||||||
|  |         <template #renderItem="{ item }"> | ||||||
|  |           <ListItem> | ||||||
|  |             <Card hoverable class="w-30 h-28 mt-3 pb-3"> | ||||||
|  |               <template #cover> | ||||||
|  |                 <img class="w-40px h-40px mt-2" :src="icons[item.code]" /> | ||||||
|  |                 <p class="mt-3 text-center"> {{ item.name }} </p> | ||||||
|  |               </template> | ||||||
|  |               <template #actions> | ||||||
|  |                 <Icon icon="ant-design:alipay-outlined" @click="submit(item.code)" /> | ||||||
|  |               </template> | ||||||
|  |             </Card> | ||||||
|  |           </ListItem> | ||||||
|  |         </template> | ||||||
|  |       </List> | ||||||
|  |       <List :grid="{ column: 8 }" class="mt-4" header="选择微信支付" :data-source="wxPayChannels"> | ||||||
|  |         <template #renderItem="{ item }"> | ||||||
|  |           <ListItem> | ||||||
|  |             <Card hoverable class="w-30 h-28 pt-3 pb-3"> | ||||||
|  |               <template #cover> | ||||||
|  |                 <img class="w-40px h-40px mt-2" :src="icons[item.code]" /> | ||||||
|  |                 <p class="mt-3 text-center"> {{ item.name }} </p> | ||||||
|  |               </template> | ||||||
|  |             </Card> | ||||||
|  |           </ListItem> | ||||||
|  |         </template> | ||||||
|  |       </List> | ||||||
|  |       <List :grid="{ column: 8 }" class="mt-4" header="选择其它支付" :data-source="otherPayChannels"> | ||||||
|  |         <template #renderItem="{ item }"> | ||||||
|  |           <ListItem> | ||||||
|  |             <Card hoverable class="w-30 h-28 pt-3 pb-3"> | ||||||
|  |               <template #cover> | ||||||
|  |                 <img class="w-40px h-40px mt-2" :src="icons[item.code]" /> | ||||||
|  |                 <p class="mt-3 text-center"> {{ item.name }} </p> | ||||||
|  |               </template> | ||||||
|  |             </Card> | ||||||
|  |           </ListItem> | ||||||
|  |         </template> | ||||||
|  |       </List> | ||||||
|  |     </Card> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | <script lang="ts" setup name="PayOrderSubmit"> | ||||||
|  | import { ref, onMounted } from 'vue' | ||||||
|  | import { Card, List } from 'ant-design-vue' | ||||||
|  | import { Description } from '@/components/Description' | ||||||
|  | import { descSchema } from './submit.data' | ||||||
|  | import { getOrder, submitOrder } from '@/api/pay/order' | ||||||
|  | import { DICT_TYPE, getStrDictOptions } from '@/utils/dict' | ||||||
|  | import { useRoute } from 'vue-router' | ||||||
|  | import alipay_qr from '@/assets/images/pay/icon/alipay_qr.svg' | ||||||
|  | import alipay_app from '@/assets/images/pay/icon/alipay_app.svg' | ||||||
|  | import alipay_wap from '@/assets/images/pay/icon/alipay_wap.svg' | ||||||
|  | import alipay_pc from '@/assets/images/pay/icon/alipay_pc.svg' | ||||||
|  | import alipay_bar from '@/assets/images/pay/icon/alipay_bar.svg' | ||||||
|  | import wx_app from '@/assets/images/pay/icon/wx_app.svg' | ||||||
|  | import wx_lite from '@/assets/images/pay/icon/wx_lite.svg' | ||||||
|  | import wx_pub from '@/assets/images/pay/icon/wx_pub.svg' | ||||||
|  | import mock from '@/assets/images/pay/icon/mock.svg' | ||||||
|  | 
 | ||||||
|  | const ListItem = List.Item | ||||||
|  | 
 | ||||||
|  | const icons = { | ||||||
|  |   alipay_qr: alipay_qr, | ||||||
|  |   alipay_app: alipay_app, | ||||||
|  |   alipay_wap: alipay_wap, | ||||||
|  |   alipay_pc: alipay_pc, | ||||||
|  |   alipay_bar: alipay_bar, | ||||||
|  |   wx_app: wx_app, | ||||||
|  |   wx_lite: wx_lite, | ||||||
|  |   wx_pub: wx_pub, | ||||||
|  |   mock: mock | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const { query } = useRoute() | ||||||
|  | const orderData = ref() | ||||||
|  | const aliPayChannels = ref<any[]>([]) | ||||||
|  | const wxPayChannels = ref<any[]>([]) | ||||||
|  | const otherPayChannels = ref<any[]>([]) | ||||||
|  | 
 | ||||||
|  | function initPayChannels() { | ||||||
|  |   // 微信支付 | ||||||
|  |   for (const dict of getStrDictOptions(DICT_TYPE.PAY_CHANNEL_CODE_TYPE)) { | ||||||
|  |     const payChannel = { | ||||||
|  |       name: dict.label, | ||||||
|  |       code: dict.value as string | ||||||
|  |     } | ||||||
|  |     if (payChannel.code.startsWith('wx_')) { | ||||||
|  |       wxPayChannels.value.push(payChannel) | ||||||
|  |     } else if (payChannel.code.startsWith('alipay_')) { | ||||||
|  |       aliPayChannels.value.push(payChannel) | ||||||
|  |     } else if (payChannel.code) { | ||||||
|  |       otherPayChannels.value.push(payChannel) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | async function getDetail() { | ||||||
|  |   const queryId = query.id as unknown as number | ||||||
|  |   if (!queryId) { | ||||||
|  |     return | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const res = await getOrder(queryId) | ||||||
|  |   orderData.value = res | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function submit(channelCode) { | ||||||
|  |   submitOrder({ id: query.id as unknown as number, channelCode }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | onMounted(async () => { | ||||||
|  |   await initPayChannels() | ||||||
|  |   await getDetail() | ||||||
|  | }) | ||||||
|  | </script> | ||||||
| @ -0,0 +1,38 @@ | |||||||
|  | import { DescItem } from '@/components/Description' | ||||||
|  | import { useRender } from '@/components/Table' | ||||||
|  | 
 | ||||||
|  | export const descSchema: DescItem[] = [ | ||||||
|  |   { | ||||||
|  |     label: '支付单号', | ||||||
|  |     field: 'id' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '商品标题', | ||||||
|  |     field: 'subject' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '商品内容', | ||||||
|  |     field: 'body' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '支付金额', | ||||||
|  |     field: 'amount', | ||||||
|  |     render: (curVal) => { | ||||||
|  |       return useRender.renderText('¥', parseFloat(curVal || 0 / 100).toFixed(2)) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '创建时间', | ||||||
|  |     field: 'createTime', | ||||||
|  |     render: (curVal) => { | ||||||
|  |       return useRender.renderDate(curVal) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '过期时间', | ||||||
|  |     field: 'expireTime', | ||||||
|  |     render: (curVal) => { | ||||||
|  |       return useRender.renderDate(curVal) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | ] | ||||||
		Reference in new issue