2026-04-22 18:04:19 +08:00
|
|
|
|
<template>
|
2025-06-06 15:31:45 +08:00
|
|
|
|
<commonManage>
|
|
|
|
|
|
<div class="head">
|
|
|
|
|
|
<div class="left">
|
|
|
|
|
|
<p class="desctipt">标题:</p>
|
|
|
|
|
|
<el-input v-model="data.tableNeed.title" class="m-2" placeholder="请输入文章标题" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="right">
|
|
|
|
|
|
<p v-for="(item, index) in handelData" :key="index" :class="item.className"
|
|
|
|
|
|
@click="btnClick(item.engName)">
|
|
|
|
|
|
{{ item.chinName }}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="cont">
|
2026-04-22 18:04:19 +08:00
|
|
|
|
<el-table :data="data.tableNeed.tableData" style="width: calc(100% - 40px) ;height: calc(100vh - 210px); margin:0 20px ;" fit="true"
|
2025-06-06 15:31:45 +08:00
|
|
|
|
:header-cell-style="{ 'text-align': 'center', 'font-size': '12px', 'color': '#3F404A', padding: '3px', background: '#F8F8FA', height: '50px' }"
|
|
|
|
|
|
:cell-style="getCellStyles" :row-style="{ height: '0px' }">
|
|
|
|
|
|
<el-table-column fixed prop="ind" label="序号" width="80" />
|
|
|
|
|
|
<el-table-column prop="title" label="文章标题" />
|
|
|
|
|
|
<el-table-column prop="abstract" label="摘要" show-overflow-tooltip />
|
|
|
|
|
|
<el-table-column prop="updateDate" label="更新时间" width="180" />
|
|
|
|
|
|
<el-table-column label="操作" width="180">
|
|
|
|
|
|
<template v-slot="{ row }">
|
|
|
|
|
|
<div class="operate">
|
|
|
|
|
|
<p class="edit" @click="viewDetail(row)">查看详情</p>
|
|
|
|
|
|
<p class="delete" @click="handleDelete(row)">删除</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
<el-pagination class="pagination" :current-page="data.tableNeed.pageIndex"
|
|
|
|
|
|
:page-size="data.tableNeed.pageSize" :page-sizes="[10, 50, 100, 200]"
|
|
|
|
|
|
layout="total, sizes, prev, pager, next, jumper" :total="data.tableNeed.total"
|
|
|
|
|
|
@size-change="handleSizeChange" @current-change="changePage" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</commonManage>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 文章详情弹窗 -->
|
|
|
|
|
|
<el-dialog v-model="data.detailDialog.show" title="文章详情" width="50%" :close-on-click-modal="false">
|
|
|
|
|
|
<div class="article-detail">
|
|
|
|
|
|
<h2 class="article-title">{{ data.detailDialog.article.title }}</h2>
|
|
|
|
|
|
<div class="article-meta">
|
|
|
|
|
|
<span>更新时间: {{ formatDate(data.detailDialog.article.updateDate) }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="article-cover" v-if="data.detailDialog.article.coverImage">
|
|
|
|
|
|
<img :src="data.detailDialog.article.coverImage" alt="封面图">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="article-abstract">
|
|
|
|
|
|
<h3>摘要</h3>
|
|
|
|
|
|
<p>{{ data.detailDialog.article.abstract }}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="article-link" v-if="data.detailDialog.article.articleUrl">
|
|
|
|
|
|
<h3>原文链接</h3>
|
|
|
|
|
|
<a :href="data.detailDialog.article.articleUrl" target="_blank">{{ data.detailDialog.article.articleUrl }}</a>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
|
<span class="dialog-footer">
|
|
|
|
|
|
<el-button @click="data.detailDialog.show = false">关闭</el-button>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 新增文章弹窗 -->
|
|
|
|
|
|
<el-drawer v-model="data.addDialog.show" direction="rtl" size="50%" :close-on-click-modal="false" :show-close="false">
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
<p class="title">新增文章</p>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<template #default>
|
|
|
|
|
|
<el-form ref="addFormRef" :model="addForm" :rules="addRules" label-width="120px" class="demo-ruleForm" size="default" status-icon>
|
|
|
|
|
|
<el-form-item label="文章标题" prop="title">
|
|
|
|
|
|
<el-input v-model="addForm.title" placeholder="请输入文章标题" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="文章摘要" prop="abstract">
|
|
|
|
|
|
<el-input v-model="addForm.abstract" type="textarea" :rows="4" placeholder="请输入文章摘要" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="原文链接" prop="articleUrl">
|
|
|
|
|
|
<el-input v-model="addForm.articleUrl" placeholder="请输入原文链接" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="封面图片" prop="coverImage" style="display: flex;align-items: center;">
|
|
|
|
|
|
<el-upload class="upload-demo" ref="uploadRef" drag :before-upload="handleBeforeUpload" :file-list="addForm.fileList">
|
|
|
|
|
|
<div class="el-upload__text">
|
|
|
|
|
|
将文件拖拽到这里或<em>点击上传</em>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-upload>
|
|
|
|
|
|
<div class="coverImg" v-if="coverImgUrl">
|
|
|
|
|
|
<img style="width: 100px;height: 100px;margin-left: 10px;object-fit: contain;" :src="coverImgUrl" alt="封面">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
|
<div class="footer">
|
|
|
|
|
|
<p class="cancle" @click="cancelAdd">取消</p>
|
|
|
|
|
|
<p class="confirm" @click="confirmAdd">确定</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-drawer>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 删除确认弹窗 -->
|
|
|
|
|
|
<el-dialog v-model="data.deleteDialog.show" title="提示" width="30%" :close-on-click-modal="false">
|
|
|
|
|
|
<span>确定要删除该文章吗?</span>
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
|
<span class="dialog-footer">
|
|
|
|
|
|
<el-button @click="data.deleteDialog.show = false">取消</el-button>
|
|
|
|
|
|
<el-button type="danger" @click="confirmDelete">确定</el-button>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import { ref, reactive, onMounted, computed } from 'vue';
|
|
|
|
|
|
import { getArticlePageList, getArticleDetails, addArticle, uploadArticleImage, deleteArticle } from '@/api/article';
|
|
|
|
|
|
import { ElMessage } from 'element-plus';
|
|
|
|
|
|
|
|
|
|
|
|
// 数据定义
|
|
|
|
|
|
const data = reactive({
|
|
|
|
|
|
tableNeed: {
|
|
|
|
|
|
title: '',
|
|
|
|
|
|
pageIndex: 1,
|
|
|
|
|
|
pageSize: 10,
|
|
|
|
|
|
total: 0,
|
|
|
|
|
|
tableData: []
|
|
|
|
|
|
},
|
|
|
|
|
|
detailDialog: {
|
|
|
|
|
|
show: false,
|
|
|
|
|
|
article: {}
|
|
|
|
|
|
},
|
|
|
|
|
|
addDialog: {
|
|
|
|
|
|
show: false
|
|
|
|
|
|
},
|
|
|
|
|
|
deleteDialog: {
|
|
|
|
|
|
show: false,
|
|
|
|
|
|
articleId: null
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 新增表单引用
|
|
|
|
|
|
const addFormRef = ref(null);
|
|
|
|
|
|
const uploadRef = ref(null);
|
|
|
|
|
|
let coverImgUrl = ref('');
|
|
|
|
|
|
|
|
|
|
|
|
// 文件上传表单
|
|
|
|
|
|
const photoForm = new FormData();
|
|
|
|
|
|
|
|
|
|
|
|
// 新增表单数据
|
|
|
|
|
|
const addForm = reactive({
|
|
|
|
|
|
title: '',
|
|
|
|
|
|
abstract: '',
|
|
|
|
|
|
articleUrl: '',
|
|
|
|
|
|
coverImage: '',
|
|
|
|
|
|
fileList: []
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 表单验证规则
|
|
|
|
|
|
const addRules = {
|
|
|
|
|
|
title: [
|
|
|
|
|
|
{ required: true, message: '请输入文章标题', trigger: 'blur' },
|
|
|
|
|
|
],
|
|
|
|
|
|
articleUrl: [
|
|
|
|
|
|
{ required: true, message: '请输入原文链接', trigger: 'blur' },
|
|
|
|
|
|
],
|
|
|
|
|
|
coverImage: [
|
|
|
|
|
|
{ required: true, message: '请上传封面图片', trigger: 'change' },
|
|
|
|
|
|
]
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 表格样式
|
|
|
|
|
|
const getCellStyles = () => {
|
|
|
|
|
|
return {
|
|
|
|
|
|
'text-align': 'center',
|
|
|
|
|
|
'font-size': '12px',
|
|
|
|
|
|
'color': '#3F404A',
|
|
|
|
|
|
'padding': '3px',
|
|
|
|
|
|
'height': '50px'
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 操作按钮数据
|
|
|
|
|
|
const handelData = computed(() => {
|
|
|
|
|
|
return [
|
|
|
|
|
|
{
|
|
|
|
|
|
chinName: '查询',
|
|
|
|
|
|
engName: 'search',
|
|
|
|
|
|
className: 'Search'
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
chinName: '重置',
|
|
|
|
|
|
engName: 'reset',
|
|
|
|
|
|
className: 'reset'
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
chinName: '新增',
|
|
|
|
|
|
engName: 'add',
|
|
|
|
|
|
className: 'Add'
|
|
|
|
|
|
}
|
|
|
|
|
|
];
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 按钮点击事件
|
|
|
|
|
|
const btnClick = (type) => {
|
|
|
|
|
|
if (type === 'search') {
|
|
|
|
|
|
data.tableNeed.pageIndex = 1;
|
|
|
|
|
|
getArticleList();
|
|
|
|
|
|
} else if (type === 'reset') {
|
|
|
|
|
|
data.tableNeed.title = '';
|
|
|
|
|
|
data.tableNeed.pageIndex = 1;
|
|
|
|
|
|
getArticleList();
|
|
|
|
|
|
} else if (type === 'add') {
|
|
|
|
|
|
// 打开新增弹窗
|
|
|
|
|
|
resetAddForm();
|
|
|
|
|
|
data.addDialog.show = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 重置新增表单
|
|
|
|
|
|
const resetAddForm = () => {
|
|
|
|
|
|
if (addFormRef.value) {
|
|
|
|
|
|
addFormRef.value.resetFields();
|
|
|
|
|
|
}
|
|
|
|
|
|
addForm.title = '';
|
|
|
|
|
|
addForm.abstract = '';
|
|
|
|
|
|
addForm.articleUrl = '';
|
|
|
|
|
|
addForm.coverImage = '';
|
|
|
|
|
|
addForm.fileList = [];
|
|
|
|
|
|
coverImgUrl.value = '';
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 图片上传前处理
|
|
|
|
|
|
const handleBeforeUpload = (file) => {
|
|
|
|
|
|
const isImage = file.type.indexOf('image') !== -1;
|
|
|
|
|
|
const isLt2M = file.size / 1024 / 1024 < 2;
|
|
|
|
|
|
|
|
|
|
|
|
if (!isImage) {
|
|
|
|
|
|
ElMessage.error('上传文件只能是图片格式!');
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!isLt2M) {
|
|
|
|
|
|
ElMessage.error('上传图片大小不能超过 2MB!');
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
const reader = new FileReader();
|
|
|
|
|
|
reader.readAsDataURL(file);
|
|
|
|
|
|
reader.onload = function () {
|
|
|
|
|
|
photoForm.append("file", file);
|
|
|
|
|
|
uploadArticleImage(photoForm).then(response => {
|
|
|
|
|
|
if (response.data.code == 200) {
|
|
|
|
|
|
const newUrl = response.data.data + '?timestamp=' + new Date().getTime();
|
|
|
|
|
|
coverImgUrl.value = newUrl;
|
|
|
|
|
|
addForm.coverImage = newUrl;
|
|
|
|
|
|
photoForm.delete("file");
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ElMessage.error(response.data.message);
|
|
|
|
|
|
photoForm.delete("file");
|
|
|
|
|
|
}
|
|
|
|
|
|
}).catch(error => {
|
|
|
|
|
|
console.error(error);
|
|
|
|
|
|
photoForm.delete("file");
|
|
|
|
|
|
reject(error);
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
reader.onerror = function (error) {
|
|
|
|
|
|
reject(error);
|
|
|
|
|
|
};
|
|
|
|
|
|
reader.onloadend = function () {
|
|
|
|
|
|
resolve(coverImgUrl.value);
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 取消新增
|
|
|
|
|
|
const cancelAdd = () => {
|
|
|
|
|
|
data.addDialog.show = false;
|
|
|
|
|
|
resetAddForm();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 确认新增
|
|
|
|
|
|
const confirmAdd = async () => {
|
|
|
|
|
|
if (!addFormRef.value) return;
|
|
|
|
|
|
|
|
|
|
|
|
await addFormRef.value.validate(async (valid) => {
|
|
|
|
|
|
if (valid) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const formData = {
|
|
|
|
|
|
title: addForm.title,
|
|
|
|
|
|
abstract: addForm.abstract,
|
|
|
|
|
|
articleUrl: addForm.articleUrl,
|
|
|
|
|
|
coverImage: addForm.coverImage
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const res = await addArticle(formData);
|
|
|
|
|
|
if (res && res.data) {
|
|
|
|
|
|
ElMessage.success('新增文章成功');
|
|
|
|
|
|
data.addDialog.show = false;
|
|
|
|
|
|
resetAddForm();
|
|
|
|
|
|
getArticleList(); // 刷新列表
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
ElMessage.error('新增文章失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 分页大小变化
|
|
|
|
|
|
const handleSizeChange = (val) => {
|
|
|
|
|
|
data.tableNeed.pageSize = val;
|
|
|
|
|
|
getArticleList();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 页码变化
|
|
|
|
|
|
const changePage = (val) => {
|
|
|
|
|
|
data.tableNeed.pageIndex = val;
|
|
|
|
|
|
getArticleList();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 查看详情
|
|
|
|
|
|
const viewDetail = async (row) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await getArticleDetails(row.id);
|
|
|
|
|
|
if (res && res.data) {
|
|
|
|
|
|
data.detailDialog.article = res.data;
|
|
|
|
|
|
data.detailDialog.show = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
ElMessage.error('获取文章详情失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 处理删除
|
|
|
|
|
|
const handleDelete = (row) => {
|
|
|
|
|
|
data.deleteDialog.articleId = row.id;
|
|
|
|
|
|
data.deleteDialog.show = true;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 确认删除
|
|
|
|
|
|
const confirmDelete = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
console.log(data.deleteDialog.articleId);
|
|
|
|
|
|
const res = await deleteArticle(data.deleteDialog.articleId);
|
|
|
|
|
|
if (res && res.data && res.data.status) {
|
|
|
|
|
|
ElMessage.success('删除文章成功');
|
|
|
|
|
|
data.deleteDialog.show = false;
|
|
|
|
|
|
getArticleList(); // 刷新列表
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ElMessage.error(res.data.message || '删除文章失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
ElMessage.error('删除文章失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化日期
|
|
|
|
|
|
const formatDate = (dateString) => {
|
|
|
|
|
|
if (!dateString) return '';
|
|
|
|
|
|
const date = new Date(dateString);
|
|
|
|
|
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 获取文章列表
|
|
|
|
|
|
const getArticleList = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await getArticlePageList(
|
|
|
|
|
|
data.tableNeed.pageIndex,
|
|
|
|
|
|
data.tableNeed.pageSize,
|
|
|
|
|
|
data.tableNeed.title
|
|
|
|
|
|
);
|
|
|
|
|
|
if (res && res.data) {
|
|
|
|
|
|
data.tableNeed.tableData = res.data.datas.map((item, index) => {
|
|
|
|
|
|
return {
|
|
|
|
|
|
...item,
|
|
|
|
|
|
ind: (data.tableNeed.pageIndex - 1) * data.tableNeed.pageSize + index + 1
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
data.tableNeed.total = res.data.total;
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
ElMessage.error('获取文章列表失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 页面加载时获取数据
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
getArticleList();
|
|
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
|
|
|
.head {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 72px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
|
|
.left {
|
|
|
|
|
|
width: auto;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
|
|
.desctipt {
|
|
|
|
|
|
width: 50px;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-family: PingFangSC;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
color: #3F404A;
|
|
|
|
|
|
margin-left: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.m-2 {
|
|
|
|
|
|
width: 250px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.right {
|
|
|
|
|
|
width: 80%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
|
|
|
|
|
|
|
.reset {
|
|
|
|
|
|
width: 95px;
|
|
|
|
|
|
height: 40px;
|
|
|
|
|
|
background: #FAFAFA;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
border: 1px solid rgba(0, 0, 0, 0.15);
|
|
|
|
|
|
font-family: PingFangSC;
|
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: rgba(0, 0, 0, 0.65);
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
line-height: 40px;
|
|
|
|
|
|
margin-right: 20px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
user-select: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.Search,
|
|
|
|
|
|
.Add {
|
|
|
|
|
|
margin-right: 20px;
|
|
|
|
|
|
width: 98px;
|
|
|
|
|
|
height: 40px;
|
|
|
|
|
|
background: #4188FE;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
font-family: PingFangSC;
|
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.operate {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.edit {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #4468BD;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.delete {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #F56C6C;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.pagination {
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
|
padding-right: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.article-detail {
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.article-title {
|
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.article-meta {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.article-cover {
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.article-cover img {
|
|
|
|
|
|
max-width: 100%;
|
|
|
|
|
|
max-height: 300px;
|
|
|
|
|
|
object-fit: contain;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.article-abstract h3,
|
|
|
|
|
|
.article-link h3 {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.article-abstract p {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.article-link a {
|
|
|
|
|
|
color: #4468BD;
|
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.article-link a:hover {
|
|
|
|
|
|
text-decoration: underline;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 新增弹窗样式 */
|
|
|
|
|
|
.title {
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.footer {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.cancle {
|
|
|
|
|
|
width: 80px;
|
|
|
|
|
|
height: 32px;
|
|
|
|
|
|
background: #FFFFFF;
|
|
|
|
|
|
border: 1px solid #DCDFE6;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #3F404A;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
line-height: 32px;
|
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.confirm {
|
|
|
|
|
|
width: 80px;
|
|
|
|
|
|
height: 32px;
|
|
|
|
|
|
background: #4468BD;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
line-height: 32px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.coverImg {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|