fix:修复bug

This commit is contained in:
2026-02-06 18:09:23 +08:00
parent f476cee76d
commit bb5a6dd100
51 changed files with 4491 additions and 2630 deletions
+457
View File
@@ -0,0 +1,457 @@
<template>
<view class="feedback-container">
<!-- 投诉记录入口 -->
<view class="record-entry" @click="navigateToRecord">
<view class="entry-left">
<image class="entry-icon" src="/static/complaint.png" mode="aspectFit"></image>
<text class="entry-text">{{ $t('feedback.recordList') }}</text>
</view>
<view class="entry-right">
<text class="entry-desc">{{ $t('feedback.viewRecords') }}</text>
<uv-icon name="arrow-right" size="16" color="#999"></uv-icon>
</view>
</view>
<!-- <form> -->
<!-- 问题类型选择 -->
<view class="type-section">
<view class="section-title">{{ $t('feedback.issueType') }}</view>
<view class="type-grid">
<view v-for="(type, index) in types" :key="index" class="type-item"
:class="{ active: selectedType === index }" @click="selectType(index)">
{{ $t(type) }}
</view>
</view>
</view>
<!-- 问题描述 -->
<view class="description-section">
<view class="section-title">{{ $t('feedback.issueDescription') }}</view>
<textarea class="description-input" v-model="description" :placeholder="$t('feedback.placeholder')"
maxlength="500" name="description" />
<view class="word-count">{{ description.length }}/500</view>
</view>
<!-- 图片上传 -->
<view class="upload-section">
<view class="section-title">{{ $t('feedback.imageUpload') }}</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">{{ $t('feedback.uploadImage') }}</text>
</view>
</view>
</view>
<!-- 联系方式 -->
<view class="contact-section">
<view class="section-title">{{ $t('feedback.contactInfo') }}</view>
<input class="contact-input" v-model="contact" :placeholder="$t('feedback.contactPlaceholder')"
type="number" maxlength="11" name="contact" />
</view>
<!-- 提交按钮 -->
<view class="submit-section">
<view class="submit-btn" @click="submitFeedback">{{ $t('feedback.submit') }}</view>
</view>
<!-- </form> -->
</view>
</template>
<script setup>
import {
ref,
onMounted
} from 'vue'
import {
onLoad
} from "@dcloudio/uni-app"
import {
addUserFeedback
} from '@/config/api/feedback'
import {
uploadOssResource
} from '@/config/api/user'
import {
useI18n
} from '@/utils/i18n.js'
const {
t
} = useI18n()
// 跳转到投诉记录列表
const navigateToRecord = () => {
uni.navigateTo({
url: '/pages/feedback/list'
})
}
onMounted(() => {
uni.setNavigationBarTitle({
title: t('feedback.title')
})
})
onLoad((options) => {
if (uni.getStorageSync("userInfo").phone) {
contact.value = uni.getStorageSync('userInfo').phone;
}
if(options.selectedType) {
selectedType.value = parseInt(options.selectedType);
}
})
// 响应式数据
const types = ref(['feedback.deviceFault', 'feedback.chargingIssue', 'feedback.usageSuggestion', 'feedback.other'])
const selectedType = ref(-1)
const paramsType = ref('')
const description = ref('')
const images = ref([])
const contact = ref('')
// 方法
const selectType = (index) => {
selectedType.value = index
}
const chooseImage = () => {
uni.chooseImage({
count: 3 - images.value.length,
success: (res) => {
// 直接保存本地路径,不上传
const toUpload = res.tempFilePaths || []
images.value.push(...toUpload)
}
})
}
const deleteImage = (index) => {
images.value.splice(index, 1)
}
const submitFeedback = async () => {
if (selectedType.value === -1) {
uni.showToast({
title: t('feedback.pleaseSelectType'),
icon: 'none'
})
return
}
if (!description.value.trim()) {
uni.showToast({
title: t('feedback.pleaseDescribe'),
icon: 'none'
})
return
}
if (!contact.value) {
uni.showToast({
title: t('feedback.pleaseContact'),
icon: 'none'
})
return
}
if (types.value[selectedType.value] === 'feedback.deviceFault' || types.value[selectedType.value] ===
'feedback.chargingIssue') {
paramsType.value = 'complain'
} else {
paramsType.value = 'suggestion'
}
try {
// 显示上传进度
uni.showLoading({
title: t('feedback.uploading') || '上传中...',
mask: true
})
// 先逐步上传所有文件到OSS
const files = []
if (images.value.length > 0) {
for (let i = 0; i < images.value.length; i++) {
const filePath = images.value[i]
try {
const remoteUrl = await uploadOssResource(filePath)
files.push(remoteUrl)
} catch (err) {
console.error(`文件 ${i + 1} 上传失败:`, err)
uni.hideLoading()
uni.showToast({
title: t('feedback.imageUploadFailed'),
icon: 'none'
})
return
}
}
}
// 构建反馈数据
const feedbackData = {
type: paramsType.value,
content: description.value,
phone: contact.value,
files: files
}
// 调用API提交反馈(使用 hideLoading 避免重复显示loading
const res = await addUserFeedback(feedbackData)
uni.hideLoading()
// 处理响应
if (res && (res.code === 200 || res === true || res?.success === true)) {
uni.showToast({
title: t('feedback.submitSuccess'),
icon: 'success'
})
setTimeout(() => {
uni.navigateBack();
}, 1500);
} else {
uni.showToast({
title: (res && (res.msg || res.message)) || t('feedback.submitFailed'),
icon: 'none'
})
}
} catch (err) {
console.error('feedback submit failed:', err)
uni.hideLoading()
uni.showToast({
title: t('error.networkError') || '网络错误,请重试',
icon: 'none'
})
}
}
</script>
<style lang="scss" scoped>
.feedback-container {
min-height: 100vh;
background: #f7f8fa;
padding: 30rpx;
// 投诉记录入口
.record-entry {
background: #fff;
border-radius: 20rpx;
padding: 28rpx 30rpx;
margin-bottom: 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
.entry-left {
display: flex;
align-items: center;
flex: 1;
.entry-icon {
width: 40rpx;
height: 40rpx;
margin-right: 16rpx;
}
.entry-text {
font-size: 30rpx;
color: #333;
font-weight: 500;
}
}
.entry-right {
display: flex;
align-items: center;
gap: 8rpx;
.entry-desc {
font-size: 24rpx;
color: #999;
}
}
&:active {
opacity: 0.8;
}
}
.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;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
.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: #07c160;
}
}
}
}
.description-section {
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
.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;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
.upload-grid {
display: flex;
flex-wrap: wrap;
.upload-item {
width: 180rpx;
height: 180rpx;
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: 180rpx;
height: 180rpx;
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: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
.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: 20rpx 0 40rpx 0;
.submit-btn {
width: 100%;
height: 88rpx;
background: #07c160;
color: #fff;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 12rpx rgba(7, 193, 96, 0.3);
&:active {
opacity: 0.8;
transform: scale(0.98);
}
}
}
}
</style>