|
|
@@ -0,0 +1,401 @@
|
|
|
+<template>
|
|
|
+ <div class="notice-management">
|
|
|
+ <!-- 搜索和操作区域 -->
|
|
|
+ <div class="search-section mb-4">
|
|
|
+ <a-row :gutter="16" type="flex" justify="start">
|
|
|
+ <a-col>
|
|
|
+ <a-input
|
|
|
+ v-model:value="searchForm.title"
|
|
|
+ placeholder="请输入标题搜索"
|
|
|
+ allow-clear
|
|
|
+ @press-enter="handleSearch"
|
|
|
+ >
|
|
|
+ <template #suffix>
|
|
|
+ <SearchOutlined @click="handleSearch" />
|
|
|
+ </template>
|
|
|
+ </a-input>
|
|
|
+ </a-col>
|
|
|
+ <a-col>
|
|
|
+ <a-button type="primary" @click="handleSearch">
|
|
|
+ <SearchOutlined />
|
|
|
+ 搜索
|
|
|
+ </a-button>
|
|
|
+ </a-col>
|
|
|
+ <a-col>
|
|
|
+ <a-button type="primary" @click="handleAdd">
|
|
|
+ <PlusOutlined />
|
|
|
+ 新增公告
|
|
|
+ </a-button>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 表格区域 -->
|
|
|
+ <a-table
|
|
|
+ :columns="columns"
|
|
|
+ :data-source="tableData"
|
|
|
+ :loading="loading"
|
|
|
+ :pagination="pagination"
|
|
|
+ row-key="noticeId"
|
|
|
+ @change="handleTableChange"
|
|
|
+ >
|
|
|
+ <template #bodyCell="{ column, record }">
|
|
|
+ <template v-if="column.key === 'platform'">
|
|
|
+ <a-tag :color="record.platform === 1 ? 'blue' : 'green'">
|
|
|
+ {{ record.platform === 1 ? '课程' : '考试' }}
|
|
|
+ </a-tag>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="column.key === 'noticeStatus'">
|
|
|
+ <a-tag :color="record.noticeStatus === 1 ? 'success' : 'default'">
|
|
|
+ {{ record.noticeStatus === 1 ? '已发布' : '未发布' }}
|
|
|
+ </a-tag>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="column.key === 'createTime'">
|
|
|
+ {{ dayjs(record.createTime).format('YYYY-MM-DD HH:mm:ss') }}
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="column.key === 'action'">
|
|
|
+ <a-space>
|
|
|
+ <a-button type="link" size="small" @click="handleView(record)"> 查看 </a-button>
|
|
|
+ <a-button type="link" size="small" @click="handleEdit(record)"> 编辑 </a-button>
|
|
|
+ <a-button v-if="record.noticeStatus === 0" type="link" size="small" @click="handlePublish(record)">
|
|
|
+ 发布
|
|
|
+ </a-button>
|
|
|
+ <a-button v-if="record.noticeStatus === 1" type="link" size="small" @click="handleCancelPublish(record)">
|
|
|
+ 取消发布
|
|
|
+ </a-button>
|
|
|
+ <a-popconfirm title="确定要删除这条公告吗?" @confirm="handleDelete(record)">
|
|
|
+ <a-button type="link" size="small" danger> 删除 </a-button>
|
|
|
+ </a-popconfirm>
|
|
|
+ </a-space>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </a-table>
|
|
|
+
|
|
|
+ <!-- 新增/编辑弹窗 -->
|
|
|
+ <a-modal v-model:visible="modalVisible" :title="modalTitle" width="800px" @ok="handleSubmit" @cancel="handleCancel">
|
|
|
+ <a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
|
|
|
+ <a-form-item label="标题" name="title">
|
|
|
+ <a-input v-model:value="formData.title" placeholder="请输入标题" />
|
|
|
+ </a-form-item>
|
|
|
+
|
|
|
+ <a-form-item label="平台" name="platform">
|
|
|
+ <a-radio-group v-model:value="formData.platform">
|
|
|
+ <a-radio :value="1">课程</a-radio>
|
|
|
+ <a-radio :value="2">考试</a-radio>
|
|
|
+ </a-radio-group>
|
|
|
+ </a-form-item>
|
|
|
+
|
|
|
+ <a-form-item label="内容" name="content">
|
|
|
+ <a-textarea v-model:value="formData.content" placeholder="请输入公告内容" :rows="6" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-form>
|
|
|
+ </a-modal>
|
|
|
+
|
|
|
+ <!-- 查看详情弹窗 -->
|
|
|
+ <a-modal v-model:visible="detailVisible" title="公告详情" width="800px" :footer="null">
|
|
|
+ <div v-if="detailData">
|
|
|
+ <a-descriptions :column="2" bordered>
|
|
|
+ <a-descriptions-item label="标题">
|
|
|
+ {{ detailData.title }}
|
|
|
+ </a-descriptions-item>
|
|
|
+ <a-descriptions-item label="平台">
|
|
|
+ <a-tag :color="detailData.platform === 1 ? 'blue' : 'green'">
|
|
|
+ {{ detailData.platform === 1 ? '课程' : '考试' }}
|
|
|
+ </a-tag>
|
|
|
+ </a-descriptions-item>
|
|
|
+ <a-descriptions-item label="状态">
|
|
|
+ <a-tag :color="detailData.noticeStatus === 1 ? 'success' : 'default'">
|
|
|
+ {{ detailData.noticeStatus === 1 ? '已发布' : '未发布' }}
|
|
|
+ </a-tag>
|
|
|
+ </a-descriptions-item>
|
|
|
+ <a-descriptions-item label="创建时间">
|
|
|
+ {{ dayjs(detailData.createTime).format('YYYY-MM-DD HH:mm:ss') }}
|
|
|
+ </a-descriptions-item>
|
|
|
+ <a-descriptions-item label="修改时间" v-if="detailData.modifyTime">
|
|
|
+ {{ dayjs(detailData.modifyTime).format('YYYY-MM-DD HH:mm:ss') }}
|
|
|
+ </a-descriptions-item>
|
|
|
+ <a-descriptions-item label="发布时间" v-if="detailData.publishTime">
|
|
|
+ {{ dayjs(detailData.publishTime).format('YYYY-MM-DD HH:mm:ss') }}
|
|
|
+ </a-descriptions-item>
|
|
|
+ </a-descriptions>
|
|
|
+
|
|
|
+ <a-divider>公告内容</a-divider>
|
|
|
+ <div class="content-display">
|
|
|
+ {{ detailData.content }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </a-modal>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+ import { ref, reactive, onMounted } from 'vue'
|
|
|
+ import { message } from 'ant-design-vue'
|
|
|
+ import { SearchOutlined, PlusOutlined } from '@ant-design/icons-vue'
|
|
|
+ import dayjs from 'dayjs'
|
|
|
+ import { list, addItem, editItem, detail, courceDownList, publish, cancelPublish } from '@/api/notice'
|
|
|
+
|
|
|
+ // 响应式数据
|
|
|
+ const loading = ref(false)
|
|
|
+ const tableData = ref([])
|
|
|
+ const modalVisible = ref(false)
|
|
|
+ const detailVisible = ref(false)
|
|
|
+ const modalTitle = ref('')
|
|
|
+ const isEdit = ref(false)
|
|
|
+ const formRef = ref()
|
|
|
+ const detailData = ref(null)
|
|
|
+
|
|
|
+ // 搜索表单
|
|
|
+ const searchForm = reactive({
|
|
|
+ title: ''
|
|
|
+ })
|
|
|
+
|
|
|
+ // 表单数据
|
|
|
+ const formData = reactive({
|
|
|
+ noticeId: null,
|
|
|
+ title: '',
|
|
|
+ platform: 1,
|
|
|
+ content: ''
|
|
|
+ })
|
|
|
+
|
|
|
+ // 分页配置
|
|
|
+ const pagination = reactive({
|
|
|
+ current: 1,
|
|
|
+ pageSize: 20,
|
|
|
+ total: 0,
|
|
|
+ showSizeChanger: true,
|
|
|
+ showQuickJumper: true,
|
|
|
+ showTotal: (total) => `共 ${total} 条记录`
|
|
|
+ })
|
|
|
+
|
|
|
+ // 表格列配置
|
|
|
+ const columns = [
|
|
|
+ {
|
|
|
+ title: '标题',
|
|
|
+ dataIndex: 'title',
|
|
|
+ key: 'title',
|
|
|
+ ellipsis: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '平台',
|
|
|
+ dataIndex: 'platform',
|
|
|
+ key: 'platform',
|
|
|
+ width: 100
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '状态',
|
|
|
+ dataIndex: 'noticeStatus',
|
|
|
+ key: 'noticeStatus',
|
|
|
+ width: 100
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '创建时间',
|
|
|
+ dataIndex: 'createTime',
|
|
|
+ key: 'createTime',
|
|
|
+ width: 180
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ key: 'action',
|
|
|
+ width: 250,
|
|
|
+ fixed: 'right'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+
|
|
|
+ // 表单验证规则
|
|
|
+ const formRules = {
|
|
|
+ title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
|
|
|
+ platform: [{ required: true, message: '请选择平台', trigger: 'change' }],
|
|
|
+ content: [{ required: true, message: '请输入内容', trigger: 'blur' }]
|
|
|
+ }
|
|
|
+ // 获取列表数据
|
|
|
+ const getList = async () => {
|
|
|
+ try {
|
|
|
+ loading.value = true
|
|
|
+ const params = {
|
|
|
+ current: pagination.current,
|
|
|
+ size: pagination.pageSize,
|
|
|
+ ...searchForm
|
|
|
+ }
|
|
|
+
|
|
|
+ const response = await list(params)
|
|
|
+ if (response.code === 200) {
|
|
|
+ tableData.value = response.data.records
|
|
|
+ pagination.total = response.data.total
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ message.error('获取列表失败')
|
|
|
+ console.error(error)
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 搜索
|
|
|
+ const handleSearch = () => {
|
|
|
+ pagination.current = 1
|
|
|
+ getList()
|
|
|
+ }
|
|
|
+
|
|
|
+ // 表格变化处理
|
|
|
+ const handleTableChange = (pag) => {
|
|
|
+ pagination.current = pag.current
|
|
|
+ pagination.pageSize = pag.pageSize
|
|
|
+ getList()
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增
|
|
|
+ const handleAdd = () => {
|
|
|
+ modalTitle.value = '新增公告'
|
|
|
+ isEdit.value = false
|
|
|
+ resetForm()
|
|
|
+ modalVisible.value = true
|
|
|
+ }
|
|
|
+
|
|
|
+ // 编辑
|
|
|
+ const handleEdit = (record) => {
|
|
|
+ modalTitle.value = '编辑公告'
|
|
|
+ isEdit.value = true
|
|
|
+ formData.noticeId = record.noticeId
|
|
|
+ formData.title = record.title
|
|
|
+ formData.platform = record.platform
|
|
|
+ formData.content = record.content
|
|
|
+ modalVisible.value = true
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查看详情
|
|
|
+ const handleView = async (record) => {
|
|
|
+ try {
|
|
|
+ const response = await detail({ noticeId: record.noticeId })
|
|
|
+ if (response.code === 200) {
|
|
|
+ detailData.value = response.data
|
|
|
+ detailVisible.value = true
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ message.error('获取详情失败')
|
|
|
+ console.error(error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 发布
|
|
|
+ const handlePublish = async (record) => {
|
|
|
+ try {
|
|
|
+ const response = await publish({ noticeId: record.noticeId })
|
|
|
+ if (response.code === 200) {
|
|
|
+ message.success('发布成功')
|
|
|
+ getList()
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ message.error('发布失败')
|
|
|
+ console.error(error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 取消发布
|
|
|
+ const handleCancelPublish = async (record) => {
|
|
|
+ try {
|
|
|
+ const response = await cancelPublish({ noticeId: record.noticeId })
|
|
|
+ if (response.code === 200) {
|
|
|
+ message.success('取消发布成功')
|
|
|
+ getList()
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ message.error('取消发布失败')
|
|
|
+ console.error(error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 删除
|
|
|
+ const handleDelete = async (record) => {
|
|
|
+ try {
|
|
|
+ const response = await courceDownList([{ noticeId: record.noticeId }])
|
|
|
+ if (response.code === 200) {
|
|
|
+ message.success('删除成功')
|
|
|
+ getList()
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ message.error('删除失败')
|
|
|
+ console.error(error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提交表单
|
|
|
+ const handleSubmit = async () => {
|
|
|
+ try {
|
|
|
+ await formRef.value.validate()
|
|
|
+
|
|
|
+ const apiCall = isEdit.value ? editItem : addItem
|
|
|
+ const response = await apiCall(formData)
|
|
|
+
|
|
|
+ if (response.code === 200) {
|
|
|
+ message.success(isEdit.value ? '编辑成功' : '新增成功')
|
|
|
+ modalVisible.value = false
|
|
|
+ getList()
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ if (error.errorFields) {
|
|
|
+ message.error('请检查表单输入')
|
|
|
+ } else {
|
|
|
+ message.error(isEdit.value ? '编辑失败' : '新增失败')
|
|
|
+ console.error(error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 取消弹窗
|
|
|
+ const handleCancel = () => {
|
|
|
+ modalVisible.value = false
|
|
|
+ resetForm()
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重置表单
|
|
|
+ const resetForm = () => {
|
|
|
+ formData.noticeId = null
|
|
|
+ formData.title = ''
|
|
|
+ formData.platform = 1
|
|
|
+ formData.content = ''
|
|
|
+ formRef.value?.resetFields()
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化
|
|
|
+ onMounted(() => {
|
|
|
+ getList()
|
|
|
+ })
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="less">
|
|
|
+ .notice-management {
|
|
|
+ padding: 20px;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .search-section {
|
|
|
+ padding: 16px;
|
|
|
+ background: #fafafa;
|
|
|
+ border-radius: 6px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .content-display {
|
|
|
+ padding: 16px;
|
|
|
+ background: #fafafa;
|
|
|
+ border-radius: 6px;
|
|
|
+ white-space: pre-wrap;
|
|
|
+ word-break: break-word;
|
|
|
+ max-height: 300px;
|
|
|
+ overflow-y: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.ant-table) {
|
|
|
+ .ant-table-tbody > tr > td {
|
|
|
+ vertical-align: top;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.ant-descriptions-item-label) {
|
|
|
+ font-weight: 600;
|
|
|
+ }
|
|
|
+</style>
|