This commit is contained in:
sjk
2025-11-17 14:11:46 +08:00
commit ad4a600af9
1659 changed files with 171560 additions and 0 deletions

View File

@@ -0,0 +1,239 @@
import { createComment } from '../../../services/comments/createComment';
import Toast from 'tdesign-miniprogram/toast/index';
Page({
data: {
orderItem: null,
rating: 5,
content: '',
images: [],
isAnonymous: false,
submitting: false,
maxImages: 9,
maxContentLength: 500
},
onLoad(options) {
console.log('评论页面加载', options);
// 从页面参数获取订单项信息
if (options.orderItemData) {
try {
const orderItem = JSON.parse(decodeURIComponent(options.orderItemData));
this.setData({ orderItem });
console.log('订单项信息', orderItem);
} catch (e) {
console.error('解析订单项数据失败', e);
Toast({
context: this,
selector: '#t-toast',
message: '参数错误',
icon: 'error-circle',
});
setTimeout(() => {
wx.navigateBack();
}, 1500);
}
} else {
Toast({
context: this,
selector: '#t-toast',
message: '缺少订单信息',
icon: 'error-circle',
});
setTimeout(() => {
wx.navigateBack();
}, 1500);
}
},
// 评分变化
onRatingChange(e) {
this.setData({
rating: e.detail.value
});
},
// 评论内容输入
onContentInput(e) {
this.setData({
content: e.detail.value
});
},
// 匿名评论切换
onAnonymousChange(e) {
this.setData({
isAnonymous: e.detail.value
});
},
// 选择图片
onChooseImage() {
const { images, maxImages } = this.data;
const remainCount = maxImages - images.length;
if (remainCount <= 0) {
Toast({
context: this,
selector: '#t-toast',
message: `最多只能上传${maxImages}张图片`,
icon: 'error-circle',
});
return;
}
wx.chooseMedia({
count: remainCount,
mediaType: ['image'],
sourceType: ['album', 'camera'],
success: (res) => {
const newImages = res.tempFiles.map(file => file.tempFilePath);
this.setData({
images: [...images, ...newImages]
});
},
fail: (err) => {
console.error('选择图片失败', err);
Toast({
context: this,
selector: '#t-toast',
message: '选择图片失败',
icon: 'error-circle',
});
}
});
},
// 删除图片
onDeleteImage(e) {
const { index } = e.currentTarget.dataset;
const { images } = this.data;
images.splice(index, 1);
this.setData({ images });
},
// 预览图片
onPreviewImage(e) {
const { index } = e.currentTarget.dataset;
const { images } = this.data;
wx.previewImage({
current: images[index],
urls: images
});
},
// 上传图片到服务器
async uploadImages(images) {
const uploadPromises = images.map(imagePath => {
return new Promise((resolve, reject) => {
wx.uploadFile({
url: `${getApp().globalData.config.apiBaseUrl}/upload/image`,
filePath: imagePath,
name: 'file',
header: {
'Authorization': `Bearer ${wx.getStorageSync('token')}`
},
success: (res) => {
try {
const data = JSON.parse(res.data);
if (data.code === 200) {
resolve(data.data.url);
} else {
reject(new Error(data.message || '上传失败'));
}
} catch (e) {
reject(new Error('解析上传结果失败'));
}
},
fail: reject
});
});
});
return Promise.all(uploadPromises);
},
// 提交评论
async onSubmit() {
const { orderItem, rating, content, images, isAnonymous, submitting } = this.data;
if (submitting) return;
if (!content.trim()) {
Toast({
context: this,
selector: '#t-toast',
message: '请输入评论内容',
icon: 'error-circle',
});
return;
}
this.setData({ submitting: true });
try {
// 上传图片
let uploadedImages = [];
if (images.length > 0) {
Toast({
context: this,
selector: '#t-toast',
message: '正在上传图片...',
icon: 'loading',
});
uploadedImages = await this.uploadImages(images);
}
// 提交评论
const commentData = {
orderItemId: orderItem.id,
productId: orderItem.product_id,
rating,
content: content.trim(),
images: uploadedImages,
isAnonymous
};
await createComment(commentData);
Toast({
context: this,
selector: '#t-toast',
message: '评论提交成功',
icon: 'check-circle',
});
// 设置上一页刷新标志
const pages = getCurrentPages();
const prevPage = pages[pages.length - 2]; // 上一页(订单详情页)
if (prevPage) {
prevPage.setData({ backRefresh: true });
}
// 延迟返回上一页
setTimeout(() => {
wx.navigateBack({
delta: 1
});
}, 1500);
} catch (error) {
console.error('提交评论失败', error);
Toast({
context: this,
selector: '#t-toast',
message: error.message || '提交失败,请重试',
icon: 'error-circle',
});
} finally {
this.setData({ submitting: false });
}
},
// 返回上一页
onBack() {
wx.navigateBack();
}
});

View File

@@ -0,0 +1,13 @@
{
"usingComponents": {
"t-navbar": "tdesign-miniprogram/navbar/navbar",
"t-rate": "tdesign-miniprogram/rate/rate",
"t-textarea": "tdesign-miniprogram/textarea/textarea",
"t-icon": "tdesign-miniprogram/icon/icon",
"t-switch": "tdesign-miniprogram/switch/switch",
"t-button": "tdesign-miniprogram/button/button",
"t-toast": "tdesign-miniprogram/toast/toast",
"price": "/components/price/index"
},
"navigationStyle": "custom"
}

View File

