| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- <template>
- <div class="article-panel">
- <div class="article-header">
- <div class="filter-container">
- <el-select
- v-model="filterForm.category_id"
- placeholder="全部分类"
- clearable
- @change="handleFilter"
- >
- <el-option label="全部分类" value="" />
- <el-option
- v-for="item in categories"
- :key="item.id"
- :label="item.name"
- :value="item.id"
- />
- </el-select>
- <el-select
- v-model="filterForm.status"
- placeholder="全部状态"
- clearable
- @change="handleFilter"
- >
- <el-option label="全部状态" value="" />
- <el-option label="草稿" :value="0" />
- <el-option label="已发布" :value="1" />
- <el-option label="已下线" :value="2" />
- </el-select>
- </div>
- <el-button type="primary" @click="handleAddArticle">新增文章</el-button>
- </div>
-
- <el-table
- v-loading="loading"
- :data="articles"
- border
- style="width: 100%">
- <el-table-column prop="id" label="ID" width="80" />
- <el-table-column label="封面" width="120">
- <template #default="scope">
- <el-image
- v-if="scope.row.cover"
- :src="scope.row.cover"
- :preview-src-list="[scope.row.cover]"
- fit="cover"
- style="width: 80px; height: 45px"
- />
- <span v-else>无封面</span>
- </template>
- </el-table-column>
- <el-table-column prop="title" label="标题" show-overflow-tooltip />
- <el-table-column prop="category_name" label="分类" width="120" />
- <el-table-column label="置顶" width="80">
- <template #default="scope">
- <el-tag :type="scope.row.is_top === 1 ? 'danger' : 'info'" size="small">
- {{ scope.row.is_top === 1 ? '是' : '否' }}
- </el-tag>
- </template>
- </el-table-column>
- <el-table-column label="状态" width="80">
- <template #default="scope">
- <el-tag :type="getStatusType(scope.row.status)" size="small">
- {{ getStatusText(scope.row.status) }}
- </el-tag>
- </template>
- </el-table-column>
- <el-table-column label="创建时间" width="160">
- <template #default="scope">
- {{ formatDateTime(scope.row.create_time) }}
- </template>
- </el-table-column>
- <el-table-column label="操作" width="200" fixed="right">
- <template #default="scope">
- <el-button type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button>
- <el-button type="danger" size="small" @click="handleDelete(scope.row)">删除</el-button>
- </template>
- </el-table-column>
- </el-table>
- <div class="pagination-container">
- <el-pagination
- v-model:current-page="pagination.page"
- v-model:page-size="pagination.limit"
- :page-sizes="[10, 20, 50, 100]"
- layout="total, sizes, prev, pager, next, jumper"
- :total="pagination.total"
- @size-change="handleSizeChange"
- @current-change="handleCurrentChange"
- />
- </div>
- </div>
- </template>
- <script>
- import { defineComponent, ref, reactive, onMounted, computed } from 'vue'
- import { useRouter } from 'vue-router'
- import { ElMessageBox } from 'element-plus'
- import { useNews } from '../../composables/useNews'
- export default defineComponent({
- name: 'ArticlePanel',
- setup() {
- const router = useRouter()
- const {
- loading,
- articles,
- categories,
- pagination,
- getArticleList,
- getCategoryList,
- deleteArticle
- } = useNews()
- const filterForm = reactive({
- category_id: '',
- status: ''
- })
- // 获取文章列表
- const loadData = async () => {
- const params = {}
- if (filterForm.category_id) {
- params.category_id = filterForm.category_id
- }
- if (filterForm.status !== '') {
- params.status = filterForm.status
- }
- await getArticleList(params)
- }
- // 获取状态文本
- const getStatusText = (status) => {
- switch (status) {
- case 0: return '草稿'
- case 1: return '已发布'
- case 2: return '已下线'
- default: return '未知'
- }
- }
- // 获取状态类型
- const getStatusType = (status) => {
- switch (status) {
- case 0: return 'info'
- case 1: return 'success'
- case 2: return 'warning'
- default: return 'info'
- }
- }
- // 筛选
- const handleFilter = () => {
- pagination.page = 1
- loadData()
- }
- // 分页大小变化
- const handleSizeChange = (val) => {
- pagination.limit = val
- loadData()
- }
- // 页码变化
- const handleCurrentChange = (val) => {
- pagination.page = val
- loadData()
- }
- // 新增文章
- const handleAddArticle = () => {
- router.push('/news/article/create')
- }
- // 编辑文章
- const handleEdit = (row) => {
- router.push(`/news/article/edit/${row.id}`)
- }
- // 删除文章
- const handleDelete = (row) => {
- ElMessageBox.confirm('确定要删除该文章吗?删除后不可恢复', '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }).then(async () => {
- const success = await deleteArticle(row.id)
- if (success) {
- loadData()
- }
- }).catch(() => {})
- }
- // 时间格式化函数
- const formatDateTime = (dateTimeStr) => {
- if (!dateTimeStr || dateTimeStr === '0001-01-01T00:00:00Z') {
- return '-'
- }
-
- const date = new Date(dateTimeStr)
- // 转换为东八区时间
- const options = {
- year: 'numeric',
- month: '2-digit',
- day: '2-digit',
- hour: '2-digit',
- minute: '2-digit',
- second: '2-digit',
- timeZone: 'Asia/Shanghai'
- }
-
- return date.toLocaleString('zh-CN', options)
- }
- // 初始化
- onMounted(async () => {
- await getCategoryList()
- await loadData()
- })
- return {
- loading,
- articles,
- categories,
- pagination,
- filterForm,
- getStatusText,
- getStatusType,
- formatDateTime,
- handleFilter,
- handleSizeChange,
- handleCurrentChange,
- handleAddArticle,
- handleEdit,
- handleDelete
- }
- }
- })
- </script>
- <style scoped>
- .article-panel {
- padding: 20px 0;
- }
- .article-header {
- margin-bottom: 20px;
- display: flex;
- justify-content: space-between;
- }
- .filter-container {
- width: 380px;
- display: flex;
- gap: 10px;
- }
- .pagination-container {
- margin-top: 20px;
- display: flex;
- justify-content: flex-end;
- }
- </style>
|