Files
medical-mall/pages/mall/delivery/feedback.uvue
2026-01-28 19:13:13 +08:00

451 lines
10 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="feedback-container">
<!-- 顶部导航栏 -->
<view class="header-bar">
<view class="nav-left" @click="goBack">
<text class="nav-icon">←</text>
</view>
<text class="page-title">意见反馈</text>
<view class="nav-right"></view>
</view>
<!-- 表单区域 -->
<view class="form-wrapper">
<!-- 问题类型 -->
<view class="form-item">
<text class="label">问题类型</text>
<picker mode="selector" :range="feedbackTypes" @change="onTypeChange" :value="selectedTypeIndex">
<view class="picker-input">{{ feedbackTypes[selectedTypeIndex] }}</view>
</picker>
</view>
<!-- 标题 -->
<view class="form-item">
<text class="label">标题</text>
<input
type="text"
placeholder="请简要描述问题"
v-model="title"
class="input-field"
maxlength="50"
/>
</view>
<!-- 内容 -->
<view class="form-item">
<text class="label">详细内容</text>
<textarea
placeholder="请描述具体问题、发生时间、订单号等信息至少10字"
v-model="content"
class="textarea-field"
maxlength="500"
auto-height
/>
</view>
<!-- 上传截图(可选) -->
<view class="form-item">
<text class="label">上传截图(可选)</text>
<view class="upload-area" @click="chooseImage">
<text class="upload-icon">🖼️</text>
<text class="upload-text">点击上传截图</text>
<text class="upload-tip">支持 JPG/PNG最多3张</text>
</view>
<!-- 已上传图片预览 -->
<view class="preview-list" v-if="previewImages.length > 0">
<view class="preview-item" v-for="(img, index) in previewImages" :key="index">
<image :src="img" class="preview-img" mode="aspectFill" />
<text class="remove-btn" @click="removeImage(index)">×</text>
</view>
</view>
</view>
<!-- 关联订单号(下拉选择) -->
<view class="form-item">
<text class="label">关联订单号(可选)</text>
<picker mode="selector" :range="orderOptions" @change="onOrderChange" :value="selectedOrderIndex">
<view class="picker-input">
{{ selectedOrderIndex === -1 ? '请选择订单' : orderOptions[selectedOrderIndex] }}
</view>
</picker>
</view>
<!-- 提交按钮 -->
<view class="submit-section">
<button
class="submit-btn"
:disabled="!isValid || isSubmitting"
@click="submitFeedback"
>
{{ isSubmitting ? '提交中...' : '提交反馈' }}
</button>
</view>
</view>
<!-- 底部提示 -->
<view class="footer-tip">
<text>您的反馈将被优先处理我们将在24小时内回复</text>
</view>
</view>
</template>
<script lang="uts">
export default {
data() {
return {
// 表单数据
title: '',
content: '',
selectedTypeIndex: 0,
selectedOrderIndex: -1, // -1 表示未选择
previewImages: [] as string[],
// 配置
feedbackTypes: [
'订单问题',
'配送异常',
'系统故障',
'账号/认证问题',
'车辆/设备问题',
'收入结算问题',
'其他'
],
// 模拟历史订单(实际项目中应从接口获取)
orders: [
{ id: 'ORD20250122001', status: '已完成', created_at: '2025-01-22 14:30' },
{ id: 'ORD20250122002', status: '配送中', created_at: '2025-01-22 13:15' },
{ id: 'ORD20250122003', status: '已取消', created_at: '2025-01-22 10:45' },
{ id: 'ORD20250122004', status: '待接单', created_at: '2025-01-22 09:20' }
],
isSubmitting: false
}
},
computed: {
// 订单选项:格式为 "ORDxxx - 状态 - 时间"
orderOptions() {
if (this.orders.length === 0) return ['无可用订单']
return this.orders.map(order =>
`${order.id} - ${order.status} - ${order.created_at.split(' ')[0]}`
)
},
isValid() {
return this.title.trim().length >= 2 &&
this.content.trim().length >= 10 &&
this.selectedTypeIndex >= 0
}
},
methods: {
goBack() {
uni.navigateBack()
},
onTypeChange(e: UniEvent<HTMLInputElement>) {
this.selectedTypeIndex = e.detail.value as number
},
onOrderChange(e: UniEvent<HTMLInputElement>) {
const index = e.detail.value as number
this.selectedOrderIndex = index
// 如果选择了有效订单,自动填充 orderId 字段(可选)
if (index >= 0 && index < this.orders.length) {
// 实际业务中可绑定 order.id 到某个字段,此处仅作示意
} else {
// 未选择时清空
}
},
chooseImage() {
if (this.previewImages.length >= 3) {
uni.showToast({
title: '最多上传3张图片',
icon: 'none'
})
return
}
uni.chooseImage({
count: 3 - this.previewImages.length,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
const tempFilePaths = res.tempFilePaths
const newImages = [...this.previewImages, ...tempFilePaths]
if (newImages.length > 3) {
this.previewImages = newImages.slice(0, 3)
} else {
this.previewImages = newImages
}
}
})
},
removeImage(index: number) {
this.previewImages.splice(index, 1)
},
submitFeedback() {
if (!this.isValid) {
let errorMsg = ''
if (this.title.trim().length < 2) {
errorMsg = '请填写标题至少2字'
} else if (this.content.trim().length < 10) {
errorMsg = '请填写详细内容至少10字'
} else if (this.selectedTypeIndex < 0) {
errorMsg = '请选择问题类型'
}
uni.showToast({
title: errorMsg,
icon: 'none'
})
return
}
if (this.isSubmitting) return
this.isSubmitting = true
// 模拟提交
uni.showLoading({ title: '提交中...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({
title: '反馈已提交成功!',
icon: 'success'
})
// 1.5秒后返回上一页
setTimeout(() => {
uni.navigateBack()
}, 1500)
}, 1000)
}
}
}
</script>
<style scoped>
.feedback-container {
background-color: #f8f9fa;
min-height: 100vh;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
/* 顶部导航 */
.header-bar {
background-color: #fff;
padding: 20rpx 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1rpx solid #e9ecef;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
}
.nav-left {
display: flex;
align-items: center;
cursor: pointer;
padding: 10rpx;
border-radius: 8rpx;
transition: background-color 0.2s ease;
}
.nav-left:hover {
background-color: #f0f0f0;
}
.nav-left:active {
background-color: #e0e0e0;
}
.nav-icon {
font-size: 36rpx;
color: #333;
}
.page-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
text-align: center;
flex: 1;
}
.nav-right {
width: 60rpx;
height: 1rpx;
}
/* 表单区域 */
.form-wrapper {
padding: 30rpx;
background-color: #fff;
}
.form-item {
margin-bottom: 30rpx;
}
.label {
display: block;
font-size: 28rpx;
color: #333;
margin-bottom: 12rpx;
font-weight: 500;
}
/* 输入框统一样式 */
.input-field,
.textarea-field,
.picker-input {
width: 100%;
padding: 20rpx 24rpx;
border: 1rpx solid #e0e0e0;
border-radius: 12rpx;
font-size: 28rpx;
color: #333;
background-color: #fafafa;
box-sizing: border-box;
}
.textarea-field {
min-height: 180rpx;
height: auto;
padding: 24rpx;
line-height: 1.6;
}
.picker-input {
background-color: #fff;
text-align: right;
color: #666;
padding-right: 40rpx;
position: relative;
}
.picker-input::after {
content: '▼';
position: absolute;
right: 24rpx;
top: 50%;
transform: translateY(-50%);
font-size: 24rpx;
color: #999;
}
/* 上传区域 */
.upload-area {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40rpx 20rpx;
border: 2rpx dashed #e0e0e0;
border-radius: 16rpx;
background-color: #f8f9fa;
cursor: pointer;
transition: all 0.3s;
}
.upload-area:hover {
border-color: #74b9ff;
background-color: #e8f4fd;
}
.upload-icon {
font-size: 60rpx;
color: #999;
margin-bottom: 16rpx;
}
.upload-text {
font-size: 28rpx;
color: #666;
margin-bottom: 10rpx;
}
.upload-tip {
font-size: 24rpx;
color: #999;
}
/* 图片预览 */
.preview-list {
display: flex;
gap: 20rpx;
margin-top: 20rpx;
flex-wrap: wrap;
}
.preview-item {
position: relative;
width: 120rpx;
height: 120rpx;
border-radius: 12rpx;
overflow: hidden;
}
.preview-img {
width: 100%;
height: 100%;
}
.remove-btn {
position: absolute;
top: 8rpx;
right: 8rpx;
width: 32rpx;
height: 32rpx;
background-color: rgba(0, 0, 0, 0.7);
color: white;
font-size: 24rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
z-index: 1;
}
/* 提交按钮 */
.submit-section {
margin-top: 40rpx;
}
.submit-btn {
width: 100%;
height: 88rpx;
background: linear-gradient(135deg, #74b9ff 0%, #0984e3 100%);
color: white;
font-size: 32rpx;
font-weight: bold;
border-radius: 44rpx;
border: none;
box-shadow: 0 8rpx 20rpx rgba(116, 185, 255, 0.3);
transition: all 0.3s;
}
.submit-btn:disabled {
background: #cccccc; /* 禁用时灰色背景 */
color: #999;
cursor: not-allowed; /* 禁用时显示禁止光标 */
}
.submit-btn:active {
transform: scale(0.98);
box-shadow: 0 4rpx 12rpx rgba(116, 185, 255, 0.2);
}
/* 底部提示 */
.footer-tip {
text-align: center;
padding: 30rpx;
color: #999;
font-size: 24rpx;
background-color: #fff;
border-top: 1rpx solid #e9ecef;
}
</style>