统一排行榜对齐星雀UI,页面资源后台配置实时刷新

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-06-27 01:26:11 +08:00
parent 1ab2e2080a
commit 21112173f2
292 changed files with 64010 additions and 81 deletions

View File

@@ -0,0 +1,412 @@
// pages/dingdanxiangqing/dingdanxiangqing.js
const app = getApp()
import request from '../../utils/request.js'
Page({
data: {
// 从跳转参数获取的基础数据
jibenShuju: {
dingdanId: '',
tupian: '',
jieshao: '',
chuangjianshijian: '',
jine: '',
nicheng: '',
beizhu: '',
zhuangtai: 0
},
// 从后端获取的详细数据
xiangxiShuju: {
zhiding: '', // 指定打手
dashou: '', // 服务打手
dashoujiaofu: [], // 打手交付图片列表
dashouliuyan: '' // 打手留言
},
// 结算相关数据
jiesuanShuju: {
pingfen: 0, // 评分 0-5
liuyan: '' // 留言
},
// 页面状态
isLoading: true, // 页面加载中
isJiesuanLoading: false, // 结单请求中
// 状态颜色映射
zhuangtaiYanseMap: {
1: '#E8F5E9', // 已下单 - 浅绿色
2: '#E3F2FD', // 进行中 - 浅蓝色
3: '#F3E5F5', // 已完成 - 浅紫色
4: '#FFF3E0', // 退款中 - 浅橙色
5: '#FFEBEE', // 已退款 - 浅红色
6: '#EFEBE9', // 退款失败 - 浅棕色
7: '#E0F7FA', // 指定中 - 浅青色
8: '#FFF8E1' // 结算中 - 浅黄色
},
// 状态文字映射
zhuangtaiWenziMap: {
1: '已下单',
2: '进行中',
3: '已完成',
4: '退款中',
5: '已退款',
6: '退款失败',
7: '指定中',
8: '结算中'
},
// 星星评分数据
xingxingData: [
{ id: 1, active: false },
{ id: 2, active: false },
{ id: 3, active: false },
{ id: 4, active: false },
{ id: 5, active: false }
]
},
onLoad(options) {
// 设置页面标题
wx.setNavigationBarTitle({
title: '订单详情'
})
// 解析跳转参数
this.jiexiTiaozhuanCanshu(options)
},
onShow() {
// 原有代码...
// 🆕 注册通知组件
this.registerNotificationComponent();
},
// 🆕 新增:注册通知组件
registerNotificationComponent() {
const app = getApp();
const notificationComp = this.selectComponent('#global-notification');
if (notificationComp && notificationComp.showNotification) {
console.log('🏪 商城页面注册通知组件');
app.globalData.globalNotification = {
show: (data) => notificationComp.showNotification(data),
hide: () => notificationComp.hideNotification()
};
}
},
/**
* 解析跳转参数
*/
jiexiTiaozhuanCanshu(options) {
try {
const dingdanDataStr = options.dingdanData || ''
if (!dingdanDataStr) {
wx.showToast({
title: '订单数据错误',
icon: 'none'
})
setTimeout(() => {
wx.navigateBack()
}, 1500)
return
}
// 解析订单数据
const dingdanData = JSON.parse(decodeURIComponent(dingdanDataStr))
// 处理图片URL拼接完整路径
let tupianUrl = dingdanData.tupian || ''
if (tupianUrl && !tupianUrl.startsWith('http')) {
const ossImageUrl = app.globalData.ossImageUrl || ''
tupianUrl = ossImageUrl + tupianUrl
}
// 格式化价格
let jine = dingdanData.jine || 0
jine = parseFloat(jine)
if (isNaN(jine)) {
jine = 0
}
const formattedJine = jine.toFixed(2)
// 设置基础数据(状态先用跳转的,等后端返回后更新)
this.setData({
'jibenShuju.dingdanId': dingdanData.dingdanId || '',
'jibenShuju.tupian': tupianUrl,
'jibenShuju.jieshao': dingdanData.jieshao || '',
'jibenShuju.chuangjianshijian': dingdanData.chuangjianshijian || '',
'jibenShuju.jine': formattedJine,
'jibenShuju.nicheng': dingdanData.nicheng || '',
'jibenShuju.beizhu': dingdanData.beizhu || '',
// 这里先使用跳转的状态,等后端返回后会被覆盖
'jibenShuju.zhuangtai': dingdanData.zhuangtai || 0,
isLoading: false
})
// 加载详细数据
this.jiazaiXiangxiShuju(dingdanData.dingdanId)
} catch (error) {
console.error('解析订单数据失败:', error)
wx.showToast({
title: '数据解析失败',
icon: 'none'
})
setTimeout(() => {
wx.navigateBack()
}, 1500)
}
},
/**
* 加载详细数据
*/
async jiazaiXiangxiShuju(dingdanId) {
if (!dingdanId) return
try {
const res = await request({
url: '/dingdan/dingdanxiangqing',
method: 'POST',
data: { dingdanId: dingdanId },
header: { 'content-type': 'application/json' }
})
// 关键修正:使用正确的数据访问路径
if (res && res.data.code === 0 && res.data.data) {
const data = res.data.data
// 处理打手交付图片拼接完整URL
let dashoujiaofuList = data.dashoujiaofu || []
dashoujiaofuList = dashoujiaofuList.map(imgUrl => {
if (imgUrl && !imgUrl.startsWith('http')) {
const ossImageUrl = app.globalData.ossImageUrl || ''
return ossImageUrl + imgUrl
}
return imgUrl
})
// 核心修正:使用后端返回的订单状态,覆盖跳转时的状态
this.setData({
'xiangxiShuju.zhiding': data.zhiding || '',
'xiangxiShuju.dashou': data.dashou || '',
'xiangxiShuju.dashoujiaofu': dashoujiaofuList,
'xiangxiShuju.dashouliuyan': data.dashouliuyan || '',
// 关键:使用后端返回的状态覆盖跳转的状态
'jibenShuju.zhuangtai': data.zhuangtai || 0
})
} else {
console.warn('获取详细数据失败:', res?.msg || '未知错误')
wx.showToast({
title: res?.msg || '获取订单详情失败',
icon: 'none',
duration: 2000
})
}
} catch (error) {
console.error('加载详细数据失败:', error)
wx.showToast({
title: '加载数据失败,请重试',
icon: 'none',
duration: 2000
})
}
},
/**
* 复制文本到剪贴板
*/
async fuzhiWenben(e) {
const text = e.currentTarget.dataset.text
if (!text) return
try {
await wx.setClipboardData({
data: text
})
wx.showToast({
title: '复制成功',
icon: 'success',
duration: 1500
})
} catch (error) {
console.error('复制失败:', error)
wx.showToast({
title: '复制失败',
icon: 'none'
})
}
},
/**
* 预览图片
*/
yulanTupian(e) {
const currentUrl = e.currentTarget.dataset.url
const urls = e.currentTarget.dataset.urls || []
if (!currentUrl) return
wx.previewImage({
current: currentUrl,
urls: urls.length > 0 ? urls : [currentUrl]
})
},
/**
* 点击星星评分
*/
dianjiXingxing(e) {
const pingfen = e.currentTarget.dataset.index
// 更新星星状态
const xingxingData = this.data.xingxingData.map((item, index) => ({
...item,
active: index < pingfen
}))
this.setData({
xingxingData: xingxingData,
'jiesuanShuju.pingfen': pingfen
})
},
/**
* 输入留言
*/
shuruLiuyan(e) {
const liuyan = e.detail.value.slice(0, 50) // 限制50字
this.setData({
'jiesuanShuju.liuyan': liuyan
})
},
/**
* 提交结单
*/
async tijiaoJiedan() {
const { jibenShuju, jiesuanShuju } = this.data
console.log('提交结单,数据:', {
dingdanId: jibenShuju.dingdanId,
pingfen: jiesuanShuju.pingfen,
liuyan: jiesuanShuju.liuyan
})
// 验证订单状态
if (jibenShuju.zhuangtai !== 8) {
wx.showToast({
title: '订单不在结算状态',
icon: 'none'
})
return
}
// 验证评分范围
if (jiesuanShuju.pingfen < 0 || jiesuanShuju.pingfen > 5) {
wx.showToast({
title: '请选择0-5分评分',
icon: 'none'
})
return
}
// 验证订单ID
if (!jibenShuju.dingdanId) {
wx.showToast({
title: '订单信息错误',
icon: 'none'
})
return
}
// 显示加载中
this.setData({ isJiesuanLoading: true })
wx.showLoading({
title: '提交中...',
mask: true
})
try {
const res = await request({
url: '/dingdan/jiedan',
method: 'POST',
data: {
dingdanId: jibenShuju.dingdanId,
pingfen: jiesuanShuju.pingfen,
liuyan: jiesuanShuju.liuyan
},
header: { 'content-type': 'application/json' }
})
wx.hideLoading()
this.setData({ isJiesuanLoading: false })
// 使用正确的数据访问路径
if (res && res.data.code === 0) {
// 结单成功,更新订单状态
this.setData({
'jibenShuju.zhuangtai': 3, // 变为已完成状态
'jiesuanShuju.pingfen': 0,
'jiesuanShuju.liuyan': ''
})
// 重置星星
const resetXingxingData = this.data.xingxingData.map(item => ({
...item,
active: false
}))
this.setData({ xingxingData: resetXingxingData })
wx.showToast({
title: '结单成功',
icon: 'success',
duration: 2000
})
} else {
wx.showToast({
title: res?.msg || '结单失败',
icon: 'none'
})
}
} catch (error) {
console.error('结单失败:', error)
wx.hideLoading()
this.setData({ isJiesuanLoading: false })
wx.showToast({
title: '网络错误,请重试',
icon: 'none'
})
}
},
})

