|
|
|
@ -1,150 +1,760 @@ |
|
|
|
<!--订单列表内容组件--> |
|
|
|
<!--订单列表组件 - 独立业务组件--> |
|
|
|
<template> |
|
|
|
<view class="order-list-card"> |
|
|
|
<!-- 操作按钮区域 --> |
|
|
|
<view class="action-header" v-if="orderList && orderList.length > 0"> |
|
|
|
<view class="add-order-btn" @click.stop="handleAddOrder"> |
|
|
|
<text class="add-icon">+</text> |
|
|
|
<text class="add-text">新增订单</text> |
|
|
|
</view> |
|
|
|
<!-- 加载状态 --> |
|
|
|
<view v-if="loading" class="loading-state"> |
|
|
|
<text class="loading-icon">⏳</text> |
|
|
|
<text class="loading-text">加载中...</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 订单列表 --> |
|
|
|
<scroll-view |
|
|
|
class="order-list" |
|
|
|
v-if="orderList && orderList.length > 0" |
|
|
|
scroll-y="true" |
|
|
|
:enhanced="true" |
|
|
|
style="height: 70vh;" |
|
|
|
> |
|
|
|
<view |
|
|
|
class="order-item" |
|
|
|
v-for="(order, index) in orderList" |
|
|
|
:key="order && order.id ? order.id : `order-${index}`" |
|
|
|
:class="{ 'pending-payment': order && order.status === 'pending' }" |
|
|
|
@click.stop="order ? handleOrderClick(order) : null" |
|
|
|
v-if="order" |
|
|
|
> |
|
|
|
<view class="order-header"> |
|
|
|
<view class="order-info"> |
|
|
|
<view class="order-no">订单号:{{ order.order_no || 'N/A' }}</view> |
|
|
|
<view class="order-time" v-if="order.create_time"> |
|
|
|
{{ formatTime(order.create_time) }} |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<view :class="['order-status',getStatusClass(order && order.status)]"> |
|
|
|
{{ getStatusText(order && order.status) }} |
|
|
|
</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> |
|
|
|
|
|
|
|
<!-- 订单内容 --> |
|
|
|
<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 }} |
|
|
|
<!-- 订单列表 --> |
|
|
|
<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-details"> |
|
|
|
<!-- 价格信息 --> |
|
|
|
<view class="detail-row" v-if="order.total_amount"> |
|
|
|
<text class="detail-label">订单金额:</text> |
|
|
|
<text class="detail-value price">¥{{ order.total_amount }}</text> |
|
|
|
<!-- 订单内容 --> |
|
|
|
<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="detail-row" v-if="order.paid_amount !== undefined"> |
|
|
|
<text class="detail-label">已付金额:</text> |
|
|
|
<text class="detail-value paid">¥{{ order.paid_amount }}</text> |
|
|
|
</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" v-if="order.unpaid_amount !== undefined"> |
|
|
|
<text class="detail-label">未付金额:</text> |
|
|
|
<text class="detail-value unpaid">¥{{ order.unpaid_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" v-if="order.payment_method"> |
|
|
|
<text class="detail-label">支付方式:</text> |
|
|
|
<text class="detail-value">{{ order.payment_method }}</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.salesperson_name"> |
|
|
|
<text class="detail-label">销售顾问:</text> |
|
|
|
<text class="detail-value">{{ order.salesperson_name }}</text> |
|
|
|
<!-- 其他信息 --> |
|
|
|
<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="detail-row" v-if="order.course_count"> |
|
|
|
<text class="detail-label">课时数量:</text> |
|
|
|
<text class="detail-value">{{ order.course_count }}节</text> |
|
|
|
<!-- 备注信息 --> |
|
|
|
<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="order-remark"> |
|
|
|
<view class="remark-label">备注:</view> |
|
|
|
<view class="remark-content">{{ order.remark }}</view> |
|
|
|
</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> |
|
|
|
</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" @click.stop="handleAddOrder"> |
|
|
|
<text>新增订单</text> |
|
|
|
</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: { |
|
|
|
// 订单列表数据 |
|
|
|
orderList: { |
|
|
|
type: Array, |
|
|
|
default: () => [] |
|
|
|
// 学员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: { |
|
|
|
// 查看订单详情 |
|
|
|
viewOrderDetail(order) { |
|
|
|
this.$emit('view-detail', order) |
|
|
|
/** |
|
|
|
* 构建学生信息对象 |
|
|
|
* 通过员工端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 |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 新增订单 |
|
|
|
handleAddOrder() { |
|
|
|
this.$emit('add-order') |
|
|
|
/** |
|
|
|
* 加载字典数据 |
|
|
|
*/ |
|
|
|
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' } |
|
|
|
] |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 订单点击处理(根据状态决定是查看详情还是支付) |
|
|
|
handleOrderClick(order) { |
|
|
|
console.log('点击订单:', order) |
|
|
|
// 防护检查:确保order对象存在 |
|
|
|
if (!order) { |
|
|
|
console.warn('订单数据不存在,无法处理点击事件') |
|
|
|
/** |
|
|
|
* 加载订单列表 |
|
|
|
*/ |
|
|
|
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.$emit('pay-order', order) |
|
|
|
// 待支付订单,触发支付 |
|
|
|
this.handleOrderPay(order) |
|
|
|
} else { |
|
|
|
// 已支付订单,查看详情 |
|
|
|
this.$emit('view-detail', order) |
|
|
|
// 已支付订单,查看详情 |
|
|
|
this.viewOrderDetail(order) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 获取状态样式类 |
|
|
|
getStatusClass(status) { |
|
|
|
if (!status) return 'status-default' |
|
|
|
/** |
|
|
|
* 处理订单支付 |
|
|
|
*/ |
|
|
|
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', |
|
|
|
@ -156,10 +766,10 @@ export default { |
|
|
|
return statusMap[status] || 'status-default' |
|
|
|
}, |
|
|
|
|
|
|
|
// 获取状态文本 |
|
|
|
/** |
|
|
|
* 获取状态文本 |
|
|
|
*/ |
|
|
|
getStatusText(status) { |
|
|
|
if (!status) return '未知状态' |
|
|
|
|
|
|
|
const statusMap = { |
|
|
|
'pending': '待支付', |
|
|
|
'paid': '已支付', |
|
|
|
@ -171,7 +781,9 @@ export default { |
|
|
|
return statusMap[status] || '未知状态' |
|
|
|
}, |
|
|
|
|
|
|
|
// 格式化时间 |
|
|
|
/** |
|
|
|
* 格式化时间 |
|
|
|
*/ |
|
|
|
formatTime(timeStr) { |
|
|
|
if (!timeStr) return '' |
|
|
|
try { |
|
|
|
@ -190,6 +802,24 @@ export default { |
|
|
|
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; |
|
|
|
@ -211,19 +841,6 @@ export default { |
|
|
|
&.pending-payment { |
|
|
|
border-color: #FFC107; |
|
|
|
background: rgba(255, 193, 7, 0.05); |
|
|
|
|
|
|
|
&::after { |
|
|
|
position: absolute; |
|
|
|
bottom: 16rpx; |
|
|
|
right: 16rpx; |
|
|
|
background: #FFC107; |
|
|
|
color: #000000; |
|
|
|
font-size: 24rpx; |
|
|
|
padding: 8rpx 16rpx; |
|
|
|
border-radius: 20rpx; |
|
|
|
font-weight: 500; |
|
|
|
z-index: 10; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|