Files
DJKB/my-vue-app/src/components/FeedbackForm.vue
lbw_9527443 b0c2f28d7f feat(录音管理): 添加优秀录音组件并优化API调用
refactor(性能优化): 使用Promise.all并行请求核心KPI接口

style(样式调整): 修改ProblemRanking组件高度和内边距

chore: 移除调试用的console.log语句
2025-10-29 17:11:57 +08:00

334 lines
7.3 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>
<div v-if="isVisible" class="modal-overlay" @click="closeModal">
<div class="modal-container" @click.stop>
<div class="modal-header">
<h3>意见反馈</h3>
<button class="modal-close-btn" @click="closeModal">×</button>
</div>
<div class="feedback-form-container">
<h2>意见反馈</h2>
<p class="subtitle">我们期待听到您的声音不断改进我们的产品</p>
<!-- 提交成功或失败的提示信息 -->
<div v-if="submitStatus === 'success'" class="feedback-message success">
感谢您的反馈我们已经收到您的宝贵意见
</div>
<div v-if="submitStatus === 'error'" class="feedback-message error">
提交失败请检查网络或稍后重试
</div>
<form v-if="submitStatus !== 'success'" @submit.prevent="handleSubmit">
<!-- 反馈类型 -->
<div class="form-group">
<label for="feedback-type">反馈类型</label>
<select id="feedback-type" v-model="formData.type">
<option>功能建议</option>
<option>界面优化</option>
<option>Bug 反馈</option>
<option>其他</option>
</select>
</div>
<!-- 反馈内容 -->
<div class="form-group">
<label for="feedback-content">反馈内容 (必填)</label>
<textarea
id="feedback-content"
v-model="formData.content"
placeholder="请详细描述您的问题或建议..."
rows="6"
required
></textarea>
</div>
<!-- 提交按钮 -->
<div class="form-actions">
<button type="submit" :disabled="isSubmitting">
<span v-if="isSubmitting">正在提交...</span>
<span v-else>提交反馈</span>
</button>
</div>
</form>
</div>
</div>
</div>
</template>
<script setup>
import axios from 'axios';
import { ref, reactive } from 'vue';
// 定义组件的props
const props = defineProps({
isVisible: {
type: Boolean,
default: false
}
});
// 定义组件要触发的事件
const emit = defineEmits(['submit-feedback', 'close']);
// 使用 reactive 创建响应式表单数据对象
const formData = reactive({
type: '功能建议', // 默认值
content: '',
contact: '',
screenshot: null, // 存储文件对象
});
// ref 用于独立的响应式值
const isSubmitting = ref(false); // 是否正在提交
const submitStatus = ref(null); // 'success', 'error', or null
const imagePreviewUrl = ref(null); // 图片预览 URL
const fileInputRef = ref(null); // 用于引用文件输入元素
// 文件选择变化时的处理函数
const handleFileChange = (event) => {
const file = event.target.files[0];
if (file) {
formData.screenshot = file;
// 创建一个临时的 URL 用于图片预览
imagePreviewUrl.value = URL.createObjectURL(file);
}
};
// 移除已选图片
const removeImage = () => {
formData.screenshot = null;
imagePreviewUrl.value = null;
// 清空文件输入框的值,以便用户可以再次选择相同的文件
if (fileInputRef.value) {
fileInputRef.value.value = '';
}
};
// 关闭模态框
const closeModal = () => {
emit('close');
};
// 表单提交处理函数
const handleSubmit = async () => {
// 简单验证
if (!formData.content.trim()) {
alert('反馈内容不能为空!');
return;
}
isSubmitting.value = true;
submitStatus.value = null;
try {
// 创建 FormData 对象
// 获取 token (假设存储在 localStorage 中)
const token = localStorage.getItem('token') || '';
// 发送 POST 请求到后端接口
const response = await axios.post('https://feedback.api.nycjy.cn/api/v1/feedback/submit_feedback', {project:'mldash',type: formData.type, content: formData.content}, {
headers: {
'Authorization': `Bearer ${token}`
}
});
// console.log('响应状态8888:', response.data.message);
// 提交成功
submitStatus.value = 'success';
// 触发父组件的事件,并传递数据
emit('submit-feedback', { ...formData });
} catch (error) {
console.error('提交反馈失败:', error);
// 提交失败
submitStatus.value = 'error';
} finally {
// 请求结束
isSubmitting.value = false;
}
};
</script>
<style scoped>
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-container {
background-color: #ffffff;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
max-width: 600px;
width: 90%;
max-height: 90vh;
overflow-y: auto;
position: relative;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
border-bottom: 1px solid #e2e8f0;
}
.modal-header h3 {
margin: 0;
color: #1a202c;
font-size: 1.25rem;
}
.modal-close-btn {
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: #718096;
padding: 0;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
}
.modal-close-btn:hover {
color: #1a202c;
}
.feedback-form-container {
padding: 2rem;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}
h2 {
text-align: center;
color: #1a202c;
margin-top: 0;
margin-bottom: 0.5rem;
}
.subtitle {
text-align: center;
color: #718096;
margin-bottom: 2rem;
}
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
color: #4a5568;
}
input[type="text"],
select,
textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid #cbd5e0;
border-radius: 6px;
font-size: 1rem;
color: #2d3748;
transition: border-color 0.2s, box-shadow 0.2s;
}
input[type="text"]:focus,
select:focus,
textarea:focus {
outline: none;
border-color: #4299e1;
box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
}
input[type="file"] {
width: 100%;
padding: 0.5rem;
}
.image-preview {
position: relative;
margin-top: 1rem;
max-width: 200px;
}
.image-preview img {
width: 100%;
height: auto;
border-radius: 6px;
border: 1px solid #e2e8f0;
}
.remove-image-btn {
position: absolute;
top: -10px;
right: -10px;
background-color: #e53e3e;
color: white;
border: none;
border-radius: 50%;
width: 24px;
height: 24px;
font-size: 16px;
line-height: 24px;
text-align: center;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.form-actions {
text-align: center;
}
button[type="submit"] {
padding: 0.75rem 2rem;
background-color: #4299e1;
color: white;
border: none;
border-radius: 6px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: background-color 0.2s;
width: 100%;
}
button[type="submit"]:hover:not(:disabled) {
background-color: #3182ce;
}
button[type="submit"]:disabled {
background-color: #a0aec0;
cursor: not-allowed;
}
.feedback-message {
padding: 1rem;
border-radius: 6px;
text-align: center;
margin-bottom: 1.5rem;
font-weight: 500;
}
.feedback-message.success {
background-color: #c6f6d5;
color: #2f855a;
border: 1px solid #9ae6b4;
}
.feedback-message.error {
background-color: #fed7d7;
color: #c53030;
border: 1px solid #feb2b2;
}
</style>