View File

@@ -0,0 +1,5 @@
{
"usingComponents": {
"global-notification": "/components/global-notification/global-notification"
}
}

View File

@@ -0,0 +1,202 @@
<!--pages/dingdanxiangqing/dingdanxiangqing.wxml-->
<view class="dingdanxiangqing-page">
<!-- 加载中状态 -->
<view class="loading-container" wx:if="{{isLoading}}">
<view class="loading-spinner"></view>
<text class="loading-text">加载订单详情...</text>
</view>
<!-- 内容区域 -->
<view class="content-container" wx:if="{{!isLoading}}">
<!-- 商品图片和介绍区域 -->
<view class="shangpin-area">
<view class="shangpin-image-container">
<image
class="shangpin-image"
src="{{jibenShuju.tupian}}"
mode="aspectFill"
binderror="onImageError"
></image>
</view>
<view class="shangpin-jieshao">
<text class="jieshao-text">{{jibenShuju.jieshao || '暂无描述'}}</text>
</view>
</view>
<!-- 订单信息区域 -->
<view
class="dingdan-info-area"
style="background-color: {{zhuangtaiYanseMap[jibenShuju.zhuangtai] || '#F5F5F5'}}"
>
<view class="info-title">订单信息</view>
<!-- 游戏昵称 -->
<view class="info-item-row" wx:if="{{jibenShuju.nicheng}}">
<text class="item-label">游戏昵称:</text>
<text class="item-value">{{jibenShuju.nicheng}}</text>
</view>
<!-- 备注信息 -->
<view class="info-item-row" wx:if="{{jibenShuju.beizhu}}">
<text class="item-label">备注信息:</text>
<text class="item-value">{{jibenShuju.beizhu}}</text>
</view>
<!-- 指定打手 -->
<view class="info-item-row" wx:if="{{xiangxiShuju.zhiding}}">
<text class="item-label">指定打手:</text>
<text class="item-value">{{xiangxiShuju.zhiding}}</text>
</view>
<!-- 订单ID可复制 -->
<view class="info-item-row">
<text class="item-label">订单ID</text>
<view class="item-right-area">
<text class="item-value">{{jibenShuju.dingdanId}}</text>
<view
class="copy-btn"
bindtap="fuzhiWenben"
data-text="{{jibenShuju.dingdanId}}"
hover-class="copy-btn-hover"
>
<text class="copy-icon">📋</text>
<text class="copy-text">复制</text>
</view>
</view>
</view>
<!-- 创建时间 -->
<view class="info-item-row">
<text class="item-label">创建时间:</text>
<text class="item-value">{{jibenShuju.chuangjianshijian}}</text>
</view>
<!-- 订单价格(红色) -->
<view class="info-item-row">
<text class="item-label">订单价格:</text>
<text class="item-value jine-red">¥{{jibenShuju.jine}}</text>
</view>
<!-- 订单状态 -->
<view class="info-item-row">
<text class="item-label">订单状态:</text>
<text class="item-value zhuangtai-text">{{zhuangtaiWenziMap[jibenShuju.zhuangtai] || '未知状态'}}</text>
</view>
</view>
<!-- 服务区域(有服务数据时显示) -->
<view
class="fuwu-area"
wx:if="{{xiangxiShuju.dashou || xiangxiShuju.dashoujiaofu.length > 0 || xiangxiShuju.dashouliuyan}}"
>
<view class="info-title">服务详情</view>
<!-- 服务打手(可复制) -->
<view class="info-item-row" wx:if="{{xiangxiShuju.dashou}}">
<text class="item-label">服务打手:</text>
<view class="item-right-area">
<text class="item-value">{{xiangxiShuju.dashou}}</text>
<view
class="copy-btn"
bindtap="fuzhiWenben"
data-text="{{xiangxiShuju.dashou}}"
hover-class="copy-btn-hover"
>
<text class="copy-icon">📋</text>
<text class="copy-text">复制</text>
</view>
</view>
</view>
<!-- 打手交付图片 -->
<view class="dashou-jiaofu-container" wx:if="{{xiangxiShuju.dashoujiaofu.length > 0}}">
<text class="section-subtitle">打手交付</text>
<view class="jiaofu-grid">
<block wx:for="{{xiangxiShuju.dashoujiaofu}}" wx:key="index">
<view
class="jiaofu-image-item"
bindtap="yulanTupian"
data-url="{{item}}"
data-urls="{{xiangxiShuju.dashoujiaofu}}"
>
<image
class="jiaofu-image"
src="{{item}}"
mode="aspectFill"
></image>
</view>
</block>
</view>
</view>
<!-- 打手留言 -->
<view class="dashou-liuyan-container" wx:if="{{xiangxiShuju.dashouliuyan}}">
<text class="section-subtitle">打手留言</text>
<view class="liuyan-content">
{{xiangxiShuju.dashouliuyan}}
</view>
</view>
</view>
<!-- 结算区域(仅状态=8时显示 -->
<view class="jiesuan-area" wx:if="{{jibenShuju.zhuangtai == 8}}">
<view class="info-title">订单结算</view>
<!-- 星星评分 -->
<view class="pingfen-container">
<view class="xingxing-layout">
<text class="section-subtitle">打星评分:</text>
<view class="xingxing-wrapper">
<block wx:for="{{xingxingData}}" wx:key="id">
<text
class="xingxing-icon {{item.active ? 'xingxing-active' : ''}}"
bindtap="dianjiXingxing"
data-index="{{index + 1}}"
>
{{item.active ? '★' : '☆'}}
</text>
</block>
</view>
</view>
</view>
<!-- 留言输入 -->
<view class="liuyan-input-container">
<text class="section-subtitle">订单留言(可选)</text>
<textarea
class="liuyan-textarea"
value="{{jiesuanShuju.liuyan}}"
placeholder="请输入留言最多50字"
maxlength="50"
bindinput="shuruLiuyan"
></textarea>
<text class="zi-shu">
已输入 {{jiesuanShuju.liuyan.length}}/50 字
</text>
</view>
</view>
<!-- 底部安全区域 -->
<view class="safe-area"></view>
</view>
<!-- 结单按钮(固定在底部,仅状态=8时显示 -->
<view
class="jiedan-btn-container"
wx:if="{{!isLoading && jibenShuju.zhuangtai == 8}}"
>
<button
class="jiedan-btn"
bindtap="tijiaoJiedan"
hover-class="btn-hover"
loading="{{isJiesuanLoading}}"
disabled="{{isJiesuanLoading}}"
>
<text class="btn-text">结单</text>
<view class="btn-sparkle"></view>
</button>
</view>
</view>
<global-notification id="global-notification" />

View File

@@ -0,0 +1,422 @@
/* pages/dingdanxiangqing/dingdanxiangqing.wxss */
/* 页面基础样式 */
.dingdanxiangqing-page {
min-height: 100vh;
background-color: #f8f9fa;
padding-bottom: 140rpx;
}
/* 加载中状态 */
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 60vh;
}
.loading-spinner {
width: 80rpx;
height: 80rpx;
border: 8rpx solid #e0e0e0;
border-top-color: #4caf50;
border-radius: 50%;
animation: spin 1.2s linear infinite;
margin-bottom: 30rpx;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.loading-text {
font-size: 30rpx;
color: #666666;
}
/* 内容区域 */
.content-container {
padding: 25rpx;
}
/* 商品图片和介绍区域 */
.shangpin-area {
display: flex;
background-color: #ffffff;
border-radius: 20rpx;
padding: 25rpx;
margin-bottom: 25rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
}
.shangpin-image-container {
flex-shrink: 0;
width: 180rpx;
height: 180rpx;
margin-right: 25rpx;
}
.shangpin-image {
width: 100%;
height: 100%;
border-radius: 12rpx;
background-color: #f5f5f5;
}
.shangpin-jieshao {
flex: 1;
display: flex;
align-items: flex-start;
}
.jieshao-text {
font-size: 28rpx;
line-height: 42rpx;
color: #333333;
font-weight: 400;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4;
overflow: hidden;
text-overflow: ellipsis;
}
/* 通用区域样式 */
.info-title {
font-size: 32rpx;
color: #333333;
font-weight: 600;
margin-bottom: 20rpx;
padding-bottom: 12rpx;
border-bottom: 2rpx solid rgba(0, 0, 0, 0.08);
}
.section-subtitle {
font-size: 28rpx;
color: #555555;
font-weight: 500;
display: block;
}
/* 左右布局的订单信息项 */
.dingdan-info-area {
background-color: #ffffff;
border-radius: 20rpx;
padding: 25rpx;
margin-bottom: 25rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
}
.info-item-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 18rpx;
padding: 12rpx 0;
}
.info-item-row:last-child {
margin-bottom: 0;
}
.item-label {
font-size: 28rpx;
color: #666666;
font-weight: 400;
flex-shrink: 0;
min-width: 150rpx;
}
/* 右侧区域容器 */
.item-right-area {
flex: 1;
display: flex;
align-items: center;
justify-content: flex-end;
}
.item-value {
font-size: 28rpx;
color: #333333;
font-weight: 500;
word-break: break-all;
text-align: right;
margin-right: 15rpx;
}
/* 特殊样式 */
.jine-red {
color: #ff4444 !important;
font-weight: 600 !important;
font-size: 32rpx !important;
}
.zhuangtai-text {
font-weight: 600 !important;
font-size: 30rpx !important;
color: #333333 !important;
}
/* 复制按钮 */
.copy-btn {
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
color: #4caf50;
background-color: #e8f5e9;
padding: 6rpx 16rpx;
border-radius: 20rpx;
border: 1rpx solid #4caf50;
transition: all 0.2s ease;
white-space: nowrap;
flex-shrink: 0;
}
.copy-btn-hover {
background-color: #c8e6c9;
transform: scale(0.95);
}
.copy-icon {
font-size: 20rpx;
margin-right: 6rpx;
}
.copy-text {
font-weight: 500;
}
/* 服务区域 */
.fuwu-area {
background-color: #ffffff;
border-radius: 20rpx;
padding: 25rpx;
margin-bottom: 25rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
}
/* 打手交付图片网格 */
.dashou-jiaofu-container {
margin-bottom: 20rpx;
margin-top: 15rpx;
}
.jiaofu-grid {
display: flex;
flex-wrap: wrap;
margin: -5rpx;
}
.jiaofu-image-item {
width: calc(33.333% - 10rpx);
margin: 5rpx;
aspect-ratio: 1/1;
}
.jiaofu-image {
width: 100%;
height: 100%;
border-radius: 12rpx;
background-color: #f5f5f5;
transition: transform 0.2s ease;
}
.jiaofu-image:active {
transform: scale(0.95);
}
/* 打手留言 */
.dashou-liuyan-container {
margin-top: 15rpx;
}
.liuyan-content {
font-size: 26rpx;
line-height: 40rpx;
color: #555555;
padding: 15rpx;
background-color: #f9f9f9;
border-radius: 12rpx;
border-left: 4rpx solid #4caf50;
}
/* 结算区域 */
.jiesuan-area {
background-color: #ffffff;
border-radius: 20rpx;
padding: 25rpx;
margin-bottom: 25rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
}
/* 星星评分布局修正 */
.pingfen-container {
margin-bottom: 25rpx;
}
.xingxing-layout {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10rpx;
}
.xingxing-wrapper {
display: flex;
align-items: center;
}
.xingxing-icon {
font-size: 52rpx;
color: #cccccc;
margin-right: 10rpx;
transition: all 0.3s ease;
cursor: pointer;
/* 去掉点击时的蓝色矩形框 */
user-select: none;
-webkit-tap-highlight-color: transparent;
outline: none;
border: none;
background: none;
}
.xingxing-icon:last-child {
margin-right: 0;
}
.xingxing-active {
color: #FFD700;
text-shadow: 0 0 10rpx rgba(255, 215, 0, 0.5);
transform: scale(1.1);
}
.xingxing-icon:active {
transform: scale(0.9);
}
/* 留言输入 */
.liuyan-input-container {
margin-top: 15rpx;
}
.liuyan-textarea {
width: 100%;
min-height: 120rpx;
font-size: 28rpx;
color: #333333;
background-color: #f9f9f9;
border-radius: 12rpx;
padding: 20rpx;
margin-top: 10rpx;
box-sizing: border-box;
}
.zi-shu {
display: block;
text-align: right;
font-size: 24rpx;
color: #999999;
margin-top: 8rpx;
}
/* 底部安全区域 */
.safe-area {
height: 40rpx;
}
/* 结单按钮容器修正 */
.jiedan-btn-container {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(to top, rgba(255,255,255,0.9), transparent);
padding: 20rpx 30rpx;
backdrop-filter: blur(10rpx);
z-index: 100;
}
.jiedan-btn {
background: linear-gradient(135deg, #4caf50, #2e7d32);
color: #ffffff;
border: none;
border-radius: 50rpx;
height: 90rpx;
font-size: 32rpx;
font-weight: 600;
position: relative;
overflow: hidden;
box-shadow: 0 6rpx 20rpx rgba(76, 175, 80, 0.3);
transition: all 0.3s ease;
width: 100%;
/* 垂直居中 */
display: flex;
align-items: center;
justify-content: center;
}
.jiedan-btn::after {
border: none;
}
.btn-hover {
transform: translateY(-2rpx);
box-shadow: 0 8rpx 25rpx rgba(76, 175, 80, 0.4);
}
.btn-text {
position: relative;
z-index: 2;
/* 确保文字垂直居中 */
line-height: 1;
}
/* 按钮闪光特效 */
.btn-sparkle {
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(255,255,255,0.3) 1%, transparent 10%);
animation: sparkle 2s infinite linear;
z-index: 1;
}
@keyframes sparkle {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* 响应式调整 */
@media (max-width: 375px) {
.shangpin-image-container {
width: 160rpx;
height: 160rpx;
}
.xingxing-icon {
font-size: 48rpx;
}
.jiedan-btn {
height: 85rpx;
font-size: 30rpx;
}
.item-label {
min-width: 140rpx;
font-size: 26rpx;
}
.item-value {
font-size: 26rpx;
}
.jiedan-btn-container {
padding: 20rpx 25rpx;
}
}