增加客户留言板界面
This commit is contained in:
parent
5786bd4f76
commit
2d6b89dfec
47
src/api/feedback/index.ts
Normal file
47
src/api/feedback/index.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
// 留言板 VO
|
||||
export interface FeedbackVO {
|
||||
id: number // 主键
|
||||
content: string // 客户提交的反馈内容
|
||||
backContent: string // 医生回复的内容
|
||||
userId: number // 客户id
|
||||
doctorName: string // 医生姓名
|
||||
doctorId: number // 医生id
|
||||
backTime: Date | number // 医生回复时间(支持Date对象或时间戳)
|
||||
orgid: number // 机构ID
|
||||
orgname: string // 机构名称
|
||||
}
|
||||
|
||||
// 留言板 API
|
||||
export const FeedbackApi = {
|
||||
// 查询留言板分页
|
||||
getFeedbackPage: async (params: any) => {
|
||||
return await request.get({ url: `/system/feedback/page`, params })
|
||||
},
|
||||
|
||||
// 查询留言板详情
|
||||
getFeedback: async (id: number) => {
|
||||
return await request.get({ url: `/system/feedback/get?id=` + id })
|
||||
},
|
||||
|
||||
// 新增留言板
|
||||
createFeedback: async (data: FeedbackVO) => {
|
||||
return await request.post({ url: `/system/feedback/create`, data })
|
||||
},
|
||||
|
||||
// 修改留言板
|
||||
updateFeedback: async (data: FeedbackVO) => {
|
||||
return await request.put({ url: `/system/feedback/update`, data })
|
||||
},
|
||||
|
||||
// 删除留言板
|
||||
deleteFeedback: async (id: number) => {
|
||||
return await request.delete({ url: `/system/feedback/delete?id=` + id })
|
||||
},
|
||||
|
||||
// 导出留言板 Excel
|
||||
exportFeedback: async (params) => {
|
||||
return await request.download({ url: `/system/feedback/export-excel`, params })
|
||||
},
|
||||
}
|
204
src/views/notice/FeedbackReply.vue
Normal file
204
src/views/notice/FeedbackReply.vue
Normal file
@ -0,0 +1,204 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="isViewMode ? '查看回复' : '回复留言'"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
@close="handleClose"
|
||||
>
|
||||
<div class="reply-dialog-content">
|
||||
<!-- 原留言内容 -->
|
||||
<div class="original-message">
|
||||
<h4>客户留言:</h4>
|
||||
<div class="message-box">
|
||||
<p>{{ feedbackData.content }}</p>
|
||||
<div class="message-info">
|
||||
<span>客户ID: {{ feedbackData.userId }}</span>
|
||||
<span>机构: {{ feedbackData.orgname }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 回复表单 -->
|
||||
<div class="reply-form">
|
||||
<h4>{{ isViewMode ? '回复内容:' : '请输入回复:' }}</h4>
|
||||
<el-form :model="replyForm" ref="replyFormRef" :rules="replyRules">
|
||||
<el-form-item prop="backContent">
|
||||
<el-input
|
||||
v-model="replyForm.backContent"
|
||||
type="textarea"
|
||||
:rows="6"
|
||||
placeholder="请输入回复内容..."
|
||||
:disabled="isViewMode"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button
|
||||
v-if="!isViewMode"
|
||||
type="primary"
|
||||
@click="handleSubmit"
|
||||
:loading="submitLoading"
|
||||
>
|
||||
提交回复
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, watch } from 'vue'
|
||||
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
|
||||
import { FeedbackApi, type FeedbackVO } from '@/api/feedback'
|
||||
|
||||
// 定义组件属性
|
||||
interface Props {
|
||||
visible: boolean
|
||||
feedbackData: FeedbackVO
|
||||
doctorName?: string
|
||||
}
|
||||
|
||||
// 定义组件事件
|
||||
interface Emits {
|
||||
(e: 'update:visible', value: boolean): void
|
||||
(e: 'success'): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// 响应式数据
|
||||
const submitLoading = ref(false)
|
||||
const replyFormRef = ref<FormInstance>()
|
||||
|
||||
// 回复表单
|
||||
const replyForm = reactive<FeedbackVO>({
|
||||
id: 0,
|
||||
content: '',
|
||||
backContent: '',
|
||||
userId: 0,
|
||||
doctorName: '',
|
||||
doctorId: 0,
|
||||
backTime: Date.now(),
|
||||
orgid: 0,
|
||||
orgname: ''
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
const replyRules: FormRules = {
|
||||
backContent: [
|
||||
{ required: true, message: '请输入回复内容', trigger: 'blur' },
|
||||
{ min: 1, max: 500, message: '回复内容长度在 1 到 500 个字符', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
|
||||
// 计算属性
|
||||
const dialogVisible = computed({
|
||||
get: () => props.visible,
|
||||
set: (value) => emit('update:visible', value)
|
||||
})
|
||||
|
||||
const isViewMode = computed(() => {
|
||||
return !!props.feedbackData.backTime
|
||||
})
|
||||
|
||||
// 监听数据变化,更新表单
|
||||
watch(() => props.feedbackData, (newData) => {
|
||||
if (newData && newData.id) {
|
||||
Object.assign(replyForm, newData)
|
||||
}
|
||||
}, { immediate: true, deep: true })
|
||||
|
||||
// 提交回复
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
await replyFormRef.value?.validate()
|
||||
submitLoading.value = true
|
||||
|
||||
const submitData = {
|
||||
...replyForm,
|
||||
backTime: Date.now(),
|
||||
doctorName: props.doctorName || '未知医生'
|
||||
}
|
||||
|
||||
await FeedbackApi.updateFeedback(submitData)
|
||||
ElMessage.success('回复成功')
|
||||
emit('success')
|
||||
handleClose()
|
||||
} catch (error: any) {
|
||||
console.error('回复失败:', error)
|
||||
ElMessage.error('回复失败')
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
dialogVisible.value = false
|
||||
// 重置表单
|
||||
replyFormRef.value?.resetFields()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.reply-dialog-content {
|
||||
.original-message {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h4 {
|
||||
margin: 0 0 12px 0;
|
||||
color: #303133;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.message-box {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
|
||||
p {
|
||||
margin: 0 0 12px 0;
|
||||
line-height: 1.6;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.message-info {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
|
||||
span {
|
||||
background: #e4e7ed;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reply-form {
|
||||
h4 {
|
||||
margin: 0 0 12px 0;
|
||||
color: #303133;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
}
|
||||
</style>
|
532
src/views/notice/msgboard.vue
Normal file
532
src/views/notice/msgboard.vue
Normal file
@ -0,0 +1,532 @@
|
||||
<template>
|
||||
<div class="msgboard-container">
|
||||
<!-- 页面头部 -->
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1 class="page-title">
|
||||
<el-icon class="title-icon"><ChatDotRound /></el-icon>
|
||||
留言板管理
|
||||
</h1>
|
||||
<p class="page-desc">查看客户留言并及时回复,提升客户满意度</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 搜索区域 -->
|
||||
<div class="search-section">
|
||||
<el-card class="search-card" shadow="never">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" class="search-form">
|
||||
<el-form-item label="客户ID" prop="userId">
|
||||
<el-input
|
||||
v-model="queryParams.userId"
|
||||
placeholder="请输入客户ID"
|
||||
clearable
|
||||
style="width: 120px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="回复状态" prop="replyStatus">
|
||||
<el-select v-model="queryParams.replyStatus" placeholder="请选择回复状态" clearable style="width: 150px">
|
||||
<el-option label="已回复" value="replied" />
|
||||
<el-option label="未回复" value="unreplied" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="回复时间" prop="backTimeRange">
|
||||
<el-date-picker
|
||||
v-model="queryParams.backTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">
|
||||
<el-icon><Search /></el-icon>
|
||||
搜索
|
||||
</el-button>
|
||||
<el-button @click="handleReset">
|
||||
<el-icon><RefreshLeft /></el-icon>
|
||||
重置
|
||||
</el-button>
|
||||
<el-button type="success" @click="handleExport">
|
||||
<el-icon><Download /></el-icon>
|
||||
导出
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 留言列表 -->
|
||||
<div class="message-list-section">
|
||||
<el-card class="list-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="header-title">留言列表</span>
|
||||
<div class="header-stats">
|
||||
<el-tag type="info">总计: {{ total }}</el-tag>
|
||||
<el-tag type="success">已回复: {{ repliedCount }}</el-tag>
|
||||
<el-tag type="warning">未回复: {{ unrepliedCount }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="messageList"
|
||||
style="width: 100%"
|
||||
row-key="id"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="留言内容" prop="content" min-width="300" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<div class="message-content">
|
||||
<div class="content-text">{{ row.content }}</div>
|
||||
<div class="content-meta">
|
||||
<el-tag size="small" type="info">客户ID: {{ row.userId }}</el-tag>
|
||||
<el-tag size="small" type="primary">{{ row.orgname }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="回复状态" prop="backContent" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
:type="row.backTime ? 'success' : 'warning'"
|
||||
size="small"
|
||||
>
|
||||
{{ row.backTime ? '已回复' : '未回复' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="回复内容" prop="backContent" min-width="180" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.backContent" class="reply-content">{{ row.backContent }}</span>
|
||||
<span v-else class="no-reply">暂无回复</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="回复医生" prop="doctorName" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.doctorName">{{ row.doctorName }}</span>
|
||||
<span v-else class="no-doctor">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="回复时间" prop="backTime" width="160" align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.backTime">{{ formatDate(row.backTime) }}</span>
|
||||
<span v-else class="no-time">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleReply(row)"
|
||||
:disabled="!!row.backTime"
|
||||
>
|
||||
<el-icon><ChatDotRound /></el-icon>
|
||||
{{ row.backTime ? '查看回复' : '回复' }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
v-model:current-page="queryParams.pageNo"
|
||||
v-model:page-size="queryParams.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 回复对话框 -->
|
||||
<FeedbackReply
|
||||
v-model:visible="replyDialogVisible"
|
||||
:feedback-data="currentFeedback"
|
||||
:doctor-name="doctorName"
|
||||
@success="handleReplySuccess"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { ElMessage, ElMessageBox, type FormInstance } from 'element-plus'
|
||||
import { ChatDotRound, Download, Search, RefreshLeft } from '@element-plus/icons-vue'
|
||||
import { FeedbackApi, type FeedbackVO } from '@/api/feedback'
|
||||
import FeedbackReply from './FeedbackReply.vue'
|
||||
import { getUserProfile } from '@/api/system/user/profile'
|
||||
// 响应式数据
|
||||
const loading = ref(false)
|
||||
const replyDialogVisible = ref(false)
|
||||
const messageList = ref<FeedbackVO[]>([])
|
||||
const total = ref(0)
|
||||
const selectedIds = ref<number[]>([])
|
||||
const currentFeedback = ref<FeedbackVO>({
|
||||
id: 0,
|
||||
content: '',
|
||||
backContent: '',
|
||||
userId: 0,
|
||||
doctorName: '',
|
||||
doctorId: 0,
|
||||
backTime: Date.now(),
|
||||
orgid: 0,
|
||||
orgname: ''
|
||||
})
|
||||
const userProfile = ref<any>({})
|
||||
|
||||
// 查询参数
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 20,
|
||||
userId: '',
|
||||
replyStatus: '',
|
||||
backTimeRange: [] as string[],
|
||||
backTime: [] as string[],
|
||||
orgid: undefined as number | undefined
|
||||
})
|
||||
|
||||
// 表单引用
|
||||
const queryFormRef = ref<FormInstance>()
|
||||
|
||||
// 计算属性
|
||||
const repliedCount = computed(() => {
|
||||
return messageList.value.filter(item => item.backTime).length
|
||||
})
|
||||
|
||||
const unrepliedCount = computed(() => {
|
||||
return messageList.value.filter(item => !item.backTime).length
|
||||
})
|
||||
|
||||
// 计算医生姓名,优先使用昵称,如果没有则使用用户名
|
||||
const doctorName = computed(() => {
|
||||
return userProfile.value?.nickname || userProfile.value?.username || '未知医生'
|
||||
})
|
||||
|
||||
// 获取留言列表
|
||||
const getMessageList = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
const params = { ...queryParams }
|
||||
|
||||
// 处理回复时间范围 - 直接传递给后端的backTime字段
|
||||
if (params.backTimeRange && params.backTimeRange.length === 2) {
|
||||
// 如果日期格式不包含时间,则自动补充时间
|
||||
const startDate = params.backTimeRange[0].includes(' ')
|
||||
? params.backTimeRange[0]
|
||||
: params.backTimeRange[0] + ' 00:00:00'
|
||||
const endDate = params.backTimeRange[1].includes(' ')
|
||||
? params.backTimeRange[1]
|
||||
: params.backTimeRange[1] + ' 23:59:59'
|
||||
params.backTime = [startDate, endDate]
|
||||
} else {
|
||||
params.backTime = []
|
||||
}
|
||||
params.backTimeRange = []
|
||||
|
||||
// 添加orgid参数
|
||||
if (userProfile.value?.dept?.id) {
|
||||
params.orgid = userProfile.value.dept.id
|
||||
}
|
||||
|
||||
const res = await FeedbackApi.getFeedbackPage(params)
|
||||
|
||||
// 更安全的数据访问 - res已经是处理过的数据
|
||||
if (res) {
|
||||
messageList.value = res.list || res.records || res.data || []
|
||||
total.value = res.total || res.totalCount || 0
|
||||
} else {
|
||||
messageList.value = []
|
||||
total.value = 0
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('获取留言列表失败:', error)
|
||||
ElMessage.error('获取留言列表失败')
|
||||
messageList.value = []
|
||||
total.value = 0
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
getMessageList()
|
||||
}
|
||||
|
||||
// 重置搜索
|
||||
const handleReset = () => {
|
||||
queryFormRef.value?.resetFields()
|
||||
queryParams.pageNo = 1
|
||||
getMessageList()
|
||||
}
|
||||
|
||||
// 导出
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
const exportParams = { ...queryParams }
|
||||
|
||||
// 处理回复时间范围 - 直接传递给后端的backTime字段
|
||||
if (exportParams.backTimeRange && exportParams.backTimeRange.length === 2) {
|
||||
// 如果日期格式不包含时间,则自动补充时间
|
||||
const startDate = exportParams.backTimeRange[0].includes(' ')
|
||||
? exportParams.backTimeRange[0]
|
||||
: exportParams.backTimeRange[0] + ' 00:00:00'
|
||||
const endDate = exportParams.backTimeRange[1].includes(' ')
|
||||
? exportParams.backTimeRange[1]
|
||||
: exportParams.backTimeRange[1] + ' 23:59:59'
|
||||
exportParams.backTime = [startDate, endDate]
|
||||
} else {
|
||||
exportParams.backTime = []
|
||||
}
|
||||
exportParams.backTimeRange = []
|
||||
|
||||
// 添加orgid参数
|
||||
if (userProfile.value?.dept?.id) {
|
||||
exportParams.orgid = userProfile.value.dept.id
|
||||
}
|
||||
|
||||
await FeedbackApi.exportFeedback(exportParams)
|
||||
ElMessage.success('导出成功')
|
||||
} catch (error) {
|
||||
console.error('导出失败:', error)
|
||||
ElMessage.error('导出失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 分页处理
|
||||
const handleSizeChange = (val: number) => {
|
||||
queryParams.pageSize = val
|
||||
getMessageList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (val: number) => {
|
||||
queryParams.pageNo = val
|
||||
getMessageList()
|
||||
}
|
||||
|
||||
// 选择处理
|
||||
const handleSelectionChange = (selection: FeedbackVO[]) => {
|
||||
selectedIds.value = selection.map(item => item.id)
|
||||
}
|
||||
|
||||
// 回复留言
|
||||
const handleReply = (row: FeedbackVO) => {
|
||||
currentFeedback.value = { ...row }
|
||||
replyDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 回复成功回调
|
||||
const handleReplySuccess = () => {
|
||||
getMessageList()
|
||||
}
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (date: Date | string | number) => {
|
||||
if (!date) return ''
|
||||
|
||||
let d: Date
|
||||
if (typeof date === 'number') {
|
||||
d = new Date(date)
|
||||
} else {
|
||||
d = new Date(date)
|
||||
}
|
||||
|
||||
if (isNaN(d.getTime())) {
|
||||
return ''
|
||||
}
|
||||
|
||||
return d.toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})
|
||||
}
|
||||
|
||||
// 页面加载时获取数据
|
||||
onMounted(async () => {
|
||||
try {
|
||||
// 首先获取用户信息
|
||||
userProfile.value = await getUserProfile()
|
||||
queryParams.orgid = userProfile.value.dept.id
|
||||
// 然后获取留言列表
|
||||
await getMessageList()
|
||||
} catch (error) {
|
||||
console.error('初始化失败:', error)
|
||||
ElMessage.error('初始化失败')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.msgboard-container {
|
||||
padding: 20px;
|
||||
background: #f5f7fa;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 20px;
|
||||
padding: 16px 24px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 12px;
|
||||
color: white;
|
||||
box-shadow: 0 4px 20px rgba(102, 126, 234, 0.15);
|
||||
|
||||
.header-content {
|
||||
.page-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
margin: 0 0 6px 0;
|
||||
|
||||
.title-icon {
|
||||
margin-right: 12px;
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.page-desc {
|
||||
margin: 0;
|
||||
opacity: 0.9;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-section {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.search-card {
|
||||
border-radius: 12px;
|
||||
border: none;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 16px 20px;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
margin: 0;
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 12px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__label) {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.message-list-section {
|
||||
.list-card {
|
||||
border-radius: 12px;
|
||||
border: none;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 16px 20px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.header-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.header-stats {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-table) {
|
||||
.el-table__body-wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.message-content {
|
||||
.content-text {
|
||||
margin-bottom: 8px;
|
||||
line-height: 1.5;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.content-meta {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.reply-content {
|
||||
color: #67c23a;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.no-reply {
|
||||
color: #909399;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.no-doctor,
|
||||
.no-time {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
// 响应式设计
|
||||
@media (max-width: 768px) {
|
||||
.msgboard-container {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user