Kaynağa Gözat

feat(notice): 添加公告管理功能模块

- 新增公告管理页面,包含公告的增删改查功能
- 实现公告的发布和取消发布功能
- 添加公告详情查看功能
- 移除登录页面的部分未使用组件
tanshanming 6 ay önce
ebeveyn
işleme
f568e685f2

+ 4 - 0
src/api/notice/index.js

@@ -16,3 +16,7 @@ export const detail = (p) => request('disk/notice/detail', p, 'get')
 //收藏增加
 //资源列表 排除没权限得条目
 export const courceDownList = (p) => request('disk/notice/delete', p, 'post')
+//发布
+export const publish = (p) => request('disk/notice/publish', p, 'get')
+//取消发布
+export const cancelPublish = (p) => request('disk/notice/cancel', p, 'get')

+ 9 - 9
src/views/auth/login/login.vue

@@ -77,9 +77,9 @@
 									</a-row>
 								</a-form-item>
 
-								<a-form-item>
+								<!-- <a-form-item>
 									<a href="/findpwd" style="color: #0d84ff">{{ $t('login.forgetPassword') }}?</a>
-								</a-form-item>
+								</a-form-item> -->
 								<a-form-item>
 									<a-button type="primary" class="w-full" :loading="loading" round size="large" @click="login"
 										>{{ $t('login.signIn') }}
@@ -87,11 +87,11 @@
 								</a-form-item>
 							</a-form>
 						</a-tab-pane>
-						<a-tab-pane key="userSms" :tab="$t('login.phoneSms')" force-render>
+						<!-- <a-tab-pane key="userSms" :tab="$t('login.phoneSms')" force-render>
 							<phone-login-form />
-						</a-tab-pane>
+						</a-tab-pane> -->
 					</a-tabs>
-					<three-login />
+					<!-- <three-login /> -->
 				</a-card>
 			</div>
 		</div>
@@ -101,7 +101,7 @@
 <script>
 	import loginApi from '@/api/auth/loginApi'
 	import phoneLoginForm from './phoneLoginForm.vue'
-	import threeLogin from './threeLogin.vue'
+	// import threeLogin from './threeLogin.vue'
 	import smCrypto from '@/utils/smCrypto'
 	import { required } from '@/utils/formRules'
 	import { afterLogin } from './util'
@@ -114,8 +114,8 @@
 	export default {
 		name: 'Login',
 		components: {
-			phoneLoginForm,
-			threeLogin
+			// phoneLoginForm
+			// threeLogin
 		},
 		data() {
 			return {
@@ -152,7 +152,7 @@
 			}
 		},
 		computed: {
-			...mapState(globalStore, ['sysBaseConfig']),
+			...mapState(globalStore, ['sysBaseConfig'])
 		},
 		watch: {
 			'config.theme': function (val) {

+ 401 - 0
src/views/notice/index.vue

@@ -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>