|
@@ -0,0 +1,413 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <view class="feedback-page">
|
|
|
|
|
+ <!-- 页面标题 -->
|
|
|
|
|
+ <view class="page-header">
|
|
|
|
|
+ <view class="header-left" @click="goBack">
|
|
|
|
|
+ <text class="back-icon">←</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="header-title">用户反馈</view>
|
|
|
|
|
+ <view class="header-right"></view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 反馈内容 -->
|
|
|
|
|
+ <view class="feedback-content">
|
|
|
|
|
+ <view class="section">
|
|
|
|
|
+ <view class="section-title">反馈类型</view>
|
|
|
|
|
+ <view class="feedback-type">
|
|
|
|
|
+ <view class="type-item"
|
|
|
|
|
+ :class="{ active: feedbackType === '意见建议' }"
|
|
|
|
|
+ @click="feedbackType = '意见建议'">
|
|
|
|
|
+ <text class="type-text">意见建议</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="type-item"
|
|
|
|
|
+ :class="{ active: feedbackType === '功能改进' }"
|
|
|
|
|
+ @click="feedbackType = '功能改进'">
|
|
|
|
|
+ <text class="type-text">功能改进</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="type-item"
|
|
|
|
|
+ :class="{ active: feedbackType === 'bug报告' }"
|
|
|
|
|
+ @click="feedbackType = 'bug报告'">
|
|
|
|
|
+ <text class="type-text">bug报告</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <view class="section">
|
|
|
|
|
+ <view class="section-title">反馈内容</view>
|
|
|
|
|
+ <textarea
|
|
|
|
|
+ class="feedback-input"
|
|
|
|
|
+ placeholder="请详细描述您的问题或建议..."
|
|
|
|
|
+ v-model="feedbackContent"
|
|
|
|
|
+ maxlength="500"
|
|
|
|
|
+ auto-height
|
|
|
|
|
+ ></textarea>
|
|
|
|
|
+ <view class="word-count">{{ feedbackContent.length }}/500</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <view class="section">
|
|
|
|
|
+ <view class="section-title">上传图片(可选)</view>
|
|
|
|
|
+ <view class="image-uploader">
|
|
|
|
|
+ <view class="upload-item" v-for="(image, index) in images" :key="index">
|
|
|
|
|
+ <image class="uploaded-image" :src="image" mode="aspectFill"></image>
|
|
|
|
|
+ <view class="delete-icon" @click="deleteImage(index)">×</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="upload-btn" @click="chooseImage" v-if="images.length < 3">
|
|
|
|
|
+ <text class="upload-icon">+</text>
|
|
|
|
|
+ <text class="upload-text">添加图片</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="upload-tip">最多可上传3张图片</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 提交按钮 -->
|
|
|
|
|
+ <view class="submit-section">
|
|
|
|
|
+ <button class="submit-btn" @click="submitFeedback" :disabled="!feedbackContent.trim()">
|
|
|
|
|
+ 提交反馈
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script>
|
|
|
|
|
+import api from '@/utils/api.js';
|
|
|
|
|
+
|
|
|
|
|
+export default {
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ feedbackType: '意见建议',
|
|
|
|
|
+ feedbackContent: '',
|
|
|
|
|
+ images: [],
|
|
|
|
|
+ uploadedImages: []
|
|
|
|
|
+ };
|
|
|
|
|
+ },
|
|
|
|
|
+ onLoad() {
|
|
|
|
|
+ // 确保 __route__ 属性存在,避免渲染错误
|
|
|
|
|
+ if (!this.__route__) {
|
|
|
|
|
+ this.__route__ = '/pages/feedback/index';
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ // 返回上一页
|
|
|
|
|
+ goBack() {
|
|
|
|
|
+ uni.navigateBack();
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 选择图片
|
|
|
|
|
+ chooseImage() {
|
|
|
|
|
+ uni.chooseImage({
|
|
|
|
|
+ count: 3 - this.images.length,
|
|
|
|
|
+ sizeType: ['compressed'],
|
|
|
|
|
+ sourceType: ['album', 'camera'],
|
|
|
|
|
+ success: (res) => {
|
|
|
|
|
+ this.images = [...this.images, ...res.tempFilePaths];
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 删除图片
|
|
|
|
|
+ deleteImage(index) {
|
|
|
|
|
+ this.images.splice(index, 1);
|
|
|
|
|
+ this.uploadedImages.splice(index, 1);
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 上传单张图片
|
|
|
|
|
+ async uploadSingleImage(filePath) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ console.log('上传图片:', filePath);
|
|
|
|
|
+ // 调用后端的图片上传接口
|
|
|
|
|
+ const imageUrl = await api.feedback.uploadImage(filePath);
|
|
|
|
|
+ return imageUrl;
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('上传图片失败:', error);
|
|
|
|
|
+ throw error;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 上传所有图片
|
|
|
|
|
+ async uploadAllImages() {
|
|
|
|
|
+ const uploadedUrls = [];
|
|
|
|
|
+ for (let i = 0; i < this.images.length; i++) {
|
|
|
|
|
+ if (!this.uploadedImages[i]) {
|
|
|
|
|
+ const url = await this.uploadSingleImage(this.images[i]);
|
|
|
|
|
+ if (url) {
|
|
|
|
|
+ this.uploadedImages[i] = url;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ uploadedUrls.push(this.uploadedImages[i]);
|
|
|
|
|
+ }
|
|
|
|
|
+ return uploadedUrls.filter(url => url);
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 提交反馈
|
|
|
|
|
+ async submitFeedback() {
|
|
|
|
|
+ if (!this.feedbackContent.trim()) {
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: '请输入反馈内容',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ });
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ uni.showLoading({
|
|
|
|
|
+ title: '提交中...'
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 上传图片
|
|
|
|
|
+ const imageUrls = await this.uploadAllImages();
|
|
|
|
|
+
|
|
|
|
|
+ // 获取当前用户ID
|
|
|
|
|
+ const userInfo = uni.getStorageSync('userInfo');
|
|
|
|
|
+ const userId = userInfo?.userId || uni.getStorageSync('userId');
|
|
|
|
|
+
|
|
|
|
|
+ // 转换反馈类型为数字格式(1=意见建议,2=功能改进,3=bug报告)
|
|
|
|
|
+ let feedbackTypeNum = 1;
|
|
|
|
|
+ if (this.feedbackType === '功能改进') {
|
|
|
|
|
+ feedbackTypeNum = 2;
|
|
|
|
|
+ } else if (this.feedbackType === 'bug报告') {
|
|
|
|
|
+ feedbackTypeNum = 3;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 构造反馈数据,与后端接口字段匹配
|
|
|
|
|
+ const feedbackData = {
|
|
|
|
|
+ userId: userId,
|
|
|
|
|
+ feedbackType: feedbackTypeNum,
|
|
|
|
|
+ content: this.feedbackContent,
|
|
|
|
|
+ imageUrls: imageUrls.join(',') // 将图片URL数组转换为逗号分隔的字符串
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 提交反馈
|
|
|
|
|
+ await api.feedback.submit(feedbackData);
|
|
|
|
|
+
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: '反馈提交成功',
|
|
|
|
|
+ icon: 'success'
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 提交成功后返回上一页
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ this.goBack();
|
|
|
|
|
+ }, 1500);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ console.error('提交反馈失败:', error);
|
|
|
|
|
+ let errorMsg = '反馈提交失败,请稍后重试';
|
|
|
|
|
+ if (error && error.message) {
|
|
|
|
|
+ errorMsg = error.message;
|
|
|
|
|
+ } else if (error && error.errMsg) {
|
|
|
|
|
+ errorMsg = error.errMsg;
|
|
|
|
|
+ }
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: errorMsg,
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+.feedback-page {
|
|
|
|
|
+ min-height: 100vh;
|
|
|
|
|
+ background: #F5F5F5;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 页面标题 */
|
|
|
|
|
+.page-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ height: 88rpx;
|
|
|
|
|
+ background: #FFFFFF;
|
|
|
|
|
+ padding: 0 30rpx;
|
|
|
|
|
+ box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
|
|
|
|
+ position: sticky;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ z-index: 99;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.header-left,
|
|
|
|
|
+.header-right {
|
|
|
|
|
+ width: 60rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.back-icon {
|
|
|
|
|
+ font-size: 40rpx;
|
|
|
|
|
+ color: #333333;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.header-title {
|
|
|
|
|
+ font-size: 32rpx;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #333333;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 反馈内容 */
|
|
|
|
|
+.feedback-content {
|
|
|
|
|
+ padding: 30rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.section {
|
|
|
|
|
+ background: #FFFFFF;
|
|
|
|
|
+ border-radius: 12rpx;
|
|
|
|
|
+ padding: 30rpx;
|
|
|
|
|
+ margin-bottom: 30rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.section-title {
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #333333;
|
|
|
|
|
+ margin-bottom: 20rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 反馈类型 */
|
|
|
|
|
+.feedback-type {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 20rpx;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.type-item {
|
|
|
|
|
+ padding: 16rpx 32rpx;
|
|
|
|
|
+ background: #F5F5F5;
|
|
|
|
|
+ border-radius: 20rpx;
|
|
|
|
|
+ border: 2rpx solid #E0E0E0;
|
|
|
|
|
+ transition: all 0.2s ease;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.type-item.active {
|
|
|
|
|
+ background: #FFE5F1;
|
|
|
|
|
+ border-color: #E91E63;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.type-text {
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ color: #666666;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.type-item.active .type-text {
|
|
|
|
|
+ color: #E91E63;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 反馈输入 */
|
|
|
|
|
+.feedback-input {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ min-height: 200rpx;
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ color: #333333;
|
|
|
|
|
+ border: 2rpx solid #E0E0E0;
|
|
|
|
|
+ border-radius: 12rpx;
|
|
|
|
|
+ padding: 20rpx;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ resize: none;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.feedback-input::placeholder {
|
|
|
|
|
+ color: #CCCCCC;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.word-count {
|
|
|
|
|
+ text-align: right;
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+ color: #999999;
|
|
|
|
|
+ margin-top: 10rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 图片上传 */
|
|
|
|
|
+.image-uploader {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 20rpx;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.upload-item {
|
|
|
|
|
+ width: 200rpx;
|
|
|
|
|
+ height: 200rpx;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ border-radius: 12rpx;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ border: 2rpx solid #E0E0E0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.uploaded-image {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.delete-icon {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 10rpx;
|
|
|
|
|
+ right: 10rpx;
|
|
|
|
|
+ width: 40rpx;
|
|
|
|
|
+ height: 40rpx;
|
|
|
|
|
+ background: rgba(0, 0, 0, 0.5);
|
|
|
|
|
+ color: #FFFFFF;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ font-size: 30rpx;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.upload-btn {
|
|
|
|
|
+ width: 200rpx;
|
|
|
|
|
+ height: 200rpx;
|
|
|
|
|
+ border: 2rpx dashed #E0E0E0;
|
|
|
|
|
+ border-radius: 12rpx;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ background: #F9F9F9;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.upload-icon {
|
|
|
|
|
+ font-size: 60rpx;
|
|
|
|
|
+ color: #CCCCCC;
|
|
|
|
|
+ margin-bottom: 10rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.upload-text {
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+ color: #999999;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.upload-tip {
|
|
|
|
|
+ font-size: 22rpx;
|
|
|
|
|
+ color: #999999;
|
|
|
|
|
+ margin-top: 10rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 提交按钮 */
|
|
|
|
|
+.submit-section {
|
|
|
|
|
+ padding: 30rpx;
|
|
|
|
|
+ background: #FFFFFF;
|
|
|
|
|
+ margin-top: 30rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.submit-btn {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 90rpx;
|
|
|
|
|
+ background: #E91E63;
|
|
|
|
|
+ color: #FFFFFF;
|
|
|
|
|
+ font-size: 32rpx;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ border-radius: 45rpx;
|
|
|
|
|
+ border: none;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.submit-btn:disabled {
|
|
|
|
|
+ background: #CCCCCC;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.submit-btn::after {
|
|
|
|
|
+ border: none;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+</style>
|