feat: 管理后台全面升级——修复菜单无数据根因(items字段不匹配+trends接口缺失),新增知识管理(审核/检测题编辑)/访问日志/看板v2(最近访问+点亮分布+全量指标),trends CRUD,用户/反馈列表修正

This commit is contained in:
2026-09-13 17:45:29 +08:00
parent a4da3722ef
commit c5ade459a5
8 changed files with 555 additions and 84 deletions
+29 -16
View File
@@ -1,26 +1,39 @@
<template>
<div>
<div class="head"><h2>反馈管理</h2></div>
<el-table :data="list">
<el-table-column prop="content" label="内容" show-overflow-tooltip />
<el-table-column prop="user" label="用户" width="120" />
<el-table-column label="状态" width="90">
<template #default="{row}"><el-tag :type="row.status==='resolved'?'success':'info'" size="small">{{ row.status==='resolved'?'已处理':'待处理' }}</el-tag></template>
<div class="page">
<el-table :data="list" stripe v-loading="loading">
<el-table-column prop="userName" label="用户" width="110" />
<el-table-column prop="content" label="反馈内容" min-width="260" show-overflow-tooltip />
<el-table-column prop="contact" label="联系方式" width="140" show-overflow-tooltip />
<el-table-column prop="type" label="类型" width="90" />
<el-table-column label="状态" width="80">
<template #default="{ row }"><el-tag :type="row.status === 'resolved' ? 'success' : 'warning'" size="small">{{ row.status === 'resolved' ? '已处理' : '待处理' }}</el-tag></template>
</el-table-column>
<el-table-column prop="createdAt" label="时间" width="160"><template #default="{row}">{{ row.createdAt?.slice(0,10) }}</template></el-table-column>
<el-table-column label="操作" width="100">
<template #default="{row}"><el-button size="small" type="danger" plain @click="del(row)">删除</el-button></template>
<el-table-column label="时间" width="150">
<template #default="{ row }">{{ fmt(row.createdAt) }}</template>
</el-table-column>
</el-table>
<el-pagination background layout="total, prev, pager, next" :total="total" :page-size="pageSize" v-model:current-page="page" @current-change="load" style="margin-top: 12px" />
<p v-if="!loading && !list.length" class="empty">还没有收到反馈</p>
</div>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import { ElMessageBox } from 'element-plus'
import { ref, onMounted } from 'vue'
import { apiGet } from '../api'
const list = ref([])
async function load() { const r = await apiGet('/api/admin/feedback'); list.value = r.feedbacks || r.data || [] }
async function del(row) { await ElMessageBox.confirm('确认删除?'); await apiDelete(`/api/admin/feedback/${row._id}`); load() }
async function apiDelete(url) { await fetch(url, { method: 'DELETE', headers: { Authorization: `Bearer ${localStorage.getItem('dim_admin_token')}` } }) }
const list = ref([]), total = ref(0), page = ref(1), pageSize = 20, loading = ref(false)
function fmt(t) { return t ? new Date(t).toLocaleString('zh-CN', { hour12: false }) : '—' }
async function load() {
loading.value = true
try {
const r = await apiGet(`/api/admin/feedback?page=${page.value}&limit=${pageSize}`)
list.value = r.items || []
total.value = r.pagination?.total || 0
} finally { loading.value = false }
}
onMounted(load)
</script>
<style scoped>
.page { background: #fff; border-radius: 12px; padding: 16px; box-shadow: 0 1px 4px rgba(0,0,0,.06); }
.empty { color: #b6bac9; text-align: center; padding: 24px 0; font-size: 13px; }
</style>