consumer-app/pages/profileSub/serviceRecords.vue

1065 lines
27 KiB
Vue
Raw Normal View History

2025-12-19 12:27:55 +00:00
<template>
<view class="service-records-page">
2026-03-09 03:37:41 +00:00
<view class="header-fixed-wrapper" :style="{ height: headerHeight + 'px' }">
<NavHeader title="服务记录" />
</view>
<view class="main-wrap" :style="{ paddingTop: headerHeight + 'px' }">
2025-12-19 12:27:55 +00:00
<!-- Tab 切换 -->
<view class="tab-bar">
<view
class="tab-item"
:class="{ active: currentTab === 'pending_payment' }"
@click="switchTab('pending_payment')"
>
2026-03-27 01:54:40 +00:00
<text class="tab-text">待结算</text>
2025-12-19 12:27:55 +00:00
</view>
<view
class="tab-item"
:class="{ active: currentTab === 'pending_verification' }"
@click="switchTab('pending_verification')"
>
2026-03-21 11:16:08 +00:00
<text class="tab-text">待核销</text>
2025-12-19 12:27:55 +00:00
</view>
<view
class="tab-item"
2026-03-21 11:16:08 +00:00
:class="{ active: currentTab === 'completed' }"
@click="switchTab('completed')"
2025-12-19 12:27:55 +00:00
>
2026-03-21 11:16:08 +00:00
<text class="tab-text">已完成</text>
2025-12-19 12:27:55 +00:00
</view>
<view
class="tab-item"
:class="{ active: currentTab === 'cancelled' }"
@click="switchTab('cancelled')"
>
<text class="tab-text">已取消</text>
</view>
</view>
<!-- 列表内容 -->
<scroll-view
class="record-list"
scroll-y="true"
:refresher-enabled="true"
:refresher-triggered="refreshing"
@refresherrefresh="handleRefresh"
@scrolltolower="handleLoadMore"
:lower-threshold="100"
>
<!-- 空数据提示 -->
<view class="empty-state" v-if="!loading && currentList.length === 0">
<image
class="empty-icon"
src="/static/home/entry_icon.png"
mode="aspectFit"
></image>
<text class="empty-text">暂无{{ getTabLabel() }}记录</text>
</view>
<!-- 记录列表项 -->
<view
class="record-item"
v-for="(item, index) in currentList"
:key="index"
>
2026-03-04 08:58:40 +00:00
<!-- 头部门店 + 状态 -->
2025-12-19 12:27:55 +00:00
<view class="record-header">
2026-03-04 08:58:40 +00:00
<view class="record-shop-row">
<text class="shop-name">{{ item.shopName }}</text>
2025-12-19 12:27:55 +00:00
<view class="status-badge" :class="getStatusClass(item.status)">
<text class="status-text">{{ getStatusText(item.status) }}</text>
</view>
</view>
2026-03-04 08:58:40 +00:00
<text class="record-time">{{ formatTime(item.createTime) }}</text>
2025-12-19 12:27:55 +00:00
</view>
2026-03-04 08:58:40 +00:00
<!-- 中部类似商品卡片 -->
<view class="record-body" @click="handleRecordClick(item)">
<view
class="record-goods"
v-for="(goods, gIndex) in getGoodsList(item)"
2026-03-18 16:27:42 +00:00
:key="goods.id || goods.voucherId || gIndex"
2026-03-04 08:58:40 +00:00
>
<image
class="goods-image"
:src="
goods.coverUrl ||
2026-03-18 16:27:42 +00:00
goods.voucherCoverUrl ||
2026-03-04 08:58:40 +00:00
goods.picUrl ||
'/static/home/entry_icon.png'
"
mode="aspectFill"
></image>
<view class="goods-info">
2026-03-05 11:04:23 +00:00
<text class="goods-title">{{
2026-03-18 16:27:42 +00:00
goods.voucherName || goods.name
2026-03-05 11:04:23 +00:00
}}</text>
2026-03-04 08:58:40 +00:00
<!-- <text class="goods-subtitle">
订单号{{ item.orderNumber }}
</text> -->
<view class="goods-meta-row">
2026-03-05 11:04:23 +00:00
<text class="goods-price"
>¥{{ formatFen(goods.salePrice) }}</text
>
2026-03-04 08:58:40 +00:00
<text
class="goods-count"
2026-03-05 11:04:23 +00:00
v-if="
(goods.num || goods.count || goods.quantity || goods.qty) >
1
"
2026-03-04 08:58:40 +00:00
>
×{{ goods.num || goods.count || goods.quantity || goods.qty }}
</text>
</view>
</view>
2026-03-05 11:04:23 +00:00
<view
class="qr-code-icon-wrapper"
@click.stop="handleQrCode(item, goods)"
>
<image
src="/static/home/qr_code_icon.png"
mode="aspectFill"
class="qr-code-icon"
2026-03-09 03:37:41 +00:00
:class="{ gray: item.status === 4 }"
2026-03-05 11:04:23 +00:00
></image>
</view>
2025-12-19 12:27:55 +00:00
</view>
2026-03-04 08:58:40 +00:00
</view>
<!-- 底部合计 + 操作按钮 -->
<view class="record-footer">
<view class="total-info">
<text class="total-label">实付款</text>
2026-03-05 11:04:23 +00:00
<text class="total-amount"
>¥{{ formatFen(item.payableAmount) }}</text
>
2025-12-19 12:27:55 +00:00
</view>
2026-03-04 08:58:40 +00:00
<!-- 操作按钮区域 -->
2026-03-04 15:30:04 +00:00
<view class="record-actions" v-if="item.status === 0">
2026-03-04 08:58:40 +00:00
<button
class="action-btn cancel-btn"
@click.stop="handleCancel(item)"
>
取消订单
</button>
<button class="action-btn pay-btn" @click.stop="handlePay(item)">
2026-03-27 01:54:40 +00:00
去结算
2026-03-04 08:58:40 +00:00
</button>
2025-12-19 12:27:55 +00:00
</view>
2026-03-04 15:30:04 +00:00
<view class="record-actions" v-else-if="item.status === 1">
2026-03-04 08:58:40 +00:00
<!-- <button
class="action-btn detail-btn"
@click.stop="handleViewDetail(item)"
>
去核销
</button> -->
2025-12-19 12:27:55 +00:00
</view>
2026-03-04 08:58:40 +00:00
<view class="record-actions" v-else-if="item.status === 3">
<!-- <button
2025-12-19 12:27:55 +00:00
class="action-btn detail-btn"
@click.stop="handleViewDetail(item)"
>
查看详情
</button>
<button
class="action-btn review-btn"
@click.stop="handleReview(item)"
>
评价
2026-03-04 08:58:40 +00:00
</button> -->
</view>
<view class="record-actions" v-else-if="item.status === 4">
<button
class="action-btn detail-btn"
2026-03-05 11:04:23 +00:00
@click.stop="handleDelete(item)"
2026-03-04 08:58:40 +00:00
>
删除
</button>
</view>
2025-12-19 12:27:55 +00:00
</view>
</view>
<!-- 加载更多提示 -->
<view class="load-more" v-if="currentList.length > 0">
<text v-if="loadingMore" class="load-more-text">...</text>
<text v-else-if="!hasMore" class="load-more-text">没有更多数据了</text>
<text v-else class="load-more-text">上拉加载更多</text>
</view>
</scroll-view>
2026-03-05 11:04:23 +00:00
<!-- 券码二维码弹窗 -->
<view
class="qr-modal-mask"
v-if="qrModalVisible"
@click="closeQrModal"
></view>
<view class="qr-modal-wrap" v-if="qrModalVisible">
<view class="qr-modal" @click.stop>
<view class="qr-modal-header">
<text class="qr-modal-title">核销码</text>
<view
class="qr-modal-status"
:class="getQrUseStatusClass(qrModalData.useStatus)"
>
{{ getQrUseStatusText(qrModalData.useStatus) }}
</view>
<view class="qr-modal-close" @click="closeQrModal">×</view>
</view>
<view class="qr-modal-body">
2026-03-18 16:27:42 +00:00
<view class="qr-code-box" v-if="qrModalData.voucherCode">
2026-03-05 11:04:23 +00:00
<image
class="qr-code-image"
:src="qrCodeImageUrl"
mode="aspectFit"
></image>
2026-03-18 16:27:42 +00:00
<!-- <text class="qr-code-text">{{ qrModalData.voucherCode }}</text> -->
2026-03-05 11:04:23 +00:00
</view>
<text v-else class="qr-code-empty">暂无券码</text>
</view>
</view>
</view>
2026-03-09 03:37:41 +00:00
</view>
2025-12-19 12:27:55 +00:00
</view>
</template>
<script>
import NavHeader from "@/components/NavHeader/NavHeader.vue";
2026-03-05 11:04:23 +00:00
import { getLuMyOrderPage, cancelOrder, getPaySign,deleteOrder } from "@/api/service";
2025-12-19 12:27:55 +00:00
export default {
components: {
2026-03-04 08:58:40 +00:00
NavHeader,
2025-12-19 12:27:55 +00:00
},
data() {
return {
2026-03-09 03:37:41 +00:00
statusBarHeight: 0,
2025-12-19 12:27:55 +00:00
currentTab: "pending_payment", // 当前选中的 tab
refreshing: false,
loading: false,
loadingMore: false,
hasMore: true,
pageNo: 1,
pageSize: 10,
2026-03-04 08:58:40 +00:00
// 各状态对应的订单列表
recordsMap: {
pending_payment: [],
pending_verification: [],
completed: [],
cancelled: [],
2025-12-19 12:27:55 +00:00
},
2026-03-05 11:04:23 +00:00
qrModalVisible: false,
qrModalData: {
useStatus: 0,
2026-03-18 16:27:42 +00:00
voucherCode: "",
2026-03-05 11:04:23 +00:00
},
2025-12-19 12:27:55 +00:00
};
},
computed: {
2026-03-09 03:37:41 +00:00
headerHeight() {
return this.statusBarHeight + 44;
},
2025-12-19 12:27:55 +00:00
currentList() {
2026-03-04 08:58:40 +00:00
return this.recordsMap[this.currentTab] || [];
2025-12-19 12:27:55 +00:00
},
2026-03-05 11:04:23 +00:00
qrCodeImageUrl() {
2026-03-18 16:27:42 +00:00
const code = this.qrModalData.voucherCode || "";
2026-03-05 11:04:23 +00:00
if (!code) return "";
return `https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=${encodeURIComponent(code)}`;
},
2025-12-19 12:27:55 +00:00
},
2026-03-04 08:58:40 +00:00
onLoad(options) {
2026-03-09 03:37:41 +00:00
const systemInfo = uni.getSystemInfoSync();
this.statusBarHeight = systemInfo.statusBarHeight || 0;
2026-03-04 08:58:40 +00:00
if (options && options.tab) {
this.currentTab = options.tab;
}
2025-12-19 12:27:55 +00:00
this.loadData();
},
methods: {
2026-03-18 16:27:42 +00:00
// 一个订单可能包含多个商品voucherPurchaseRespVOS
2026-03-04 08:58:40 +00:00
getGoodsList(order) {
2026-03-18 16:27:42 +00:00
const list = (order && order.voucherPurchaseRespVOS) || [];
2026-03-04 08:58:40 +00:00
return Array.isArray(list) && list.length ? list : [order || {}];
},
// 金额分转元(去掉后两位)
formatFen(fen) {
const n = Number(fen);
if (!Number.isFinite(n)) return fen || "0.00";
return (n / 100).toFixed(2);
},
// 时间戳转可读时间(支持秒/毫秒)
formatTime(val) {
if (val == null || val === "") return "";
let ts = Number(val);
if (!Number.isFinite(ts)) return val;
if (String(ts).length <= 10) ts *= 1000;
const d = new Date(ts);
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
const h = String(d.getHours()).padStart(2, "0");
const min = String(d.getMinutes()).padStart(2, "0");
const s = String(d.getSeconds()).padStart(2, "0");
return `${y}-${m}-${day} ${h}:${min}:${s}`;
},
// 根据当前 tab 映射到接口所需的 status 值
getStatusValue() {
const map = {
2026-03-27 01:54:40 +00:00
pending_payment: 0, // 待结算
2026-03-05 11:04:23 +00:00
pending_verification: 1, // 已完成
2026-03-04 15:30:04 +00:00
chargeback: 3, // 已退款
2026-03-04 08:58:40 +00:00
cancelled: 4, // 已取消
};
return map[this.currentTab];
},
2025-12-19 12:27:55 +00:00
// 切换 Tab
switchTab(tab) {
if (this.currentTab === tab) return;
this.currentTab = tab;
this.pageNo = 1;
this.hasMore = true;
this.loadData();
},
// 获取 Tab 标签文本
getTabLabel() {
const labels = {
2026-03-27 01:54:40 +00:00
pending_payment: "待结算",
2025-12-19 12:27:55 +00:00
pending_verification: "待核销",
completed: "已完成",
cancelled: "已取消",
};
return labels[this.currentTab] || "";
},
// 获取状态文本
getStatusText(status) {
2026-03-04 15:30:04 +00:00
return status === 0
2026-03-27 01:54:40 +00:00
? "待结算"
2026-03-04 15:30:04 +00:00
: status === 1
2026-03-04 08:58:40 +00:00
? "已完成"
2026-03-04 15:30:04 +00:00
: status === 3
? "已退款"
2026-03-04 08:58:40 +00:00
: status === 4
? "已取消"
: "";
2025-12-19 12:27:55 +00:00
},
// 获取状态样式类
getStatusClass(status) {
2026-03-04 15:30:04 +00:00
return status === 0
2026-03-04 08:58:40 +00:00
? "status-pending"
2026-03-04 15:30:04 +00:00
: status === 1
2026-03-04 08:58:40 +00:00
? "status-verification"
: status === 3
? "status-completed"
: status === 4
? "status-cancelled"
: "";
2025-12-19 12:27:55 +00:00
},
2026-03-05 11:04:23 +00:00
// 加载数据(真机/预览无数据时请检查1. 小程序后台「服务器域名」已配置接口域名 2. 真机已登录)
2026-03-04 08:58:40 +00:00
async loadData(append = false) {
if (this.loading) return;
2025-12-19 12:27:55 +00:00
this.loading = true;
2026-03-04 08:58:40 +00:00
const status = this.getStatusValue();
try {
const res = await getLuMyOrderPage({
pageNo: this.pageNo,
pageSize: this.pageSize,
status,
});
2026-03-05 11:04:23 +00:00
// 兼容多种后端返回结构list / records / data.list
const rawList =
res.list ||
res.records ||
(res.data && (res.data.list || res.data.records)) ||
[];
const list = Array.isArray(rawList) ? rawList : [];
2026-03-04 08:58:40 +00:00
const currentList = this.recordsMap[this.currentTab] || [];
this.recordsMap = {
...this.recordsMap,
[this.currentTab]: append ? currentList.concat(list) : list,
};
// 是否还有更多
this.hasMore = list.length >= this.pageSize;
} catch (e) {
2026-03-05 11:04:23 +00:00
const msg = (e && e.message) ? String(e.message) : "";
2026-03-04 08:58:40 +00:00
console.error("加载服务记录失败:", e);
uni.showToast({
2026-03-05 11:04:23 +00:00
title: msg ? `加载失败:${msg}` : "加载服务记录失败",
2026-03-04 08:58:40 +00:00
icon: "none",
2026-03-05 11:04:23 +00:00
duration: 2500,
2026-03-04 08:58:40 +00:00
});
} finally {
2025-12-19 12:27:55 +00:00
this.loading = false;
this.refreshing = false;
this.loadingMore = false;
2026-03-04 08:58:40 +00:00
}
2025-12-19 12:27:55 +00:00
},
// 下拉刷新
handleRefresh() {
this.refreshing = true;
this.pageNo = 1;
this.hasMore = true;
this.loadData();
},
// 上拉加载更多
handleLoadMore() {
if (this.hasMore && !this.loadingMore && !this.loading) {
this.loadingMore = true;
this.pageNo += 1;
2026-03-04 08:58:40 +00:00
this.loadData(true);
2025-12-19 12:27:55 +00:00
}
},
// 点击记录项
handleRecordClick(item) {
// 可以跳转到详情页
console.log("点击记录:", item);
},
// 取消订单
handleCancel(item) {
uni.showModal({
title: "提示",
content: "确定要取消该订单吗?",
2026-03-04 08:58:40 +00:00
success: async (res) => {
2025-12-19 12:27:55 +00:00
if (res.confirm) {
// 这里应该调用接口取消订单,然后刷新列表
2026-03-04 08:58:40 +00:00
const res = await cancelOrder({
id: item.id,
});
if (res) {
uni.showToast({
title: "订单已取消",
icon: "success",
2025-12-19 12:27:55 +00:00
});
2026-03-04 08:58:40 +00:00
this.loadData();
2025-12-19 12:27:55 +00:00
}
}
},
});
},
2026-03-05 11:04:23 +00:00
// 删除订单
handleDelete(item) {
uni.showModal({
title: "提示",
content: "确定要删除该订单吗?",
success: async (res) => {
if (res.confirm) {
const resData = await deleteOrder({
id: item.id,
});
if (resData) {
uni.showToast({
title: "订单已删除",
icon: "success",
});
this.loadData();
}
}
},
});
},
2026-03-27 01:54:40 +00:00
// 去结算(与店铺详情页 handlePay 逻辑一致,跳转收银台小程序)
2026-03-04 08:58:40 +00:00
async handlePay(item) {
if (!item || !item.orderNumber) {
uni.showToast({ title: "订单信息异常", icon: "none" });
return;
}
2026-03-18 16:27:42 +00:00
const voucherArray = item.voucherPurchaseRespVOS || [];
const voucherMap = new Map();
voucherArray.forEach((goods) => {
const key = goods.voucherId;
2026-03-04 08:58:40 +00:00
if (!key) return;
2026-03-18 16:27:42 +00:00
const currentList = voucherMap.get(key) || [];
2026-03-04 08:58:40 +00:00
currentList.push(goods);
2026-03-18 16:27:42 +00:00
voucherMap.set(key, currentList);
2026-03-04 08:58:40 +00:00
});
let bodyStr = "";
2026-03-18 16:27:42 +00:00
voucherMap.forEach((voucherList) => {
2026-03-04 08:58:40 +00:00
bodyStr =
bodyStr +
2026-03-18 16:27:42 +00:00
(voucherList[0] && voucherList[0].voucherName
? voucherList[0].voucherName
2026-03-04 08:58:40 +00:00
: "商品") +
"x" +
2026-03-18 16:27:42 +00:00
voucherList.length +
2026-03-04 08:58:40 +00:00
";";
2025-12-19 12:27:55 +00:00
});
2026-03-04 08:58:40 +00:00
const randomstr = Math.floor(Math.random() * 10000000) + "";
const trxamt =
item.payableAmount != null && item.payableAmount !== ""
? String(item.payableAmount)
: "1";
const params = {
appid: "00390105",
body: bodyStr,
cusid: "56479107531MPMN",
notify_url:
"http://e989c692.natappfree.cc/admin-api/member/lu-order/tlNotice",
orgid: "56479107392N35H",
paytype: "W06",
randomstr: randomstr,
orderNumber: item.orderNumber,
remark: "1:" + item.orderNumber + ":" + bodyStr,
reqsn: item.orderNumber,
sign: "",
signtype: "RSA",
trxamt,
version: "12",
};
if (item.orderNumber) {
uni.setStorageSync("lastOrderNumber", item.orderNumber);
}
try {
const sign = await getPaySign(params);
params["sign"] = sign;
uni.navigateToMiniProgram({
appId: "wxef277996acc166c3",
extraData: params,
success(res) {
console.log("小程序跳转成功", res);
},
fail(err) {
console.error("小程序跳转失败", err);
uni.showToast({ title: "跳转失败,请稍后重试", icon: "none" });
},
});
} catch (e) {
2026-03-27 01:54:40 +00:00
console.error("获取签名失败:", e);
uni.showToast({ title: "结算准备失败,请稍后重试", icon: "none" });
2026-03-04 08:58:40 +00:00
}
2025-12-19 12:27:55 +00:00
},
// 查看详情
handleViewDetail(item) {
uni.showToast({
2026-01-13 04:12:48 +00:00
title: "该功能正在开发中",
2025-12-19 12:27:55 +00:00
icon: "none",
});
},
// 评价
handleReview(item) {
uni.showToast({
2026-01-13 04:12:48 +00:00
title: "该功能正在开发中",
2025-12-19 12:27:55 +00:00
icon: "none",
});
},
2026-03-18 16:27:42 +00:00
// 点击二维码图标:打开弹窗,展示券状态 + 根据 voucherCode 生成二维码
2026-03-05 11:04:23 +00:00
handleQrCode(item, goods) {
const useStatus = goods?.useStatus ?? item?.useStatus ?? 0;
2026-03-18 16:27:42 +00:00
const voucherCode =
(goods && (goods.voucherCode || goods.voucherNo)) ||
item?.voucherCode ||
item?.voucherNo ||
2026-03-05 11:04:23 +00:00
"";
2026-03-18 16:27:42 +00:00
this.qrModalData = { useStatus, voucherCode };
2026-03-05 11:04:23 +00:00
this.qrModalVisible = true;
},
getQrUseStatusText(useStatus) {
const map = { 0: "未使用", 1: "已使用", 3: "已退款", 4: "已取消" };
return map[useStatus] ?? "未使用";
},
getQrUseStatusClass(useStatus) {
const map = {
0: "status-unused",
1: "status-used",
3: "status-refund",
4: "status-cancelled",
};
return map[useStatus] ?? "status-unused";
},
closeQrModal() {
this.qrModalVisible = false;
},
2025-12-19 12:27:55 +00:00
},
};
</script>
<style lang="scss" scoped>
.service-records-page {
min-height: 100vh;
background: #e2e8f1;
display: flex;
flex-direction: column;
}
2026-03-09 03:37:41 +00:00
.header-fixed-wrapper {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
background: #e2e8f1;
}
.main-wrap {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
}
2025-12-19 12:27:55 +00:00
/* Tab 切换栏 */
.tab-bar {
display: flex;
padding: 0 20rpx;
.tab-item {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
height: 88rpx;
position: relative;
.tab-text {
font-family: PingFang-SC, PingFang-SC;
font-weight: 500;
font-size: 28rpx;
color: #999999;
}
&.active {
.tab-text {
color: #004294;
font-weight: 600;
}
&::after {
content: "";
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 4rpx;
background-color: #004294;
border-radius: 2rpx;
}
}
}
}
/* 列表区域 */
.record-list {
flex: 1;
padding: 20rpx;
height: 0; // 配合 flex: 1 使用
box-sizing: border-box;
/* 空数据提示 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 200rpx 0;
min-height: 500rpx;
.empty-icon {
width: 200rpx;
height: 200rpx;
margin-bottom: 40rpx;
opacity: 0.5;
}
.empty-text {
font-family: PingFang-SC, PingFang-SC;
font-weight: 500;
font-size: 28rpx;
color: #999999;
}
}
/* 加载更多提示 */
.load-more {
display: flex;
justify-content: center;
align-items: center;
padding: 40rpx 0;
min-height: 80rpx;
.load-more-text {
font-family: PingFang-SC, PingFang-SC;
font-weight: 400;
font-size: 24rpx;
color: #999999;
}
}
/* 记录项 */
.record-item {
background-color: #ffffff;
border-radius: 20rpx;
margin-bottom: 20rpx;
2026-03-04 08:58:40 +00:00
padding: 24rpx 24rpx 20rpx;
2025-12-19 12:27:55 +00:00
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
.record-header {
2026-03-04 08:58:40 +00:00
margin-bottom: 16rpx;
2025-12-19 12:27:55 +00:00
2026-03-04 08:58:40 +00:00
.record-shop-row {
2025-12-19 12:27:55 +00:00
display: flex;
align-items: center;
justify-content: space-between;
2026-03-04 08:58:40 +00:00
margin-bottom: 8rpx;
2025-12-19 12:27:55 +00:00
2026-03-04 08:58:40 +00:00
.shop-name {
2025-12-19 12:27:55 +00:00
flex: 1;
font-family: PingFang-SC, PingFang-SC;
2026-03-04 08:58:40 +00:00
font-weight: 600;
font-size: 28rpx;
2025-12-19 12:27:55 +00:00
color: #1a1819;
}
.status-badge {
padding: 6rpx 16rpx;
border-radius: 20rpx;
font-size: 22rpx;
.status-text {
font-family: PingFang-SC, PingFang-SC;
font-weight: 500;
}
&.status-pending {
background-color: rgba(255, 107, 0, 0.1);
.status-text {
color: #ff6b00;
}
}
&.status-verification {
background-color: rgba(0, 66, 148, 0.1);
.status-text {
color: #004294;
}
}
&.status-completed {
background-color: rgba(76, 175, 80, 0.1);
.status-text {
color: #4caf50;
}
}
&.status-cancelled {
background-color: rgba(158, 158, 158, 0.1);
.status-text {
color: #9e9e9e;
}
}
}
}
.record-time {
font-family: PingFang-SC, PingFang-SC;
font-weight: 400;
font-size: 22rpx;
color: #999999;
}
}
.record-content {
margin-bottom: 24rpx;
.record-info-row {
display: flex;
align-items: flex-start;
margin-bottom: 16rpx;
line-height: 1.5;
&:last-child {
margin-bottom: 0;
}
.info-label {
font-family: PingFang-SC, PingFang-SC;
font-weight: 500;
font-size: 24rpx;
color: #888888;
margin-right: 8rpx;
flex-shrink: 0;
}
.info-value {
font-family: PingFang-SC, PingFang-SC;
font-weight: 500;
font-size: 24rpx;
color: #333333;
flex: 1;
&.price {
color: #d51c3c;
font-weight: 600;
font-size: 28rpx;
}
}
}
}
2026-03-04 08:58:40 +00:00
.record-body {
background-color: #f8f9fb;
border-radius: 16rpx;
padding: 18rpx;
.record-goods {
display: flex;
align-items: center;
margin-bottom: 16rpx;
.goods-image {
width: 120rpx;
height: 120rpx;
border-radius: 12rpx;
margin-right: 16rpx;
flex-shrink: 0;
}
.goods-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 8rpx;
.goods-title {
font-family: PingFang-SC, PingFang-SC;
font-weight: 500;
font-size: 26rpx;
color: #1a1819;
}
2025-12-19 12:27:55 +00:00
2026-03-04 08:58:40 +00:00
.goods-subtitle {
font-family: PingFang-SC, PingFang-SC;
font-weight: 400;
font-size: 22rpx;
color: #888888;
}
.goods-meta-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 4rpx;
.goods-price {
font-family: PingFang-SC, PingFang-SC;
font-weight: 600;
font-size: 28rpx;
color: #d51c3c;
}
.goods-count {
font-family: PingFang-SC, PingFang-SC;
font-weight: 400;
font-size: 22rpx;
color: #666666;
}
}
}
2026-03-05 11:04:23 +00:00
.qr-code-icon-wrapper {
flex-shrink: 0;
padding: 12rpx;
margin-left: 8rpx;
}
.qr-code-icon {
width: 44rpx;
height: 44rpx;
2026-03-09 03:37:41 +00:00
&.gray {
filter: grayscale(100%);
opacity: 0.6;
}
2026-03-05 11:04:23 +00:00
}
2026-03-04 08:58:40 +00:00
}
}
.record-footer {
2025-12-19 12:27:55 +00:00
display: flex;
align-items: center;
2026-03-04 08:58:40 +00:00
justify-content: space-between;
margin-top: 4rpx;
.total-info {
display: flex;
align-items: baseline;
.total-label {
font-family: PingFang-SC, PingFang-SC;
font-weight: 400;
font-size: 22rpx;
color: #666666;
}
.total-amount {
margin-left: 4rpx;
font-family: PingFang-SC, PingFang-SC;
font-weight: 600;
font-size: 30rpx;
color: #1a1819;
}
2025-12-19 12:27:55 +00:00
}
2026-03-04 08:58:40 +00:00
.record-actions {
2025-12-19 12:27:55 +00:00
display: flex;
align-items: center;
2026-03-04 08:58:40 +00:00
gap: 16rpx;
2025-12-19 12:27:55 +00:00
2026-03-04 08:58:40 +00:00
button {
margin: 0;
padding: 0;
}
.action-btn {
min-width: 150rpx;
height: 56rpx;
padding: 0 20rpx;
font-family: PingFang-SC, PingFang-SC;
font-weight: 500;
font-size: 24rpx;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
2025-12-19 12:27:55 +00:00
}
2026-03-04 08:58:40 +00:00
.pay-btn {
2025-12-19 12:27:55 +00:00
background-color: #004294;
color: #ffffff;
}
2026-03-04 08:58:40 +00:00
.detail-btn {
2025-12-19 12:27:55 +00:00
background-color: #f5f5f5;
color: #666666;
}
2026-03-04 08:58:40 +00:00
.review-btn {
2025-12-19 12:27:55 +00:00
background-color: #004294;
color: #ffffff;
}
}
}
}
}
2026-03-05 11:04:23 +00:00
/* 券码二维码弹窗 */
.qr-modal-mask {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 900;
}
.qr-modal-wrap {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 901;
display: flex;
align-items: center;
justify-content: center;
padding: 36rpx;
box-sizing: border-box;
}
.qr-modal {
width: 100%;
max-width: 720rpx;
background: #ffffff;
border-radius: 28rpx;
overflow: hidden;
box-shadow: 0 8rpx 40rpx rgba(0, 0, 0, 0.15);
}
.qr-modal-header {
position: relative;
padding: 40rpx 32rpx 28rpx;
border-bottom: 1rpx solid #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
gap: 16rpx;
}
.qr-modal-title {
font-family: PingFang-SC, PingFang-SC;
font-weight: 600;
font-size: 36rpx;
color: #1a1819;
}
.qr-modal-status {
padding: 8rpx 20rpx;
border-radius: 24rpx;
font-family: PingFang-SC, PingFang-SC;
font-weight: 500;
font-size: 24rpx;
&.status-unused {
background: rgba(0, 66, 148, 0.1);
color: #004294;
}
&.status-used {
background: rgba(158, 158, 158, 0.15);
color: #9e9e9e;
}
&.status-refund {
background: rgba(76, 175, 80, 0.1);
color: #4caf50;
}
&.status-cancelled {
background: rgba(158, 158, 158, 0.15);
color: #9e9e9e;
}
}
.qr-modal-close {
position: absolute;
right: 20rpx;
top: 50%;
transform: translateY(-50%);
width: 56rpx;
height: 56rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 44rpx;
color: #999999;
line-height: 1;
}
.qr-modal-body {
padding: 48rpx 32rpx 56rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.qr-code-box {
display: flex;
flex-direction: column;
align-items: center;
}
.qr-code-image {
width: 520rpx;
height: 520rpx;
background: #fff;
border: 2rpx solid #e8e8e8;
border-radius: 20rpx;
margin-bottom: 28rpx;
}
.qr-code-text {
font-family: PingFang-SC, PingFang-SC;
font-weight: 500;
font-size: 26rpx;
color: #333333;
word-break: break-all;
text-align: center;
padding: 0 20rpx;
}
.qr-code-empty {
font-family: PingFang-SC, PingFang-SC;
font-size: 28rpx;
color: #999999;
}
2025-12-19 12:27:55 +00:00
</style>