index.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. <template>
  2. <doc-alert title="支付宝支付接入" url="https://doc.iocoder.cn/pay/alipay-pay-demo/" />
  3. <doc-alert title="支付宝、微信退款接入" url="https://doc.iocoder.cn/pay/refund-demo/" />
  4. <doc-alert title="微信公众号支付接入" url="https://doc.iocoder.cn/pay/wx-pub-pay-demo/" />
  5. <doc-alert title="微信小程序支付接入" url="https://doc.iocoder.cn/pay/wx-lite-pay-demo/" />
  6. <!-- 操作工具栏 -->
  7. <el-row :gutter="10" class="mb8">
  8. <el-col :span="1.5">
  9. <el-button type="primary" plain @click="openForm"><Icon icon="ep:plus" />发起订单</el-button>
  10. </el-col>
  11. </el-row>
  12. <!-- 列表 -->
  13. <ContentWrap>
  14. <el-table v-loading="loading" :data="list">
  15. <el-table-column label="订单编号" align="center" prop="id" />
  16. <el-table-column label="用户编号" align="center" prop="userId" />
  17. <el-table-column label="商品名字" align="center" prop="spuName" />
  18. <el-table-column label="支付价格" align="center" prop="price">
  19. <template #default="scope">
  20. <span>¥{{ (scope.row.price / 100.0).toFixed(2) }}</span>
  21. </template>
  22. </el-table-column>
  23. <el-table-column label="退款金额" align="center" prop="refundPrice">
  24. <template #default="scope">
  25. <span>¥{{ (scope.row.refundPrice / 100.0).toFixed(2) }}</span>
  26. </template>
  27. </el-table-column>
  28. <el-table-column
  29. label="创建时间"
  30. align="center"
  31. prop="createTime"
  32. width="180"
  33. :formatter="dateFormatter"
  34. />
  35. <el-table-column label="支付单号" align="center" prop="payOrderId" />
  36. <el-table-column label="是否支付" align="center" prop="payStatus">
  37. <template #default="scope">
  38. <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.payStatus" />
  39. </template>
  40. </el-table-column>
  41. <el-table-column
  42. label="支付时间"
  43. align="center"
  44. prop="payTime"
  45. width="180"
  46. :formatter="dateFormatter"
  47. />
  48. <el-table-column label="退款时间" align="center" prop="refundTime" width="180">
  49. <template #default="scope">
  50. <span v-if="scope.row.refundTime">{{ formatDate(scope.row.refundTime) }}</span>
  51. <span v-else-if="scope.row.payRefundId">退款中,等待退款结果</span>
  52. </template>
  53. </el-table-column>
  54. <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  55. <template #default="scope">
  56. <el-button link type="primary" @click="handlePay(scope.row)" v-if="!scope.row.payStatus">
  57. 前往支付
  58. </el-button>
  59. <el-button
  60. link
  61. type="danger"
  62. @click="handleRefund(scope.row)"
  63. v-if="scope.row.payStatus && !scope.row.payRefundId"
  64. >
  65. 发起退款
  66. </el-button>
  67. </template>
  68. </el-table-column>
  69. </el-table>
  70. <!-- 分页组件 -->
  71. <Pagination
  72. :total="total"
  73. v-model:page="queryParams.pageNo"
  74. v-model:limit="queryParams.pageSize"
  75. @pagination="getList"
  76. />
  77. </ContentWrap>
  78. <!-- 对话框(添加 / 修改) -->
  79. <Dialog title="发起订单" v-model="dialogVisible" width="500px">
  80. <el-form
  81. ref="formRef"
  82. v-loading="formLoading"
  83. :model="formData"
  84. :rules="formRules"
  85. label-width="80px"
  86. >
  87. <el-form-item label="商品" prop="spuId">
  88. <el-select
  89. v-model="formData.spuId"
  90. placeholder="请输入下单商品"
  91. clearable
  92. style="width: 380px"
  93. >
  94. <el-option v-for="item in spus" :key="item.id" :label="item.name" :value="item.id">
  95. <span style="float: left">{{ item.name }}</span>
  96. <span style="float: right; font-size: 13px; color: #8492a6">
  97. ¥{{ (item.price / 100.0).toFixed(2) }}
  98. </span>
  99. </el-option>
  100. </el-select>
  101. </el-form-item>
  102. </el-form>
  103. <template #footer>
  104. <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
  105. <el-button @click="dialogVisible = false">取 消</el-button>
  106. </template>
  107. </Dialog>
  108. </template>
  109. <script lang="ts" setup name="PayDemoOrder">
  110. import * as PayDemoApi from '@/api/pay/demo'
  111. import { dateFormatter, formatDate } from '@/utils/formatTime'
  112. import { DICT_TYPE } from '@/utils/dict'
  113. const { t } = useI18n() // 国际化
  114. const router = useRouter() // 路由对象
  115. const message = useMessage() // 消息弹窗
  116. const loading = ref(true) // 列表的加载中
  117. const total = ref(0) // 列表的总页数
  118. const list = ref([]) // 列表的数据
  119. // 查询条件
  120. const queryParams = reactive({
  121. pageNo: 1,
  122. pageSize: 10
  123. })
  124. const formRef = ref()
  125. /** 查询列表 */
  126. const getList = async () => {
  127. loading.value = true
  128. try {
  129. const data = await PayDemoApi.getDemoOrderPage(queryParams)
  130. list.value = data.list
  131. total.value = data.total
  132. } finally {
  133. loading.value = false
  134. }
  135. }
  136. /** 支付按钮操作 */
  137. const handlePay = (row: any) => {
  138. router.push({
  139. name: 'PayCashier',
  140. query: {
  141. id: row.payOrderId,
  142. returnUrl: encodeURIComponent('/pay/demo-order?id=' + row.id)
  143. }
  144. })
  145. }
  146. /** 退款按钮操作 */
  147. const handleRefund = async (row: any) => {
  148. const id = row.id
  149. try {
  150. await message.confirm('是否确认退款编号为"' + id + '"的示例订单?')
  151. await PayDemoApi.refundDemoOrder(id)
  152. await getList()
  153. message.success('发起退款成功!')
  154. } catch {}
  155. }
  156. // ========== 弹窗 ==========
  157. // 商品数组
  158. const spus = ref([
  159. {
  160. id: 1,
  161. name: '华为手机',
  162. price: 1
  163. },
  164. {
  165. id: 2,
  166. name: '小米电视',
  167. price: 10
  168. },
  169. {
  170. id: 3,
  171. name: '苹果手表',
  172. price: 100
  173. },
  174. {
  175. id: 4,
  176. name: '华硕笔记本',
  177. price: 1000
  178. },
  179. {
  180. id: 5,
  181. name: '蔚来汽车',
  182. price: 200000
  183. }
  184. ])
  185. const dialogVisible = ref(false) // 弹窗的是否展示
  186. const formLoading = ref(false) // 表单的加载中
  187. const formData = ref<any>({}) // 表单数据
  188. const formRules = {
  189. spuId: [{ required: true, message: '商品编号不能为空', trigger: 'blur' }]
  190. }
  191. /** 表单重置 */
  192. const reset = () => {
  193. formData.value = {
  194. spuId: undefined
  195. }
  196. formRef.value?.resetFields()
  197. }
  198. /** 新增按钮操作 */
  199. const openForm = () => {
  200. reset()
  201. dialogVisible.value = true
  202. }
  203. /** 提交按钮 */
  204. const submitForm = async () => {
  205. // 校验表单
  206. if (!formRef) return
  207. const valid = await formRef.value.validate()
  208. if (!valid) return
  209. // 提交请求
  210. formLoading.value = true
  211. try {
  212. await PayDemoApi.createDemoOrder(formData.value)
  213. message.success(t('common.createSuccess'))
  214. dialogVisible.value = false
  215. } finally {
  216. formLoading.value = false
  217. getList()
  218. }
  219. }
  220. /** 初始化 **/
  221. onMounted(() => {
  222. getList()
  223. })
  224. </script>