index.vue 6.99 KB
<!--
 * @Date: 2022-09-19 14:11:06
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2025-07-07 16:46:44
 * @FilePath: /jgdl/src/pages/feedBack/index.vue
 * @Description: 意见反馈页面
-->
<template>
  <view class="feedback-page">
    <view class="content">
      <!-- 提示文字 -->
      <view class="tip-text">
        感谢您的宝贵意见,我们将不断完善产品和服务
      </view>

      <!-- 反馈分类 -->
      <view class="category-section">
        <view class="category-grid">
          <view
            v-for="category in categories"
            :key="category.id"
            class="category-item"
            :class="{ active: selectedCategory === category.id }"
            @click="selectCategory(category.id)"
          >
            <view class="category-icon" :class="{ active: selectedCategory === category.id }">
              <text class="icon-text">{{ category.icon }}</text>
            </view>
            <text class="category-name">{{ category.name }}</text>
          </view>
        </view>
      </view>

      <!-- 反馈内容 -->
      <view class="feedback-section">
        <textarea
          v-model="feedbackText"
          placeholder="请详细描述您遇到的问题或建议..."
          class="feedback-textarea"
          maxlength="200"
        />
        <view class="char-count">
          {{ feedbackText.length }}/200
        </view>
      </view>

      <!-- 图片上传 -->
      <view class="image-section">
        <view class="section-label">上传图片(选填)</view>
        <view class="image-upload-grid">
          <!-- 已上传的图片 -->
          <view
            v-for="(image, index) in uploadedImages"
            :key="index"
            class="image-item"
          >
            <view class="image-preview" @click="previewImage(image)">
              <image :src="image" class="preview-image" mode="aspectFill" />
              <view class="delete-btn" @click.stop="deleteImage(index)">
                <Close class="delete-icon" />
              </view>
            </view>
          </view>

          <!-- 上传按钮 -->
          <view
            v-if="uploadedImages.length < 3"
            class="upload-button"
            @click="triggerUpload"
          >
            <Plus class="upload-icon" />
          </view>
        </view>
        <view class="upload-tip">最多上传3张</view>
      </view>

      <!-- 联系方式 -->
      <view class="contact-section">
        <view class="section-label">联系方式(选填)</view>
        <nut-input
          v-model="contactInfo"
          placeholder="请留下您的手机号或微信号"
        />
      </view>

      <!-- 提交按钮 -->
      <view class="submit-section">
        <button
          class="submit-btn"
          :class="{ disabled: !canSubmit }"
          :disabled="!canSubmit"
          @click="handleSubmit"
        >
          提交反馈
        </button>
      </view>
    </view>

    <!-- 图片预览组件 -->
    <nut-image-preview
      v-model:show="previewVisible"
      :images="previewImages"
      :init-no="previewIndex"
      @close="closePreview"
    />

    <!-- 成功提示弹窗 -->
    <nut-overlay v-model:visible="showSuccessModal" @click="closeSuccessModal">
      <view class="success-modal">
        <view class="success-content">
          <view class="success-icon">
            <text class="check-icon">✓</text>
          </view>
          <view class="success-title">反馈成功</view>
          <view class="success-desc">感谢您的反馈</view>
        </view>
      </view>
    </nut-overlay>
  </view>
</template>

<script setup>
import { ref, computed } from 'vue'
import Taro from '@tarojs/taro'
import { Left, Plus, Close } from '@nutui/icons-vue-taro'
import { Toast } from '@nutui/nutui-taro'
import './index.less'

// 反馈分类
const categories = ref([
  { id: 'feature', name: '功能建议', icon: '💡' },
  { id: 'ui', name: '界面设计', icon: '✖️' },
  { id: 'vehicle', name: '车辆信息', icon: '🚲' },
  { id: 'other', name: '其他问题', icon: '❓' }
])

// 表单数据
const selectedCategory = ref(null)
const feedbackText = ref('')
const contactInfo = ref('')
const uploadedImages = ref([])

// 图片预览相关
const previewVisible = ref(false)
const previewImages = ref([])
const previewIndex = ref(0)

// 成功弹窗
const showSuccessModal = ref(false)

// 计算属性:是否可以提交
const canSubmit = computed(() => {
  return selectedCategory.value && feedbackText.value.trim()
})

/**
 * 返回上一页
 */
const goBack = () => {
  Taro.navigateBack()
}

/**
 * 选择反馈分类
 */
const selectCategory = (categoryId) => {
  selectedCategory.value = categoryId
}

/**
 * 触发图片上传
 */
const triggerUpload = () => {
  if (uploadedImages.value.length >= 3) {
    Toast.fail('最多只能上传3张图片')
    return
  }

  Taro.chooseImage({
    count: 1,
    sizeType: ['compressed'],
    sourceType: ['album', 'camera'],
    success: function (res) {
      const tempFilePath = res.tempFilePaths[0]
      uploadImage(tempFilePath)
    },
    fail: function () {
      Toast.fail('选择图片失败')
    }
  })
}

/**
 * 上传图片到服务器
 */
const uploadImage = (filePath) => {
  Taro.showLoading({ title: '上传中', mask: true })

  // 模拟上传成功(实际项目中替换为真实的上传逻辑)
  setTimeout(() => {
    Taro.hideLoading()

    // 模拟服务器返回的图片URL
    const mockImageUrl = filePath // 在实际项目中,这里应该是服务器返回的URL

    // 添加到已上传图片列表
    uploadedImages.value.push(mockImageUrl)

    Taro.showToast({
      title: '上传成功',
      icon: 'success',
      duration: 2000
    })
  }, 1500)
}

/**
 * 预览图片
 */
const previewImage = (imageUrl) => {
  previewImages.value = [{ src: imageUrl }]
  previewIndex.value = 0
  previewVisible.value = true
}

/**
 * 删除图片
 */
const deleteImage = (index) => {
  uploadedImages.value.splice(index, 1)
  Toast.success('删除成功')
}

/**
 * 关闭图片预览
 */
const closePreview = () => {
  previewVisible.value = false
}

/**
 * 提交反馈
 */
const handleSubmit = () => {
  if (!canSubmit.value) return

  Taro.showLoading({ title: '提交中...', mask: true })

  // 构建提交数据
  const submitData = {
    category: selectedCategory.value,
    content: feedbackText.value.trim(),
    contact: contactInfo.value.trim(),
    images: uploadedImages.value
  }

  // TODO: 调用实际的API接口提交数据
  // submitFeedback(submitData)

  // 模拟提交
  setTimeout(() => {
    Taro.hideLoading()
    showSuccessModal.value = true

    // 2秒后自动关闭并重置表单
    setTimeout(() => {
      closeSuccessModal()
    }, 2000)
  }, 1500)
}

/**
 * 关闭成功弹窗并重置表单
 */
const closeSuccessModal = () => {
  showSuccessModal.value = false

  // 重置表单
  selectedCategory.value = null
  feedbackText.value = ''
  contactInfo.value = ''
  uploadedImages.value = []
}
</script>

<script>
export default {
  name: 'FeedbackPage'
}
</script>