238 lines
6.9 KiB
Vue
238 lines
6.9 KiB
Vue
<template>
|
|
<ElDialog v-model="visible" title="套餐充值" width="600px" @closed="handleDialogClosed">
|
|
<ElForm ref="formRef" :model="form" :rules="rules" label-width="120px">
|
|
<ElFormItem label="资产信息">
|
|
<span style="font-weight: bold; color: #409eff">
|
|
{{ assetIdentifier }}
|
|
</span>
|
|
</ElFormItem>
|
|
<ElFormItem label="选择套餐" prop="package_id">
|
|
<ElSelect
|
|
v-model="form.package_id"
|
|
placeholder="请选择套餐"
|
|
filterable
|
|
remote
|
|
reserve-keyword
|
|
:remote-method="handlePackageSearch"
|
|
:loading="packageSearchLoading"
|
|
clearable
|
|
style="width: 100%"
|
|
>
|
|
<ElOption
|
|
v-for="pkg in packageOptions"
|
|
:key="pkg.id"
|
|
:label="`${pkg.package_name} (¥${((pkg.cost_price || 0) / 100).toFixed(2)})`"
|
|
:value="pkg.id"
|
|
>
|
|
<div style="display: flex; justify-content: space-between">
|
|
<span>{{ pkg.package_name }}</span>
|
|
<span style="font-size: 12px; color: var(--el-text-color-secondary)">
|
|
¥{{ ((pkg.cost_price || 0) / 100).toFixed(2) }}
|
|
</span>
|
|
</div>
|
|
</ElOption>
|
|
</ElSelect>
|
|
</ElFormItem>
|
|
<ElFormItem label="支付方式" prop="payment_method">
|
|
<ElSelect v-model="form.payment_method" placeholder="请选择支付方式" style="width: 100%">
|
|
<ElOption label="钱包支付" value="wallet" />
|
|
<ElOption v-if="showOfflinePayment" label="线下支付" value="offline" />
|
|
</ElSelect>
|
|
<div style="margin-top: 8px; font-size: 12px; color: var(--el-text-color-secondary)">
|
|
<template v-if="form.payment_method === 'wallet'">
|
|
提示: 使用钱包支付时,订单将直接完成
|
|
</template>
|
|
<template v-else-if="form.payment_method === 'offline'">
|
|
提示: 线下支付订单需要手动确认支付
|
|
</template>
|
|
</div>
|
|
</ElFormItem>
|
|
</ElForm>
|
|
<template #footer>
|
|
<div class="dialog-footer">
|
|
<ElButton @click="handleCancel">取消</ElButton>
|
|
<ElButton type="primary" @click="handleConfirm" :loading="loading"> 确认充值 </ElButton>
|
|
</div>
|
|
</template>
|
|
</ElDialog>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, reactive, computed, watch } from 'vue'
|
|
import {
|
|
ElDialog,
|
|
ElForm,
|
|
ElFormItem,
|
|
ElSelect,
|
|
ElOption,
|
|
ElButton,
|
|
ElMessage
|
|
} from 'element-plus'
|
|
import type { FormInstance, FormRules } from 'element-plus'
|
|
import { OrderService, PackageManageService } from '@/api/modules'
|
|
import type { CreateOrderRequest, PackageResponse } from '@/types/api'
|
|
import { useUserStore } from '@/store/modules/user'
|
|
|
|
interface Props {
|
|
modelValue: boolean
|
|
assetIdentifier: string
|
|
assetType: 'card' | 'device'
|
|
seriesId?: number
|
|
}
|
|
|
|
interface Emits {
|
|
(e: 'update:modelValue', value: boolean): void
|
|
(e: 'confirm'): void
|
|
(e: 'success'): void
|
|
}
|
|
|
|
const props = defineProps<Props>()
|
|
const emit = defineEmits<Emits>()
|
|
|
|
const userStore = useUserStore()
|
|
const formRef = ref<FormInstance>()
|
|
const loading = ref(false)
|
|
const packageSearchLoading = ref(false)
|
|
const packageOptions = ref<PackageResponse[]>([])
|
|
|
|
const form = reactive({
|
|
package_id: undefined as number | undefined,
|
|
payment_method: 'wallet' as 'wallet' | 'offline'
|
|
})
|
|
|
|
const rules: FormRules = {
|
|
package_id: [{ required: true, message: '请选择套餐', trigger: 'change' }],
|
|
payment_method: [{ required: true, message: '请选择支付方式', trigger: 'change' }]
|
|
}
|
|
|
|
const visible = computed({
|
|
get: () => props.modelValue,
|
|
set: (value) => emit('update:modelValue', value)
|
|
})
|
|
|
|
// 只有平台用户(user_type 1:超级管理员, 2:平台用户)才显示线下支付选项
|
|
const showOfflinePayment = computed(() => {
|
|
return userStore.info.user_type === 1 || userStore.info.user_type === 2
|
|
})
|
|
|
|
// 监听对话框打开,加载套餐列表
|
|
watch(visible, async (newVal) => {
|
|
if (newVal) {
|
|
await loadPackages()
|
|
}
|
|
})
|
|
|
|
const loadPackages = async () => {
|
|
if (!props.seriesId) return
|
|
|
|
try {
|
|
packageSearchLoading.value = true
|
|
|
|
const response = await PackageManageService.getPackages({
|
|
series_id: props.seriesId,
|
|
page: 1,
|
|
page_size: 20,
|
|
status: 1, // 只获取启用的套餐
|
|
shelf_status: 1 // 只获取已上架的套餐
|
|
})
|
|
|
|
if (response.code === 0 && response.data) {
|
|
packageOptions.value = response.data.items || []
|
|
}
|
|
} catch (error: any) {
|
|
console.error('加载套餐列表失败:', error)
|
|
ElMessage.error(error?.message || '加载套餐列表失败')
|
|
} finally {
|
|
packageSearchLoading.value = false
|
|
}
|
|
}
|
|
|
|
const handlePackageSearch = async (query: string) => {
|
|
if (!props.seriesId) return
|
|
|
|
try {
|
|
packageSearchLoading.value = true
|
|
|
|
const response = await PackageManageService.getPackages({
|
|
package_name: query || undefined,
|
|
series_id: props.seriesId,
|
|
page: 1,
|
|
page_size: 20,
|
|
status: 1,
|
|
shelf_status: 1
|
|
})
|
|
|
|
if (response.code === 0 && response.data) {
|
|
packageOptions.value = response.data.items || []
|
|
}
|
|
} catch (error: any) {
|
|
console.error('搜索套餐失败:', error)
|
|
} finally {
|
|
packageSearchLoading.value = false
|
|
}
|
|
}
|
|
|
|
const handleCancel = () => {
|
|
visible.value = false
|
|
}
|
|
|
|
const handleConfirm = async () => {
|
|
if (!formRef.value) return
|
|
|
|
try {
|
|
await formRef.value.validate()
|
|
|
|
if (!form.package_id) {
|
|
ElMessage.error('请选择套餐')
|
|
return
|
|
}
|
|
|
|
loading.value = true
|
|
|
|
// 创建订单(后端接收数组,前端单选转为单元素数组)
|
|
const data: CreateOrderRequest = {
|
|
identifier: props.assetIdentifier,
|
|
package_ids: [form.package_id],
|
|
payment_method: form.payment_method
|
|
}
|
|
|
|
await OrderService.createOrder(data)
|
|
|
|
// 根据支付方式显示不同的成功消息
|
|
if (form.payment_method === 'wallet') {
|
|
ElMessage.success('订单创建成功,已自动完成支付')
|
|
} else {
|
|
ElMessage.success('订单创建成功')
|
|
}
|
|
|
|
visible.value = false
|
|
emit('confirm')
|
|
emit('success')
|
|
} catch (error: any) {
|
|
// 用户取消确认对话框
|
|
if (error === 'cancel') {
|
|
return
|
|
}
|
|
console.error('创建订单失败:', error)
|
|
ElMessage.error(error?.message || '创建订单失败')
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
const handleDialogClosed = () => {
|
|
formRef.value?.resetFields()
|
|
form.package_id = undefined
|
|
form.payment_method = 'wallet'
|
|
packageOptions.value = []
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.dialog-footer {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 12px;
|
|
}
|
|
</style>
|