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> |
||||
<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 #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