<!DOCTYPE html>
|
<html lang="zh-CN">
|
|
<head>
|
<meta charset="utf-8">
|
<title>系统公告管理</title>
|
<meta name="renderer" content="webkit">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<link rel="stylesheet" href="../../static/vue/element/element.css">
|
<style>
|
* {
|
margin: 0;
|
padding: 0;
|
box-sizing: border-box;
|
}
|
|
body {
|
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
|
background: #f5f7fa;
|
padding: 15px;
|
}
|
|
.app-container {
|
background: #fff;
|
border-radius: 8px;
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
padding: 20px;
|
}
|
|
.header-section {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 20px;
|
flex-wrap: wrap;
|
gap: 10px;
|
}
|
|
.search-section {
|
display: flex;
|
gap: 10px;
|
flex-wrap: wrap;
|
align-items: center;
|
}
|
|
.action-buttons {
|
display: flex;
|
gap: 10px;
|
}
|
|
.table-section {
|
margin-top: 15px;
|
}
|
|
.pagination-section {
|
margin-top: 20px;
|
display: flex;
|
justify-content: flex-end;
|
}
|
</style>
|
</head>
|
|
<body>
|
<div id="app">
|
<div class="app-container" v-loading="tableLoading">
|
<div class="header-section">
|
<div class="search-section">
|
<el-input v-model="searchForm.title" placeholder="标题" size="small" clearable style="width: 180px;">
|
</el-input>
|
<el-select v-model="searchForm.status" placeholder="状态" clearable size="small" style="width: 120px;">
|
<el-option label="正常" value="1"></el-option>
|
<el-option label="禁用" value="0"></el-option>
|
</el-select>
|
<el-button type="primary" size="small" icon="el-icon-search" @click="handleSearch">搜索</el-button>
|
<el-button size="small" icon="el-icon-refresh-left" @click="handleReset">重置</el-button>
|
</div>
|
<div class="action-buttons">
|
<el-button type="primary" size="small" icon="el-icon-plus" @click="openAdd">新增</el-button>
|
<el-button type="danger" size="small" icon="el-icon-delete" @click="handleBatchDelete"
|
:disabled="selectedRows.length === 0">删除</el-button>
|
<!-- <el-button size="small" icon="el-icon-download" @click="handleExport">导出</el-button> -->
|
</div>
|
</div>
|
|
<div class="table-section">
|
<el-table :data="tableData" border stripe @selection-change="handleSelectionChange"
|
style="width: 100%;" :header-cell-style="{ background: '#f5f7fa', color: '#606266' }">
|
<el-table-column type="selection" width="50" align="center"></el-table-column>
|
<el-table-column prop="id" label="ID" width="70" align="center"></el-table-column>
|
<el-table-column prop="title" label="标题" min-width="160" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="content" label="内容" min-width="260" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="status$" label="状态" width="90" align="center"></el-table-column>
|
<el-table-column prop="createTime$" label="创建时间" width="170" align="center"></el-table-column>
|
<el-table-column prop="updateTime$" label="修改时间" width="170" align="center"></el-table-column>
|
<el-table-column label="操作" width="160" align="center" fixed="right">
|
<template slot-scope="scope">
|
<el-button type="text" size="small" @click="openDetail(scope.row)">详情</el-button>
|
<el-button type="text" size="small" @click="openEdit(scope.row)">编辑</el-button>
|
<el-button type="text" size="small" style="color:#f56c6c"
|
@click="handleDelete(scope.row)">删除</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
|
<div class="pagination-section">
|
<el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="total"
|
:page-size="pageSize" :current-page="currentPage" :page-sizes="[10, 20, 50, 100]"
|
@size-change="handleSizeChange" @current-change="handlePageChange">
|
</el-pagination>
|
</div>
|
</div>
|
|
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="520px" :close-on-click-modal="false">
|
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px">
|
<el-form-item label="标题" prop="title">
|
<el-input v-model="formData.title" :disabled="isDetail"></el-input>
|
</el-form-item>
|
<el-form-item label="内容" prop="content">
|
<el-input type="textarea" v-model="formData.content" :rows="5" :disabled="isDetail"></el-input>
|
</el-form-item>
|
<el-form-item label="状态" prop="status">
|
<el-select v-model="formData.status" :disabled="isDetail" style="width: 140px;">
|
<el-option label="正常" value="1"></el-option>
|
<el-option label="禁用" value="0"></el-option>
|
</el-select>
|
</el-form-item>
|
</el-form>
|
<div slot="footer" class="dialog-footer">
|
<el-button @click="dialogVisible = false">取消</el-button>
|
<el-button type="primary" @click="submitForm" v-if="!isDetail" :loading="submitting">保存</el-button>
|
</div>
|
</el-dialog>
|
</div>
|
|
<script src="../../static/vue/js/vue.min.js"></script>
|
<script src="../../static/vue/element/element.js"></script>
|
<script src="../../static/js/jquery/jquery-3.3.1.min.js"></script>
|
<script src="../../static/js/common.js"></script>
|
<script>
|
new Vue({
|
el: '#app',
|
data: {
|
tableData: [],
|
tableLoading: false,
|
total: 0,
|
currentPage: 1,
|
pageSize: 10,
|
selectedRows: [],
|
searchForm: {
|
title: '',
|
status: ''
|
},
|
dialogVisible: false,
|
dialogMode: 'add',
|
submitting: false,
|
formData: {
|
id: '',
|
title: '',
|
content: '',
|
status: '1'
|
},
|
formRules: {
|
title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
|
content: [{ required: true, message: '请输入内容', trigger: 'blur' }],
|
status: [{ required: true, message: '请选择状态', trigger: 'change' }]
|
}
|
},
|
computed: {
|
isDetail() {
|
return this.dialogMode === 'detail';
|
},
|
dialogTitle() {
|
if (this.dialogMode === 'add') {
|
return '新增公告';
|
}
|
if (this.dialogMode === 'edit') {
|
return '编辑公告';
|
}
|
return '公告详情';
|
}
|
},
|
created() {
|
this.loadData();
|
},
|
methods: {
|
getHeaders() {
|
return { 'token': localStorage.getItem('token') };
|
},
|
loadData() {
|
this.tableLoading = true;
|
const params = {
|
curr: this.currentPage,
|
limit: this.pageSize,
|
...this.searchForm
|
};
|
$.ajax({
|
url: baseUrl + '/announcement/list/auth',
|
headers: this.getHeaders(),
|
data: params,
|
success: (res) => {
|
this.tableLoading = false;
|
if (res.code === 200) {
|
this.tableData = res.data.records || [];
|
this.total = res.data.total || 0;
|
} else if (res.code === 403) {
|
top.location.href = baseUrl + '/';
|
} else {
|
this.$message.error(res.msg || '加载失败');
|
}
|
},
|
error: () => {
|
this.tableLoading = false;
|
this.$message.error('请求失败');
|
}
|
});
|
},
|
handleSearch() {
|
this.currentPage = 1;
|
this.loadData();
|
},
|
handleReset() {
|
this.searchForm = { title: '', status: '' };
|
this.currentPage = 1;
|
this.loadData();
|
},
|
handleSizeChange(size) {
|
this.pageSize = size;
|
this.currentPage = 1;
|
this.loadData();
|
},
|
handlePageChange(page) {
|
this.currentPage = page;
|
this.loadData();
|
},
|
handleSelectionChange(rows) {
|
this.selectedRows = rows;
|
},
|
openAdd() {
|
this.dialogMode = 'add';
|
this.formData = { id: '', title: '', content: '', status: '1' };
|
this.dialogVisible = true;
|
this.$nextTick(() => {
|
if (this.$refs.formRef) {
|
this.$refs.formRef.clearValidate();
|
}
|
});
|
},
|
openEdit(row) {
|
this.dialogMode = 'edit';
|
this.formData = {
|
id: row.id,
|
title: row.title,
|
content: row.content,
|
status: String(row.status)
|
};
|
this.dialogVisible = true;
|
this.$nextTick(() => {
|
if (this.$refs.formRef) {
|
this.$refs.formRef.clearValidate();
|
}
|
});
|
},
|
openDetail(row) {
|
this.dialogMode = 'detail';
|
this.formData = {
|
id: row.id,
|
title: row.title,
|
content: row.content,
|
status: String(row.status)
|
};
|
this.dialogVisible = true;
|
},
|
submitForm() {
|
this.$refs.formRef.validate((valid) => {
|
if (!valid) {
|
return;
|
}
|
this.submitting = true;
|
const payload = {
|
id: this.formData.id,
|
title: this.formData.title,
|
content: this.formData.content,
|
status: this.formData.status
|
};
|
$.ajax({
|
url: baseUrl + '/announcement/edit/auth',
|
headers: this.getHeaders(),
|
data: payload,
|
method: 'POST',
|
success: (res) => {
|
this.submitting = false;
|
if (res.code === 200) {
|
this.$message.success('保存成功');
|
this.dialogVisible = false;
|
this.loadData();
|
} else if (res.code === 403) {
|
top.location.href = baseUrl + '/';
|
} else {
|
this.$message.error(res.msg || '保存失败');
|
}
|
},
|
error: () => {
|
this.submitting = false;
|
this.$message.error('请求失败');
|
}
|
});
|
});
|
},
|
handleDelete(row) {
|
this.$confirm('确定删除该公告吗?', '提示', { type: 'warning' }).then(() => {
|
$.ajax({
|
url: baseUrl + '/announcement/delete/auth',
|
headers: this.getHeaders(),
|
data: { ids: [row.id] },
|
method: 'POST',
|
traditional: true,
|
success: (res) => {
|
if (res.code === 200) {
|
this.$message.success('删除成功');
|
this.loadData();
|
} else if (res.code === 403) {
|
top.location.href = baseUrl + '/';
|
} else {
|
this.$message.error(res.msg || '删除失败');
|
}
|
}
|
});
|
}).catch(() => {});
|
},
|
handleBatchDelete() {
|
const ids = this.selectedRows.map(item => item.id);
|
if (!ids.length) {
|
this.$message.warning('请选择数据');
|
return;
|
}
|
this.$confirm('确定删除选中的公告吗?', '提示', { type: 'warning' }).then(() => {
|
$.ajax({
|
url: baseUrl + '/announcement/delete/auth',
|
headers: this.getHeaders(),
|
data: { ids: ids },
|
method: 'POST',
|
traditional: true,
|
success: (res) => {
|
if (res.code === 200) {
|
this.$message.success('删除成功');
|
this.selectedRows = [];
|
this.loadData();
|
} else if (res.code === 403) {
|
top.location.href = baseUrl + '/';
|
} else {
|
this.$message.error(res.msg || '删除失败');
|
}
|
}
|
});
|
}).catch(() => {});
|
},
|
handleExport() {
|
const fields = ['id', 'title', 'content', 'status', 'createTime', 'updateTime'];
|
const titles = ['ID', '标题', '内容', '状态', '创建时间', '修改时间'];
|
const params = {
|
announcement: { ...this.searchForm },
|
fields: fields
|
};
|
$.ajax({
|
url: baseUrl + '/announcement/export/auth',
|
headers: this.getHeaders(),
|
data: JSON.stringify(params),
|
dataType: 'json',
|
contentType: 'application/json;charset=UTF-8',
|
method: 'POST',
|
success: (res) => {
|
if (res.code === 200) {
|
const rows = res.data || [];
|
const csvRows = [titles.join(',')];
|
rows.forEach(row => {
|
const values = fields.map(field => {
|
const value = row[field];
|
const text = value == null ? '' : String(value).replace(/"/g, '""');
|
return `"${text}"`;
|
});
|
csvRows.push(values.join(','));
|
});
|
const blob = new Blob([csvRows.join('\n')], { type: 'text/csv;charset=utf-8;' });
|
const link = document.createElement('a');
|
link.href = URL.createObjectURL(blob);
|
link.download = 'announcement.csv';
|
document.body.appendChild(link);
|
link.click();
|
document.body.removeChild(link);
|
} else if (res.code === 403) {
|
top.location.href = baseUrl + '/';
|
} else {
|
this.$message.error(res.msg || '导出失败');
|
}
|
}
|
});
|
}
|
}
|
});
|
</script>
|
</body>
|
|
</html>
|