You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1073 lines
27 KiB
1073 lines
27 KiB
<!--订单列表组件 - 独立业务组件-->
|
|
<template>
|
|
<view class="order-list-card">
|
|
<!-- 加载状态 -->
|
|
<view v-if="loading" class="loading-state">
|
|
<text class="loading-icon">⏳</text>
|
|
<text class="loading-text">加载中...</text>
|
|
</view>
|
|
|
|
<!-- 订单内容 -->
|
|
<view v-else>
|
|
<!-- 操作按钮区域 -->
|
|
<view class="action-header" v-if="showAddButton && orderList.length > 0">
|
|
<view class="add-order-btn" @click.stop="openAddOrder">
|
|
<text class="add-icon">+</text>
|
|
<text class="add-text">新增订单</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 订单列表 -->
|
|
<scroll-view
|
|
class="order-list"
|
|
v-if="orderList.length > 0"
|
|
scroll-y="true"
|
|
:enhanced="true"
|
|
:style="{height: maxHeight}"
|
|
>
|
|
<view
|
|
class="order-item"
|
|
v-for="order in orderList"
|
|
:key="order.id"
|
|
:class="{ 'pending-payment': order.status === 'pending' }"
|
|
@click.stop="handleOrderClick(order)"
|
|
>
|
|
<view class="order-header">
|
|
<view class="order-info">
|
|
<view class="order-no">订单号:{{ order.order_no }}</view>
|
|
<view class="order-time" v-if="order.create_time">
|
|
{{ formatTime(order.create_time) }}
|
|
</view>
|
|
</view>
|
|
<view :class="['order-status', getStatusClass(order.status)]">
|
|
{{ getStatusText(order.status) }}
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 订单内容 -->
|
|
<view class="order-content">
|
|
<view class="product-info" v-if="order.product_name">
|
|
<view class="product-name">{{ order.product_name }}</view>
|
|
<view class="product-specs" v-if="order.product_specs">
|
|
{{ order.product_specs }}
|
|
</view>
|
|
</view>
|
|
|
|
<view class="order-details">
|
|
<!-- 价格信息 -->
|
|
<view class="detail-row">
|
|
<text class="detail-label">订单金额:</text>
|
|
<text class="detail-value price">¥{{ order.total_amount }}</text>
|
|
</view>
|
|
|
|
<view class="detail-row">
|
|
<text class="detail-label">已付金额:</text>
|
|
<text class="detail-value paid">¥{{ order.paid_amount }}</text>
|
|
</view>
|
|
|
|
<view class="detail-row">
|
|
<text class="detail-label">未付金额:</text>
|
|
<text class="detail-value unpaid">¥{{ order.unpaid_amount }}</text>
|
|
</view>
|
|
|
|
<!-- 其他信息 -->
|
|
<view class="detail-row" v-if="order.payment_method">
|
|
<text class="detail-label">支付方式:</text>
|
|
<text class="detail-value">{{ order.payment_method }}</text>
|
|
</view>
|
|
|
|
<view class="detail-row" v-if="order.salesperson_name">
|
|
<text class="detail-label">销售顾问:</text>
|
|
<text class="detail-value">{{ order.salesperson_name }}</text>
|
|
</view>
|
|
|
|
<view class="detail-row" v-if="order.course_count">
|
|
<text class="detail-label">课时数量:</text>
|
|
<text class="detail-value">{{ order.course_count }}节</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 备注信息 -->
|
|
<view class="order-remark" v-if="order.remark">
|
|
<view class="remark-label">备注:</view>
|
|
<view class="remark-content">{{ order.remark }}</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
|
|
<!-- 空状态 -->
|
|
<view class="empty-state" v-else>
|
|
<view class="empty-icon">📋</view>
|
|
<view class="empty-text">暂无订单记录</view>
|
|
<view class="empty-tip">客户还未产生任何订单</view>
|
|
<view class="empty-add-btn" v-if="showAddButton" @click.stop="openAddOrder">
|
|
<text>新增订单</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 新增订单弹窗 -->
|
|
<uni-popup ref="orderFormPopup" type="bottom">
|
|
<OrderFormPopup
|
|
:visible="showOrderForm"
|
|
:student-info="studentInfo"
|
|
:resource-id="resourceId"
|
|
@cancel="closeOrderForm"
|
|
@confirm="handleOrderCreated"
|
|
/>
|
|
</uni-popup>
|
|
|
|
<!-- 二维码支付弹窗 -->
|
|
<uni-popup ref="qrCodePopup" type="center" @close="closeQRCodeModal">
|
|
<QRCodePaymentDialog
|
|
v-if="qrCodePaymentData"
|
|
:payment-data="qrCodePaymentData"
|
|
@close="closeQRCodeModal"
|
|
@confirm="confirmQRCodePayment"
|
|
/>
|
|
</uni-popup>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import apiRoute from '@/api/apiRoute.js'
|
|
import dictUtilSimple from '@/common/dictUtilSimple.js'
|
|
import OrderFormPopup from '@/components/order-form-popup/index.vue'
|
|
import QRCodePaymentDialog from './qrcode-payment-dialog.vue'
|
|
|
|
export default {
|
|
name: 'OrderListCard',
|
|
components: {
|
|
OrderFormPopup,
|
|
QRCodePaymentDialog
|
|
},
|
|
|
|
props: {
|
|
// 学员ID
|
|
studentId: {
|
|
type: [Number, String],
|
|
default: null
|
|
},
|
|
// 资源ID
|
|
resourceId: {
|
|
type: [Number, String],
|
|
default: null
|
|
},
|
|
// 是否自动加载数据
|
|
autoLoad: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
// 是否显示新增按钮
|
|
showAddButton: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
// 列表最大高度
|
|
maxHeight: {
|
|
type: String,
|
|
default: '70vh'
|
|
}
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
// 订单数据
|
|
orderList: [],
|
|
loading: false,
|
|
|
|
// 弹窗状态
|
|
showOrderForm: false,
|
|
showQRCodeModal: false,
|
|
|
|
// 当前操作的订单
|
|
currentOrder: null,
|
|
|
|
// 二维码支付数据
|
|
qrCodePaymentData: null,
|
|
|
|
// 字典数据
|
|
paymentTypeDict: [],
|
|
|
|
// 学生信息对象(用于传递给订单表单组件)
|
|
studentInfo: {}
|
|
}
|
|
},
|
|
|
|
mounted() {
|
|
// 加载字典数据
|
|
this.loadDictData()
|
|
|
|
// 构建学生信息对象
|
|
if (this.studentId) {
|
|
this.buildStudentInfo()
|
|
}
|
|
|
|
// 自动加载订单列表
|
|
if (this.autoLoad && (this.studentId || this.resourceId)) {
|
|
this.loadOrderList()
|
|
}
|
|
},
|
|
|
|
watch: {
|
|
// 监听学员ID变化,自动刷新
|
|
studentId(newVal) {
|
|
if (newVal && this.autoLoad) {
|
|
this.loadOrderList()
|
|
this.buildStudentInfo()
|
|
}
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
/**
|
|
* 构建学生信息对象
|
|
* 通过员工端API获取学生详情包含 campus_id
|
|
*/
|
|
async buildStudentInfo() {
|
|
if (!this.studentId) {
|
|
this.studentInfo = {}
|
|
return
|
|
}
|
|
|
|
try {
|
|
// 使用员工端学生信息接口
|
|
const res = await apiRoute.getStudentBasicInfo({ student_id: this.studentId })
|
|
|
|
if (res.code === 1 && res.data) {
|
|
this.studentInfo = {
|
|
id: res.data.id,
|
|
name: res.data.name,
|
|
campus_id: res.data.campus_id,
|
|
gender: res.data.gender,
|
|
gender_text: res.data.gender_text,
|
|
birthday: res.data.birthday,
|
|
headimg: res.data.headimg,
|
|
emergency_contact: res.data.emergency_contact,
|
|
contact_phone: res.data.contact_phone
|
|
}
|
|
console.log('学生信息加载成功:', this.studentInfo)
|
|
} else {
|
|
console.error('获取学生信息失败:', res.msg)
|
|
// 降级方案: 使用基本信息
|
|
this.studentInfo = {
|
|
id: this.studentId,
|
|
name: '学员',
|
|
campus_id: null
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('获取学生信息异常:', error)
|
|
// 降级方案
|
|
this.studentInfo = {
|
|
id: this.studentId,
|
|
name: '学员',
|
|
campus_id: null
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 加载字典数据
|
|
*/
|
|
async loadDictData() {
|
|
try {
|
|
const dictResult = await dictUtilSimple.getBatchDict(['payment_type'])
|
|
|
|
if (dictResult.payment_type && Array.isArray(dictResult.payment_type)) {
|
|
this.paymentTypeDict = dictResult.payment_type
|
|
} else {
|
|
// 使用备用数据
|
|
this.paymentTypeDict = [
|
|
{ name: '现金支付', value: 'cash' },
|
|
{ name: '扫码支付', value: 'scan_code' },
|
|
{ name: '订阅支付', value: 'subscription' },
|
|
{ name: '微信在线代付', value: 'wxpay_online' },
|
|
{ name: '客户自行付款', value: 'client_wxpay' },
|
|
{ name: '定金', value: 'deposit' }
|
|
]
|
|
}
|
|
} catch (error) {
|
|
console.error('加载支付方式字典失败:', error)
|
|
// 使用备用数据
|
|
this.paymentTypeDict = [
|
|
{ name: '现金支付', value: 'cash' },
|
|
{ name: '扫码支付', value: 'scan_code' },
|
|
{ name: '订阅支付', value: 'subscription' },
|
|
{ name: '微信在线代付', value: 'wxpay_online' },
|
|
{ name: '客户自行付款', value: 'client_wxpay' },
|
|
{ name: '定金', value: 'deposit' }
|
|
]
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 加载订单列表
|
|
*/
|
|
async loadOrderList() {
|
|
if (!this.studentId && !this.resourceId) {
|
|
console.warn('OrderListCard: 缺少必要参数 studentId 或 resourceId')
|
|
return
|
|
}
|
|
|
|
this.loading = true
|
|
try {
|
|
const params = {}
|
|
if (this.studentId) {
|
|
params.student_id = this.studentId
|
|
} else if (this.resourceId) {
|
|
params.resource_id = this.resourceId
|
|
}
|
|
|
|
const res = await apiRoute.xs_orderTableList(params)
|
|
|
|
if (res.code === 1) {
|
|
this.orderList = this.processOrderData(res.data?.data || [])
|
|
this.$emit('loaded', this.orderList)
|
|
} else {
|
|
console.error('获取订单列表失败:', res.msg)
|
|
this.orderList = []
|
|
this.$emit('error', { type: 'load', message: res.msg })
|
|
}
|
|
} catch (error) {
|
|
console.error('获取订单列表异常:', error)
|
|
uni.showToast({ title: '加载失败', icon: 'none' })
|
|
this.$emit('error', { type: 'load', error })
|
|
} finally {
|
|
this.loading = false
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 处理订单数据格式
|
|
*/
|
|
processOrderData(orders) {
|
|
if (!Array.isArray(orders)) return []
|
|
|
|
return orders.map(order => ({
|
|
id: order.id,
|
|
student_id: order.student_id,
|
|
order_no: order.payment_id || `ORD${order.id}`,
|
|
product_name: order.course_id_name || '课程',
|
|
total_amount: order.order_amount || '0.00',
|
|
paid_amount: order.order_status === 'paid' ? order.order_amount : '0.00',
|
|
unpaid_amount: order.order_status === 'paid' ? '0.00' : order.order_amount,
|
|
payment_method: this.formatPaymentType(order.payment_type),
|
|
salesperson_name: order.staff_id_name || '未指定',
|
|
course_count: order.total_hours || 0,
|
|
status: this.mapOrderStatus(order.order_status),
|
|
create_time: order.created_at,
|
|
contract_id: order.contract_id,
|
|
contract_sign_id: order.contract_sign_id,
|
|
remark: order.remark || '',
|
|
_raw: order
|
|
}))
|
|
},
|
|
|
|
/**
|
|
* 格式化支付类型
|
|
*/
|
|
formatPaymentType(paymentType) {
|
|
if (!paymentType) return '未知'
|
|
|
|
const paymentItem = this.paymentTypeDict.find(item => item.value === paymentType)
|
|
if (paymentItem) return paymentItem.name
|
|
|
|
const fallbackMap = {
|
|
'cash': '现金支付',
|
|
'scan_code': '扫码支付',
|
|
'subscription': '订阅支付',
|
|
'wxpay_online': '微信在线代付',
|
|
'client_wxpay': '客户自行付款',
|
|
'deposit': '定金'
|
|
}
|
|
return fallbackMap[paymentType] || paymentType || '未知'
|
|
},
|
|
|
|
/**
|
|
* 映射订单状态
|
|
*/
|
|
mapOrderStatus(orderStatus) {
|
|
const statusMap = {
|
|
'pending': 'pending',
|
|
'paid': 'paid',
|
|
'signed': 'completed',
|
|
'completed': 'completed',
|
|
'transfer': 'partial'
|
|
}
|
|
return statusMap[orderStatus] || 'pending'
|
|
},
|
|
|
|
/**
|
|
* 订单点击处理
|
|
*/
|
|
handleOrderClick(order) {
|
|
this.currentOrder = order
|
|
|
|
if (order.status === 'pending') {
|
|
// 待支付订单,触发支付
|
|
this.handleOrderPay(order)
|
|
} else {
|
|
// 已支付订单,查看详情
|
|
this.viewOrderDetail(order)
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 处理订单支付
|
|
*/
|
|
handleOrderPay(order) {
|
|
const paymentType = order._raw?.payment_type
|
|
|
|
switch(paymentType) {
|
|
case 'cash':
|
|
this.processCashPayment(order)
|
|
break
|
|
case 'scan_code':
|
|
this.processQRCodePayment(order)
|
|
break
|
|
case 'subscription':
|
|
this.processSubscriptionPayment(order)
|
|
break
|
|
case 'wxpay_online':
|
|
this.processWechatPayment(order)
|
|
break
|
|
default:
|
|
uni.showToast({ title: '不支持的支付方式', icon: 'none' })
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 现金支付处理
|
|
*/
|
|
async processCashPayment(order) {
|
|
uni.showModal({
|
|
title: '现金支付确认',
|
|
content: `确认已收到现金支付 ¥${order.total_amount}?`,
|
|
success: async (res) => {
|
|
if (res.confirm) {
|
|
await this.updateOrderPaymentStatus(order, 'paid', `CASH${Date.now()}`)
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 二维码支付处理
|
|
*/
|
|
async processQRCodePayment(order) {
|
|
uni.showLoading({ title: '生成支付二维码...' })
|
|
|
|
try {
|
|
const res = await apiRoute.getOrderPayQrcode({
|
|
order_id: order._raw?.id || order.id
|
|
})
|
|
|
|
uni.hideLoading()
|
|
|
|
if (res.code === 1 && res.data) {
|
|
this.qrCodePaymentData = {
|
|
order: order,
|
|
qrcode: res.data.code_url,
|
|
qrcodeImage: res.data.qrcode_base64 || res.data.qrcode_url
|
|
}
|
|
this.showQRCodeModal = true
|
|
this.$refs.qrCodePopup.open()
|
|
} else {
|
|
uni.showToast({ title: res.msg || '获取支付二维码失败', icon: 'none' })
|
|
}
|
|
} catch (error) {
|
|
uni.hideLoading()
|
|
console.error('获取支付二维码失败:', error)
|
|
uni.showToast({ title: '获取支付二维码失败', icon: 'none' })
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 订阅支付处理
|
|
*/
|
|
processSubscriptionPayment(order) {
|
|
uni.showActionSheet({
|
|
itemList: ['确认分期支付方案', '取消支付'],
|
|
success: async (res) => {
|
|
if (res.tapIndex === 0) {
|
|
uni.showModal({
|
|
title: '分期支付确认',
|
|
content: `确认使用分期支付方式支付 ¥${order.total_amount}?`,
|
|
success: async (modalRes) => {
|
|
if (modalRes.confirm) {
|
|
await this.updateOrderPaymentStatus(order, 'partial', `SUB${Date.now()}`)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 微信支付处理
|
|
*/
|
|
processWechatPayment(order) {
|
|
uni.showModal({
|
|
title: '微信支付',
|
|
content: `将调用微信支付 ¥${order.total_amount}`,
|
|
confirmText: '确认支付',
|
|
cancelText: '取消',
|
|
success: async (res) => {
|
|
if (res.confirm) {
|
|
uni.showLoading({ title: '正在调用微信支付...' })
|
|
|
|
setTimeout(async () => {
|
|
uni.hideLoading()
|
|
|
|
uni.showModal({
|
|
title: '支付结果',
|
|
content: '微信支付完成,请确认是否已收到款项?',
|
|
success: async (confirmRes) => {
|
|
if (confirmRes.confirm) {
|
|
await this.updateOrderPaymentStatus(order, 'paid', `WX${Date.now()}`)
|
|
}
|
|
}
|
|
})
|
|
}, 1500)
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 更新订单支付状态
|
|
*/
|
|
async updateOrderPaymentStatus(order, status, paymentId = '') {
|
|
try {
|
|
const updateData = {
|
|
order_id: order._raw?.id || order.id,
|
|
order_status: status,
|
|
payment_id: paymentId
|
|
}
|
|
|
|
const result = await apiRoute.xs_orderTableUpdatePaymentStatus(updateData)
|
|
|
|
if (result.code === 1) {
|
|
const statusText = {
|
|
'paid': '支付成功',
|
|
'partial': '分期支付确认成功',
|
|
'cancelled': '支付已取消'
|
|
}
|
|
uni.showToast({
|
|
title: statusText[status] || '状态更新成功',
|
|
icon: 'success'
|
|
})
|
|
|
|
// 刷新订单列表
|
|
await this.refresh()
|
|
|
|
// 触发支付成功事件
|
|
this.$emit('payment-success', order)
|
|
} else {
|
|
uni.showToast({ title: result.msg || '状态更新失败', icon: 'none' })
|
|
}
|
|
} catch (error) {
|
|
console.error('更新订单状态失败:', error)
|
|
uni.showToast({ title: '状态更新失败', icon: 'none' })
|
|
this.$emit('error', { type: 'payment', error })
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 关闭二维码支付弹窗
|
|
*/
|
|
closeQRCodeModal() {
|
|
this.showQRCodeModal = false
|
|
this.qrCodePaymentData = null
|
|
this.$refs.qrCodePopup.close()
|
|
},
|
|
|
|
/**
|
|
* 确认二维码支付完成
|
|
*/
|
|
async confirmQRCodePayment() {
|
|
if (!this.qrCodePaymentData?.order) return
|
|
|
|
const order = this.qrCodePaymentData.order
|
|
|
|
uni.showModal({
|
|
title: '支付确认',
|
|
content: '请确认是否已完成扫码支付?',
|
|
success: async (res) => {
|
|
if (res.confirm) {
|
|
try {
|
|
await this.updateOrderPaymentStatus(order, 'paid', `QR${Date.now()}`)
|
|
this.closeQRCodeModal()
|
|
} catch (error) {
|
|
console.error('支付确认失败:', error)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 查看订单详情
|
|
*/
|
|
viewOrderDetail(order) {
|
|
const orderInfo = order._raw || order
|
|
const isOrderPaid = order.status === 'paid'
|
|
|
|
const detailText = `
|
|
订单号:${order.order_no}
|
|
课程:${order.product_name}
|
|
金额:¥${order.total_amount}
|
|
已付:¥${order.paid_amount}
|
|
未付:¥${order.unpaid_amount}
|
|
支付方式:${order.payment_method}
|
|
销售顾问:${order.salesperson_name}
|
|
课时数:${order.course_count}节
|
|
状态:${this.getStatusText(order.status)}
|
|
创建时间:${this.formatTime(order.create_time)}
|
|
${orderInfo.paid_at ? '支付时间:' + this.formatTime(orderInfo.paid_at) : ''}
|
|
`.trim()
|
|
|
|
uni.showModal({
|
|
title: '订单详情',
|
|
content: detailText,
|
|
showCancel: isOrderPaid,
|
|
cancelText: isOrderPaid ? '知道了' : '',
|
|
confirmText: isOrderPaid ? '合同签署' : '知道了',
|
|
success: (res) => {
|
|
if (res.confirm && isOrderPaid) {
|
|
this.goToContractSign(order)
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 跳转到合同签署页面
|
|
*/
|
|
goToContractSign(order) {
|
|
const studentId = order.student_id || this.studentId
|
|
const contractId = order.contract_id || order._raw?.contract_id
|
|
const contractSignId = order.contract_sign_id || order._raw?.contract_sign_id
|
|
|
|
if (!studentId) {
|
|
uni.showToast({ title: '缺少学生信息', icon: 'none' })
|
|
return
|
|
}
|
|
|
|
if (!contractId) {
|
|
this.getContractByOrder(order, studentId)
|
|
return
|
|
}
|
|
|
|
let url = `/pages-student/contracts/sign?contract_id=${contractId}&student_id=${studentId}&contract_name=${encodeURIComponent(order.product_name + '合同')}&user_role=staff`
|
|
|
|
if (contractSignId) {
|
|
url += `&contract_sign_id=${contractSignId}`
|
|
}
|
|
|
|
uni.navigateTo({ url })
|
|
},
|
|
|
|
/**
|
|
* 根据订单获取合同信息
|
|
*/
|
|
async getContractByOrder(order, studentId) {
|
|
try {
|
|
uni.showLoading({ title: '获取合同信息...' })
|
|
|
|
const res = await apiRoute.getContractByOrder({
|
|
order_id: order._raw?.id || order.id,
|
|
student_id: studentId
|
|
})
|
|
|
|
uni.hideLoading()
|
|
|
|
if (res.code === 1 && res.data) {
|
|
const contractInfo = res.data
|
|
uni.navigateTo({
|
|
url: `/pages-student/contracts/sign?contract_id=${contractInfo.contract_id}&student_id=${studentId}&contract_name=${encodeURIComponent(contractInfo.contract_name || order.product_name + '合同')}&user_role=staff`
|
|
})
|
|
} else {
|
|
uni.showToast({ title: res.msg || '未找到相关合同', icon: 'none' })
|
|
}
|
|
} catch (error) {
|
|
uni.hideLoading()
|
|
console.error('获取合同信息失败:', error)
|
|
uni.showToast({ title: '获取合同信息失败', icon: 'none' })
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 新增订单
|
|
*/
|
|
openAddOrder() {
|
|
if (!this.studentId) {
|
|
uni.showToast({ title: '缺少学员信息', icon: 'none' })
|
|
return
|
|
}
|
|
|
|
this.showOrderForm = true
|
|
this.$refs.orderFormPopup.open()
|
|
},
|
|
|
|
/**
|
|
* 关闭新增订单弹窗
|
|
*/
|
|
closeOrderForm() {
|
|
this.showOrderForm = false
|
|
this.$refs.orderFormPopup.close()
|
|
},
|
|
|
|
/**
|
|
* 订单创建成功回调
|
|
*/
|
|
async handleOrderCreated() {
|
|
this.closeOrderForm()
|
|
|
|
uni.showToast({ title: '订单创建成功', icon: 'success' })
|
|
|
|
// 刷新订单列表
|
|
await this.refresh()
|
|
|
|
// 触发订单创建事件
|
|
this.$emit('order-created')
|
|
},
|
|
|
|
/**
|
|
* 刷新订单列表(对外暴露方法)
|
|
*/
|
|
async refresh() {
|
|
await this.loadOrderList()
|
|
this.$emit('refreshed')
|
|
},
|
|
|
|
/**
|
|
* 获取当前订单列表(对外暴露方法)
|
|
*/
|
|
getOrderList() {
|
|
return this.orderList
|
|
},
|
|
|
|
/**
|
|
* 获取状态样式类
|
|
*/
|
|
getStatusClass(status) {
|
|
const statusMap = {
|
|
'pending': 'status-pending',
|
|
'paid': 'status-paid',
|
|
'partial': 'status-partial',
|
|
'cancelled': 'status-cancelled',
|
|
'completed': 'status-completed',
|
|
'refunded': 'status-refunded'
|
|
}
|
|
return statusMap[status] || 'status-default'
|
|
},
|
|
|
|
/**
|
|
* 获取状态文本
|
|
*/
|
|
getStatusText(status) {
|
|
const statusMap = {
|
|
'pending': '待支付',
|
|
'paid': '已支付',
|
|
'partial': '部分支付',
|
|
'cancelled': '已取消',
|
|
'completed': '已完成',
|
|
'refunded': '已退款'
|
|
}
|
|
return statusMap[status] || '未知状态'
|
|
},
|
|
|
|
/**
|
|
* 格式化时间
|
|
*/
|
|
formatTime(timeStr) {
|
|
if (!timeStr) return ''
|
|
try {
|
|
const date = new Date(timeStr)
|
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`
|
|
} catch (e) {
|
|
return timeStr
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.order-list-card {
|
|
padding: 0;
|
|
}
|
|
|
|
.loading-state {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 80rpx 40rpx;
|
|
}
|
|
|
|
.loading-icon {
|
|
font-size: 60rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.loading-text {
|
|
font-size: 28rpx;
|
|
color: #999999;
|
|
}
|
|
|
|
.order-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 24rpx;
|
|
}
|
|
|
|
.order-item {
|
|
background: #3A3A3A;
|
|
border-radius: 16rpx;
|
|
padding: 32rpx;
|
|
border: 1px solid #404040;
|
|
transition: all 0.3s ease;
|
|
position: relative;
|
|
|
|
&:active {
|
|
background: #4A4A4A;
|
|
}
|
|
|
|
&.pending-payment {
|
|
border-color: #FFC107;
|
|
background: rgba(255, 193, 7, 0.05);
|
|
}
|
|
}
|
|
|
|
.order-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
margin-bottom: 24rpx;
|
|
padding-bottom: 20rpx;
|
|
border-bottom: 1px solid #404040;
|
|
}
|
|
|
|
.order-info {
|
|
flex: 1;
|
|
}
|
|
|
|
.order-no {
|
|
font-size: 30rpx;
|
|
font-weight: 600;
|
|
color: #ffffff;
|
|
margin-bottom: 8rpx;
|
|
}
|
|
|
|
.order-time {
|
|
font-size: 24rpx;
|
|
color: #999999;
|
|
}
|
|
|
|
.order-status {
|
|
padding: 8rpx 16rpx;
|
|
border-radius: 20rpx;
|
|
font-size: 24rpx;
|
|
font-weight: 500;
|
|
|
|
&.status-pending {
|
|
background: rgba(255, 193, 7, 0.2);
|
|
color: #FFC107;
|
|
}
|
|
|
|
&.status-paid {
|
|
background: rgba(76, 175, 80, 0.2);
|
|
color: #4CAF50;
|
|
}
|
|
|
|
&.status-partial {
|
|
background: rgba(255, 152, 0, 0.2);
|
|
color: #FF9800;
|
|
}
|
|
|
|
&.status-cancelled {
|
|
background: rgba(158, 158, 158, 0.2);
|
|
color: #9E9E9E;
|
|
}
|
|
|
|
&.status-completed {
|
|
background: rgba(41, 211, 180, 0.2);
|
|
color: #29D3B4;
|
|
}
|
|
|
|
&.status-refunded {
|
|
background: rgba(244, 67, 54, 0.2);
|
|
color: #F44336;
|
|
}
|
|
|
|
&.status-default {
|
|
background: rgba(158, 158, 158, 0.2);
|
|
color: #9E9E9E;
|
|
}
|
|
}
|
|
|
|
.order-content {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20rpx;
|
|
}
|
|
|
|
.product-info {
|
|
padding: 20rpx;
|
|
background: rgba(41, 211, 180, 0.05);
|
|
border-radius: 12rpx;
|
|
border-left: 4rpx solid #29D3B4;
|
|
}
|
|
|
|
.product-name {
|
|
font-size: 28rpx;
|
|
font-weight: 600;
|
|
color: #ffffff;
|
|
margin-bottom: 8rpx;
|
|
}
|
|
|
|
.product-specs {
|
|
font-size: 24rpx;
|
|
color: #cccccc;
|
|
}
|
|
|
|
.order-details {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 16rpx;
|
|
}
|
|
|
|
.detail-row {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.detail-label {
|
|
font-size: 26rpx;
|
|
color: #999999;
|
|
min-width: 140rpx;
|
|
}
|
|
|
|
.detail-value {
|
|
font-size: 26rpx;
|
|
color: #ffffff;
|
|
flex: 1;
|
|
text-align: right;
|
|
|
|
&.price {
|
|
color: #FFC107;
|
|
font-weight: 600;
|
|
font-size: 28rpx;
|
|
}
|
|
|
|
&.paid {
|
|
color: #4CAF50;
|
|
font-weight: 600;
|
|
}
|
|
|
|
&.unpaid {
|
|
color: #F44336;
|
|
font-weight: 600;
|
|
}
|
|
}
|
|
|
|
.order-remark {
|
|
padding: 20rpx;
|
|
background: rgba(255, 255, 255, 0.05);
|
|
border-radius: 12rpx;
|
|
}
|
|
|
|
.remark-label {
|
|
font-size: 24rpx;
|
|
color: #999999;
|
|
margin-bottom: 12rpx;
|
|
}
|
|
|
|
.remark-content {
|
|
font-size: 26rpx;
|
|
color: #cccccc;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.empty-state {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 80rpx 40rpx;
|
|
text-align: center;
|
|
}
|
|
|
|
.empty-icon {
|
|
font-size: 120rpx;
|
|
margin-bottom: 32rpx;
|
|
opacity: 0.6;
|
|
}
|
|
|
|
.empty-text {
|
|
font-size: 32rpx;
|
|
color: #ffffff;
|
|
margin-bottom: 16rpx;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.empty-tip {
|
|
font-size: 26rpx;
|
|
color: #999999;
|
|
line-height: 1.4;
|
|
margin-bottom: 32rpx;
|
|
}
|
|
|
|
.empty-add-btn {
|
|
background: #29D3B4;
|
|
border-radius: 30rpx;
|
|
padding: 16rpx 40rpx;
|
|
color: #ffffff;
|
|
font-size: 28rpx;
|
|
font-weight: 500;
|
|
transition: all 0.3s ease;
|
|
|
|
&:active {
|
|
background: #1fb396;
|
|
}
|
|
}
|
|
|
|
.action-header {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
margin-bottom: 24rpx;
|
|
}
|
|
|
|
.add-order-btn {
|
|
display: flex;
|
|
align-items: center;
|
|
background: #29D3B4;
|
|
border-radius: 30rpx;
|
|
padding: 12rpx 24rpx;
|
|
color: #ffffff;
|
|
font-size: 26rpx;
|
|
font-weight: 500;
|
|
transition: all 0.3s ease;
|
|
|
|
&:active {
|
|
background: #1fb396;
|
|
}
|
|
}
|
|
|
|
.add-icon {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
margin-right: 8rpx;
|
|
line-height: 1;
|
|
}
|
|
|
|
.add-text {
|
|
font-size: 26rpx;
|
|
}
|
|
</style>
|
|
|