| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- <template>
- <div class="teacher-consult-container page-container">
- <el-card>
- <div slot="header">
- <span>家长咨询管理</span>
- <el-button style="float: right" size="small" @click="loadMessages" :loading="loading">刷新</el-button>
- </div>
- <!-- 搜索筛选 -->
- <el-form :inline="true" style="margin-bottom: 15px">
- <el-form-item label="状态">
- <el-select v-model="searchForm.status" placeholder="全部" clearable @change="loadMessages">
- <el-option label="待回复" value="pending"></el-option>
- <el-option label="已回复" value="replied"></el-option>
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" @click="loadMessages">搜索</el-button>
- </el-form-item>
- </el-form>
- <!-- 咨询列表 -->
- <el-table :max-height="tableHeight" :data="messages" border v-loading="loading">
- <el-table-column prop="id" label="ID" width="60">
- <template slot="header">
- <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="familyId" label="家庭ID" width="80">
- <template slot="header">
- <span class="sort-header" @click.stop="onSortClick('familyId', $event)">家庭ID<span v-if="sortIndex('familyId') !== null" class="sort-index" :class="sortClass('familyId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('familyId') }}</span>{{ sortIcon('familyId') }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="content" label="咨询内容" min-width="200">
- <template slot="header">
- <span class="sort-header" @click.stop="onSortClick('content', $event)">咨询内容<span v-if="sortIndex('content') !== null" class="sort-index" :class="sortClass('content') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('content') }}</span>{{ sortIcon('content') }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="status" label="状态" width="80">
- <template slot-scope="{ row }">
- <el-tag :type="row.status === 'pending' ? 'warning' : 'success'" size="small">
- {{ row.status === 'pending' ? '待回复' : '已回复' }}
- </el-tag>
- </template>
- <template slot="header">
- <span class="sort-header" @click.stop="onSortClick('status', $event)">状态<span v-if="sortIndex('status') !== null" class="sort-index" :class="sortClass('status') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('status') }}</span>{{ sortIcon('status') }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="createdAt" label="咨询时间" width="160">
- <template slot-scope="{ row }">{{ formatDate(row.createdAt) }}</template>
- <template slot="header">
- <span class="sort-header" @click.stop="onSortClick('createdAt', $event)">咨询时间<span v-if="sortIndex('createdAt') !== null" class="sort-index" :class="sortClass('createdAt') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('createdAt') }}</span>{{ sortIcon('createdAt') }}</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" width="150" fixed="right">
- <template slot-scope="{ row }">
- <el-button type="text" size="small" @click="showReplyDialog(row)">
- {{ row.status === 'pending' ? '回复' : '查看' }}
- </el-button>
- </template>
- </el-table-column>
- </el-table>
- <!-- 分页 -->
- <el-pagination
- v-if="total > 0"
- style="margin-top: 20px; text-align: right"
- :current-page="pagination.page"
- :page-size="pagination.size"
- :total="total"
- layout="total, prev, pager, next"
- @current-change="handlePageChange"
- />
- </el-card>
- <!-- 回复弹窗 -->
- <el-dialog :title="replyDialogTitle" :visible.sync="replyDialogVisible" width="500px">
- <div v-if="currentMessage">
- <div class="message-content">
- <div class="label">咨询内容:</div>
- <div class="content">{{ currentMessage.content }}</div>
- </div>
- <el-divider></el-divider>
- <div v-if="currentMessage.status === 'replied'" class="reply-content">
- <div class="label">我的回复:</div>
- <div class="content">{{ currentMessage.replyContent }}</div>
- </div>
- <el-form v-else>
- <el-form-item label="回复内容">
- <el-input type="textarea" v-model="replyForm.replyContent" rows="4" placeholder="请输入回复内容"></el-input>
- </el-form-item>
- </el-form>
- </div>
- <div slot="footer">
- <el-button @click="replyDialogVisible = false">关闭</el-button>
- <el-button v-if="currentMessage && currentMessage.status === 'pending'" type="primary" @click="submitReply" :loading="replyLoading">提交回复</el-button>
- </div>
- </el-dialog>
- </div>
- </template>
- <script>
- import SortMixin from '@/mixins/SortMixin'
- import { getConsultMessages, replyConsultMessage } from '@/api/teacherMessage'
- export default {
- name: 'TeacherConsult',
- mixins: [SortMixin],
- data() {
- return {
- loading: false,
- replyLoading: false,
- messages: [],
- total: 0,
- sortableColumns: { id: 'ID', familyId: '家庭ID', content: '咨询内容', status: '状态', createdAt: '咨询时间' },
- searchForm: {
- status: ''
- },
- pagination: {
- page: 1,
- size: 10
- },
- replyDialogVisible: false,
- currentMessage: null,
- replyForm: {
- replyContent: ''
- }
- }
- },
- computed: {
- tableHeight() {
- return window.innerHeight - 340
- },
- replyDialogTitle() {
- if (!this.currentMessage) return '回复咨询'
- return this.currentMessage.status === 'pending' ? '回复咨询' : '查看回复'
- }
- },
- mounted() {
- this.loadMessages()
- },
- methods: {
- loadList() {
- this.loadMessages()
- },
- async loadMessages() {
- this.loading = true
- try {
- const res = await getConsultMessages(this.pagination.page, this.pagination.size, this.searchForm.status, this.sortState.length > 0 ? this.sortState : null)
- this.messages = res.data.records || []
- this.total = res.data.total || 0
- } catch (e) {
- this.$message.error('加载失败')
- } finally {
- this.loading = false
- }
- },
- handlePageChange(page) {
- this.pagination.page = page
- this.loadMessages()
- },
- showReplyDialog(row) {
- this.currentMessage = row
- this.replyForm.replyContent = ''
- this.replyDialogVisible = true
- },
- async submitReply() {
- if (!this.replyForm.replyContent.trim()) {
- this.$message.warning('请输入回复内容')
- return
- }
- this.replyLoading = true
- try {
- await replyConsultMessage(this.currentMessage.id, this.replyForm.replyContent)
- this.$message.success('回复成功')
- this.replyDialogVisible = false
- this.loadMessages()
- } catch (e) {
- this.$message.error('回复失败')
- } finally {
- this.replyLoading = false
- }
- },
- formatDate(date) {
- if (!date) return '-'
- return new Date(date).toLocaleString()
- }
- }
- }
- </script>
- <style scoped>
- .teacher-consult-container { padding: 20px; }
- .message-content, .reply-content {
- margin-bottom: 15px;
- }
- .message-content .label, .reply-content .label {
- font-weight: bold;
- margin-bottom: 8px;
- color: #606266;
- }
- .message-content .content, .reply-content .content {
- padding: 10px;
- background: #f5f7fa;
- border-radius: 4px;
- }
- .sort-header {
- cursor: pointer;
- user-select: none;
- font-weight: 500;
- font-size: 12px;
- white-space: nowrap;
- }
- .sort-header:hover {
- color: #409eff;
- }
- </style>
|