Ver código fonte

code review:优化示例订单的实现

(cherry picked from commit 26cf4ca64a728d0f198f01bb472735531db4a5c7)
YunaiV 1 ano atrás
pai
commit
3af92d076e
3 arquivos alterados com 205 adições e 371 exclusões
  1. 63 67
      src/views/pay/cashier/index.vue
  2. 142 151
      src/views/pay/demo/index.vue
  3. 0 153
      src/views/pay/merchant/index.vue

+ 63 - 67
src/views/pay/cashier/index.vue

@@ -116,7 +116,7 @@
 
 <script lang="ts" setup>
 import QrcodeVue from 'qrcode.vue'
-import { getOrder, submitOrder } from '@/api/pay/order'
+import * as PayOrderApi from '@/api/pay/order'
 import { PayChannelEnum, PayDisplayModeEnum, PayOrderStatusEnum } from '@/utils/constants'
 import { formatDate } from '@/utils/formatTime'
 import { useTagsViewStore } from '@/store/modules/tagsView'
@@ -224,34 +224,31 @@ const barCode = ref({
 })
 
 /** 获得支付信息 */
-const getDetail = () => {
+const getDetail = async () => {
   // 1.1 未传递订单编号
   if (!id.value) {
     message.error('未传递支付单号,无法查看对应的支付信息')
     goReturnUrl('cancel')
     return
   }
-  getOrder(id.value).then((data) => {
-    // 1.2 无法查询到支付信息
-    if (!data) {
-      message.error('支付订单不存在,请检查!')
-      goReturnUrl('cancel')
-      return
-    }
-    // 1.3 如果已支付、或者已关闭,则直接跳转
-    if (data.status === PayOrderStatusEnum.SUCCESS.status) {
-      message.success('支付成功')
-      goReturnUrl('success')
-      return
-    } else if (data.status === PayOrderStatusEnum.CLOSED.status) {
-      message.error('无法支付,原因:订单已关闭')
-      goReturnUrl('close')
-      return
-    }
-
-    // 2. 可以展示
-    payOrder.value = data
-  })
+  const data = await PayOrderApi.getOrder(id.value)
+  payOrder.value = data
+  // 1.2 无法查询到支付信息
+  if (!data) {
+    message.error('支付订单不存在,请检查!')
+    goReturnUrl('cancel')
+    return
+  }
+  // 1.3 如果已支付、或者已关闭,则直接跳转
+  if (data.status === PayOrderStatusEnum.SUCCESS.status) {
+    message.success('支付成功')
+    goReturnUrl('success')
+    return
+  } else if (data.status === PayOrderStatusEnum.CLOSED.status) {
+    message.error('无法支付,原因:订单已关闭')
+    goReturnUrl('close')
+    return
+  }
 }
 
 /** 提交支付 */
@@ -290,38 +287,38 @@ const submit = (channelCode) => {
   submit0(channelCode)
 }
 
-const submit0 = (channelCode) => {
+const submit0 = async (channelCode) => {
   submitLoading.value = true
-  submitOrder({
-    id: id.value,
-    channelCode: channelCode,
-    returnUrl: location.href, // 支付成功后,支付渠道跳转回当前页;再由当前页,跳转回 {@link returnUrl} 对应的地址
-    ...buildSubmitParam(channelCode)
-  })
-    .then((data) => {
-      // 直接返回已支付的情况,例如说扫码支付
-      if (data.status === PayOrderStatusEnum.SUCCESS.status) {
-        clearQueryInterval()
-        message.success('支付成功!')
-        goReturnUrl('success')
-        return
-      }
+  try {
+    const formData = {
+      id: id.value,
+      channelCode: channelCode,
+      returnUrl: location.href, // 支付成功后,支付渠道跳转回当前页;再由当前页,跳转回 {@link returnUrl} 对应的地址
+      ...buildSubmitParam(channelCode)
+    }
+    const data = await PayOrderApi.submitOrder(formData)
+    // 直接返回已支付的情况,例如说扫码支付
+    if (data.status === PayOrderStatusEnum.SUCCESS.status) {
+      clearQueryInterval()
+      message.success('支付成功!')
+      goReturnUrl('success')
+      return
+    }
 
-      // 展示对应的界面
-      if (data.displayMode === PayDisplayModeEnum.URL.mode) {
-        displayUrl(channelCode, data)
-      } else if (data.displayMode === PayDisplayModeEnum.QR_CODE.mode) {
-        displayQrCode(channelCode, data)
-      } else if (data.displayMode === PayDisplayModeEnum.APP.mode) {
-        displayApp(channelCode)
-      }
+    // 展示对应的界面
+    if (data.displayMode === PayDisplayModeEnum.URL.mode) {
+      displayUrl(channelCode, data)
+    } else if (data.displayMode === PayDisplayModeEnum.QR_CODE.mode) {
+      displayQrCode(channelCode, data)
+    } else if (data.displayMode === PayDisplayModeEnum.APP.mode) {
+      displayApp(channelCode)
+    }
 
-      // 打开轮询任务
-      createQueryInterval()
-    })
-    .catch(() => {
-      submitLoading.value = false
-    })
+    // 打开轮询任务
+    createQueryInterval()
+  } finally {
+    submitLoading.value = false
+  }
 }
 
 /** 构建提交支付的额外参数 */
@@ -385,21 +382,20 @@ const createQueryInterval = () => {
   if (interval.value) {
     return
   }
-  interval.value = setInterval(() => {
-    getOrder(id.value).then((data) => {
-      // 已支付
-      if (data.status === PayOrderStatusEnum.SUCCESS.status) {
-        clearQueryInterval()
-        message.success('支付成功!')
-        goReturnUrl('success')
-      }
-      // 已取消
-      if (data.status === PayOrderStatusEnum.CLOSED.status) {
-        clearQueryInterval()
-        message.error('支付已关闭!')
-        goReturnUrl('close')
-      }
-    })
+  interval.value = setInterval(async () => {
+    const data = await PayOrderApi.getOrder(id.value)
+    // 已支付
+    if (data.status === PayOrderStatusEnum.SUCCESS.status) {
+      clearQueryInterval()
+      message.success('支付成功!')
+      goReturnUrl('success')
+    }
+    // 已取消
+    if (data.status === PayOrderStatusEnum.CLOSED.status) {
+      clearQueryInterval()
+      message.error('支付已关闭!')
+      goReturnUrl('close')
+    }
   }, 1000 * 2)
 }
 

+ 142 - 151
src/views/pay/demo/index.vue

@@ -2,140 +2,163 @@
   <!-- 操作工具栏 -->
   <el-row :gutter="10" class="mb8">
     <el-col :span="1.5">
-      <el-button type="primary" plain @click="handleAdd"><Icon icon="ep:plus" />发起订单</el-button>
+      <el-button type="primary" plain @click="openForm"><Icon icon="ep:plus" />发起订单</el-button>
     </el-col>
   </el-row>
 
   <!-- 列表 -->
-  <el-table v-loading="loading" :data="list">
-    <el-table-column label="订单编号" align="center" prop="id" />
-    <el-table-column label="用户编号" align="center" prop="userId" />
-    <el-table-column label="商品名字" align="center" prop="spuName" />
-    <el-table-column label="支付价格" align="center" prop="price">
-      <template #default="scope">
-        <span>¥{{ (scope.row.price / 100.0).toFixed(2) }}</span>
-      </template>
-    </el-table-column>
-    <el-table-column label="退款金额" align="center" prop="refundPrice">
-      <template #default="scope">
-        <span>¥{{ (scope.row.refundPrice / 100.0).toFixed(2) }}</span>
-      </template>
-    </el-table-column>
-    <el-table-column
-      label="创建时间"
-      align="center"
-      prop="createTime"
-      width="180"
-      :formatter="dateFormatter"
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list">
+      <el-table-column label="订单编号" align="center" prop="id" />
+      <el-table-column label="用户编号" align="center" prop="userId" />
+      <el-table-column label="商品名字" align="center" prop="spuName" />
+      <el-table-column label="支付价格" align="center" prop="price">
+        <template #default="scope">
+          <span>¥{{ (scope.row.price / 100.0).toFixed(2) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="退款金额" align="center" prop="refundPrice">
+        <template #default="scope">
+          <span>¥{{ (scope.row.refundPrice / 100.0).toFixed(2) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        width="180"
+        :formatter="dateFormatter"
+      />
+      <el-table-column label="支付单号" align="center" prop="payOrderId" />
+      <el-table-column label="是否支付" align="center" prop="payStatus">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.payStatus" />
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="支付时间"
+        align="center"
+        prop="payTime"
+        width="180"
+        :formatter="dateFormatter"
+      />
+      <el-table-column label="退款时间" align="center" prop="refundTime" width="180">
+        <template #default="scope">
+          <span v-if="scope.row.refundTime">{{ formatDate(scope.row.refundTime) }}</span>
+          <span v-else-if="scope.row.payRefundId">退款中,等待退款结果</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" @click="handlePay(scope.row)" v-if="!scope.row.payStatus">
+            前往支付
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleRefund(scope.row)"
+            v-if="scope.row.payStatus && !scope.row.payRefundId"
+          >
+            发起退款
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页组件 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
     />
-    <el-table-column label="支付单号" align="center" prop="payOrderId" />
-    <el-table-column label="是否支付" align="center" prop="payStatus">
-      <template #default="scope">
-        <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.payStatus" />
-      </template>
-    </el-table-column>
-    <el-table-column
-      label="支付时间"
-      align="center"
-      prop="payTime"
-      width="180"
-      :formatter="dateFormatter"
-    />
-    <el-table-column label="退款时间" align="center" prop="refundTime" width="180">
-      <template #default="scope">
-        <span v-if="scope.row.refundTime">{{ formatDate(scope.row.refundTime) }}</span>
-        <span v-else-if="scope.row.payRefundId">退款中,等待退款结果</span>
-      </template>
-    </el-table-column>
-    <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-      <template #default="scope">
-        <el-button
-          size="small"
-          type="text"
-          icon="el-icon-edit"
-          @click="handlePay(scope.row)"
-          v-if="!scope.row.payStatus"
-          >前往支付</el-button
-        >
-        <el-button
-          size="small"
-          type="text"
-          icon="el-icon-delete"
-          @click="handleRefund(scope.row)"
-          v-if="scope.row.payStatus && !scope.row.payRefundId"
-          >发起退款</el-button
-        >
-      </template>
-    </el-table-column>
-  </el-table>
-  <!-- 分页组件 -->
-  <pagination
-    v-show="total > 0"
-    :total="total"
-    v-model:page="queryParams.pageNo"
-    v-model:limit="queryParams.pageSize"
-    @pagination="getList"
-  />
+  </ContentWrap>
 
   <!-- 对话框(添加 / 修改) -->
-  <el-dialog :title="title" v-model="open" width="500px" append-to-body destroy-on-close>
-    <el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
+  <Dialog title="发起订单" v-model="dialogVisible" width="500px">
+    <el-form
+      ref="formRef"
+      v-loading="formLoading"
+      :model="formData"
+      :rules="formRules"
+      label-width="80px"
+    >
       <el-form-item label="商品" prop="spuId">
         <el-select
-          v-model="form.spuId"
+          v-model="formData.spuId"
           placeholder="请输入下单商品"
           clearable
-          size="small"
           style="width: 380px"
         >
           <el-option v-for="item in spus" :key="item.id" :label="item.name" :value="item.id">
             <span style="float: left">{{ item.name }}</span>
-            <span style="float: right; color: #8492a6; font-size: 13px"
-              >¥{{ (item.price / 100.0).toFixed(2) }}</span
-            >
+            <span style="float: right; color: #8492a6; font-size: 13px">
+              ¥{{ (item.price / 100.0).toFixed(2) }}
+            </span>
           </el-option>
         </el-select>
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button type="primary" @click="submitForm">确 定</el-button>
-      <el-button @click="cancel">取 消</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
-  </el-dialog>
+  </Dialog>
 </template>
-
 <script lang="ts" setup name="PayDemoOrder">
-import { createDemoOrder, getDemoOrderPage, refundDemoOrder } from '@/api/pay/demo'
-import { ref, onMounted } from 'vue'
+import * as PayDemoApi from '@/api/pay/demo'
 import { dateFormatter, formatDate } from '@/utils/formatTime'
 import { DICT_TYPE } from '@/utils/dict'
 
+const { t } = useI18n() // 国际化
 const router = useRouter() // 路由对象
 const message = useMessage() // 消息弹窗
 
-// 遮罩层
-const loading = ref(true)
-// 总条数
-const total = ref(0)
-// 示例订单列表
-const list = ref([])
-// 弹出层标题
-const title = ref('')
-// 是否显示弹出层
-const open = ref(false)
-// 查询参数
+const loading = ref(true) // 列表的加载中
+const total = ref(0) // 列表的总页数
+const list = ref([]) // 列表的数据
 const queryParams = ref({
   pageNo: 1,
   pageSize: 10
 })
 
-// 表单参数
-const form = ref({})
-// 表单校验
-const rules = {
-  spuId: [{ required: true, message: '商品编号不能为空', trigger: 'blur' }]
+const formRef = ref()
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await PayDemoApi.getDemoOrderPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
 }
 
+/** 支付按钮操作 */
+const handlePay = (row) => {
+  router.push({
+    name: 'PayCashier',
+    query: {
+      id: row.payOrderId,
+      returnUrl: encodeURIComponent('/pay/demo-order?id=' + row.id)
+    }
+  })
+}
+
+/** 退款按钮操作 */
+const handleRefund = async (row: any) => {
+  const id = row.id
+  try {
+    await message.confirm('是否确认退款编号为"' + id + '"的示例订单?')
+    await PayDemoApi.refundDemoOrder(id)
+    await getList()
+    message.success('发起退款成功!')
+  } catch {}
+}
+
+// ========== 弹窗 ==========
+
 // 商品数组
 const spus = ref([
   {
@@ -165,77 +188,45 @@ const spus = ref([
   }
 ])
 
-const formRef = ref()
-
-/** 查询列表 */
-const getList = () => {
-  loading.value = true
-  // 执行查询
-  getDemoOrderPage(queryParams.value).then((data) => {
-    list.value = data.list
-    total.value = data.total
-    loading.value = false
-  })
-}
-
-/** 取消按钮 */
-const cancel = () => {
-  open.value = false
-  reset()
+const dialogVisible = ref(false) // 弹窗的是否展示
+const formLoading = ref(false) // 表单的加载中
+const formData = ref({}) // 表单数据
+const formRules = {
+  spuId: [{ required: true, message: '商品编号不能为空', trigger: 'blur' }]
 }
 
 /** 表单重置 */
 const reset = () => {
-  form.value = {
+  formData.value = {
     spuId: undefined
   }
   formRef.value?.resetFields()
 }
 
 /** 新增按钮操作 */
-const handleAdd = () => {
+const openForm = () => {
   reset()
-  open.value = true
-  title.value = '发起订单'
+  dialogVisible.value = true
 }
 
 /** 提交按钮 */
 const submitForm = async () => {
-  const valid = await formRef.value?.validate()
-  if (!valid) {
-    return
-  }
-  // 添加的提交
-  createDemoOrder(form.value).then(() => {
-    message.success('新增成功')
-    open.value = false
-    getList()
-  })
-}
-
-/** 支付按钮操作 */
-const handlePay = (row) => {
-  router.push({
-    name: 'PayCashier',
-    query: {
-      id: row.payOrderId,
-      returnUrl: encodeURIComponent('/pay/demo-order?id=' + row.id)
-    }
-  })
-}
-
-/** 退款按钮操作 */
-const handleRefund = async (row: any) => {
-  const id = row.id
-
+  // 校验表单
+  if (!formRef) return
+  const valid = await formRef.value.validate()
+  if (!valid) return
+  // 提交请求
+  formLoading.value = true
   try {
-    await message.confirm('是否确认退款编号为"' + id + '"的示例订单?')
-    await refundDemoOrder(id)
-    getList()
-    message.success('发起退款成功!')
-  } catch {}
+    await PayDemoApi.createDemoOrder(formData.value)
+    message.success(t('common.createSuccess'))
+    dialogVisible.value = false
+  } finally {
+    formLoading.value = false
+  }
 }
 
+/** 初始化 **/
 onMounted(() => {
   getList()
 })

+ 0 - 153
src/views/pay/merchant/index.vue

@@ -1,153 +0,0 @@
-<template>
-  <ContentWrap>
-    <!-- 列表 -->
-    <XTable @register="registerTable">
-      <template #toolbar_buttons>
-        <!-- 操作:新增 -->
-        <XButton
-          type="primary"
-          preIcon="ep:zoom-in"
-          :title="t('action.add')"
-          v-hasPermi="['pay:merchant:create']"
-          @click="handleCreate()"
-        />
-        <!-- 操作:导出 -->
-        <XButton
-          type="warning"
-          preIcon="ep:download"
-          :title="t('action.export')"
-          v-hasPermi="['pay:merchant:export']"
-          @click="exportList('商户列表.xls')"
-        />
-      </template>
-      <template #actionbtns_default="{ row }">
-        <!-- 操作:修改 -->
-        <XTextButton
-          preIcon="ep:edit"
-          :title="t('action.edit')"
-          v-hasPermi="['pay:merchant:update']"
-          @click="handleUpdate(row.id)"
-        />
-        <!-- 操作:详情 -->
-        <XTextButton
-          preIcon="ep:view"
-          :title="t('action.detail')"
-          v-hasPermi="['pay:merchant:query']"
-          @click="handleDetail(row.id)"
-        />
-        <!-- 操作:删除 -->
-        <XTextButton
-          preIcon="ep:delete"
-          :title="t('action.del')"
-          v-hasPermi="['pay:merchant:delete']"
-          @click="deleteData(row.id)"
-        />
-      </template>
-    </XTable>
-  </ContentWrap>
-  <XModal v-model="dialogVisible" :title="dialogTitle">
-    <!-- 对话框(添加 / 修改) -->
-    <Form
-      v-if="['create', 'update'].includes(actionType)"
-      :schema="allSchemas.formSchema"
-      :rules="rules"
-      ref="formRef"
-    />
-    <!-- 对话框(详情) -->
-    <Descriptions
-      v-if="actionType === 'detail'"
-      :schema="allSchemas.detailSchema"
-      :data="detailData"
-    />
-    <!-- 操作按钮 -->
-    <template #footer>
-      <!-- 按钮:保存 -->
-      <XButton
-        v-if="['create', 'update'].includes(actionType)"
-        type="primary"
-        :title="t('action.save')"
-        :loading="actionLoading"
-        @click="submitForm()"
-      />
-      <!-- 按钮:关闭 -->
-      <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
-    </template>
-  </XModal>
-</template>
-<script setup lang="ts" name="PayMerchant">
-import type { FormExpose } from '@/components/Form'
-import { rules, allSchemas } from './merchant.data'
-import * as MerchantApi from '@/api/pay/merchant'
-
-const { t } = useI18n() // 国际化
-const message = useMessage() // 消息弹窗
-// 列表相关的变量
-const [registerTable, { reload, deleteData, exportList }] = useXTable({
-  allSchemas: allSchemas,
-  getListApi: MerchantApi.getMerchantPageApi,
-  deleteApi: MerchantApi.deleteMerchantApi,
-  exportListApi: MerchantApi.exportMerchantApi
-})
-
-// ========== 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 handleCreate = () => {
-  setDialogTile('create')
-}
-
-// 修改操作
-const handleUpdate = async (rowId: number) => {
-  setDialogTile('update')
-  // 设置数据
-  const res = await MerchantApi.getMerchantApi(rowId)
-  unref(formRef)?.setValues(res)
-}
-
-// 详情操作
-const handleDetail = async (rowId: number) => {
-  setDialogTile('detail')
-  const res = await MerchantApi.getMerchantApi(rowId)
-  detailData.value = res
-}
-
-// 提交按钮
-const submitForm = async () => {
-  const elForm = unref(formRef)?.getElFormRef()
-  if (!elForm) return
-  elForm.validate(async (valid) => {
-    if (valid) {
-      actionLoading.value = true
-      // 提交请求
-      try {
-        const data = unref(formRef)?.formModel as MerchantApi.MerchantVO
-        if (actionType.value === 'create') {
-          await MerchantApi.createMerchantApi(data)
-          message.success(t('common.createSuccess'))
-        } else {
-          await MerchantApi.updateMerchantApi(data)
-          message.success(t('common.updateSuccess'))
-        }
-        dialogVisible.value = false
-      } finally {
-        actionLoading.value = false
-        // 刷新列表
-        await reload()
-      }
-    }
-  })
-}
-</script>