SpringBoot3+vue3实现系统公告功能

设计数据库表

1.创建系统公共表

1
2
3
4
5
6
7
CREATE TABLE `notice` (
`id` int NOT NULL COMMENT '主键ID',
`title` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '公共标题',
`content` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '公告内容',
`time` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '发布时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统公告表';

公告首页渲染

Timeline 时间线 | Element Plus

Notice.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
<template>
<div>
<div class="card" style="margin-bottom: 5px">
<!-- 加上clearable这个属性可以快速清除也就是那个叉叉顺便刷新一下 v-model="data.name" 将输入的文字显示到输入框内-->
<el-input clearable @clear="load" style="width: 240px;margin-right: 5px;" v-model="data.title" placeholder="请输入标题查询" :prefix-icon="Search"></el-input>

<el-button type="primary" @click="load">查 询</el-button>
<el-button @click="reset">重 置</el-button>
</div>


<div class="card" style="margin-bottom: 5px">
<el-button type="primary" @click="handleAdd">新 增</el-button>
</div>


<div class="card" style="margin-bottom: 5px">
<el-table :data="data.tableData" style="width: 100%" :header-cell-style="{fontWeight: 'bold',color: '#333',backgroundColor: '#c902f6'}">

<el-table-column prop="title" label="公告标题"/>
<el-table-column prop="content" label="公告内容" />
<el-table-column prop="time" label="公告时间" />
<el-table-column label="操作" width="100">
<template #default="scope">
<el-button type="primary" icon="Edit" circle @click="handleEdit(scope.row)"></el-button>
<el-button type="danger" icon="Delete" circle @click="del(scope.row.id)"></el-button>
</template>
</el-table-column>
</el-table>
</div>


<el-dialog v-model="data.formVisible" title="公告信息" width="30%" destroy-on-close>
<el-form ref="formRef" :model="data.form" :rules="data.rules" label-width="80px" style="padding: 20px 30px 10px 0">
<el-form-item prop="title" label="公告标题">
<el-input v-model="data.form.title" autocomplete="off" placeholder="请输入公共标题"/>
</el-form-item>

<el-form-item prop="content" label="公共内容">
<el-input type="textarea" :rows="3" v-model="data.form.content" autocomplete="off" placeholder="请输入公告内容"/>
</el-form-item>



</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="data.formVisible = false">Cancel</el-button>
<el-button type="primary" @click="save()">
Confirm
</el-button>
</div>
</template>
</el-dialog>

</div>
</template>
<script setup>

import {Search} from "@element-plus/icons-vue";
import {reactive,ref} from "vue";
import request from "@/utils/request.js";
import {ElMessage, ElMessageBox} from "element-plus";


const formRef = ref()
const data = reactive({
user: JSON.parse(localStorage.getItem('code2025_user') || "{}"),
title: null,
pageNum: 1,
pageSize: 5,
total: 0,
tableData: [],
form: {},
formVisible: false,
rules: {
title: [
{required: true,message: '请填写公告标题',trigger: 'blur'}
],
content: [
{required: true,message: '请填写公告内容',trigger: 'blur'}
],

}
})

const load = () => {
request.get('/notice/selectPage',{
params: {
pageNum: data.pageNum,
pageSize: data.pageSize,
title: data.title
}
}).then(res=>{
if(res.code === '200'){
data.tableData = res.data?.list
data.total = res.data?.total
}else{
ElMessage.error(res.msg)
}
})
}
load()

const handleEdit = (row) => {
data.form = JSON.parse(JSON.stringify(row))
data.formVisible = true
}

const handleAdd = () => {
data.form = {}
data.formVisible = true
}

const add = () => {
request.post('/notice/add',data.form).then(res => {
if(res.code==='200'){
ElMessage.success("新增成功")
data.formVisible = false
load()
}else{
ElMessage.error(res.msg)
}
})
}

const save = () => {
formRef.value.validate(valid => {
if(valid) {
data.form.id?update():add()
}else{
ElMessage.error(res.msg)
}
})
}

const update = () => {
request.put('/notice/update',data.form).then(res => {
if(res.code === '200'){
ElMessage.success('更新成功')
data.formVisible = false
load()
}else{
ElMessage.error(res.msg)
}
})
}


const del = (id)=>{
ElMessageBox.confirm('删除后无法恢复,您确认删除吗?','删除确认',{ type:"warning" }).then(res => {
request.delete('/notice/delete/'+id).then(res=>{
if(res.code === '200'){
ElMessage.success('删除成功')
load()
}else{
ElMessage.error(res.msg);
}
})
}).catch(err=>{

})
}

const reset = () =>{
data.title = null;
load()
}
</script>

Home.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<template>
<div>
<div class="card">泥嚎!欢迎使用本系统!</div>
<div class="card" style="margin-top: 10px;width: 50%;">
<div style="font-size: 18px; margin-bottom: 20px;">系统公告</div>
<el-timeline style="max-width: 600px">
<el-timeline-item :timestamp="item.time" color="#0bbd87" placement="top" v-for="item in data.noticeData">
<!-- <el-card>-->
<!-- 也可以根据官网<div style="font-size: 20px">{{ item.title }}</div>-->
<h4>{{ item.title }}</h4>
<p>{{ item.content }}</p>
<!-- </el-card>-->
</el-timeline-item>
</el-timeline>
</div>
</div>
</template>

<script setup>

import {reactive} from "vue";
import request from "@/utils/request.js";
import {ElMessage} from "element-plus";

const data = reactive({
user: JSON.parse(localStorage.getItem('code2025_user') || "{}"),
noticeData: []
})

const loadNotice = () => {
request.get('/notice/selectAll').then(res=>{
if(res.code === '200'){
data.noticeData = res.data
if(data.noticeData.length > 3){
data.noticeData = data.noticeData.slice(0,3)
}
}else{
ElMessage.error(res.msg)
}
})
}
loadNotice()
</script>

后端直接根据User的来改即可.

前端渲染也可以参考手风琴效果

Collapse折叠面板 自行尝试即可