fix:修复投诉与建议图片多文件上传bug
This commit is contained in:
+17
-9
@@ -1,18 +1,18 @@
|
|||||||
import request from '../http'
|
import request from '../http'
|
||||||
|
|
||||||
// 投诉反馈
|
// 新增反馈
|
||||||
|
// data 参数包含: type, content, phone, files (数组)
|
||||||
export const addUserFeedback = (data) => {
|
export const addUserFeedback = (data) => {
|
||||||
console.log(data);
|
|
||||||
return request({
|
return request({
|
||||||
url: '/app/feedback/add',
|
url: '/app/feedback/add',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data,
|
data,
|
||||||
|
hideLoading: true, // 手动控制loading,避免重复显示
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取投诉记录列表
|
// 获取反馈列表
|
||||||
export const getFeedbackList = (params) => {
|
export const getFeedbackList = (params) => {
|
||||||
// GET请求需要将参数拼接到URL上
|
|
||||||
let url = '/app/feedback/list';
|
let url = '/app/feedback/list';
|
||||||
if (params) {
|
if (params) {
|
||||||
const queryString = Object.keys(params)
|
const queryString = Object.keys(params)
|
||||||
@@ -23,12 +23,12 @@ export const getFeedbackList = (params) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return request({
|
return request({
|
||||||
url: url,
|
url,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取投诉详情
|
// 获取反馈详情(含基础信息)
|
||||||
export const getFeedbackDetail = (id) => {
|
export const getFeedbackDetail = (id) => {
|
||||||
return request({
|
return request({
|
||||||
url: `/app/feedback/${id}`,
|
url: `/app/feedback/${id}`,
|
||||||
@@ -36,10 +36,18 @@ export const getFeedbackDetail = (id) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提交投诉回复
|
// 获取反馈对话消息
|
||||||
export const submitFeedbackReply = (data) => {
|
export const getFeedbackMessages = (id) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/app/feedback/reply',
|
url: `/app/feedback/${id}/messages`,
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户追加消息
|
||||||
|
export const sendFeedbackMessage = (id, data) => {
|
||||||
|
return request({
|
||||||
|
url: `/app/feedback/${id}/message`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
|
|||||||
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
// export const URL = "https://my.gxfs123.com/api" //正式服务器-弃用
|
// export const URL = "https://my.gxfs123.com/api" //正式服务器-弃用
|
||||||
// export const URL = "https://manager.fdzpower.com/api" //正式服务器
|
export const URL = "https://manager.fdzpower.com/api" //正式服务器
|
||||||
export const URL = "https://fansdev.gxfs123.com/api" //测试服务器
|
// export const URL = "https://fansdev.gxfs123.com/api" //测试服务器
|
||||||
// export const URL = "http://192.168.5.149:8080" //本地调试
|
// export const URL = "http://192.168.5.30:8080" //本地调试
|
||||||
// export const URL = "http://127.0.0.1:8080" //本地调试
|
// export const URL = "http://127.0.0.1:8080" //本地调试
|
||||||
|
|
||||||
export const appid = "wx2165f0be356ae7a9" //小程序appid
|
export const appid = "wx2165f0be356ae7a9" //小程序appid
|
||||||
+2
-1
@@ -335,6 +335,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
feedback: {
|
feedback: {
|
||||||
|
uploading: 'Uploading...',
|
||||||
title: 'Feedback',
|
title: 'Feedback',
|
||||||
placeholder: 'Describe the issue',
|
placeholder: 'Describe the issue',
|
||||||
submit: 'Submit',
|
submit: 'Submit',
|
||||||
@@ -350,7 +351,7 @@ export default {
|
|||||||
pleaseSelectType: 'Select type',
|
pleaseSelectType: 'Select type',
|
||||||
pleaseDescribe: 'Describe issue',
|
pleaseDescribe: 'Describe issue',
|
||||||
pleaseContact: 'Leave contact',
|
pleaseContact: 'Leave contact',
|
||||||
imageUploadFailed: 'Upload failed',
|
imageUploadFailed: 'Image upload failed, please try again',
|
||||||
deviceFault: 'Device Fault',
|
deviceFault: 'Device Fault',
|
||||||
chargingIssue: 'Charging',
|
chargingIssue: 'Charging',
|
||||||
usageSuggestion: 'Suggestion',
|
usageSuggestion: 'Suggestion',
|
||||||
|
|||||||
+2
-1
@@ -335,6 +335,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
feedback: {
|
feedback: {
|
||||||
|
uploading: '上传中...',
|
||||||
title: '投诉与建议',
|
title: '投诉与建议',
|
||||||
placeholder: '请详细描述您遇到的问题,以便我们更好地为您解决',
|
placeholder: '请详细描述您遇到的问题,以便我们更好地为您解决',
|
||||||
submit: '提交反馈',
|
submit: '提交反馈',
|
||||||
@@ -350,7 +351,7 @@ export default {
|
|||||||
pleaseSelectType: '请选择问题类型',
|
pleaseSelectType: '请选择问题类型',
|
||||||
pleaseDescribe: '请描述您的问题',
|
pleaseDescribe: '请描述您的问题',
|
||||||
pleaseContact: '请留下联系方式',
|
pleaseContact: '请留下联系方式',
|
||||||
imageUploadFailed: '图片上传失败',
|
imageUploadFailed: '图片上传失败,请重试',
|
||||||
deviceFault: '设备故障',
|
deviceFault: '设备故障',
|
||||||
chargingIssue: '收费问题',
|
chargingIssue: '收费问题',
|
||||||
usageSuggestion: '使用建议',
|
usageSuggestion: '使用建议',
|
||||||
|
|||||||
+118
-47
@@ -12,11 +12,22 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 标题 -->
|
||||||
|
<view class="title-section">
|
||||||
|
<text class="title-text">{{ detail.title || '-' }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 问题描述 -->
|
<!-- 问题描述 -->
|
||||||
<view class="content-section">
|
<view class="content-section">
|
||||||
<view class="content-text">{{ detail.content || '-' }}</view>
|
<view class="content-text">{{ detail.content || '-' }}</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 联系电话 -->
|
||||||
|
<view class="contact-section" v-if="detail.phone">
|
||||||
|
<text class="contact-label">{{ $t('feedback.contactPhone') }}</text>
|
||||||
|
<text class="contact-value">{{ detail.phone }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 上传图片 -->
|
<!-- 上传图片 -->
|
||||||
<view class="image-section" v-if="getImageList(detail).length > 0">
|
<view class="image-section" v-if="getImageList(detail).length > 0">
|
||||||
<view class="image-list">
|
<view class="image-list">
|
||||||
@@ -39,14 +50,14 @@
|
|||||||
<view class="divider-line"></view>
|
<view class="divider-line"></view>
|
||||||
</view>
|
</view>
|
||||||
<view class="reply-list">
|
<view class="reply-list">
|
||||||
<view class="reply-item" v-for="(reply, index) in allReplies" :key="index"
|
<view class="reply-item" v-for="(reply, index) in allReplies" :key="reply.id || index"
|
||||||
:class="{ 'reply-platform': reply.isPlatform, 'reply-user': !reply.isPlatform }">
|
:class="{ 'reply-platform': reply.isPlatform, 'reply-user': !reply.isPlatform }">
|
||||||
<view class="reply-avatar" :class="{ 'avatar-platform': reply.isPlatform, 'avatar-user': !reply.isPlatform }">
|
<view class="reply-avatar" :class="{ 'avatar-platform': reply.isPlatform, 'avatar-user': !reply.isPlatform }">
|
||||||
<text class="avatar-text">{{ reply.isPlatform ? '平台' : '我' }}</text>
|
<text class="avatar-text">{{ reply.isPlatform ? '平台' : '我' }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="reply-content-wrapper">
|
<view class="reply-content-wrapper">
|
||||||
<view class="reply-name-time">
|
<view class="reply-name-time">
|
||||||
<text class="reply-name">{{ reply.isPlatform ? $t('feedback.platform') : $t('feedback.me') }}</text>
|
<text class="reply-name">{{ reply.senderName || (reply.isPlatform ? $t('feedback.platform') : $t('feedback.me')) }}</text>
|
||||||
<text class="reply-time">{{ formatTime(reply.createTime) }}</text>
|
<text class="reply-time">{{ formatTime(reply.createTime) }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="reply-content">{{ reply.content || '-' }}</view>
|
<view class="reply-content">{{ reply.content || '-' }}</view>
|
||||||
@@ -56,7 +67,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 底部输入框 -->
|
<!-- 底部输入框 -->
|
||||||
<view class="bottom-input-bar" v-if="detail.status === 'processing'">
|
<view class="bottom-input-bar" v-if="canSendMessage">
|
||||||
<view class="input-wrapper">
|
<view class="input-wrapper">
|
||||||
<textarea class="reply-input" v-model="replyContent" :placeholder="$t('feedback.replyPlaceholder')"
|
<textarea class="reply-input" v-model="replyContent" :placeholder="$t('feedback.replyPlaceholder')"
|
||||||
maxlength="500" :auto-height="true"></textarea>
|
maxlength="500" :auto-height="true"></textarea>
|
||||||
@@ -71,14 +82,16 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import {
|
||||||
ref,
|
ref,
|
||||||
onMounted
|
onMounted,
|
||||||
|
computed
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import {
|
import {
|
||||||
onLoad
|
onLoad
|
||||||
} from '@dcloudio/uni-app';
|
} from '@dcloudio/uni-app';
|
||||||
import {
|
import {
|
||||||
getFeedbackDetail,
|
getFeedbackDetail,
|
||||||
submitFeedbackReply
|
getFeedbackMessages,
|
||||||
|
sendFeedbackMessage
|
||||||
} from '../../config/api/feedback.js';
|
} from '../../config/api/feedback.js';
|
||||||
import {
|
import {
|
||||||
useI18n
|
useI18n
|
||||||
@@ -97,12 +110,15 @@
|
|||||||
|
|
||||||
// 初始化状态
|
// 初始化状态
|
||||||
const detail = ref({});
|
const detail = ref({});
|
||||||
const replyList = ref([]);
|
|
||||||
const userReplyList = ref([]);
|
|
||||||
const allReplies = ref([]);
|
const allReplies = ref([]);
|
||||||
const replyContent = ref('');
|
const replyContent = ref('');
|
||||||
const feedbackId = ref('');
|
const feedbackId = ref('');
|
||||||
|
|
||||||
|
const canSendMessage = computed(() => {
|
||||||
|
const status = detail.value?.status
|
||||||
|
return ['pending', 'in_progress'].includes(status)
|
||||||
|
})
|
||||||
|
|
||||||
// 页面加载
|
// 页面加载
|
||||||
onLoad(async (options) => {
|
onLoad(async (options) => {
|
||||||
if (options.id) {
|
if (options.id) {
|
||||||
@@ -119,33 +135,49 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 加载详情
|
const normalizeMessages = (messages = []) => {
|
||||||
const loadDetail = async () => {
|
return (messages || [])
|
||||||
try {
|
.map(message => ({
|
||||||
uni.showLoading({
|
...message,
|
||||||
title: $t('common.loading')
|
isPlatform: message.senderType === 'staff' || message.senderType === 'platform' || message.isPlatform === true
|
||||||
|
}))
|
||||||
|
.sort((a, b) => {
|
||||||
|
const timeA = new Date(a.createTime || 0).getTime();
|
||||||
|
const timeB = new Date(b.createTime || 0).getTime();
|
||||||
|
return timeA - timeB;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadMessages = async (initialMessages) => {
|
||||||
|
try {
|
||||||
|
if (Array.isArray(initialMessages)) {
|
||||||
|
allReplies.value = normalizeMessages(initialMessages);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!feedbackId.value) return;
|
||||||
|
const res = await getFeedbackMessages(feedbackId.value);
|
||||||
|
if (res.code === 200) {
|
||||||
|
allReplies.value = normalizeMessages(res.data || []);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取对话消息失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载详情
|
||||||
|
const loadDetail = async (options = {}) => {
|
||||||
|
const shouldShowLoading = options.showLoading !== false;
|
||||||
|
try {
|
||||||
|
if (shouldShowLoading) {
|
||||||
|
uni.showLoading({
|
||||||
|
title: $t('common.loading')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const res = await getFeedbackDetail(feedbackId.value);
|
const res = await getFeedbackDetail(feedbackId.value);
|
||||||
if (res.code === 200 && res.data) {
|
if (res.code === 200 && res.data) {
|
||||||
detail.value = res.data;
|
detail.value = res.data;
|
||||||
|
await loadMessages(res.data.messages);
|
||||||
// 分离平台回复和用户回复
|
|
||||||
const replies = res.data.replies || res.data.replyList || [];
|
|
||||||
replyList.value = replies.filter(reply => reply.replyType === 'platform' || reply.isPlatform);
|
|
||||||
userReplyList.value = replies.filter(reply => reply.replyType === 'user' || !reply.isPlatform);
|
|
||||||
|
|
||||||
// 合并所有回复并按时间排序
|
|
||||||
allReplies.value = replies
|
|
||||||
.map(reply => ({
|
|
||||||
...reply,
|
|
||||||
isPlatform: reply.replyType === 'platform' || reply.isPlatform === true
|
|
||||||
}))
|
|
||||||
.sort((a, b) => {
|
|
||||||
const timeA = new Date(a.createTime || 0).getTime();
|
|
||||||
const timeB = new Date(b.createTime || 0).getTime();
|
|
||||||
return timeA - timeB;
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: res.msg || $t('feedback.getDetailFailed'),
|
title: res.msg || $t('feedback.getDetailFailed'),
|
||||||
@@ -165,7 +197,9 @@
|
|||||||
uni.navigateBack();
|
uni.navigateBack();
|
||||||
}, 1500);
|
}, 1500);
|
||||||
} finally {
|
} finally {
|
||||||
uni.hideLoading();
|
if (shouldShowLoading) {
|
||||||
|
uni.hideLoading();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -184,8 +218,7 @@
|
|||||||
title: $t('common.submitting')
|
title: $t('common.submitting')
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await submitFeedbackReply({
|
const res = await sendFeedbackMessage(feedbackId.value, {
|
||||||
feedbackId: feedbackId.value,
|
|
||||||
content: replyContent.value.trim()
|
content: replyContent.value.trim()
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -195,8 +228,10 @@
|
|||||||
icon: 'success'
|
icon: 'success'
|
||||||
});
|
});
|
||||||
replyContent.value = '';
|
replyContent.value = '';
|
||||||
// 重新加载详情
|
// 重新加载详情和对话
|
||||||
await loadDetail();
|
await loadDetail({
|
||||||
|
showLoading: false
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: res.msg || $t('feedback.replyFailed'),
|
title: res.msg || $t('feedback.replyFailed'),
|
||||||
@@ -217,9 +252,9 @@
|
|||||||
// 获取状态文本
|
// 获取状态文本
|
||||||
const getStatusText = (status) => {
|
const getStatusText = (status) => {
|
||||||
const statusMap = {
|
const statusMap = {
|
||||||
'processing': $t('feedback.processing'),
|
'pending': $t('feedback.pending'),
|
||||||
'completed': $t('feedback.completed'),
|
'in_progress': $t('feedback.processing'),
|
||||||
'pending': $t('feedback.pending')
|
'resolved': $t('feedback.completed')
|
||||||
};
|
};
|
||||||
return statusMap[status] || $t('feedback.pending');
|
return statusMap[status] || $t('feedback.pending');
|
||||||
};
|
};
|
||||||
@@ -227,9 +262,9 @@
|
|||||||
// 获取状态样式类
|
// 获取状态样式类
|
||||||
const getStatusClass = (status) => {
|
const getStatusClass = (status) => {
|
||||||
const classMap = {
|
const classMap = {
|
||||||
'processing': 'status-processing',
|
'pending': 'status-pending',
|
||||||
'completed': 'status-completed',
|
'in_progress': 'status-processing',
|
||||||
'pending': 'status-pending'
|
'resolved': 'status-completed'
|
||||||
};
|
};
|
||||||
return classMap[status] || 'status-pending';
|
return classMap[status] || 'status-pending';
|
||||||
};
|
};
|
||||||
@@ -270,14 +305,17 @@
|
|||||||
|
|
||||||
// 获取图片列表(支持字符串或数组)
|
// 获取图片列表(支持字符串或数组)
|
||||||
const getImageList = (item) => {
|
const getImageList = (item) => {
|
||||||
if (!item || !item.picturePath) return [];
|
if (!item) return [];
|
||||||
if (Array.isArray(item.picturePath)) return item.picturePath;
|
const pictureSource = item.pictureUrls ?? item.picturePath;
|
||||||
if (typeof item.picturePath === 'string') {
|
if (!pictureSource) return [];
|
||||||
// 如果是逗号分隔的字符串,拆分为数组
|
if (Array.isArray(pictureSource)) {
|
||||||
if (item.picturePath.includes(',')) {
|
return pictureSource.filter(img => !!img);
|
||||||
return item.picturePath.split(',').filter(img => img.trim());
|
}
|
||||||
|
if (typeof pictureSource === 'string') {
|
||||||
|
if (pictureSource.includes(',')) {
|
||||||
|
return pictureSource.split(',').map(img => img.trim()).filter(img => img);
|
||||||
}
|
}
|
||||||
return [item.picturePath];
|
return pictureSource.trim() ? [pictureSource.trim()] : [];
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
@@ -362,6 +400,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 标题
|
||||||
|
.title-section {
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
|
||||||
|
.title-text {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 问题描述
|
// 问题描述
|
||||||
.content-section {
|
.content-section {
|
||||||
margin-bottom: 20rpx;
|
margin-bottom: 20rpx;
|
||||||
@@ -374,6 +423,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 联系方式
|
||||||
|
.contact-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
padding: 16rpx;
|
||||||
|
background: #fafafa;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
|
||||||
|
.contact-label {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
margin-right: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-value {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 图片区域
|
// 图片区域
|
||||||
.image-section {
|
.image-section {
|
||||||
margin-bottom: 20rpx;
|
margin-bottom: 20rpx;
|
||||||
|
|||||||
+63
-71
@@ -71,15 +71,11 @@
|
|||||||
onLoad
|
onLoad
|
||||||
} from "@dcloudio/uni-app"
|
} from "@dcloudio/uni-app"
|
||||||
import {
|
import {
|
||||||
URL,
|
addUserFeedback
|
||||||
appid
|
} from '../../config/api/feedback'
|
||||||
} from '../../config/url'
|
|
||||||
import {
|
import {
|
||||||
uploadOssResource
|
uploadOssResource
|
||||||
} from '../../config/api/user'
|
} from '../../config/api/user'
|
||||||
import {
|
|
||||||
addUserFeedback
|
|
||||||
} from '../../config/api/feedback'
|
|
||||||
import {
|
import {
|
||||||
useI18n
|
useI18n
|
||||||
} from '@/utils/i18n.js'
|
} from '@/utils/i18n.js'
|
||||||
@@ -113,7 +109,6 @@
|
|||||||
const description = ref('')
|
const description = ref('')
|
||||||
const images = ref([])
|
const images = ref([])
|
||||||
const contact = ref('')
|
const contact = ref('')
|
||||||
const apiUrl = URL
|
|
||||||
|
|
||||||
// 方法
|
// 方法
|
||||||
const selectType = (index) => {
|
const selectType = (index) => {
|
||||||
@@ -124,29 +119,10 @@
|
|||||||
const chooseImage = () => {
|
const chooseImage = () => {
|
||||||
uni.chooseImage({
|
uni.chooseImage({
|
||||||
count: 3 - images.value.length,
|
count: 3 - images.value.length,
|
||||||
success: async (res) => {
|
success: (res) => {
|
||||||
console.log(res);
|
// 直接保存本地路径,不上传
|
||||||
const toUpload = res.tempFilePaths || []
|
const toUpload = res.tempFilePaths || []
|
||||||
for (const localPath of toUpload) {
|
images.value.push(...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'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -187,52 +163,68 @@
|
|||||||
paramsType.value = 'suggestion'
|
paramsType.value = 'suggestion'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建反馈数据
|
try {
|
||||||
const feedbackData = {
|
// 显示上传进度
|
||||||
type: paramsType.value,
|
uni.showLoading({
|
||||||
content: description.value,
|
title: $t('feedback.uploading') || '上传中...',
|
||||||
phone: contact.value,
|
mask: true
|
||||||
picturePath: images.value[0]
|
})
|
||||||
}
|
|
||||||
|
|
||||||
uni.request({
|
// 先逐步上传所有文件到OSS
|
||||||
url: `${apiUrl}/app/feedback/add`,
|
const files = []
|
||||||
method: 'POST',
|
if (images.value.length > 0) {
|
||||||
data: feedbackData,
|
for (let i = 0; i < images.value.length; i++) {
|
||||||
header: {
|
const filePath = images.value[i]
|
||||||
'Content-Type': 'application/json',
|
try {
|
||||||
'appid': appid,
|
const remoteUrl = await uploadOssResource(filePath)
|
||||||
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
|
files.push(remoteUrl)
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
} catch (err) {
|
||||||
},
|
console.error(`文件 ${i + 1} 上传失败:`, err)
|
||||||
dataType: 'json',
|
uni.hideLoading()
|
||||||
success: (res) => {
|
uni.showToast({
|
||||||
// 兼容后端返回 { code: 200 } 或 HTTP 200 情况
|
title: $t('feedback.imageUploadFailed'),
|
||||||
if ((res.statusCode === 200) && ((res.data && res.data.code === 200) || res.data ===
|
icon: 'none'
|
||||||
true || res.data?.success === true)) {
|
})
|
||||||
uni.showToast({
|
return
|
||||||
title: $t('feedback.submitSuccess'),
|
}
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
setTimeout(() => {
|
|
||||||
uni.navigateBack();
|
|
||||||
}, 1500);
|
|
||||||
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({
|
uni.showToast({
|
||||||
title: (res.data && (res.data.msg || res.data.message)) || $t(
|
title: $t('feedback.submitSuccess'),
|
||||||
'feedback.submitFailed'),
|
icon: 'success'
|
||||||
icon: 'none'
|
|
||||||
})
|
})
|
||||||
},
|
setTimeout(() => {
|
||||||
fail: (err) => {
|
uni.navigateBack();
|
||||||
console.error('feedback request failed:', err)
|
}, 1500);
|
||||||
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('error.networkError'),
|
title: (res && (res.msg || res.message)) || $t('feedback.submitFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
} catch (err) {
|
||||||
|
console.error('feedback submit failed:', err)
|
||||||
|
uni.hideLoading()
|
||||||
|
uni.showToast({
|
||||||
|
title: $t('error.networkError') || '网络错误,请重试',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -365,8 +357,8 @@
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
||||||
.upload-item {
|
.upload-item {
|
||||||
width: 200rpx;
|
width: 180rpx;
|
||||||
height: 200rpx;
|
height: 180rpx;
|
||||||
margin-right: 20rpx;
|
margin-right: 20rpx;
|
||||||
margin-bottom: 20rpx;
|
margin-bottom: 20rpx;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -394,8 +386,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.upload-btn {
|
.upload-btn {
|
||||||
width: 200rpx;
|
width: 180rpx;
|
||||||
height: 200rpx;
|
height: 180rpx;
|
||||||
background: #f5f5f5;
|
background: #f5f5f5;
|
||||||
border-radius: 10rpx;
|
border-radius: 10rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
+16
-10
@@ -104,17 +104,23 @@
|
|||||||
},
|
},
|
||||||
status: ''
|
status: ''
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
get text() {
|
||||||
|
return $t('feedback.pending')
|
||||||
|
},
|
||||||
|
status: 'pending'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
get text() {
|
get text() {
|
||||||
return $t('feedback.processing')
|
return $t('feedback.processing')
|
||||||
},
|
},
|
||||||
status: 'processing'
|
status: 'in_progress'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
get text() {
|
get text() {
|
||||||
return $t('feedback.completed')
|
return $t('feedback.completed')
|
||||||
},
|
},
|
||||||
status: 'completed'
|
status: 'resolved'
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -145,8 +151,8 @@
|
|||||||
loading.value = true;
|
loading.value = true;
|
||||||
const status = statusTabs[currentTab.value].status;
|
const status = statusTabs[currentTab.value].status;
|
||||||
const params = {
|
const params = {
|
||||||
page: currentPage.value,
|
pageNum: currentPage.value,
|
||||||
size: pageSize.value
|
pageSize: pageSize.value
|
||||||
};
|
};
|
||||||
if (status) {
|
if (status) {
|
||||||
params.status = status;
|
params.status = status;
|
||||||
@@ -205,9 +211,9 @@
|
|||||||
// 获取状态文本
|
// 获取状态文本
|
||||||
const getStatusText = (status) => {
|
const getStatusText = (status) => {
|
||||||
const statusMap = {
|
const statusMap = {
|
||||||
'processing': $t('feedback.processing'),
|
'pending': $t('feedback.pending'),
|
||||||
'completed': $t('feedback.completed'),
|
'in_progress': $t('feedback.processing'),
|
||||||
'pending': $t('feedback.pending')
|
'resolved': $t('feedback.completed')
|
||||||
};
|
};
|
||||||
return statusMap[status] || $t('feedback.pending');
|
return statusMap[status] || $t('feedback.pending');
|
||||||
};
|
};
|
||||||
@@ -215,9 +221,9 @@
|
|||||||
// 获取状态样式类
|
// 获取状态样式类
|
||||||
const getStatusClass = (status) => {
|
const getStatusClass = (status) => {
|
||||||
const classMap = {
|
const classMap = {
|
||||||
'processing': 'chip-processing',
|
'pending': 'chip-pending',
|
||||||
'completed': 'chip-completed',
|
'in_progress': 'chip-processing',
|
||||||
'pending': 'chip-pending'
|
'resolved': 'chip-completed'
|
||||||
};
|
};
|
||||||
return classMap[status] || 'chip-pending';
|
return classMap[status] || 'chip-pending';
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user