From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目

---
 src/views/pay/cashier/index.vue |  494 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 494 insertions(+), 0 deletions(-)

diff --git a/src/views/pay/cashier/index.vue b/src/views/pay/cashier/index.vue
new file mode 100644
index 0000000..f07536f
--- /dev/null
+++ b/src/views/pay/cashier/index.vue
@@ -0,0 +1,494 @@
+<template>
+  <!-- 鏀粯淇℃伅 -->
+  <el-card v-loading="loading">
+    <el-descriptions title="鏀粯淇℃伅" :column="3" border>
+      <el-descriptions-item label="鏀粯鍗曞彿">{{ payOrder.id }}</el-descriptions-item>
+      <el-descriptions-item label="鍟嗗搧鏍囬">{{ payOrder.subject }}</el-descriptions-item>
+      <el-descriptions-item label="鍟嗗搧鍐呭">{{ payOrder.body }}</el-descriptions-item>
+      <el-descriptions-item label="鏀粯閲戦">
+        锟{ (payOrder.price / 100.0).toFixed(2) }}
+      </el-descriptions-item>
+      <el-descriptions-item label="鍒涘缓鏃堕棿">
+        {{ formatDate(payOrder.createTime) }}
+      </el-descriptions-item>
+      <el-descriptions-item label="杩囨湡鏃堕棿">
+        {{ formatDate(payOrder.expireTime) }}
+      </el-descriptions-item>
+    </el-descriptions>
+  </el-card>
+
+  <!-- 鏀粯閫夋嫨妗� -->
+  <el-card style="margin-top: 10px" v-loading="submitLoading" element-loading-text="鎻愪氦鏀粯涓�...">
+    <!-- 鏀粯瀹� -->
+    <el-descriptions title="閫夋嫨鏀粯瀹濇敮浠�" />
+    <div class="pay-channel-container">
+      <div
+        class="box"
+        v-for="channel in channelsAlipay"
+        :key="channel.code"
+        @click="submit(channel.code)"
+      >
+        <img :src="channel.icon" />
+        <div class="title">{{ channel.name }}</div>
+      </div>
+    </div>
+    <!-- 寰俊鏀粯 -->
+    <el-descriptions title="閫夋嫨寰俊鏀粯" style="margin-top: 20px" />
+    <div class="pay-channel-container">
+      <div
+        class="box"
+        v-for="channel in channelsWechat"
+        :key="channel.code"
+        @click="submit(channel.code)"
+      >
+        <img :src="channel.icon" />
+        <div class="title">{{ channel.name }}</div>
+      </div>
+    </div>
+    <!-- 鍏跺畠鏀粯 -->
+    <el-descriptions title="閫夋嫨鍏跺畠鏀粯" style="margin-top: 20px" />
+    <div class="pay-channel-container">
+      <div
+        class="box"
+        v-for="channel in channelsMock"
+        :key="channel.code"
+        @click="submit(channel.code)"
+      >
+        <img :src="channel.icon" />
+        <div class="title">{{ channel.name }}</div>
+      </div>
+    </div>
+  </el-card>
+
+  <!-- 灞曠ず褰㈠紡锛氫簩缁寸爜 URL -->
+  <Dialog
+    :title="qrCode.title"
+    v-model="qrCode.visible"
+    width="350px"
+    append-to-body
+    :close-on-press-escape="false"
+  >
+    <Qrcode :text="qrCode.url" :width="310" />
+  </Dialog>
+
+  <!-- 灞曠ず褰㈠紡锛欱arCode 鏉″舰鐮� -->
+  <Dialog
+    :title="barCode.title"
+    v-model="barCode.visible"
+    width="500px"
+    append-to-body
+    :close-on-press-escape="false"
+  >
+    <el-form ref="form" label-width="80px">
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="鏉″舰鐮�" prop="name">
+            <el-input v-model="barCode.value" placeholder="璇疯緭鍏ユ潯褰㈢爜" required />
+          </el-form-item>
+        </el-col>
+        <el-col :span="24">
+          <div style="text-align: right">
+            鎴栦娇鐢�
+            <el-link
+              type="danger"
+              target="_blank"
+              href="https://baike.baidu.com/item/鏉$爜鏀粯/10711903"
+            >
+              (鎵爜鏋�/鎵爜鐩�)
+            </el-link>
+            鎵爜
+          </div>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template #footer>
+      <el-button
+        type="primary"
+        @click="submit0(barCode.channelCode)"
+        :disabled="barCode.value.length === 0"
+      >
+        纭鏀粯
+      </el-button>
+      <el-button @click="barCode.visible = false">鍙� 娑�</el-button>
+    </template>
+  </Dialog>
+</template>
+
+<script lang="ts" setup>
+import { Qrcode } from '@/components/Qrcode'
+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'
+
+// 瀵煎叆鍥炬爣
+import svg_alipay_pc from '@/assets/svgs/pay/icon/alipay_pc.svg'
+import svg_alipay_wap from '@/assets/svgs/pay/icon/alipay_wap.svg'
+import svg_alipay_app from '@/assets/svgs/pay/icon/alipay_app.svg'
+import svg_alipay_qr from '@/assets/svgs/pay/icon/alipay_qr.svg'
+import svg_alipay_bar from '@/assets/svgs/pay/icon/alipay_bar.svg'
+import svg_wx_pub from '@/assets/svgs/pay/icon/wx_pub.svg'
+import svg_wx_lite from '@/assets/svgs/pay/icon/wx_lite.svg'
+import svg_wx_app from '@/assets/svgs/pay/icon/wx_app.svg'
+import svg_wx_native from '@/assets/svgs/pay/icon/wx_native.svg'
+import svg_wx_bar from '@/assets/svgs/pay/icon/wx_bar.svg'
+import svg_wallet from '@/assets/svgs/pay/icon/wallet.svg'
+import svg_mock from '@/assets/svgs/pay/icon/mock.svg'
+
+defineOptions({ name: 'PayCashier' })
+
+const message = useMessage() // 娑堟伅寮圭獥
+const route = useRoute() // 璺敱
+const { push, currentRoute } = useRouter() // 璺敱
+const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔
+
+const id = ref(undefined) // 鏀粯鍗曞彿
+const returnUrl = ref<string | undefined>(undefined) // 鏀粯瀹岀殑鍥炶皟鍦板潃
+const loading = ref(false) // 鏀粯淇℃伅鐨� loading
+const payOrder = ref({}) // 鏀粯淇℃伅
+const channelsAlipay = [
+  {
+    name: '鏀粯瀹� PC 缃戠珯鏀粯',
+    icon: svg_alipay_pc,
+    code: 'alipay_pc'
+  },
+  {
+    name: '鏀粯瀹� Wap 缃戠珯鏀粯',
+    icon: svg_alipay_wap,
+    code: 'alipay_wap'
+  },
+  {
+    name: '鏀粯瀹� App 缃戠珯鏀粯',
+    icon: svg_alipay_app,
+    code: 'alipay_app'
+  },
+  {
+    name: '鏀粯瀹濇壂鐮佹敮浠�',
+    icon: svg_alipay_qr,
+    code: 'alipay_qr'
+  },
+  {
+    name: '鏀粯瀹濇潯鐮佹敮浠�',
+    icon: svg_alipay_bar,
+    code: 'alipay_bar'
+  }
+]
+const channelsWechat = [
+  {
+    name: '寰俊鍏紬鍙锋敮浠�',
+    icon: svg_wx_pub,
+    code: 'wx_pub'
+  },
+  {
+    name: '寰俊灏忕▼搴忔敮浠�',
+    icon: svg_wx_lite,
+    code: 'wx_lite'
+  },
+  {
+    name: '寰俊 App 鏀粯',
+    icon: svg_wx_app,
+    code: 'wx_app'
+  },
+  {
+    name: '寰俊鎵爜鏀粯',
+    icon: svg_wx_native,
+    code: 'wx_native'
+  },
+  {
+    name: '寰俊鏉$爜鏀粯',
+    icon: svg_wx_bar,
+    code: 'wx_bar'
+  }
+]
+const channelsMock = [
+  {
+    name: '閽卞寘鏀粯',
+    icon: svg_wallet,
+    code: 'wallet'
+  },
+  {
+    name: '妯℃嫙鏀粯',
+    icon: svg_mock,
+    code: 'mock'
+  }
+]
+
+const submitLoading = ref(false) // 鎻愪氦鏀粯鐨� loading
+const interval = ref<any>(undefined) // 瀹氭椂浠诲姟锛岃疆璇㈡槸鍚﹀畬鎴愭敮浠�
+const qrCode = ref({
+  // 灞曠ず褰㈠紡锛氫簩缁寸爜
+  url: '',
+  title: '',
+  visible: false
+})
+const barCode = ref({
+  // 灞曠ず褰㈠紡锛氭潯褰㈢爜
+  channelCode: '',
+  value: '',
+  title: '',
+  visible: false
+})
+
+/** 鑾峰緱鏀粯淇℃伅 */
+const getDetail = async () => {
+  // 1.1 鏈紶閫掕鍗曠紪鍙�
+  if (!id.value) {
+    message.error('鏈紶閫掓敮浠樺崟鍙凤紝鏃犳硶鏌ョ湅瀵瑰簲鐨勬敮浠樹俊鎭�')
+    goReturnUrl('cancel')
+    return
+  }
+  const data = await PayOrderApi.getOrder(id.value, true)
+  // 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. 姝e父灞曠ず鏀粯淇℃伅
+  payOrder.value = data
+}
+
+/** 鎻愪氦鏀粯 */
+const submit = (channelCode) => {
+  // 鏉″舰鐮佹敮浠橈紝闇�瑕佺壒娈婂鐞�
+  if (channelCode === PayChannelEnum.ALIPAY_BAR.code) {
+    barCode.value = {
+      channelCode: channelCode,
+      value: '',
+      title: '鈥滄敮浠樺疂鈥濇潯鐮佹敮浠�',
+      visible: true
+    }
+    return
+  }
+  if (channelCode === PayChannelEnum.WX_BAR.code) {
+    barCode.value = {
+      channelCode: channelCode,
+      value: '',
+      title: '鈥滃井淇♀�濇潯鐮佹敮浠�',
+      visible: true
+    }
+    return
+  }
+
+  // 寰俊鍏紬鍙枫�佸皬绋嬪簭鏀粯锛屾棤娉曞湪 PC 缃戦〉涓繘琛�
+  if (channelCode === PayChannelEnum.WX_PUB.code) {
+    message.error('寰俊鍏紬鍙锋敮浠橈細涓嶆敮鎸� PC 缃戠珯')
+    return
+  }
+  if (channelCode === PayChannelEnum.WX_LITE.code) {
+    message.error('寰俊灏忕▼搴忥細涓嶆敮鎸� PC 缃戠珯')
+    return
+  }
+
+  // 榛樿鐨勬彁浜ゅ鐞�
+  submit0(channelCode)
+}
+
+const submit0 = async (channelCode) => {
+  submitLoading.value = true
+  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)
+    }
+
+    // 鎵撳紑杞浠诲姟
+    createQueryInterval()
+  } finally {
+    submitLoading.value = false
+  }
+}
+
+/** 鏋勫缓鎻愪氦鏀粯鐨勯澶栧弬鏁� */
+const buildSubmitParam = (channelCode) => {
+  // 鈶� 鏀粯瀹� BarCode 鏀粯鏃讹紝闇�瑕佷紶閫� authCode 鏉″舰鐮�
+  if (channelCode === PayChannelEnum.ALIPAY_BAR.code) {
+    return {
+      channelExtras: {
+        auth_code: barCode.value.value
+      }
+    }
+  }
+  // 鈶� 寰俊 BarCode 鏀粯鏃讹紝闇�瑕佷紶閫� authCode 鏉″舰鐮�
+  if (channelCode === PayChannelEnum.WX_BAR.code) {
+    return {
+      channelExtras: {
+        authCode: barCode.value.value
+      }
+    }
+  }
+  return {}
+}
+
+/** 鎻愪氦鏀粯鍚庯紝URL 鐨勫睍绀哄舰寮� */
+const displayUrl = (_channelCode, data) => {
+  location.href = data.displayContent
+  submitLoading.value = false
+}
+
+/** 鎻愪氦鏀粯鍚庯紙鎵爜鏀粯锛� */
+const displayQrCode = (channelCode, data) => {
+  let title = '璇蜂娇鐢ㄦ墜鏈烘祻瑙堝櫒鈥滄壂涓�鎵��'
+  if (channelCode === PayChannelEnum.ALIPAY_WAP.code) {
+    // 鑰冭檻鍒� WAP 娴嬭瘯锛屾墍浠ュ紩瀵兼墜鏈烘祻瑙堝櫒鎼�
+  } else if (channelCode.indexOf('alipay_') === 0) {
+    title = '璇蜂娇鐢ㄦ敮浠樺疂鈥滄壂涓�鎵�濇壂鐮佹敮浠�'
+  } else if (channelCode.indexOf('wx_') === 0) {
+    title = '璇蜂娇鐢ㄥ井淇♀�滄壂涓�鎵�濇壂鐮佹敮浠�'
+  }
+  qrCode.value = {
+    title: title,
+    url: data.displayContent,
+    visible: true
+  }
+  submitLoading.value = false
+}
+
+/** 鎻愪氦鏀粯鍚庯紙App锛� */
+const displayApp = (channelCode) => {
+  if (channelCode === PayChannelEnum.ALIPAY_APP.code) {
+    message.error('鏀粯瀹� App 鏀粯锛氭棤娉曞湪缃戦〉鏀粯锛�')
+  }
+  if (channelCode === PayChannelEnum.WX_APP.code) {
+    message.error('寰俊 App 鏀粯锛氭棤娉曞湪缃戦〉鏀粯锛�')
+  }
+  submitLoading.value = false
+}
+
+/** 杞鏌ヨ浠诲姟 */
+const createQueryInterval = () => {
+  if (interval.value) {
+    return
+  }
+  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)
+}
+
+/** 娓呯┖鏌ヨ浠诲姟 */
+const clearQueryInterval = () => {
+  // 娓呯┖鍚勭寮圭獥
+  qrCode.value = {
+    title: '',
+    url: '',
+    visible: false
+  }
+  // 娓呯┖浠诲姟
+  clearInterval(interval.value)
+  interval.value = undefined
+}
+
+/**
+ * 鍥炲埌涓氬姟鐨� URL
+ *
+ * @param payResult 鏀粯缁撴灉
+ *                  鈶� success锛氭敮浠樻垚鍔�
+ *                  鈶� cancel锛氬彇娑堟敮浠�
+ *                  鈶� close锛氭敮浠樺凡鍏抽棴
+ */
+const goReturnUrl = (payResult) => {
+  // 娓呯悊浠诲姟
+  clearQueryInterval()
+
+  // 鏈厤缃殑鎯呭喌涓嬶紝鍙兘鍏抽棴
+  if (!returnUrl.value) {
+    delView(unref(currentRoute))
+    return
+  }
+
+  const url =
+    returnUrl.value.indexOf('?') >= 0
+      ? returnUrl.value + '&payResult=' + payResult
+      : returnUrl.value + '?payResult=' + payResult
+  // 濡傛灉鏈夐厤缃紝涓旀槸 http 寮�澶达紝鍒欐祻瑙堝櫒璺宠浆
+  if (returnUrl.value.indexOf('http') === 0) {
+    location.href = url
+  } else {
+    delView(unref(currentRoute))
+    push({
+      path: url
+    })
+  }
+}
+
+/** 鍒濆鍖� */
+onMounted(() => {
+  id.value = route.query.id
+  if (route.query.returnUrl) {
+    returnUrl.value = decodeURIComponent(route.query.returnUrl)
+  }
+  getDetail()
+})
+
+/** 閿�姣� */
+onBeforeUnmount(() => {
+  clearQueryInterval()
+})
+</script>
+
+<style lang="scss" scoped>
+.pay-channel-container {
+  display: flex;
+  margin-top: -10px;
+
+  .box {
+    width: 160px;
+    padding-top: 10px;
+    padding-bottom: 5px;
+    margin-right: 10px;
+    text-align: center;
+    cursor: pointer;
+    border: 1px solid #e6ebf5;
+
+    img {
+      width: 40px;
+      height: 40px;
+    }
+
+    .title {
+      padding-top: 5px;
+    }
+  }
+}
+</style>

--
Gitblit v1.8.0