peixue-dev/peidu/uniapp/common-package/pages/feedback/create.vue

312 lines
6.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="feedback-page">
<view class="form">
<view class="form-item">
<view class="label">反馈类型</view>
<picker :range="types" range-key="label" @change="onTypeChange">
<view class="picker">
{{ selectedType.label || '请选择' }}
<text class="arrow"></text>
</view>
</picker>
</view>
<view class="form-item">
<view class="label">反馈内容</view>
<textarea
v-model="form.content"
placeholder="请详细描述您的问题或建议"
maxlength="500"
:show-confirm-bar="false"
/>
<view class="count">{{ form.content.length }}/500</view>
</view>
<view class="form-item">
<view class="label">上传图片(选填)</view>
<view class="image-list">
<view
v-for="(img, index) in form.images"
:key="index"
class="image-item"
>
<image :src="img" mode="aspectFill" />
<view class="delete" @click="deleteImage(index)">×</view>
</view>
<view
v-if="form.images.length < 9"
class="image-item upload"
@click="chooseImage"
>
<text>+</text>
</view>
</view>
</view>
<view class="form-item">
<view class="label">联系方式(选填)</view>
<input
v-model="form.contact"
placeholder="手机号或微信号,方便我们联系您"
maxlength="50"
/>
</view>
</view>
<view class="submit-btn">
<button @click="submit" :disabled="!canSubmit">提交反馈</button>
</view>
</view>
</template>
<script>
import { feedbackApi } from '@/api/index.js'
export default {
data() {
return {
types: [
{ label: '功能建议', value: 'suggestion' },
{ label: '问题反馈', value: 'problem' },
{ label: '投诉', value: 'complaint' }
],
form: {
type: '',
content: '',
images: [],
contact: ''
}
}
},
computed: {
selectedType() {
return this.types.find(t => t.value === this.form.type) || {}
},
canSubmit() {
return this.form.type && this.form.content.trim().length >= 10
}
},
methods: {
onTypeChange(e) {
this.form.type = this.types[e.detail.value].value
},
chooseImage() {
const self = this
uni.chooseImage({
count: 9 - this.form.images.length,
sizeType: ['compressed'], // 使用压缩图
sourceType: ['album', 'camera'],
success: async (res) => {
uni.showLoading({ title: '上传中...' })
try {
// 逐个上传,避免并发过多
for (const filePath of res.tempFilePaths) {
const url = await self.uploadSingleImage(filePath)
if (url) {
self.form.images.push(url)
}
}
uni.hideLoading()
uni.showToast({ title: '上传成功', icon: 'success' })
} catch (error) {
console.error('上传失败', error)
uni.hideLoading()
uni.showToast({ title: '上传失败', icon: 'none' })
}
}
})
},
// 单张图片上传
uploadSingleImage(filePath) {
return new Promise((resolve, reject) => {
uni.uploadFile({
url: 'http://localhost:8089/api/upload/image',
filePath: filePath,
name: 'file',
success: (res) => {
if (res.statusCode === 200) {
try {
const data = JSON.parse(res.data)
if (data.code === 200) {
resolve(data.data.fileUrl || data.data.url || data.data)
} else {
reject(data.message || '上传失败')
}
} catch (e) {
reject('解析响应失败')
}
} else {
reject('上传失败')
}
},
fail: (err) => {
reject(err)
}
})
})
},
deleteImage(index) {
this.form.images.splice(index, 1)
},
async submit() {
if (!this.canSubmit) return
uni.showLoading({ title: '提交中...' })
try {
await feedbackApi.submit({
...this.form,
images: JSON.stringify(this.form.images)
})
uni.showToast({
title: '提交成功',
icon: 'success',
duration: 2000
})
setTimeout(() => {
uni.navigateBack()
}, 2000)
} catch (error) {
uni.showToast({ title: '提交失败', icon: 'none' })
} finally {
uni.hideLoading()
}
}
}
}
</script>
<style lang="scss" scoped>
.feedback-page {
min-height: 100vh;
background: #f5f5f5;
padding: 20rpx;
}
.form {
background: #fff;
border-radius: 16rpx;
padding: 20rpx;
}
.form-item {
margin-bottom: 40rpx;
.label {
font-size: 28rpx;
font-weight: bold;
margin-bottom: 20rpx;
}
.picker {
height: 80rpx;
line-height: 80rpx;
padding: 0 20rpx;
background: #f5f5f5;
border-radius: 8rpx;
display: flex;
justify-content: space-between;
align-items: center;
.arrow {
font-size: 40rpx;
color: #999;
}
}
textarea {
width: 100%;
min-height: 300rpx;
padding: 20rpx;
background: #f5f5f5;
border-radius: 8rpx;
font-size: 28rpx;
}
.count {
text-align: right;
font-size: 24rpx;
color: #999;
margin-top: 10rpx;
}
input {
height: 80rpx;
padding: 0 20rpx;
background: #f5f5f5;
border-radius: 8rpx;
font-size: 28rpx;
}
}
.image-list {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
.image-item {
width: 200rpx;
height: 200rpx;
border-radius: 8rpx;
overflow: hidden;
position: relative;
image {
width: 100%;
height: 100%;
}
.delete {
position: absolute;
top: 0;
right: 0;
width: 50rpx;
height: 50rpx;
background: rgba(0, 0, 0, 0.6);
color: #fff;
text-align: center;
line-height: 50rpx;
font-size: 40rpx;
}
&.upload {
background: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
text {
font-size: 80rpx;
color: #999;
}
}
}
.submit-btn {
margin-top: 40rpx;
button {
width: 100%;
height: 88rpx;
background: #5677fc;
color: #fff;
border: none;
border-radius: 8rpx;
font-size: 32rpx;
&[disabled] {
background: #ccc;
}
}
}
</style>