Files
uni-fans-score/pages/feedback/index.vue
T
2025-10-15 14:56:34 +08:00

360 lines
7.7 KiB
Vue
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">
<!-- <form> -->
<!-- 问题类型选择 -->
<view class="type-section">
<view class="section-title">问题类型</view>
<view class="type-grid">
<view v-for="(type, index) in types" :key="index" class="type-item"
:class="{ active: selectedType === index }" @click="selectType(index)">
{{ type }}
</view>
</view>
</view>
<!-- 问题描述 -->
<view class="description-section">
<view class="section-title">问题描述</view>
<textarea class="description-input" v-model="description" placeholder="请详细描述您遇到的问题,以便我们更好地为您解决"
maxlength="500" name="description" />
<view class="word-count">{{ description.length }}/500</view>
</view>
<!-- 图片上传 -->
<view class="upload-section">
<view class="section-title">图片上传选填</view>
<view class="upload-grid">
<view class="upload-item" v-for="(img, index) in images" :key="index">
<image :src="img" mode="aspectFill" />
<view class="delete-btn" @click="deleteImage(index)">×</view>
</view>
<view class="upload-btn" @click="chooseImage" v-if="images.length < 3">
<text class="plus">+</text>
<text class="tip">上传图片</text>
</view>
</view>
</view>
<!-- 联系方式 -->
<view class="contact-section">
<view class="section-title">联系方式</view>
<input class="contact-input" v-model="contact" placeholder="请留下您的手机号,方便我们联系您" type="number"
maxlength="11" name="contact" />
</view>
<!-- 提交按钮 -->
<view class="submit-section">
<view class="submit-btn" @click="submitFeedback">提交反馈</view>
</view>
<!-- </form> -->
</view>
</template>
<script setup>
import {
ref
} from 'vue'
import {
URL,
appid
} from '../../config/url'
import {
uploadOssResource
} from '../../config/user'
// 响应式数据
const types = ref(['设备故障', '收费问题', '使用建议', '其他'])
const selectedType = ref(-1)
const paramsType = ref('')
const description = ref('')
const images = ref([])
const contact = ref('')
const apiUrl = URL
// 方法
const selectType = (index) => {
selectedType.value = index
}
const chooseImage = () => {
uni.chooseImage({
count: 3 - images.value.length,
success: async (res) => {
console.log(res);
const toUpload = res.tempFilePaths || []
for (const localPath of toUpload) {
// 先追加本地预览,再上传并替换为远程URL
images.value.push(localPath)
try {
const remoteUrl = await uploadOssResource(localPath)
const idx = images.value.indexOf(localPath)
if (idx !== -1) {
images.value.splice(idx, 1, remoteUrl)
}
} catch (e) {
const idx = images.value.indexOf(localPath)
if (idx !== -1) {
images.value.splice(idx, 1)
}
uni.showToast({ title: '图片上传失败', icon: 'none' })
}
}
}
})
}
const deleteImage = (index) => {
images.value.splice(index, 1)
}
const submitFeedback = async () => {
if (selectedType.value === -1) {
uni.showToast({
title: '请选择问题类型',
icon: 'none'
})
return
}
if (!description.value.trim()) {
uni.showToast({
title: '请描述您的问题',
icon: 'none'
})
return
}
if (!contact.value) {
uni.showToast({
title: '请留下联系方式',
icon: 'none'
})
return
}
if (types.value[selectedType.value] == '设备故障' || types.value[selectedType.value] == '收费问题') {
paramsType.value = 'complain'
} else {
paramsType.value = 'suggestion'
}
// 构建反馈数据
const feedbackData = {
type: paramsType.value,
content: description.value,
phone: contact.value,
picturePath: images.value
}
uni.request({
url: `${apiUrl}/app/feedback/add`,
method: 'POST',
data: feedbackData,
header: {
'Content-Type': 'application/json',
'appid': appid,
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
},
dataType: 'json',
success: (res) => {
// 兼容后端返回 { code: 200 } 或 HTTP 200 情况
if ((res.statusCode === 200) && ((res.data && res.data.code === 200) || res.data === true || res.data?.success === true)) {
uni.showToast({
title: '反馈成功',
icon: 'success'
})
setTimeout(() => {
uni.navigateBack();
}, 1500);
return
}
uni.showToast({
title: (res.data && (res.data.msg || res.data.message)) || '反馈失败',
icon: 'none'
})
},
fail: (err) => {
console.error('feedback request failed:', err)
uni.showToast({
title: '网络错误,请稍后重试',
icon: 'none'
})
}
})
}
</script>
<style lang="scss" scoped>
.feedback-container {
min-height: 100vh;
background: #f8f8f8;
padding: 30rpx;
.section-title {
font-size: 30rpx;
color: #333;
font-weight: 500;
margin-bottom: 20rpx;
}
.type-section {
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 20rpx;
.type-grid {
display: flex;
flex-wrap: wrap;
margin: 0 -10rpx;
.type-item {
width: calc(50% - 20rpx);
margin: 10rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
background: #f5f5f5;
border-radius: 10rpx;
font-size: 28rpx;
color: #666;
transition: all 0.3s;
&.active {
background: #E8F5EE;
color: #3EAB64;
}
}
}
}
.description-section {
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 20rpx;
.description-input {
width: 100%;
height: 240rpx;
background: #f8f8f8;
border-radius: 10rpx;
padding: 20rpx;
font-size: 28rpx;
color: #333;
box-sizing: border-box;
}
.word-count {
text-align: right;
font-size: 24rpx;
color: #999;
margin-top: 10rpx;
}
}
.upload-section {
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 20rpx;
.upload-grid {
display: flex;
flex-wrap: wrap;
.upload-item {
width: 200rpx;
height: 200rpx;
margin-right: 20rpx;
margin-bottom: 20rpx;
position: relative;
image {
width: 100%;
height: 100%;
border-radius: 10rpx;
}
.delete-btn {
position: absolute;
right: -10rpx;
top: -10rpx;
width: 40rpx;
height: 40rpx;
background: rgba(0, 0, 0, 0.5);
color: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
}
}
.upload-btn {
width: 200rpx;
height: 200rpx;
background: #f5f5f5;
border-radius: 10rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #999;
.plus {
font-size: 60rpx;
line-height: 1;
margin-bottom: 10rpx;
}
.tip {
font-size: 24rpx;
}
}
}
}
.contact-section {
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 40rpx;
.contact-input {
width: 100%;
height: 80rpx;
background: #f8f8f8;
border-radius: 10rpx;
padding: 0 20rpx;
font-size: 28rpx;
color: #333;
box-sizing: border-box;
}
}
.submit-section {
padding: 0 40rpx;
.submit-btn {
width: 100%;
height: 88rpx;
background: #3EAB64;
color: #fff;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
&:active {
transform: scale(0.98);
}
}
}
}
</style>