This commit is contained in:
qsh
2026-02-04 16:33:03 +08:00
parent 4715116d15
commit e63e95525d
2 changed files with 186 additions and 298 deletions

View File

@@ -45,3 +45,12 @@ export const getVipType = async id => {
method: 'get' method: 'get'
}); });
}; };
// 查询充值记录
export const getRechargeRecord = async params => {
return await request({
url: '/applet/xunjia/pay/page',
method: 'get',
params: params
});
};

View File

@@ -7,7 +7,7 @@
</view> </view>
<view class="header-title">会员订单管理</view> <view class="header-title">会员订单管理</view>
<view class="header-right" @click="exportOrders"> <view class="header-right" @click="exportOrders">
<view class="export-btn">导出</view> <!-- <view class="export-btn">导出</view> -->
</view> </view>
</view> </view>
@@ -15,16 +15,14 @@
<view class="filter-section"> <view class="filter-section">
<view class="filter-row"> <view class="filter-row">
<view class="filter-item"> <view class="filter-item">
<view class="filter-label">状态</view> <view class="filter-label">订单号</view>
<view class="filter-control"> <view class="filter-control">
<picker <input
:range="statusOptions" v-model="searchParams.payNo"
:value="statusIndex" class="search-input"
@change="onStatusChange" placeholder="请输入订单号"
class="picker" @input="onSearch"
> />
<view class="picker-text">{{ statusOptions[statusIndex] }}</view>
</picker>
</view> </view>
</view> </view>
<view class="filter-item"> <view class="filter-item">
@@ -32,21 +30,22 @@
<view class="filter-control"> <view class="filter-control">
<picker <picker
:range="memberTypeOptions" :range="memberTypeOptions"
:range-key="'memberName'"
:value="memberTypeIndex" :value="memberTypeIndex"
@change="onMemberTypeChange" @change="onMemberTypeChange"
class="picker" class="picker"
> >
<view class="picker-text">{{ memberTypeOptions[memberTypeIndex] }}</view> <view class="picker-text">{{ memberTypeOptions[memberTypeIndex]?.memberName || '全部类型' }}</view>
</picker> </picker>
</view> </view>
</view> </view>
<view class="filter-item"> <view class="filter-item">
<view class="filter-label">搜索</view> <view class="filter-label">手机号</view>
<view class="filter-control"> <view class="filter-control">
<input <input
v-model="searchKeyword" v-model="searchParams.phone"
class="search-input" class="search-input"
placeholder="请输入订单号或学员姓名" placeholder="请输入手机号"
@input="onSearch" @input="onSearch"
/> />
</view> </view>
@@ -64,42 +63,46 @@
class="order-item" class="order-item"
> >
<view class="order-header"> <view class="order-header">
<view class="order-code">{{ order.code }}</view> <view class="order-code" @click="copyOrderId(order.payId)">订单号{{ order.payId }} <text class="copy-icon">📋</text></view>
<view class="order-status" :class="order.statusClass">{{ order.status }}</view> <view class="distributor-name">{{ order.distributionName || '无分销员' }}</view>
</view> </view>
<view class="order-body"> <view class="order-body">
<view class="order-info"> <view class="order-info">
<view class="info-item"> <view class="info-item">
<view class="info-label">学员姓名</view> <view class="info-label">用户姓名</view>
<view class="info-value">{{ order.studentName }}</view> <view class="info-value">{{ order.userName }}</view>
</view>
<view class="info-item">
<view class="info-label">手机号</view>
<view class="info-value">{{ order.phone }}</view>
</view> </view>
<view class="info-item"> <view class="info-item">
<view class="info-label">会员类型</view> <view class="info-label">会员类型</view>
<view class="info-value">{{ order.memberType }}</view> <view class="info-value">{{ order.memberName }}</view>
</view>
<view class="info-item">
<view class="info-label">科目</view>
<view class="info-value">{{ order.subjects }}</view>
</view>
<view class="info-item">
<view class="info-label">车型</view>
<view class="info-value">{{ order.carName }}</view>
</view> </view>
<view class="info-item"> <view class="info-item">
<view class="info-label">订单金额</view> <view class="info-label">订单金额</view>
<view class="info-value price">{{ order.amount }}</view> <view class="info-value price">{{ order.money }}</view>
</view> </view>
<view class="info-item"> <view class="info-item">
<view class="info-label">下单时间</view> <view class="info-label">支付时间</view>
<view class="info-value">{{ order.createTime }}</view> <view class="info-value">{{ order.payTime }}</view>
</view> </view>
</view> <view class="info-item">
</view> <view class="info-label">会员到期时间</view>
<view class="order-footer"> <view class="info-value">{{ order.memberEndTime }}</view>
<view class="order-actions">
<view v-if="order.status === '待处理'" class="action-btn process-btn" @click="processOrder(order.id)">
处理
</view>
<view class="action-btn detail-btn" @click="viewOrderDetail(order.id)">
详情
</view>
<view class="action-btn refund-btn" @click="refundOrder(order.id)">
退款
</view> </view>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
@@ -137,59 +140,23 @@
<script setup> <script setup>
import { ref, computed, onMounted } from "vue" import { ref, computed, onMounted } from "vue"
import { getRechargeRecord, getVipTypeList } from "@/api/member"
// 筛选条件 // 筛选条件
const statusOptions = ['全部状态', '待处理', '已完成', '已退款', '异常'] const memberTypeOptions = ref([
const statusIndex = ref(0) { memberId: '', memberName: '全部类型' }
])
const memberTypeOptions = ['全部类型', '月度会员', '季度会员', '年度会员']
const memberTypeIndex = ref(0) const memberTypeIndex = ref(0)
const searchKeyword = ref('') // 搜索参数
const searchParams = ref({
payNo: '', // 订单号
memberId: '', // 会员类型ID
phone: '' // 手机号
})
// 订单列表数据 // 订单列表数据
const orderList = ref([ const orderList = ref([])
{
id: 1,
code: 'MO20260129001',
studentName: '张三',
memberType: '年度会员',
amount: '¥299.90',
createTime: '2026-01-29 15:30:00',
status: '待处理',
statusClass: 'status-pending'
},
{
id: 2,
code: 'MO20260129002',
studentName: '李四',
memberType: '月度会员',
amount: '¥39.90',
createTime: '2026-01-29 14:20:00',
status: '已完成',
statusClass: 'status-completed'
},
{
id: 3,
code: 'MO20260129003',
studentName: '王五',
memberType: '季度会员',
amount: '¥99.90',
createTime: '2026-01-29 13:10:00',
status: '异常',
statusClass: 'status-exception'
},
{
id: 4,
code: 'MO20260129004',
studentName: '赵六',
memberType: '年度会员',
amount: '¥299.90',
createTime: '2026-01-29 12:00:00',
status: '已退款',
statusClass: 'status-refunded'
}
])
// 分页信息 // 分页信息
const currentPage = ref(1) const currentPage = ref(1)
@@ -202,10 +169,51 @@
}) })
onMounted(() => { onMounted(() => {
// 实际项目中应从接口获取订单列表 // 加载订单列表
// loadOrderList() loadOrderList()
// 加载会员类型列表
loadVipTypeList()
}) })
// 加载会员类型列表
function loadVipTypeList() {
uni.showLoading({ title: '加载中...' })
getVipTypeList().then(res => {
uni.hideLoading()
if (res.code == '0000') {
// 保留默认的"全部类型"选项,添加从接口获取的会员类型
const vipTypes = res.data.list || []
memberTypeOptions.value = [
{ memberId: '', memberName: '全部类型' },
...vipTypes
]
}
}).catch(err => {
uni.hideLoading()
console.error('加载会员类型失败:', err)
})
}
// 加载订单列表
function loadOrderList() {
uni.showLoading({ title: '加载中...' })
getRechargeRecord({
pageNo: currentPage.value,
pageSize: pageSize.value,
payNo: searchParams.value.payNo,
memberId: searchParams.value.memberId,
phone: searchParams.value.phone
}).then(res => {
uni.hideLoading()
if (res.code == '0000') {
orderList.value = res.data.list || []
totalOrders.value = res.data.total || 0
}
})
}
// 返回上一页 // 返回上一页
function goBack() { function goBack() {
uni.navigateBack({ delta: 1 }) uni.navigateBack({ delta: 1 })
@@ -234,79 +242,27 @@
}) })
} }
// 状态变更
function onStatusChange(e) {
const value = e.detail.value
statusIndex.value = value
// 实际项目中应根据状态筛选订单
// filterOrderList()
}
// 会员类型变更 // 会员类型变更
function onMemberTypeChange(e) { function onMemberTypeChange(e) {
const value = e.detail.value const value = e.detail.value
memberTypeIndex.value = value memberTypeIndex.value = value
// 实际项目中应根据会员类型筛选订单 // 根据选择的会员类型设置memberId
// filterOrderList() const selectedType = memberTypeOptions.value[value]
if (selectedType) {
searchParams.value.memberId = selectedType.memberId || ''
}
// 重新加载订单列表
loadOrderList()
} }
// 搜索 // 搜索
function onSearch() { function onSearch() {
// 实际项目中应根据关键词搜索订单 // 重置页码
// searchOrderList() currentPage.value = 1
// 重新加载订单列表
loadOrderList()
} }
// 处理订单
function processOrder(id) {
uni.showModal({
title: '处理订单',
content: '确定要处理该订单吗?',
success: function(res) {
if (res.confirm) {
// 实际项目中应调用接口处理订单
const order = orderList.value.find(item => item.id === id)
if (order) {
order.status = '已完成'
order.statusClass = 'status-completed'
}
uni.showToast({
title: '订单处理成功',
icon: 'success'
})
}
}
})
}
// 查看订单详情
function viewOrderDetail(id) {
uni.showToast({
title: '查看订单详情功能开发中',
icon: 'none'
})
}
// 退款订单
function refundOrder(id) {
uni.showModal({
title: '退款订单',
content: '确定要退款该订单吗?',
success: function(res) {
if (res.confirm) {
// 实际项目中应调用接口退款订单
const order = orderList.value.find(item => item.id === id)
if (order) {
order.status = '已退款'
order.statusClass = 'status-refunded'
}
uni.showToast({
title: '订单退款成功',
icon: 'success'
})
}
}
})
}
// 跳转到指定页码 // 跳转到指定页码
function goToPage(page) { function goToPage(page) {
@@ -314,8 +270,21 @@
return return
} }
currentPage.value = page currentPage.value = page
// 实际项目中应加载指定页码的订单 // 加载指定页码的订单
// loadOrderPage(page) loadOrderList()
}
// 复制订单号
function copyOrderId(payId) {
uni.setClipboardData({
data: payId,
success: function() {
uni.showToast({ title: '订单号已复制', icon: 'success' })
},
fail: function() {
uni.showToast({ title: '复制失败', icon: 'none' })
}
})
} }
</script> </script>
@@ -434,15 +403,16 @@
/* 订单列表 */ /* 订单列表 */
.order-list-section { .order-list-section {
flex: 1; flex: 1;
padding: 0 16rpx; padding: 0 20rpx;
margin-top: 20rpx;
} }
.section-title { .section-title {
font-size: 32rpx; font-size: 32rpx;
font-weight: bold; font-weight: bold;
color: #303133; color: #303133;
margin-bottom: 24rpx; margin-bottom: 28rpx;
padding-left: 12rpx; padding-left: 16rpx;
border-left: 8rpx solid #409eff; border-left: 8rpx solid #409eff;
line-height: 1.2; line-height: 1.2;
} }
@@ -450,121 +420,109 @@
.order-list { .order-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 16rpx; gap: 20rpx;
} }
.order-item { .order-item {
background-color: #fff; background-color: #fff;
border-radius: 16rpx; border-radius: 16rpx;
padding: 24rpx; padding: 28rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08); box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
}
.order-item:hover {
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
transform: translateY(-2rpx);
} }
.order-header { .order-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 16rpx; margin-bottom: 24rpx;
padding-bottom: 16rpx; padding-bottom: 20rpx;
border-bottom: 1rpx solid #e0e0e0; border-bottom: 2rpx solid #f0f0f0;
} }
.order-code { .order-code {
font-size: 24rpx; font-size: 26rpx;
font-weight: 600; font-weight: 600;
color: #303133; color: #303133;
word-break: break-all;
cursor: pointer;
display: flex;
align-items: center;
gap: 8rpx;
} }
.order-status { .order-code:hover {
color: #409eff;
}
.copy-icon {
font-size: 20rpx; font-size: 20rpx;
font-weight: 600; opacity: 0.7;
padding: 4rpx 12rpx;
border-radius: 12rpx;
} }
.status-pending { .distributor-name {
color: #e6a23c; font-size: 20rpx;
background-color: rgba(230, 162, 60, 0.1); color: #606266;
} background-color: #f5f7fa;
padding: 6rpx 16rpx;
.status-completed { border-radius: 16rpx;
color: #67c23a; white-space: nowrap;
background-color: rgba(103, 194, 58, 0.1); max-width: 200rpx;
} overflow: hidden;
text-overflow: ellipsis;
.status-exception {
color: #f56c6c;
background-color: rgba(245, 108, 108, 0.1);
}
.status-refunded {
color: #909399;
background-color: rgba(144, 147, 153, 0.1);
} }
.order-body { .order-body {
margin-bottom: 16rpx; margin-bottom: 0;
} }
.order-info { .order-info {
display: flex; display: grid;
flex-direction: column; grid-template-columns: repeat(auto-fit, minmax(300rpx, 1fr));
gap: 8rpx; gap: 16rpx;
} }
.info-item { .info-item {
display: flex; display: flex;
font-size: 20rpx; flex-direction: column;
gap: 4rpx;
} }
.info-label { .info-label {
color: #606266; color: #909399;
width: 120rpx; font-size: 24rpx;
width: auto;
} }
.info-value { .info-value {
color: #303133; color: #303133;
font-size: 24rpx;
font-weight: 500;
flex: 1; flex: 1;
} }
.info-value.price { .info-value.price {
color: #f56c6c; color: #f56c6c;
font-weight: 600; font-weight: 600;
font-size: 22rpx;
} }
.order-footer { /* 响应式调整 */
border-top: 1rpx solid #e0e0e0; @media (max-width: 750rpx) {
padding-top: 16rpx; .order-info {
grid-template-columns: 1fr;
}
.order-item {
padding: 24rpx;
}
} }
.order-actions {
display: flex;
justify-content: flex-end;
gap: 16rpx;
}
.action-btn {
padding: 8rpx 16rpx;
border-radius: 8rpx;
font-size: 16rpx;
font-weight: 600;
cursor: pointer;
}
.process-btn {
background-color: #ecf5ff;
color: #409eff;
}
.detail-btn {
background-color: #f0f9eb;
color: #67c23a;
}
.refund-btn {
background-color: #fef0f0;
color: #f56c6c;
}
/* 空状态 */ /* 空状态 */
.empty-state { .empty-state {
@@ -621,85 +579,6 @@
cursor: not-allowed; cursor: not-allowed;
} }
/* 平板响应式 */
@media screen and (min-width: 768px) {
.member-order-container {
max-width: 900px;
margin: 0 auto;
width: 100%;
}
.filter-section {
margin: 0 32rpx 24rpx;
padding: 32rpx;
}
.order-list-section {
padding: 0 32rpx;
}
.pagination {
margin: 0 32rpx 32rpx;
padding: 32rpx;
}
.section-title {
font-size: 36rpx;
margin-bottom: 32rpx;
}
.filter-label {
font-size: 26rpx;
}
.picker-text,
.search-input {
font-size: 26rpx;
}
.filter-control {
padding: 20rpx;
}
.order-item {
padding: 32rpx;
}
.order-code {
font-size: 28rpx;
}
.order-status {
font-size: 22rpx;
}
.info-item {
font-size: 24rpx;
}
.info-label {
width: 160rpx;
}
.action-btn {
font-size: 18rpx;
padding: 12rpx 24rpx;
}
.page-info {
font-size: 22rpx;
}
.page-btn {
font-size: 22rpx;
padding: 12rpx 24rpx;
}
.export-btn {
font-size: 28rpx;
}
}
/* 大屏设备响应式 */ /* 大屏设备响应式 */
@media screen and (min-width: 1024px) { @media screen and (min-width: 1024px) {
.member-order-container { .member-order-container {