@@ -271,16 +294,28 @@
订单信息
-
-
订单号
+
+ 支付宝订单号
{{
- selectedRechargeRecord?.order_id || '-'
+ selectedRechargeRecord?.alipay_order_id || '-'
}}
-
-
支付流水号
+
+ 微信订单号
{{
- selectedRechargeRecord?.payment_id || '-'
+ selectedRechargeRecord?.wechat_order_id || '-'
+ }}
+
+
+ 转账订单号
+ {{
+ selectedRechargeRecord?.transfer_order_id || '-'
+ }}
+
+
+ 支付平台
+ {{
+ selectedRechargeRecord?.platform || '-'
}}
@@ -402,7 +437,29 @@ const loadRechargeRecords = async () => {
const params = {
page: currentPage.value,
page_size: pageSize.value,
- ...filters,
+ }
+
+ // 只传递非空的筛选条件
+ if (filters.company_name) {
+ params.company_name = filters.company_name
+ }
+ if (filters.recharge_type) {
+ params.recharge_type = filters.recharge_type
+ }
+ if (filters.status) {
+ params.status = filters.status
+ }
+ if (filters.min_amount) {
+ params.min_amount = filters.min_amount
+ }
+ if (filters.max_amount) {
+ params.max_amount = filters.max_amount
+ }
+ if (filters.start_time) {
+ params.start_time = filters.start_time
+ }
+ if (filters.end_time) {
+ params.end_time = filters.end_time
}
// 单用户模式添加用户ID筛选
@@ -455,10 +512,10 @@ const getRechargeTypeTag = (type) => {
return 'primary'
case 'wechat':
return 'success'
- case 'bank':
+ case 'transfer':
return 'warning'
- case 'balance':
- return 'info'
+ case 'gift':
+ return 'success'
default:
return 'info'
}
@@ -469,6 +526,8 @@ const getRechargeTypeText = (type) => {
switch (type) {
case 'alipay':
return '支付宝充值'
+ case 'wechat':
+ return '微信充值'
case 'transfer':
return '对公转账'
case 'gift':
diff --git a/src/pages/finance/Wallet.vue b/src/pages/finance/Wallet.vue
index 0116251..599072c 100644
--- a/src/pages/finance/Wallet.vue
+++ b/src/pages/finance/Wallet.vue
@@ -102,6 +102,32 @@
+
+
+
+
+
+
@@ -290,6 +434,7 @@ import { useUserStore } from '@/stores/user'
import { Check } from '@element-plus/icons-vue'
import { CreditCardIcon, CurrencyYenIcon } from '@heroicons/vue/24/outline'
import { ElMessage, ElMessageBox } from 'element-plus'
+import QRCode from 'qrcode'
const userStore = useUserStore()
const userInfo = userStore.userInfo
@@ -307,7 +452,13 @@ const {
// 响应式数据
const selectedMethod = ref('alipay')
const alipayLoading = ref(false)
+const wechatLoading = ref(false)
const showBusinessConsultation = ref(false)
+const showQrCodeDialog = ref(false)
+const qrCodeCanvas = ref(null)
+const currentWechatOrderNo = ref(null)
+const isCheckingPayment = ref(false)
+let wechatOrderPollTimer = null
// 钱包信息
const walletInfo = ref({
@@ -337,6 +488,12 @@ const alipayForm = reactive({
amount: '',
})
+// 微信充值表单
+const wechatFormRef = ref()
+const wechatForm = reactive({
+ amount: '',
+})
+
// 预设金额选择
const selectedPresetAmount = ref(null)
@@ -371,6 +528,17 @@ const handleAmountInput = (value) => {
}
}
+// 处理微信金额输入变化
+const handleWechatAmountInput = (value) => {
+ const formatted = formatAmountInput(value || '')
+ wechatForm.amount = formatted
+
+ // 如果输入了自定义金额,更新选择状态
+ if (formatted && selectedPresetAmount.value !== 'custom') {
+ selectedPresetAmount.value = 'custom'
+ }
+}
+
const alipayRules = {
amount: [
{ required: true, message: '请输入充值金额', trigger: 'blur' },
@@ -410,6 +578,45 @@ const alipayRules = {
],
}
+const wechatRules = {
+ amount: [
+ { required: true, message: '请输入充值金额', trigger: 'blur' },
+ {
+ validator: (rule, value, callback) => {
+ if (!value) {
+ callback()
+ return
+ }
+
+ // 检查是否为有效数字格式
+ const amountRegex = /^\d+(\.\d{1,2})?$/
+ if (!amountRegex.test(value)) {
+ callback(new Error('请输入正确的金额格式,最多支持两位小数'))
+ return
+ }
+
+ // 检查金额范围
+ const amount = parseFloat(value)
+ const minAmount = parseFloat(rechargeConfig.value.min_amount)
+ const maxAmount = parseFloat(rechargeConfig.value.max_amount)
+
+ if (amount < minAmount) {
+ callback(new Error(`充值金额不能少于${minAmount}元`))
+ return
+ }
+
+ if (amount > maxAmount) {
+ callback(new Error(`单次充值金额不能超过${maxAmount}元`))
+ return
+ }
+
+ callback()
+ },
+ trigger: 'blur',
+ },
+ ],
+}
+
// 初始化
onMounted(() => {
loadWalletInfo()
@@ -450,7 +657,9 @@ const loadRechargeConfig = async () => {
if (rechargeConfig.value.alipay_recharge_bonus && rechargeConfig.value.alipay_recharge_bonus.length > 0) {
const firstBonus = rechargeConfig.value.alipay_recharge_bonus[0]
selectedPresetAmount.value = firstBonus.recharge_amount
- alipayForm.amount = firstBonus.recharge_amount.toString()
+ const amountStr = firstBonus.recharge_amount.toString()
+ alipayForm.amount = amountStr
+ wechatForm.amount = amountStr
}
}
} catch (error) {
@@ -513,13 +722,16 @@ const copyToClipboard = async (text) => {
// 选择预设金额
const selectPresetAmount = (amount) => {
selectedPresetAmount.value = amount
- alipayForm.amount = amount.toString()
+ const amountStr = amount.toString()
+ alipayForm.amount = amountStr
+ wechatForm.amount = amountStr
}
// 选择自定义金额
const selectCustomAmount = () => {
selectedPresetAmount.value = 'custom'
alipayForm.amount = '' // 清空金额输入框
+ wechatForm.amount = '' // 清空微信金额输入框
}
// 根据充值金额获取赠送金额
@@ -545,7 +757,9 @@ const getBonusAmount = (rechargeAmount) => {
// 获取当前预设金额的赠送金额
const getCurrentBonusAmount = () => {
if (selectedPresetAmount.value === 'custom') {
- return getBonusAmount(alipayForm.amount)
+ // 根据当前选择的充值方式获取金额
+ const currentAmount = selectedMethod.value === 'wechat' ? wechatForm.amount : alipayForm.amount
+ return getBonusAmount(currentAmount)
}
const bonus = rechargeConfig.value.alipay_recharge_bonus.find(
@@ -565,7 +779,9 @@ const getCustomBonusText = () => {
// 获取自定义金额的总到账金额
const getCustomTotalAmount = () => {
if (selectedPresetAmount.value === 'custom') {
- const amount = parseFloat(alipayForm.amount || 0)
+ // 根据当前选择的充值方式获取金额
+ const currentAmount = selectedMethod.value === 'wechat' ? wechatForm.amount : alipayForm.amount
+ const amount = parseFloat(currentAmount || 0)
const bonus = getBonusAmount(amount)
return formatPrice(amount + bonus)
}
@@ -628,6 +844,204 @@ const handleAlipayRecharge = async () => {
alipayLoading.value = false
}
}
+
+// 微信充值
+const handleWechatRecharge = async () => {
+ if (!wechatFormRef.value) return
+
+ try {
+ await wechatFormRef.value.validate()
+
+ // 显示确认框
+ await ElMessageBox.confirm(
+ `确认充值 ¥${wechatForm.amount} 到您的钱包吗?`,
+ '确认充值',
+ {
+ confirmButtonText: '确认充值',
+ cancelButtonText: '取消',
+ type: 'warning',
+ customClass: 'custom-message-box',
+ dangerouslyUseHTMLString: false
+ }
+ )
+
+ wechatLoading.value = true
+
+ // 调用后端创建微信充值订单
+ const response = await callProtectedAPI(financeApi.createWechatRecharge, {
+ amount: wechatForm.amount, // 直接传递字符串类型
+ subject: `钱包充值 ¥${wechatForm.amount}`,
+ platform: 'wx_h5', // PC/H5 场景,后端已兼容无 openid
+ })
+
+ if (!response) {
+ ElMessage.error('请先完成企业认证后再进行充值操作')
+ return
+ }
+
+ // 处理微信支付响应
+ // prepay_data 可能包含 code_url (扫码支付) 或 pay_url (H5支付)
+ if (response.data && response.data.prepay_data) {
+ const prepayData = response.data.prepay_data
+
+ // 扫码支付:显示二维码
+ if (prepayData.code_url) {
+ // 保存订单号用于轮询(从响应中获取订单号)
+ if (response.data.out_trade_no) {
+ currentWechatOrderNo.value = response.data.out_trade_no
+ await showQrCode(prepayData.code_url)
+ // 开始轮询订单状态
+ startWechatOrderPolling()
+ } else {
+ ElMessage.error('获取订单号失败,请重新支付')
+ }
+ }
+ // H5支付:跳转到支付页面
+ else if (prepayData.pay_url || response.data.pay_url) {
+ ElMessage.success('正在跳转到微信支付...')
+ window.location.href = prepayData.pay_url || response.data.pay_url
+ }
+ // 小程序或APP支付
+ else if (prepayData.prepay_id || response.data.prepay_id) {
+ ElMessage.success('请使用微信扫码支付')
+ // 这里可以根据实际返回的数据进行处理
+ } else {
+ console.warn('微信支付返回数据格式异常:', response.data)
+ ElMessage.warning('支付数据格式异常,请联系客服')
+ }
+ } else if (response.data && response.data.pay_url) {
+ // 兼容旧的返回格式(直接返回 pay_url)
+ ElMessage.success('正在跳转到微信支付...')
+ window.location.href = response.data.pay_url
+ } else {
+ console.warn('微信支付返回数据异常:', response.data)
+ ElMessage.warning('获取支付信息失败,请稍后重试')
+ }
+ } catch (error) {
+ // 如果是用户取消,不显示错误信息
+ if (error === 'cancel' || error === 'close') {
+ return
+ }
+
+ console.error('微信充值失败:', error)
+ if (canCallAPI.value) {
+ ElMessage.error('微信充值失败,请稍后重试')
+ }
+ } finally {
+ wechatLoading.value = false
+ }
+}
+
+// 显示二维码
+const showQrCode = async (codeUrl) => {
+ try {
+ showQrCodeDialog.value = true
+
+ // 等待DOM更新
+ await nextTick()
+
+ if (qrCodeCanvas.value) {
+ // 生成二维码
+ await QRCode.toCanvas(qrCodeCanvas.value, codeUrl, {
+ width: 256,
+ margin: 2,
+ color: {
+ dark: '#000000',
+ light: '#FFFFFF'
+ }
+ })
+ }
+ } catch (error) {
+ console.error('生成二维码失败:', error)
+ ElMessage.error('生成二维码失败,请稍后重试')
+ showQrCodeDialog.value = false
+ }
+}
+
+// 关闭二维码弹窗
+const closeQrCodeDialog = () => {
+ stopWechatOrderPolling()
+ showQrCodeDialog.value = false
+ currentWechatOrderNo.value = null
+ isCheckingPayment.value = false
+}
+
+// 开始轮询微信订单状态
+const startWechatOrderPolling = () => {
+ // 清除之前的定时器
+ stopWechatOrderPolling()
+
+ // 立即检查一次
+ checkWechatOrderStatus()
+
+ // 每3秒轮询一次
+ wechatOrderPollTimer = setInterval(() => {
+ checkWechatOrderStatus()
+ }, 3000)
+}
+
+// 停止轮询
+const stopWechatOrderPolling = () => {
+ if (wechatOrderPollTimer) {
+ clearInterval(wechatOrderPollTimer)
+ wechatOrderPollTimer = null
+ }
+}
+
+// 检查微信订单状态
+const checkWechatOrderStatus = async () => {
+ if (!currentWechatOrderNo.value) {
+ return
+ }
+
+ try {
+ isCheckingPayment.value = true
+ const response = await callProtectedAPI(financeApi.getWechatOrderStatus, {
+ out_trade_no: currentWechatOrderNo.value
+ })
+
+ if (!response || !response.data) {
+ isCheckingPayment.value = false
+ return
+ }
+
+ const orderStatus = response.data.status
+
+ // 订单状态:pending, success, failed, closed
+ if (orderStatus === 'success') {
+ // 支付成功
+ stopWechatOrderPolling()
+ isCheckingPayment.value = false
+ closeQrCodeDialog()
+ ElMessage.success('充值成功!')
+
+ // 刷新钱包余额
+ await loadWalletInfo()
+
+ // 重置表单
+ wechatForm.amount = ''
+ selectedPresetAmount.value = null
+ } else if (orderStatus === 'failed' || orderStatus === 'closed') {
+ // 支付失败或关闭
+ stopWechatOrderPolling()
+ isCheckingPayment.value = false
+ ElMessage.error('支付失败,请重新支付')
+ closeQrCodeDialog()
+ } else {
+ // pending 状态继续轮询
+ isCheckingPayment.value = false
+ }
+ } catch (error) {
+ console.error('查询微信订单状态失败:', error)
+ isCheckingPayment.value = false
+ // 不显示错误,继续轮询
+ }
+}
+
+// 组件卸载时清理定时器
+onBeforeUnmount(() => {
+ stopWechatOrderPolling()
+})
diff --git a/src/pages/finance/recharge-records/index.vue b/src/pages/finance/recharge-records/index.vue
index b6c8599..9200a36 100644
--- a/src/pages/finance/recharge-records/index.vue
+++ b/src/pages/finance/recharge-records/index.vue
@@ -14,6 +14,7 @@
class="w-full"
>
+
@@ -100,6 +101,10 @@
支付宝订单:
{{ row.alipay_order_id }}
+
+ 微信订单:
+ {{ row.wechat_order_id }}
+
转账订单:
{{ row.transfer_order_id }}
@@ -203,11 +208,19 @@ let searchTimer = null
const loadRecords = async () => {
loading.value = true
try {
+ // 构建参数,过滤掉空值
const params = {
page: currentPage.value,
- page_size: pageSize.value,
- ...filters
+ page_size: pageSize.value
}
+
+ // 只添加非空的筛选条件
+ Object.keys(filters).forEach(key => {
+ const value = filters[key]
+ if (value !== '' && value !== null && value !== undefined) {
+ params[key] = value
+ }
+ })
const response = await financeApi.getUserRechargeRecords(params)
records.value = response.data?.items || []
@@ -247,6 +260,7 @@ const formatTime = (date) => {
const getRechargeTypeTagType = (type) => {
const typeMap = {
alipay: 'primary',
+ wechat: 'success',
transfer: 'warning',
gift: 'success'
}
@@ -257,6 +271,7 @@ const getRechargeTypeTagType = (type) => {
const getRechargeTypeText = (type) => {
const typeMap = {
alipay: '支付宝充值',
+ wechat: '微信充值',
transfer: '对公转账',
gift: '赠送'
}
diff --git a/src/pages/products/detail.vue b/src/pages/products/detail.vue
index 67fe782..68a3808 100644
--- a/src/pages/products/detail.vue
+++ b/src/pages/products/detail.vue
@@ -3,15 +3,21 @@