Pārlūkot izejas kodu

意见反馈内容完成

yuanmingze 2 mēneši atpakaļ
vecāks
revīzija
97691d5dd8

+ 220 - 0
src/pages-mine/feedback/index.vue

@@ -0,0 +1,220 @@
+<template>
+  <view class="feedback-page">
+    <view class="feedback-header">
+      <view class="title">意见反馈</view>
+      <view class="desc">请填写你遇到的问题或建议,我们会认真查看并持续优化。</view>
+    </view>
+
+    <view class="feedback-card">
+      <view class="card-head">
+        <text class="card-title">反馈内容</text>
+        <text class="card-count" :class="{ limit: feedbackLength >= MAX_LENGTH }">
+          {{ feedbackLength }}/{{ MAX_LENGTH }}
+        </text>
+      </view>
+
+      <textarea
+        v-model="feedbackContent"
+        class="feedback-textarea"
+        :maxlength="MAX_LENGTH"
+        placeholder="请尽量描述清楚问题场景、操作步骤或改进建议"
+        placeholder-style="color:#A8AFBC"
+        cursor-spacing="120"
+      />
+    </view>
+
+    <view class="submit-bar">
+      <view class="submit-btn" :class="{ disabled: submitting }" @click="handleSubmit">
+        {{ submitting ? '提交中...' : '提交反馈' }}
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup lang="ts">
+import { computed, ref } from 'vue'
+
+import { saveFeedbackApi } from '@/services/modules/common'
+
+import { useUserStore } from '@/stores/modules/user'
+
+const MAX_LENGTH = 500
+
+const userStore = useUserStore()
+
+const feedbackContent = ref('')
+const submitting = ref(false)
+
+const currentUserInfo = computed(() => userStore.currentUserInfo)
+
+const feedbackLength = computed(() => feedbackContent.value.length)
+
+const handleSubmit = async () => {
+  if (submitting.value) return
+
+  const content = feedbackContent.value.trim()
+
+  if (!content) {
+    uni.showToast({
+      title: '请输入反馈内容',
+      icon: 'none',
+    })
+    return
+  }
+
+  const userId = currentUserInfo.value.userId
+
+  if (!userId) {
+    uni.showToast({
+      title: '用户信息异常,请重新登录',
+      icon: 'none',
+    })
+    return
+  }
+
+  submitting.value = true
+
+  try {
+    await saveFeedbackApi({
+      ygContent: content,
+      yjUserid: userId,
+    })
+
+    uni.showToast({
+      title: '提交成功',
+      icon: 'none',
+    })
+
+    setTimeout(() => {
+      uni.navigateBack()
+    }, 800)
+  } catch (error) {
+    console.error('提交意见反馈失败:', error)
+
+    uni.showToast({
+      title: '提交失败,请稍后重试',
+      icon: 'none',
+    })
+  } finally {
+    submitting.value = false
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.feedback-page {
+  min-height: 100vh;
+  padding: 36rpx 28rpx calc(132rpx + env(safe-area-inset-bottom));
+  background: #f6f7fb;
+  box-sizing: border-box;
+}
+
+.feedback-header {
+  padding: 12rpx 4rpx 32rpx;
+
+  .title {
+    font-size: 40rpx;
+    font-weight: 700;
+    line-height: 1.3;
+    color: #172033;
+    letter-spacing: 1rpx;
+  }
+
+  .desc {
+    margin-top: 14rpx;
+    font-size: 26rpx;
+    line-height: 1.6;
+    color: #7b8494;
+  }
+}
+
+.feedback-card {
+  padding: 30rpx;
+  background: #ffffff;
+  border-radius: 28rpx;
+  box-shadow: 0 12rpx 32rpx rgba(23, 32, 51, 0.06);
+  box-sizing: border-box;
+}
+
+.card-head {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 22rpx;
+
+  .card-title {
+    position: relative;
+    padding-left: 18rpx;
+    font-size: 30rpx;
+    font-weight: 600;
+    color: #172033;
+
+    &::before {
+      position: absolute;
+      top: 50%;
+      left: 0;
+      width: 6rpx;
+      height: 28rpx;
+      border-radius: 999rpx;
+      background: #2f6bff;
+      transform: translateY(-50%);
+      content: '';
+    }
+  }
+
+  .card-count {
+    font-size: 24rpx;
+    color: #9aa3b2;
+
+    &.limit {
+      color: #ff6b4a;
+    }
+  }
+}
+
+.feedback-textarea {
+  width: 100%;
+  height: 430rpx;
+  padding: 24rpx;
+  background: #f8fafc;
+  border: 1rpx solid #edf1f6;
+  border-radius: 22rpx;
+  font-size: 28rpx;
+  line-height: 1.7;
+  color: #172033;
+  box-sizing: border-box;
+}
+
+.submit-bar {
+  position: fixed;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  padding: 18rpx 28rpx calc(18rpx + env(safe-area-inset-bottom));
+  background: rgba(246, 247, 251, 0.92);
+  backdrop-filter: blur(20rpx);
+  box-sizing: border-box;
+}
+
+.submit-btn {
+  height: 92rpx;
+  line-height: 92rpx;
+  text-align: center;
+  border-radius: 999rpx;
+  background: #2f6bff;
+  box-shadow: 0 12rpx 28rpx rgba(47, 107, 255, 0.26);
+  font-size: 30rpx;
+  font-weight: 600;
+  color: #ffffff;
+
+  &:active {
+    transform: scale(0.985);
+    opacity: 0.92;
+  }
+
+  &.disabled {
+    opacity: 0.55;
+    pointer-events: none;
+  }
+}
+</style>

+ 7 - 0
src/pages.json

@@ -70,6 +70,13 @@
             "navigationStyle": "default"
           }
         },
+        {
+          "path": "feedback/index",
+          "style": {
+            "navigationBarTitleText": "意见反馈",
+            "navigationStyle": "default"
+          }
+        },
         {
           "path": "agreement/index",
           "style": {

+ 1 - 0
src/pages/mine/mine.config.ts

@@ -32,6 +32,7 @@ export const functionList = [
     key: 'feedback',
     txt: '意见反馈',
     icon: 'https://yy-cloud-oss.oss-cn-beijing.aliyuncs.com/img/yjfk.png',
+    path: '/pages-mine/feedback/index',
   },
   {
     key: 'service',

+ 8 - 1
src/services/modules/common/index.ts

@@ -1,5 +1,5 @@
 import http from '../../index'
-import type { DictTypeResponse, SignAgreementRequest } from './type'
+import type { DictTypeResponse, SaveFeedbackRequest, SignAgreementRequest } from './type'
 
 export const signAgreementApi = (data: SignAgreementRequest) => {
   return http.post<boolean>('/admin/api/sign-agreement', data, {
@@ -11,3 +11,10 @@ export const signAgreementApi = (data: SignAgreementRequest) => {
 export const getDictTypeApi = (type: string) => {
   return http.get<DictTypeResponse>(`/admin/dict/type/${type}`)
 }
+
+export const saveFeedbackApi = (data: SaveFeedbackRequest) => {
+  return http.post<boolean>('/admin/api/saveFeedBack', data, {
+    loading: true,
+    loadingText: '提交中...',
+  })
+}

+ 5 - 0
src/services/modules/common/type.d.ts

@@ -20,3 +20,8 @@ export interface DictItem {
   createTime: string
   updateTime: string
 }
+
+export interface SaveFeedbackRequest {
+  ygContent: string
+  yjUserid: string
+}