831 lines
20 KiB
Vue
831 lines
20 KiB
Vue
<template>
|
||
<div class="demand-hall">
|
||
<div class="page-header">
|
||
<h1>需求列表</h1>
|
||
<h3>该功能仅做预约联系使用,不设计现实中的货币、账户、一般等价物;请用户分辨明细,防止电信诈骗。</h3>
|
||
</div>
|
||
<button class="btn-common btn-gradient btn-margin-right" @click="openAddModal">添加需求</button>
|
||
<button class="btn-common btn-light" @click="fetchDemands">刷新</button>
|
||
<div class="table-container">
|
||
<table class="maps-table">
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>请求者</th>
|
||
<th>QQ号</th>
|
||
<th>请求内容</th>
|
||
<th>悬赏金额</th>
|
||
<th>需求创建时间</th>
|
||
<th>回复</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr v-for="(demand, index) in demands" :key="demand.id" class="table-row" @click="showDetail(demand)">
|
||
<td class="id">{{ index + 1 }}</td>
|
||
<td class="requester">
|
||
<span v-if="!demand.requester" class="tag no-reward">匿名</span>
|
||
<span v-else>{{ demand.requester }}</span></td>
|
||
<td class="name">
|
||
<span v-if="!demand.qq_code" class="tag no-reward">匿名</span>
|
||
<span v-else>{{ demand.qq_code }}</span>
|
||
</td>
|
||
<td class="content">{{ demand.content }}</td>
|
||
<td class="reward">
|
||
<span :class="['tag', isNoReward(demand.reward) ? 'no-reward' : 'has-reward']">
|
||
{{ isNoReward(demand.reward) ? '无赏金' : demand.reward }}
|
||
</span>
|
||
</td>
|
||
<td class="date">{{ formatDate(demand.date) }}</td>
|
||
<td>
|
||
<button class="btn-common btn-gradient btn-reply" @click.stop="showReply(demand)">回复</button>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- 回复查看表单,联系方式,昵称,相关建议-->
|
||
<div v-if="replyModal" class="modal-overlay" @click="closeReplyModal">
|
||
<div class="modal-content" @click.stop>
|
||
<div class="modal-header">
|
||
<h2>回复</h2>
|
||
<button class="close-btn" @click="closeReplyModal">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form class="add-modal-form" @submit.prevent="submitReply">
|
||
<div class="form-row">
|
||
<span class="label">昵称:</span>
|
||
<input
|
||
v-model="addForm.author"
|
||
class="input"
|
||
placeholder="请输入您的昵称"
|
||
required
|
||
/>
|
||
</div>
|
||
<div class="form-row">
|
||
<span class="label">QQ号:</span>
|
||
<input
|
||
v-model="addForm.author_contact"
|
||
class="input"
|
||
placeholder="请输入您的QQ号"
|
||
required
|
||
/>
|
||
</div>
|
||
<div class="form-row">
|
||
<span class="label">相关建议:</span>
|
||
<textarea
|
||
v-model="addForm.sendcontent"
|
||
class="input"
|
||
placeholder="请输入相关建议"
|
||
rows="3"
|
||
ref="autoTextarea"
|
||
@input="autoResize"
|
||
required
|
||
></textarea>
|
||
</div>
|
||
<div v-if="addError" class="error">{{ addError }}</div>
|
||
<button class="btn-common btn-gradient submit-btn" :disabled="addLoading">
|
||
{{ addLoading ? '提交中...' : '提交' }}
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- 详情弹窗 -->
|
||
<div v-if="showModal" class="modal-overlay" @click="closeModal">
|
||
<div class="modal-content" @click.stop>
|
||
<div class="modal-header">
|
||
<h2>需求详情</h2>
|
||
<button class="close-btn" @click="closeModal">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="detail-item">
|
||
<span class="label">QQ号:</span>
|
||
<span v-if="!selectedDemand?.qq_code" class="tag no-reward">匿名</span>
|
||
<span v-else>{{ selectedDemand?.qq_code }}</span>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="label">请求者:</span>
|
||
<span v-if="!selectedDemand?.requester" class="tag no-reward">匿名</span>
|
||
<span v-else>{{ selectedDemand?.requester }}</span>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="label">需求内容:</span>
|
||
<span class="value">{{ selectedDemand?.content }}</span>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="label">赏金:</span>
|
||
<span :class="['tag', isNoReward(selectedDemand?.reward) ? 'no-reward' : 'has-reward']">
|
||
{{ isNoReward(selectedDemand?.reward) ? '无赏金' : selectedDemand?.reward }}
|
||
</span>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="label">发布时间:</span>
|
||
<span class="value">{{ formatDate(selectedDemand?.date) }}</span>
|
||
</div>
|
||
<div class="reply-section">
|
||
<h3>回复内容</h3>
|
||
<div class="reply-list">
|
||
<div v-if="selectedDemand?.replies && selectedDemand.replies.length > 0">
|
||
<div v-for="reply in selectedDemand.replies" :key="reply.id" class="reply-item">
|
||
<div class="reply-header">
|
||
<span class="reply-author">{{ reply.author || '匿名用户' }}</span>
|
||
<span class="reply-time">{{ formatDate(reply.time) }}</span>
|
||
</div>
|
||
<div class="reply-content">{{ reply.content }}</div>
|
||
</div>
|
||
</div>
|
||
<div v-else class="no-reply">
|
||
<div v-if="selectedDemand?.sendcontent">
|
||
<div v-for="(reply, index) in selectedDemand.sendcontent.split('|')" :key="index" class="reply-content">
|
||
<div class="reply-with-avatar">
|
||
<img :src="`https://q1.qlogo.cn/g?b=qq&nk=${reply.match(/\((\d+)\)/)?.[1] || ''}&s=40`" alt="User Avatar" class="reply-avatar" />
|
||
<div class="reply-text">
|
||
<b>{{ reply.split('):')[0] + ')' }}</b>{{ reply.split('):')[1] }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div v-else>
|
||
暂无回复
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 添加需求弹窗 -->
|
||
<div v-if="showAddModal" class="modal-overlay" @click="closeAddModal">
|
||
<div class="modal-content" @click.stop>
|
||
<div class="modal-header">
|
||
<h2>添加需求</h2>
|
||
<button class="close-btn" @click="closeAddModal">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
需求一经发布不许修改
|
||
</div>
|
||
<div class="modal-body">
|
||
<form class="add-modal-form" @submit.prevent="submitAddForm">
|
||
<div class="form-row">
|
||
<span class="label">请求者:</span>
|
||
<input v-model="addForm.requester" class="input" placeholder="可选" />
|
||
</div>
|
||
<div class="form-row">
|
||
<span class="label">QQ号:</span>
|
||
<input
|
||
v-model="addForm.qq_code"
|
||
class="input"
|
||
placeholder="可选"
|
||
@input="validateQQ"
|
||
type="text"
|
||
pattern="[0-9]*"
|
||
inputmode="numeric"
|
||
/>
|
||
</div>
|
||
<div class="form-row">
|
||
<span class="label">需求内容:</span>
|
||
<textarea
|
||
v-model="addForm.content"
|
||
class="input"
|
||
placeholder="请输入需求内容"
|
||
rows="3"
|
||
ref="autoTextarea"
|
||
@input="autoResize"
|
||
></textarea>
|
||
</div>
|
||
<div class="form-row">
|
||
<span class="label">赏金:</span>
|
||
<input v-model="addForm.reward" class="input" placeholder="可选" />
|
||
</div>
|
||
<div v-if="addError" class="error">{{ addError }}</div>
|
||
<button class="btn-common btn-gradient submit-btn" :disabled="addLoading">
|
||
{{ addLoading ? '提交中...' : '提交' }}
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted, nextTick } from 'vue'
|
||
import { getDemandsList, addDemand, updateDemand } from '../../api/demands'
|
||
|
||
// 响应式数据
|
||
const demands = ref([])
|
||
const loading = ref(false)
|
||
const error = ref(null)
|
||
const showModal = ref(false)
|
||
const reply = ref(null)
|
||
const replyModal = ref(false)
|
||
const selectedDemand = ref(null)
|
||
const showAddModal = ref(false)
|
||
const addError = ref('')
|
||
const addForm = ref({
|
||
requester: '',
|
||
content: '',
|
||
reward: '',
|
||
qq_code: '',
|
||
sendcontent: '',
|
||
author: '',
|
||
author_contact: ''
|
||
})
|
||
const addLoading = ref(false)
|
||
const autoTextarea = ref(null)
|
||
|
||
// 判断是否为无赏金
|
||
const isNoReward = (reward) => {
|
||
return !reward || reward === '无赏金'
|
||
}
|
||
// 格式化日期
|
||
const formatDate = (dateString) => {
|
||
if (!dateString || dateString === 'Test_date') return '日期未提供'
|
||
|
||
try {
|
||
const date = new Date(dateString)
|
||
if (isNaN(date.getTime())) {
|
||
return dateString
|
||
}
|
||
|
||
const pad = num => num.toString().padStart(2, '0')
|
||
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
|
||
} catch (e) {
|
||
return dateString
|
||
}
|
||
}
|
||
|
||
// 获取需求列表
|
||
const fetchDemands = async () => {
|
||
loading.value = true
|
||
error.value = null
|
||
try {
|
||
const data = await getDemandsList()
|
||
demands.value = data
|
||
} catch (err) {
|
||
error.value = `加载失败: ${err.message}`
|
||
console.error('加载需求列表失败:', err)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
//回复显示弹窗
|
||
const showReply = (demand) => {
|
||
reply.value = demand
|
||
replyModal.value = true
|
||
resetReplyForm();
|
||
}
|
||
|
||
// 关闭回复弹窗
|
||
const closeReplyModal = () => {
|
||
replyModal.value = false;
|
||
resetReplyForm();
|
||
}
|
||
|
||
// 重置回复表单
|
||
const resetReplyForm = () => {
|
||
addForm.value = {
|
||
sendcontent: '',
|
||
author: '',
|
||
author_contact: ''
|
||
};
|
||
addError.value = '';
|
||
// 重置文本框高度
|
||
if (autoTextarea.value) {
|
||
autoTextarea.value.style.height = 'auto';
|
||
}
|
||
}
|
||
|
||
// 显示详情弹窗
|
||
const showDetail = (demand) => {
|
||
selectedDemand.value = demand
|
||
showModal.value = true
|
||
}
|
||
|
||
// 关闭弹窗
|
||
const closeModal = () => {
|
||
showModal.value = false
|
||
selectedDemand.value = null
|
||
}
|
||
|
||
// 打开弹窗
|
||
const openAddModal = () => {
|
||
// 重置表单数据
|
||
addForm.value = {
|
||
requester: '',
|
||
content: '',
|
||
reward: '',
|
||
qq_code: '',
|
||
sendcontent: '',
|
||
author: '',
|
||
author_contact: ''
|
||
};
|
||
addError.value = '';
|
||
showAddModal.value = true;
|
||
}
|
||
|
||
// 关闭弹窗
|
||
function closeAddModal() {
|
||
showAddModal.value = false
|
||
addError.value = ''
|
||
}
|
||
|
||
// 在 script setup 部分添加验证函数
|
||
const validateQQ = (event) => {
|
||
// 只保留数字
|
||
addForm.value.qq_code = event.target.value.replace(/[^\d]/g, '');
|
||
}
|
||
|
||
// 修改 submitAddForm 函数,添加 QQ 号验证
|
||
async function submitAddForm() {
|
||
if (!addForm.value.content?.trim()) {
|
||
addError.value = '需求内容不能为空';
|
||
return;
|
||
}
|
||
|
||
// 如果填写了QQ号,验证是否为纯数字
|
||
if (addForm.value.qq_code && !/^\d+$/.test(addForm.value.qq_code)) {
|
||
addError.value = 'QQ号必须为纯数字';
|
||
return;
|
||
}
|
||
|
||
addLoading.value = true;
|
||
addError.value = '';
|
||
try {
|
||
const now = new Date();
|
||
const dateStr = `${now.getFullYear()}-${(now.getMonth()+1).toString().padStart(2,'0')}-${now.getDate().toString().padStart(2,'0')} ${now.getHours().toString().padStart(2,'0')}:${now.getMinutes().toString().padStart(2,'0')}:${now.getSeconds().toString().padStart(2,'0')}`;
|
||
const payload = {
|
||
requester: addForm.value.requester || '',
|
||
sendcontent: '',
|
||
content: addForm.value.content,
|
||
reward: addForm.value.reward || '',
|
||
date: dateStr,
|
||
qq_code: addForm.value.qq_code || ''
|
||
};
|
||
|
||
console.log('提交的数据:', payload);
|
||
await addDemand(payload);
|
||
showAddModal.value = false;
|
||
fetchDemands(); // 刷新列表
|
||
} catch (e) {
|
||
console.error('提交失败:', e);
|
||
addError.value = e.response?.data?.detail || '提交失败,请稍后重试';
|
||
} finally {
|
||
addLoading.value = false;
|
||
}
|
||
}
|
||
|
||
// 提交回复
|
||
const submitReply = async () => {
|
||
if (!addForm.value.sendcontent?.trim()) {
|
||
addError.value = '回复内容不能为空';
|
||
return;
|
||
}
|
||
if (!addForm.value.author?.trim()) {
|
||
addError.value = '昵称不能为空';
|
||
return;
|
||
}
|
||
if (!addForm.value.author_contact?.trim()) {
|
||
addError.value = 'QQ号不能为空';
|
||
return;
|
||
}
|
||
// 验证QQ号是否为纯数字
|
||
if (!/^\d+$/.test(addForm.value.author_contact)) {
|
||
addError.value = 'QQ号必须为纯数字';
|
||
return;
|
||
}
|
||
|
||
addLoading.value = true;
|
||
addError.value = '';
|
||
try {
|
||
const now = new Date();
|
||
const dateStr = `${now.getFullYear()}-${(now.getMonth()+1).toString().padStart(2,'0')}-${now.getDate().toString().padStart(2,'0')} ${now.getHours().toString().padStart(2,'0')}:${now.getMinutes().toString().padStart(2,'0')}:${now.getSeconds().toString().padStart(2,'0')}`;
|
||
|
||
// 拼接回复内容
|
||
const newReply = `${addForm.value.author}(${addForm.value.author_contact}):${addForm.value.sendcontent}`;
|
||
const formattedContent = reply.value.sendcontent
|
||
? `${reply.value.sendcontent}|${newReply}`
|
||
: newReply;
|
||
|
||
const payload = {
|
||
requester: reply.value.requester || '',
|
||
sendcontent: formattedContent,
|
||
content: reply.value.content,
|
||
reward: reply.value.reward || '',
|
||
date: dateStr,
|
||
qq_code: reply.value.qq_code || '',
|
||
author: addForm.value.author,
|
||
author_contact: addForm.value.author_contact
|
||
};
|
||
|
||
console.log('提交的回复数据:', payload);
|
||
await updateDemand(reply.value.id, payload);
|
||
replyModal.value = false;
|
||
resetReplyForm();
|
||
fetchDemands(); // 刷新列表
|
||
} catch (e) {
|
||
console.error('提交回复失败:', e);
|
||
addError.value = e.response?.data?.detail || '提交失败,请稍后重试';
|
||
} finally {
|
||
addLoading.value = false;
|
||
}
|
||
}
|
||
|
||
// 组件挂载时自动加载数据
|
||
onMounted(() => {
|
||
fetchDemands()
|
||
})
|
||
|
||
function autoResize() {
|
||
nextTick(() => {
|
||
const el = autoTextarea.value
|
||
if (el) {
|
||
el.style.height = 'auto'
|
||
el.style.height = el.scrollHeight + 'px'
|
||
}
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.btn-common {
|
||
display: inline-block;
|
||
padding: 8px 22px;
|
||
font-size: 15px;
|
||
font-weight: 500;
|
||
border-radius: 6px;
|
||
border: 1px solid #b6d2ff;
|
||
cursor: pointer;
|
||
transition: background 0.2s, color 0.2s, border 0.2s;
|
||
outline: none;
|
||
box-shadow: none;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.btn-gradient {
|
||
background: linear-gradient(90deg, #71eaeb 0%, #416bdf 100%);
|
||
color: #fff;
|
||
border: 1px solid #71eaeb;
|
||
}
|
||
.btn-gradient:hover {
|
||
background: linear-gradient(90deg, #416bdf 0%, #71eaeb 100%);
|
||
color: #fff;
|
||
border: 1.5px solid #416bdf;
|
||
}
|
||
|
||
.btn-light {
|
||
background: linear-gradient(90deg, #e3f0ff 0%, #f7fbff 100%);
|
||
color: #2563eb;
|
||
border: 1px solid #b6d2ff;
|
||
}
|
||
.btn-light:hover {
|
||
background: linear-gradient(90deg, #d0e7ff 0%, #eaf4ff 100%);
|
||
color: #174ea6;
|
||
border: 1.5px solid #2563eb;
|
||
}
|
||
|
||
/* 按钮间距 */
|
||
.btn-margin-right {
|
||
margin-right: 16px;
|
||
}
|
||
|
||
.btn-reply {
|
||
padding: 5px 15px;
|
||
font-size: 14px;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.content {
|
||
max-width: 300px;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
/* 彻底重写 tag 样式,保证无阴影、紧凑、圆角 */
|
||
.tag {
|
||
display: inline-block;
|
||
padding: 2px 10px;
|
||
border-radius: 12px;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
line-height: 1.2;
|
||
background: none;
|
||
box-shadow: none;
|
||
border: none;
|
||
margin: 0;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.has-reward {
|
||
background: #fff7e6;
|
||
color: #d46b08;
|
||
border: 1px solid #ffd591;
|
||
}
|
||
|
||
.no-reward {
|
||
background: #f5f5f5;
|
||
color: #8c8c8c;
|
||
border: 1px solid #d9d9d9;
|
||
}
|
||
|
||
.maps-table td.reward,
|
||
.maps-table tr {
|
||
box-shadow: none !important;
|
||
filter: none !important;
|
||
}
|
||
|
||
/* 弹窗样式 */
|
||
.modal-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: flex-start;
|
||
padding-top: 80px;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.modal-content {
|
||
background: white;
|
||
border-radius: 8px;
|
||
width: 90%;
|
||
max-width: 800px;
|
||
max-height: 80vh;
|
||
overflow-y: auto;
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||
}
|
||
|
||
.modal-header {
|
||
padding: 20px;
|
||
border-bottom: 1px solid #eee;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.modal-header h2 {
|
||
margin: 0;
|
||
color: #1a237e;
|
||
font-size: 1.5rem;
|
||
}
|
||
|
||
.close-btn {
|
||
background: none;
|
||
border: none;
|
||
font-size: 24px;
|
||
color: #666;
|
||
cursor: pointer;
|
||
padding: 0;
|
||
line-height: 1;
|
||
}
|
||
|
||
.close-btn:hover {
|
||
color: #1a237e;
|
||
}
|
||
|
||
.modal-body {
|
||
padding: 20px;
|
||
}
|
||
|
||
.detail-item {
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.detail-item:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.label {
|
||
font-weight: 600;
|
||
color: #1a237e;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.value {
|
||
color: #333;
|
||
}
|
||
|
||
.maps-table tr {
|
||
height: 60px;
|
||
}
|
||
|
||
.maps-table th,
|
||
.maps-table td {
|
||
text-align: center;
|
||
vertical-align: middle !important;
|
||
padding: 12px 8px;
|
||
}
|
||
|
||
.maps-table td.reward {
|
||
text-align: center;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.input {
|
||
width: 70%;
|
||
padding: 6px 10px;
|
||
border: 1px solid #e0e0e0;
|
||
border-radius: 4px;
|
||
font-size: 14px;
|
||
margin-left: 8px;
|
||
margin-top: 2px;
|
||
margin-bottom: 2px;
|
||
box-sizing: border-box;
|
||
}
|
||
.input:focus {
|
||
outline: none;
|
||
border-color: #2563eb;
|
||
box-shadow: 0 0 0 2px #e3f0ff;
|
||
}
|
||
.error {
|
||
color: #f5222d;
|
||
background: #fff1f0;
|
||
border-radius: 4px;
|
||
padding: 8px 12px;
|
||
margin: 10px 0 0 0;
|
||
font-size: 14px;
|
||
text-align: center;
|
||
}
|
||
|
||
.add-modal-form {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 18px;
|
||
}
|
||
|
||
.add-modal-form .form-row {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 10px;
|
||
}
|
||
|
||
.add-modal-form .label {
|
||
min-width: 70px;
|
||
font-weight: 600;
|
||
color: #1a237e;
|
||
margin-right: 0;
|
||
text-align: right;
|
||
padding-top: 6px;
|
||
}
|
||
|
||
.add-modal-form .input,
|
||
.add-modal-form textarea {
|
||
flex: 1;
|
||
width: 100%;
|
||
padding: 8px 12px;
|
||
border: 1px solid #e0e0e0;
|
||
border-radius: 5px;
|
||
font-size: 15px;
|
||
background: #f7faff;
|
||
transition: border 0.2s, box-shadow 0.2s;
|
||
resize: none;
|
||
}
|
||
|
||
.add-modal-form .input:focus,
|
||
.add-modal-form textarea:focus {
|
||
border-color: #2563eb;
|
||
box-shadow: 0 0 0 2px #e3f0ff;
|
||
outline: none;
|
||
}
|
||
|
||
.add-modal-form .error {
|
||
color: #f5222d;
|
||
background: #fff1f0;
|
||
border-radius: 4px;
|
||
padding: 8px 12px;
|
||
font-size: 14px;
|
||
text-align: center;
|
||
margin: 0;
|
||
}
|
||
|
||
.add-modal-form .submit-btn {
|
||
width: 100%;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.add-modal-form textarea {
|
||
min-height: 60px;
|
||
max-height: 200px;
|
||
resize: vertical;
|
||
line-height: 1.6;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.reply-section {
|
||
margin-top: 20px;
|
||
padding-top: 20px;
|
||
border-top: 1px solid #eee;
|
||
}
|
||
|
||
.reply-section h3 {
|
||
color: #1a237e;
|
||
margin-bottom: 15px;
|
||
font-size: 1.2rem;
|
||
}
|
||
|
||
.reply-list {
|
||
background: none;
|
||
border-radius: 0;
|
||
padding: 0 0 0 0;
|
||
}
|
||
|
||
.reply-item {
|
||
background: none;
|
||
border-radius: 0;
|
||
padding: 0 0 0 0;
|
||
}
|
||
|
||
.reply-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.reply-author {
|
||
font-weight: 600;
|
||
color: #1a237e;
|
||
}
|
||
|
||
.reply-time {
|
||
color: #666;
|
||
font-size: 0.9em;
|
||
}
|
||
|
||
.reply-content {
|
||
color: #333;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.no-reply {
|
||
text-align: center;
|
||
color: #666;
|
||
padding: 20px;
|
||
background: #f7faff;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.no-reply .reply-content {
|
||
text-align: left;
|
||
padding: 10px 0;
|
||
color: #333;
|
||
border-left: 3px solid #2563eb;
|
||
padding-left: 15px;
|
||
margin: 10px 0;
|
||
font-size: 14px;
|
||
line-height: 1.6;
|
||
background: transparent;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.reply-with-avatar {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 8px;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.reply-with-avatar:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.reply-avatar {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
border: none;
|
||
object-fit: cover;
|
||
flex-shrink: 0;
|
||
background: #f3f6fa;
|
||
}
|
||
|
||
.reply-text {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
min-height: 40px;
|
||
font-size: 15px;
|
||
color: #222;
|
||
line-height: 1.7;
|
||
padding-left: 14px;
|
||
background: none;
|
||
border-radius: 0;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.reply-text b {
|
||
font-weight: 600;
|
||
margin-right: 6px;
|
||
color: #2563eb;
|
||
font-size: 15px;
|
||
}
|
||
</style> |