@@ -0,0 +1,106 @@
<view class="comment-page">
<!-- 导航栏 -->
<t-navbar title="评价商品" left-arrow bind:left-click="onBack" />
<!-- 商品信息 -->
<view class="product-info" wx:if="{{orderItem}}">
<image class="product-image" src="{{orderItem.product.images[0] || '/assets/placeholder.png'}}" mode="aspectFill" />
<view class="product-details">
<view class="product-name">{{orderItem.product.name}}</view>
<view class="product-spec" wx:if="{{orderItem.product_spec}}">{{orderItem.product_spec}}</view>
<view class="product-price">
<price price="{{orderItem.price}}" />
</view>
</view>
</view>
<!-- 评分 -->
<view class="rating-section">
<view class="section-title">商品评分</view>
<t-rate
value="{{rating}}"
size="60rpx"
color="#ff6b35"
bind:change="onRatingChange"
allow-half="{{false}}"
/>
</view>
<!-- 评论内容 -->
<view class="content-section">
<view class="section-title">评价内容</view>
<t-textarea
value="{{content}}"
placeholder="请输入您的评价内容..."
maxlength="{{maxContentLength}}"
indicator="{{true}}"
autosize="{{true}}"
bind:change="onContentInput"
t-class="comment-textarea"
/>
</view>
<!-- 图片上传 -->
<view class="images-section">
<view class="section-title">上传图片(可选)</view>
<view class="images-grid">
<view
class="image-item"
wx:for="{{images}}"
wx:key="index"
bind:tap="onPreviewImage"
data-index="{{index}}"
>
<image src="{{item}}" mode="aspectFill" class="uploaded-image" />
<view
class="delete-btn"
bind:tap="onDeleteImage"
data-index="{{index}}"
catch:tap="true"
>
<t-icon name="close" size="24rpx" color="#fff" />
</view>
</view>
<view
class="add-image-btn"
wx:if="{{images.length < maxImages}}"
bind:tap="onChooseImage"
>
<t-icon name="add" size="48rpx" color="#999" />
<text class="add-text">添加图片</text>
</view>
</view>
<view class="images-tip">最多可上传{{maxImages}}张图片</view>
</view>
<!-- 匿名评论 -->
<view class="anonymous-section">
<view class="anonymous-item">
<text class="anonymous-label">匿名评论</text>
<t-switch
value="{{isAnonymous}}"
bind:change="onAnonymousChange"
size="large"
/>
</view>
<view class="anonymous-tip">开启后,您的用户名将不会显示</view>
</view>
<!-- 提交按钮 -->
<view class="submit-section">
<t-button
theme="primary"
size="large"
loading="{{submitting}}"
disabled="{{submitting}}"
bind:tap="onSubmit"
t-class="submit-btn"
>
{{submitting ? '提交中...' : '提交评价'}}
</t-button>
</view>
<!-- Toast -->
<t-toast id="t-toast" />
</view>

View File

@@ -0,0 +1,179 @@
.comment-page {
background-color: #f5f5f5;
min-height: 100vh;
padding-bottom: 120rpx;
}
/* 商品信息 */
.product-info {
background: #fff;
padding: 32rpx;
margin-bottom: 20rpx;
display: flex;
align-items: center;
}
.product-image {
width: 120rpx;
height: 120rpx;
border-radius: 12rpx;
margin-right: 24rpx;
flex-shrink: 0;
}
.product-details {
flex: 1;
}
.product-name {
font-size: 32rpx;
color: #333;
font-weight: 500;
margin-bottom: 8rpx;
line-height: 1.4;
}
.product-spec {
font-size: 24rpx;
color: #999;
margin-bottom: 8rpx;
}
.product-price {
font-size: 28rpx;
color: #ff6b35;
font-weight: 600;
}
/* 评分区域 */
.rating-section {
background: #fff;
padding: 32rpx;
margin-bottom: 20rpx;
}
.section-title {
font-size: 32rpx;
color: #333;
font-weight: 500;
margin-bottom: 24rpx;
}
/* 评论内容 */
.content-section {
background: #fff;
padding: 32rpx;
margin-bottom: 20rpx;
}
.comment-textarea {
margin-top: 16rpx;
}
/* 图片上传 */
.images-section {
background: #fff;
padding: 32rpx;
margin-bottom: 20rpx;
}
.images-grid {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
margin-top: 16rpx;
}
.image-item {
position: relative;
width: 160rpx;
height: 160rpx;
}
.uploaded-image {
width: 100%;
height: 100%;
border-radius: 12rpx;
object-fit: cover;
}
.delete-btn {
position: absolute;
top: -8rpx;
right: -8rpx;
width: 32rpx;
height: 32rpx;
background: rgba(0, 0, 0, 0.6);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.add-image-btn {
width: 160rpx;
height: 160rpx;
border: 2rpx dashed #ddd;
border-radius: 12rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: #fafafa;
}
.add-text {
font-size: 24rpx;
color: #999;
margin-top: 8rpx;
}
.images-tip {
font-size: 24rpx;
color: #999;
margin-top: 16rpx;
}
/* 匿名评论 */
.anonymous-section {
background: #fff;
padding: 32rpx;
margin-bottom: 20rpx;
}
.anonymous-item {
display: flex;
align-items: center;
justify-content: space-between;
}
.anonymous-label {
font-size: 32rpx;
color: #333;
}
.anonymous-tip {
font-size: 24rpx;
color: #999;
margin-top: 16rpx;
}
/* 提交按钮 */
.submit-section {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #fff;
padding: 24rpx 32rpx;
border-top: 1rpx solid #eee;
z-index: 100;
}
.submit-btn {
width: 100%;
height: 88rpx;
border-radius: 44rpx;
}