|
|
@@ -1,6 +1,6 @@
|
|
|
<template>
|
|
|
<div>
|
|
|
- <div class="toolbar">
|
|
|
+ <div class="filter-bar">
|
|
|
<el-select v-model="statusFilter" placeholder="审核状态" @change="loadData">
|
|
|
<el-option label="全部" value="" />
|
|
|
<el-option label="待审核" value="pending" />
|
|
|
@@ -10,7 +10,8 @@
|
|
|
<el-input v-model="keyword" placeholder="搜索标题..." prefix-icon="el-icon-search" clearable @keyup.enter.native="handleSearch" @clear="handleSearch" style="width:200px" />
|
|
|
<el-button size="small" @click="loadData" :loading="loading">刷新</el-button>
|
|
|
</div>
|
|
|
- <el-table :data="list" v-loading="loading" border stripe>
|
|
|
+ <div class="table-scroll-wrap"><div style="overflow:auto;max-height:calc(100vh - 300px);">
|
|
|
+ <el-table :data="list" v-loading="loading" border stripe style="min-width:900px;">
|
|
|
<el-table-column prop="id" label="ID" width="60" />
|
|
|
<el-table-column prop="title" label="标题" min-width="200" show-overflow-tooltip />
|
|
|
<el-table-column label="审核状态" width="100">
|
|
|
@@ -23,65 +24,111 @@
|
|
|
<template slot-scope="{ row }">
|
|
|
<template v-if="row.auditStatus === 'pending'">
|
|
|
<el-button size="mini" type="success" @click="handleAudit(row, 'approved')">通过</el-button>
|
|
|
- <el-button size="mini" type="danger" @click="showReject(row)">拒绝</el-button>
|
|
|
+ <el-button size="mini" type="danger" @click="showRejectDialog(row)">驳回</el-button>
|
|
|
</template>
|
|
|
- <span v-else class="no-op">—</span>
|
|
|
+ <el-button v-else size="mini" type="primary" @click="handleView(row)">查看</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- </el-table>
|
|
|
- <el-dialog title="驳回原因" :visible.sync="rejectDialogVisible" width="400px">
|
|
|
- <el-input v-model="rejectReason" type="textarea" :rows="3" placeholder="请输入驳回原因" />
|
|
|
- <span slot="footer">
|
|
|
- <el-button @click="rejectDialogVisible = false">取消</el-button>
|
|
|
- <el-button type="danger" @click="confirmReject">确认驳回</el-button>
|
|
|
- </span>
|
|
|
- </el-dialog>
|
|
|
+ </el-table></div></div>
|
|
|
+
|
|
|
+ <el-pagination
|
|
|
+ v-if="total > 0"
|
|
|
+ :current-page="page"
|
|
|
+ :page-size="size"
|
|
|
+ :total="total"
|
|
|
+ layout="total, prev, pager, next"
|
|
|
+ @current-change="loadData"
|
|
|
+ style="margin-top:12px;text-align:right;"
|
|
|
+ />
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import { adminArticleList, adminArticleAudit } from '@/api/article'
|
|
|
+import { articleList, articleAudit } from '@/api/article'
|
|
|
|
|
|
export default {
|
|
|
+ name: 'ArticleAudit',
|
|
|
data() {
|
|
|
return {
|
|
|
- list: [], loading: false, keyword: '', statusFilter: 'pending',
|
|
|
- rejectDialogVisible: false, rejectTarget: null, rejectReason: ''
|
|
|
+ list: [],
|
|
|
+ loading: false,
|
|
|
+ keyword: '',
|
|
|
+ statusFilter: '',
|
|
|
+ page: 1,
|
|
|
+ size: 20,
|
|
|
+ total: 0,
|
|
|
+ rejectDialogVisible: false,
|
|
|
+ rejectReason: '',
|
|
|
+ currentRow: null
|
|
|
}
|
|
|
},
|
|
|
- mounted() { this.loadData() },
|
|
|
+ created() {
|
|
|
+ this.loadData()
|
|
|
+ },
|
|
|
methods: {
|
|
|
- statusType(s) { return { pending: 'warning', approved: 'success', rejected: 'danger' }[s] || 'info' },
|
|
|
- statusLabel(s) { return { pending: '待审核', approved: '已通过', rejected: '已拒绝' }[s] || s },
|
|
|
- handleSearch() { this.loadData() },
|
|
|
async loadData() {
|
|
|
this.loading = true
|
|
|
try {
|
|
|
- const res = await adminArticleList({
|
|
|
+ const res = await articleList({
|
|
|
+ page: this.page,
|
|
|
+ size: this.size,
|
|
|
+ status: 'draft',
|
|
|
auditStatus: this.statusFilter || undefined,
|
|
|
- keyword: this.keyword || undefined, page: 1, size: 50
|
|
|
+ keyword: this.keyword || undefined
|
|
|
})
|
|
|
- this.list = res.data && res.data.records || []
|
|
|
- } catch (e) { this.$message.error('加载失败')
|
|
|
- } finally { this.loading = false }
|
|
|
+ if (res.code === 200) {
|
|
|
+ this.list = res.data && res.data.records || res.data && res.data.list || []
|
|
|
+ this.total = (res.data && res.data.total) || 0
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ this.$message.error('加载失败')
|
|
|
+ } finally {
|
|
|
+ this.loading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleSearch() {
|
|
|
+ this.page = 1
|
|
|
+ this.loadData()
|
|
|
+ },
|
|
|
+ async handleAudit(row, action) {
|
|
|
+ try {
|
|
|
+ await this.$confirm(action === 'approved' ? '确认通过审核?' : '确认驳回?', '提示', { type: 'warning' })
|
|
|
+ await articleAudit({ id: row.id, action })
|
|
|
+ this.$message.success(action === 'approved' ? '已通过' : '已驳回')
|
|
|
+ this.loadData()
|
|
|
+ } catch (e) {
|
|
|
+ if (e !== 'cancel') this.$message.error('操作失败')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ showRejectDialog(row) {
|
|
|
+ this.currentRow = row
|
|
|
+ this.rejectReason = ''
|
|
|
+ this.rejectDialogVisible = true
|
|
|
},
|
|
|
- async handleAudit(row, auditStatus) {
|
|
|
+ async confirmReject() {
|
|
|
+ if (!this.rejectReason.trim()) return this.$message.warning('请填写驳回原因')
|
|
|
+ this.rejectDialogVisible = false
|
|
|
try {
|
|
|
- await adminArticleAudit({ id: row.id, auditStatus, auditReason: auditStatus === 'rejected' ? this.rejectReason : '' })
|
|
|
- this.$message.success('审核完成')
|
|
|
- this.rejectDialogVisible = false
|
|
|
+ await articleAudit({ id: this.currentRow.id, action: 'rejected', reason: this.rejectReason })
|
|
|
+ this.$message.success('已驳回')
|
|
|
this.loadData()
|
|
|
- } catch (e) { this.$message.error('操作失败') }
|
|
|
+ } catch (e) {
|
|
|
+ this.$message.error('操作失败')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleView(row) {
|
|
|
+ this.$router.push('/article-edit?id=' + row.id + '&readonly=1')
|
|
|
},
|
|
|
- showReject(row) { this.rejectTarget = row; this.rejectReason = ''; this.rejectDialogVisible = true },
|
|
|
- confirmReject() {
|
|
|
- if (!this.rejectReason) return this.$message.warning('请填写驳回原因')
|
|
|
- this.handleAudit(this.rejectTarget, 'rejected')
|
|
|
+ statusType(s) {
|
|
|
+ return { approved: 'success', pending: 'warning', rejected: 'danger' }[s] || 'info'
|
|
|
+ },
|
|
|
+ statusLabel(s) {
|
|
|
+ return { approved: '已通过', pending: '待审核', rejected: '已驳回' }[s] || s
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
+
|
|
|
<style scoped>
|
|
|
-.toolbar { display: flex; gap: 12px; align-items: center; margin-bottom: 16px; }
|
|
|
-.no-op { color: #ccc; }
|
|
|
-</style>
|
|
|
+.filter-bar { display: flex; gap: 12px; align-items: center; margin-bottom: 12px; padding: 12px; background: #fff; border-radius: 4px; box-shadow: 0 2px 4px rgba(0,0,0,0.08); }
|
|
|
+</style>
|