Files
AIGC/demo/frontend/src/views/OrderCreate.vue
2025-10-21 16:50:33 +08:00

382 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="order-create">
<el-page-header @back="$router.go(-1)" content="创建订单">
<template #extra>
<el-button type="primary" @click="handleSubmit" :loading="loading">
<el-icon><Check /></el-icon>
创建订单
</el-button>
</template>
</el-page-header>
<el-card class="form-card">
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="100px"
@submit.prevent="handleSubmit"
>
<el-form-item label="订单类型" prop="orderType">
<el-select v-model="form.orderType" placeholder="请选择订单类型">
<el-option label="AI服务" value="SERVICE" />
<el-option label="AI订阅" value="SUBSCRIPTION" />
<el-option label="数字商品" value="DIGITAL" />
<el-option label="虚拟商品" value="VIRTUAL" />
</el-select>
<div class="field-description">
<el-icon><InfoFilled /></el-icon>
<span>选择您要购买的虚拟商品类型AI服务如AI绘画AI写作AI订阅按月/年付费数字商品如软件电子书虚拟商品如游戏道具虚拟货币</span>
</div>
</el-form-item>
<el-form-item label="货币" prop="currency">
<el-select v-model="form.currency" placeholder="请选择货币">
<el-option label="人民币 (CNY)" value="CNY" />
<el-option label="美元 (USD)" value="USD" />
<el-option label="欧元 (EUR)" value="EUR" />
</el-select>
<div class="field-description">
<el-icon><InfoFilled /></el-icon>
<span>选择支付货币类型系统会根据您选择的货币进行计费和结算</span>
</div>
</el-form-item>
<el-form-item label="订单描述" prop="description">
<el-input
v-model="form.description"
type="textarea"
:rows="3"
placeholder="请详细描述您的订单需求需要AI绘画服务风格为动漫风格尺寸为1024x1024像素"
/>
<div class="field-description">
<el-icon><InfoFilled /></el-icon>
<span>详细描述您的订单需求包括服务要求特殊需求等这将帮助服务提供方更好地理解您的需求</span>
</div>
</el-form-item>
<el-form-item label="联系邮箱" prop="contactEmail">
<el-input
v-model="form.contactEmail"
type="email"
placeholder="请输入联系邮箱(用于接收虚拟商品)"
/>
<div class="field-description">
<el-icon><InfoFilled /></el-icon>
<span>必填项虚拟商品将通过此邮箱发送给您请确保邮箱地址正确且可正常接收邮件</span>
</div>
</el-form-item>
<el-form-item label="联系电话" prop="contactPhone">
<el-input
v-model="form.contactPhone"
placeholder="请输入联系电话(可选)"
/>
<div class="field-description">
<el-icon><InfoFilled /></el-icon>
<span>可选填写用于紧急情况联系或重要通知建议填写以便服务提供方在需要时联系您</span>
</div>
</el-form-item>
<!-- 虚拟商品不需要收货地址 -->
<template v-if="isPhysicalOrder">
<el-form-item label="收货地址" prop="shippingAddress">
<el-input
v-model="form.shippingAddress"
type="textarea"
:rows="3"
placeholder="请输入收货地址"
/>
</el-form-item>
<el-form-item label="账单地址" prop="billingAddress">
<el-input
v-model="form.billingAddress"
type="textarea"
:rows="3"
placeholder="请输入账单地址"
/>
</el-form-item>
</template>
<!-- 订单项 -->
<el-form-item label="虚拟商品">
<div class="field-description">
<el-icon><InfoFilled /></el-icon>
<span>添加您要购买的虚拟商品包括商品名称单价和数量支持添加多个商品</span>
</div>
<div class="order-items">
<div
v-for="(item, index) in form.orderItems"
:key="index"
class="order-item"
>
<el-row :gutter="20">
<el-col :span="8">
<el-input
v-model="item.productName"
placeholder="商品名称AI绘画服务、AI写作助手、AI翻译服务等"
@input="calculateSubtotal(index)"
/>
</el-col>
<el-col :span="4">
<el-input-number
v-model="item.unitPrice"
:precision="2"
:min="0"
placeholder="单价"
@change="calculateSubtotal(index)"
/>
</el-col>
<el-col :span="4">
<el-input-number
v-model="item.quantity"
:min="1"
placeholder="数量"
@change="calculateSubtotal(index)"
/>
</el-col>
<el-col :span="4">
<el-input
v-model="item.subtotal"
readonly
placeholder="小计"
/>
</el-col>
<el-col :span="4">
<el-button
type="danger"
:icon="Delete"
circle
@click="removeItem(index)"
v-if="form.orderItems.length > 1"
/>
</el-col>
</el-row>
</div>
<el-button
type="primary"
:icon="Plus"
@click="addItem"
class="add-item-btn"
>
添加虚拟商品
</el-button>
</div>
</el-form-item>
<el-form-item>
<div class="total-amount">
<span class="total-label">订单总计</span>
<span class="total-value">{{ form.currency }} {{ totalAmount }}</span>
</div>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script setup>
import { ref, reactive, computed } from 'vue'
import { useRouter } from 'vue-router'
import { useOrderStore } from '@/stores/orders'
import { ElMessage } from 'element-plus'
import { Plus, Delete, Check, InfoFilled } from '@element-plus/icons-vue'
const router = useRouter()
const orderStore = useOrderStore()
const formRef = ref()
const loading = ref(false)
const form = reactive({
orderType: 'SERVICE',
currency: 'CNY',
description: '',
contactEmail: '',
contactPhone: '',
shippingAddress: '',
billingAddress: '',
orderItems: [
{
productName: '',
unitPrice: 0,
quantity: 1,
subtotal: 0
}
]
})
const rules = {
orderType: [
{ required: true, message: '请选择订单类型', trigger: 'change' }
],
currency: [
{ required: true, message: '请选择货币', trigger: 'change' }
],
contactEmail: [
{ required: true, message: '请输入联系邮箱', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
]
}
// 检查是否为实体商品订单
const isPhysicalOrder = computed(() => {
return form.orderType === 'PHYSICAL'
})
// 计算总金额
const totalAmount = computed(() => {
return form.orderItems.reduce((total, item) => {
return total + parseFloat(item.subtotal || 0)
}, 0).toFixed(2)
})
// 计算小计
const calculateSubtotal = (index) => {
const item = form.orderItems[index]
if (item.unitPrice && item.quantity) {
item.subtotal = parseFloat((item.unitPrice * item.quantity).toFixed(2))
} else {
item.subtotal = 0
}
}
// 添加商品项
const addItem = () => {
form.orderItems.push({
productName: '',
unitPrice: 0,
quantity: 1,
subtotal: 0
})
}
// 删除商品项
const removeItem = (index) => {
if (form.orderItems.length > 1) {
form.orderItems.splice(index, 1)
}
}
// 提交表单
const handleSubmit = async () => {
if (!formRef.value) return
try {
const valid = await formRef.value.validate()
if (!valid) return
// 验证订单项
const validItems = form.orderItems.filter(item =>
item.productName && item.unitPrice > 0 && item.quantity > 0
)
if (validItems.length === 0) {
ElMessage.error('请至少添加一个有效虚拟商品')
return
}
loading.value = true
// 准备提交数据
const orderData = {
orderType: form.orderType,
currency: form.currency,
description: form.description,
contactEmail: form.contactEmail,
contactPhone: form.contactPhone,
shippingAddress: form.shippingAddress,
billingAddress: form.billingAddress,
totalAmount: parseFloat(totalAmount.value),
status: 'PENDING', // 新创建的订单状态为待支付
orderItems: validItems.map(item => ({
productName: item.productName,
unitPrice: parseFloat(item.unitPrice),
quantity: parseInt(item.quantity),
subtotal: parseFloat(item.subtotal)
}))
}
const response = await orderStore.createNewOrder(orderData)
if (response.success) {
ElMessage.success('虚拟商品订单创建成功!商品将发送到您的邮箱')
router.push('/orders')
} else {
ElMessage.error(response.message || '创建订单失败')
}
} catch (error) {
console.error('Create order error:', error)
ElMessage.error('创建订单失败')
} finally {
loading.value = false
}
}
</script>
<style scoped>
.order-create {
max-width: 1200px;
margin: 0 auto;
}
.form-card {
margin-top: 20px;
}
.order-items {
width: 100%;
}
.order-item {
margin-bottom: 16px;
padding: 16px;
border: 1px solid #e4e7ed;
border-radius: 8px;
background-color: #fafafa;
}
.add-item-btn {
margin-top: 16px;
}
.total-amount {
text-align: right;
padding: 16px;
background-color: #f5f7fa;
border-radius: 8px;
}
.total-label {
font-size: 16px;
color: #606266;
}
.field-description {
display: flex;
align-items: flex-start;
margin-top: 8px;
padding: 8px 12px;
background-color: #f0f9ff;
border: 1px solid #b3d8ff;
border-radius: 6px;
font-size: 13px;
color: #409eff;
line-height: 1.4;
}
.field-description .el-icon {
margin-right: 6px;
margin-top: 1px;
flex-shrink: 0;
}
.field-description span {
flex: 1;
}
</style>