fix: 意见反馈功能提交。
This commit is contained in:
21
src/api/system/feedback.js
Normal file
21
src/api/system/feedback.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import request from '@/utils/request'
|
||||
import upload from '@/utils/upload'
|
||||
|
||||
// 提交意见反馈(H5/小程序端)
|
||||
export function submitFeedback(data) {
|
||||
return request({
|
||||
url: '/system/feedback/submit',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 上传反馈截图
|
||||
export function uploadFeedbackImage(filePath) {
|
||||
return upload({
|
||||
url: '/file/upload',
|
||||
filePath,
|
||||
name: 'file',
|
||||
formData: {}
|
||||
})
|
||||
}
|
||||
@@ -187,6 +187,12 @@
|
||||
"navigationBarTitleText": "常见问题"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "feedback/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "意见反馈"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "about/index",
|
||||
"style": {
|
||||
|
||||
@@ -37,12 +37,22 @@
|
||||
</view>
|
||||
<text class="action-text">交流社区</text>
|
||||
</view>
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<button class="action-card action-button" open-type="contact" @contact="handleContact">
|
||||
<view class="action-icon" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);">
|
||||
<uni-icons type="contact" size="24" color="#ffffff"></uni-icons>
|
||||
</view>
|
||||
<text class="action-text">联系客服</text>
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef MP-WEIXIN -->
|
||||
<view class="action-card" @click="handleService">
|
||||
<view class="action-icon" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);">
|
||||
<uni-icons type="contact" size="24" color="#ffffff"></uni-icons>
|
||||
</view>
|
||||
<text class="action-text">联系客服</text>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<view class="action-card" @click="handleBuilding">
|
||||
<view class="action-icon" style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);">
|
||||
<uni-icons type="compose" size="24" color="#ffffff"></uni-icons>
|
||||
@@ -53,7 +63,7 @@
|
||||
<view class="action-icon" style="background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);">
|
||||
<uni-icons type="star" size="24" color="#ffffff"></uni-icons>
|
||||
</view>
|
||||
<text class="action-text">给个好评</text>
|
||||
<text class="action-text">支持我们</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -134,6 +144,9 @@ const userStore = useUserStore()
|
||||
const name = userStore.name;
|
||||
const userId = computed(() => userStore.userId || '');
|
||||
const version = config.appInfo.version;
|
||||
const communityWechat = 'intc126';
|
||||
const servicePhone = '17753252359';
|
||||
const officialSite = config.appInfo.site_url;
|
||||
|
||||
const popup = ref(null);
|
||||
function handleToInfo() {
|
||||
@@ -182,35 +195,73 @@ function handleAbout() {
|
||||
});
|
||||
};
|
||||
function handleJiaoLiuQun() {
|
||||
uni.showToast({
|
||||
title: 'intc126',
|
||||
mask: false,
|
||||
icon: "none",
|
||||
duration: 5000
|
||||
uni.showModal({
|
||||
title: '加入交流群',
|
||||
content: `复制微信号 ${communityWechat},添加后备注“智聪网络科技”,获取使用交流、问题答疑和功能更新。`,
|
||||
confirmText: '复制微信号',
|
||||
cancelText: '稍后再说',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
copyText(communityWechat, '微信号已复制');
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
function handleBuilding() {
|
||||
uni.showToast({
|
||||
title: '谢谢反馈~',
|
||||
mask: false,
|
||||
icon: "none",
|
||||
duration: 1000
|
||||
uni.navigateTo({
|
||||
url: '/pages_mine/pages/feedback/index'
|
||||
});
|
||||
}
|
||||
function handleService() {
|
||||
uni.showToast({
|
||||
title: '请电联或加客服微信:17753252359',
|
||||
mask: false,
|
||||
icon: "none",
|
||||
duration: 5000
|
||||
uni.showActionSheet({
|
||||
itemList: ['拨打客服电话', '复制客服微信', '查看关于我们'],
|
||||
success: ({ tapIndex }) => {
|
||||
if (tapIndex === 0) {
|
||||
uni.makePhoneCall({ phoneNumber: servicePhone });
|
||||
} else if (tapIndex === 1) {
|
||||
copyText(servicePhone, '客服微信已复制');
|
||||
} else if (tapIndex === 2) {
|
||||
handleAbout();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function handleContact() {
|
||||
// 微信小程序端由 open-type="contact" 直接打开原生客服会话
|
||||
}
|
||||
function handleUs() {
|
||||
uni.showActionSheet({
|
||||
itemList: ['推荐给朋友', '复制官网链接', '意见反馈'],
|
||||
success: ({ tapIndex }) => {
|
||||
if (tapIndex === 0) {
|
||||
uni.showModal({
|
||||
title: '感谢支持',
|
||||
content: '如果觉得好用,可以点击右上角“···”分享给朋友,也欢迎把官网链接发给需要的人。',
|
||||
confirmText: '复制官网',
|
||||
cancelText: '知道了',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
copyText(officialSite, '官网链接已复制');
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (tapIndex === 1) {
|
||||
copyText(officialSite, '官网链接已复制');
|
||||
} else if (tapIndex === 2) {
|
||||
handleBuilding();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function copyText(data, title = '复制成功') {
|
||||
uni.setClipboardData({
|
||||
data,
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: '谢谢点赞!',
|
||||
mask: false,
|
||||
icon: "none",
|
||||
duration: 1000
|
||||
title,
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@@ -403,6 +454,18 @@ page {
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.action-button {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
line-height: 1;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu-section {
|
||||
|
||||
413
src/pages_mine/pages/feedback/index.vue
Normal file
413
src/pages_mine/pages/feedback/index.vue
Normal file
@@ -0,0 +1,413 @@
|
||||
<template>
|
||||
<view class="feedback-container">
|
||||
<view class="intro-card">
|
||||
<view class="intro-icon">
|
||||
<uni-icons type="compose" size="28" color="#ffffff"></uni-icons>
|
||||
</view>
|
||||
<view class="intro-content">
|
||||
<text class="intro-title">意见反馈</text>
|
||||
<text class="intro-desc">请描述遇到的问题或功能建议。</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-card">
|
||||
<view class="form-item">
|
||||
<text class="label">反馈类型</text>
|
||||
<picker mode="selector" :range="feedbackTypes" :value="feedbackTypeIndex" @change="handleTypeChange">
|
||||
<view class="picker-row">
|
||||
<text>{{ currentType }}</text>
|
||||
<uni-icons type="right" size="16" color="#c0c4cc"></uni-icons>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label required">反馈内容</text>
|
||||
<textarea
|
||||
v-model="content"
|
||||
class="content-input"
|
||||
maxlength="500"
|
||||
placeholder="请尽量说明操作步骤、看到的问题或希望增加的功能"
|
||||
placeholder-class="placeholder"
|
||||
/>
|
||||
<text class="count-text">{{ content.length }}/500</text>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">联系方式</text>
|
||||
<input
|
||||
v-model="contact"
|
||||
class="contact-input"
|
||||
maxlength="100"
|
||||
placeholder="选填,便于客服进一步沟通"
|
||||
placeholder-class="placeholder"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="label-row">
|
||||
<text class="label">截图</text>
|
||||
<text class="tip-text">选填,最多 3 张</text>
|
||||
</view>
|
||||
<view class="image-list">
|
||||
<view v-for="(image, index) in imageList" :key="image" class="image-item">
|
||||
<image :src="image" mode="aspectFill"></image>
|
||||
<view class="remove-image" @click="removeImage(index)">
|
||||
<uni-icons type="closeempty" size="18" color="#ffffff"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="imageList.length < 3" class="add-image" @click="chooseImages">
|
||||
<uni-icons type="plusempty" size="28" color="#909399"></uni-icons>
|
||||
<text>添加截图</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="submit-section">
|
||||
<button class="submit-btn" :loading="submitting" :disabled="submitting" @click="handleSubmit">
|
||||
{{ submitting ? '提交中...' : '提交反馈' }}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import appConfig from '@/config'
|
||||
import { submitFeedback, uploadFeedbackImage } from '@/api/system/feedback'
|
||||
|
||||
const feedbackTypes = ['功能建议', '问题反馈', '数据异常', '其他']
|
||||
const feedbackTypeIndex = ref(0)
|
||||
const content = ref('')
|
||||
const contact = ref('')
|
||||
const imageList = ref([])
|
||||
const submitting = ref(false)
|
||||
const serviceWechat = '17753252359'
|
||||
|
||||
const currentType = computed(() => feedbackTypes[feedbackTypeIndex.value])
|
||||
|
||||
function handleTypeChange(e) {
|
||||
feedbackTypeIndex.value = Number(e.detail.value)
|
||||
}
|
||||
|
||||
function chooseImages() {
|
||||
const restCount = 3 - imageList.value.length
|
||||
if (restCount <= 0 || submitting.value) return
|
||||
|
||||
uni.chooseImage({
|
||||
count: restCount,
|
||||
sizeType: ['compressed'],
|
||||
success: (res) => {
|
||||
imageList.value = imageList.value.concat(res.tempFilePaths || []).slice(0, 3)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function removeImage(index) {
|
||||
if (submitting.value) return
|
||||
imageList.value.splice(index, 1)
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (submitting.value) return
|
||||
|
||||
const feedbackContent = content.value.trim()
|
||||
if (!feedbackContent) {
|
||||
uni.showToast({
|
||||
title: '请先填写反馈内容',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
submitting.value = true
|
||||
uni.showLoading({ title: imageList.value.length ? '上传截图中...' : '提交中...' })
|
||||
|
||||
try {
|
||||
const imageUrls = await uploadImages(imageList.value)
|
||||
uni.showLoading({ title: '提交中...' })
|
||||
|
||||
await submitFeedback({
|
||||
feedbackType: currentType.value,
|
||||
content: feedbackContent,
|
||||
contact: contact.value.trim(),
|
||||
images: imageUrls.join(','),
|
||||
source: getFeedbackSource()
|
||||
})
|
||||
|
||||
content.value = ''
|
||||
contact.value = ''
|
||||
imageList.value = []
|
||||
feedbackTypeIndex.value = 0
|
||||
|
||||
uni.hideLoading()
|
||||
uni.showModal({
|
||||
title: '提交成功',
|
||||
content: '您的反馈已提交,我们会尽快处理。',
|
||||
confirmText: '知道了',
|
||||
showCancel: false
|
||||
})
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
if (error !== '500') {
|
||||
uni.showToast({
|
||||
title: '提交失败,请稍后重试',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadImages(paths) {
|
||||
const urls = []
|
||||
for (const path of paths) {
|
||||
const uploadRes = await uploadFeedbackImage(path)
|
||||
urls.push(normalizeUploadUrl(uploadRes))
|
||||
}
|
||||
return urls
|
||||
}
|
||||
|
||||
function normalizeUploadUrl(uploadRes) {
|
||||
const data = uploadRes?.data || {}
|
||||
const url = data.url || data.fileName || uploadRes?.url || uploadRes?.fileName || uploadRes?.imgUrl
|
||||
if (!url) {
|
||||
throw new Error('上传截图失败')
|
||||
}
|
||||
if (/^https?:\/\//.test(url)) {
|
||||
return url
|
||||
}
|
||||
return `${appConfig.baseUrl}${url.startsWith('/') ? '' : '/'}${url}`
|
||||
}
|
||||
|
||||
function getFeedbackSource() {
|
||||
// #ifdef MP-WEIXIN
|
||||
return '小程序'
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
return 'H5'
|
||||
// #endif
|
||||
return 'App'
|
||||
}
|
||||
|
||||
function copyServiceWechat() {
|
||||
uni.setClipboardData({
|
||||
data: serviceWechat,
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: '客服微信已复制',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
background-color: #f5f7fa;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.feedback-container {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.intro-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 28rpx;
|
||||
border-radius: 24rpx;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
box-shadow: 0 8rpx 32rpx rgba(102, 126, 234, 0.22);
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.intro-icon {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 20rpx;
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 20rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.intro-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.intro-title {
|
||||
color: #ffffff;
|
||||
font-size: 34rpx;
|
||||
font-weight: 700;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.intro-desc {
|
||||
color: rgba(255, 255, 255, 0.86);
|
||||
font-size: 24rpx;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
|
||||
.form-card {
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f8f9fb 100%);
|
||||
border-radius: 24rpx;
|
||||
padding: 8rpx 28rpx 28rpx;
|
||||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.form-item {
|
||||
padding-top: 28rpx;
|
||||
}
|
||||
|
||||
.label-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: block;
|
||||
color: #303133;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.required::after {
|
||||
content: '*';
|
||||
color: #f56c6c;
|
||||
margin-left: 4rpx;
|
||||
}
|
||||
|
||||
.tip-text,
|
||||
.count-text {
|
||||
color: #909399;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.count-text {
|
||||
display: block;
|
||||
text-align: right;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.picker-row,
|
||||
.contact-input,
|
||||
.content-input {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background: #f7f8fb;
|
||||
border: 1rpx solid #e8edf3;
|
||||
border-radius: 18rpx;
|
||||
color: #303133;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.picker-row {
|
||||
min-height: 88rpx;
|
||||
padding: 0 22rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.contact-input {
|
||||
height: 88rpx;
|
||||
padding: 0 22rpx;
|
||||
}
|
||||
|
||||
.content-input {
|
||||
min-height: 220rpx;
|
||||
padding: 22rpx;
|
||||
line-height: 38rpx;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
.image-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.image-item,
|
||||
.add-image {
|
||||
width: 152rpx;
|
||||
height: 152rpx;
|
||||
border-radius: 18rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.image-item image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.remove-image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 42rpx;
|
||||
height: 42rpx;
|
||||
border-bottom-left-radius: 18rpx;
|
||||
background: rgba(0, 0, 0, 0.48);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.add-image {
|
||||
border: 2rpx dashed #dcdfe6;
|
||||
background: #f7f8fb;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #909399;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.submit-section {
|
||||
padding: 32rpx 0 16rpx;
|
||||
}
|
||||
|
||||
.submit-btn,
|
||||
.service-btn {
|
||||
height: 88rpx;
|
||||
border-radius: 44rpx;
|
||||
font-size: 28rpx;
|
||||
margin: 0 0 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
color: #ffffff;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.28);
|
||||
}
|
||||
|
||||
.service-btn {
|
||||
color: #667eea;
|
||||
background: #ffffff;
|
||||
border: 1rpx solid rgba(102, 126, 234, 0.28);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user