fix: 管理后台空值修复(users无status字段兜底正常/adminlog时间字段timestamp/知识分类中文/额度列表字段全面修正)+ 弹窗移动端宽度自适应

This commit is contained in:
2026-09-13 18:17:43 +08:00
parent 6a3c048072
commit d221a45a5e
5 changed files with 78 additions and 31 deletions
+2 -2
View File
@@ -14,7 +14,7 @@
<el-table-column label="维度" width="90">
<template #default="{ row }">{{ DIMS[row.dim - 1] || row.dim }}</template>
</el-table-column>
<el-table-column prop="category" label="分类" width="90" />
<el-table-column label="分类" width="90"><template #default="{ row }">{{ CATS[row.category] || row.category || '—' }}</template></el-table-column>
<el-table-column label="检测题" width="80">
<template #default="{ row }">
<el-tag :type="(row.options || []).length ? 'success' : 'info'" size="small">{{ (row.options || []).length ? '有' : '无' }}</el-tag>
@@ -36,7 +36,7 @@
</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" />
<el-dialog v-model="dlg" :title="form._id ? '编辑知识' : '新增知识'" width="640px" top="4vh">
<el-dialog v-model="dlg" :title="form._id ? '编辑知识' : '新增知识'" width="min(640px, 94%)" top="4vh">
<el-form label-width="76px">
<el-form-item label="标题"><el-input v-model="form.title" /></el-form-item>
<el-form-item label="维度/分类">
+3 -2
View File
@@ -19,13 +19,13 @@
<el-table-column prop="userAgent" label="UA" min-width="180" show-overflow-tooltip />
</template>
<template v-else>
<el-table-column label="时间" width="160"><template #default="{ row }">{{ fmt(row.createdAt) }}</template></el-table-column>
<el-table-column label="时间" width="160"><template #default="{ row }">{{ fmt(row.timestamp || row.createdAt) }}</template></el-table-column>
<el-table-column prop="adminName" label="管理员" width="100" />
<el-table-column prop="action" label="动作" width="90" />
<el-table-column prop="resource" label="对象" width="120" />
<el-table-column prop="ip" label="IP" width="120" />
<el-table-column label="详情" min-width="200">
<template #default="{ row }">{{ JSON.stringify(row.details || row.meta || {}).slice(0, 100) }}</template>
<template #default="{ row }">{{ row.details ? JSON.stringify(row.details).slice(0, 100) : '—' }}</template>
</el-table-column>
</template>
</el-table>
@@ -38,6 +38,7 @@ import { ref, onMounted } from 'vue'
import { apiGet } from '../api'
const tab = ref('login'), 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 }) : '—' }
// adminlog 的时间字段是 timestamp,loginlog 是 createdAt
async function load() {
loading.value = true
try {
+69 -23
View File
@@ -1,36 +1,82 @@
<template>
<div>
<div class="head"><h2>问答额度管理</h2>
<el-button type="primary" @click="addQuota">新增额度</el-button>
<div class="page">
<div class="toolbar">
<el-input v-model="kw" placeholder="搜索 openid" style="width: 220px" clearable @keyup.enter="search" />
<el-button type="primary" @click="search">搜索</el-button>
<el-button type="success" @click="addDlg = true">增加额度</el-button>
</div>
<el-table :data="list">
<el-table-column prop="user" label="用户" width="160" />
<el-table-column prop="total" label="总额度" width="90" />
<el-table-column prop="used" label="已用" width="80" />
<el-table-column prop="remaining" label="剩余" width="80" />
<el-table-column prop="date" label="日期" width="120" />
<el-table :data="list" stripe v-loading="loading">
<el-table-column label="OpenID" min-width="160">
<template #default="{ row }">
<span :title="row.openid">{{ openidShort(row.openid) }}</span>
</template>
</el-table-column>
<el-table-column label="类型" width="90">
<template #default="{ row }">{{ row.openid.startsWith('guest:') ? '游客' : '注册用户' }}</template>
</el-table-column>
<el-table-column prop="freeQuota" label="免费额度" width="90" />
<el-table-column prop="sharedQuota" label="分享获得" width="90" />
<el-table-column prop="usedQuota" label="累计使用" width="90" />
<el-table-column prop="dailyUsed" label="今日已用" width="90" />
<el-table-column label="剩余可用" width="90">
<template #default="{ row }">
<el-tag size="small" :type="remaining(row) > 0 ? 'success' : 'danger'">{{ remaining(row) }}</el-tag>
</template>
</el-table-column>
<el-table-column label="最后使用" width="150">
<template #default="{ row }">{{ fmt(row.lastUsedDate) }}</template>
</el-table-column>
</el-table>
<el-dialog v-model="dialog" title="增加额度" width="400">
<el-form label-width="80">
<el-form-item label="用户ID"><el-input v-model="form.userId" /></el-form-item>
<el-form-item label="增加次数"><el-input-number v-model="form.amount" :min="1" :max="100" /></el-form-item>
<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" />
<el-dialog v-model="addDlg" title="增加问答额度" width="min(380px, 92%)" style="max-width: 380px">
<el-form label-width="90px">
<el-form-item label="OpenID"><el-input v-model="addOpenid" placeholder="完整 openid" /></el-form-item>
<el-form-item label="增加次数"><el-input-number v-model="addAmount" :min="1" :max="100" /></el-form-item>
</el-form>
<template #footer><el-button @click="dialog=false">取消</el-button><el-button type="primary" @click="save">确认</el-button></template>
<template #footer>
<el-button @click="addDlg = false">取消</el-button>
<el-button type="primary" @click="add">确认</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { onMounted, ref, reactive } from 'vue'
import { ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { apiGet, apiPost } from '../api'
const list = ref([]); const dialog = ref(false)
const form = reactive({ userId: '', amount: 5 })
async function load() { const r = await apiGet('/api/admin/ai-chat/quota-list'); list.value = r.list || r.data || [] }
function addQuota() { dialog.value = true }
async function save() {
try { await apiPost('/api/admin/ai-chat/add-quota', { userId: form.userId, amount: form.amount }); ElMessage.success('已增加'); dialog.value = false; load() }
catch (e) { ElMessage.error(e.message) }
const list = ref([]), total = ref(0), page = ref(1), pageSize = 20, kw = ref(''), loading = ref(false)
const addDlg = ref(false), addOpenid = ref(''), addAmount = ref(5)
function openidShort(o) { return o && o.length > 18 ? o.slice(0, 16) + '…' : (o || '—') }
function fmt(t) { return t ? new Date(t).toLocaleString('zh-CN', { hour12: false }) : '—' }
function remaining(row) {
const todayUsed = row.lastUsedDate && new Date(row.lastUsedDate).toDateString() === new Date().toDateString() ? row.dailyUsed : 0
return Math.max(0, (row.freeQuota || 0) + (row.sharedQuota || 0) - todayUsed)
}
function search() { page.value = 1; load() }
async function load() {
loading.value = true
try {
const r = await apiGet(`/api/admin/ai-chat/quota-list?page=${page.value}&pageSize=${pageSize}&keyword=${encodeURIComponent(kw.value)}`)
list.value = r.list || []
total.value = r.total || 0
} finally { loading.value = false }
}
async function add() {
if (!addOpenid.value.trim()) return ElMessage.warning('请输入 openid')
try {
await apiPost('/api/admin/ai-chat/add-quota', { openid: addOpenid.value.trim(), amount: addAmount.value })
ElMessage.success('已增加')
addDlg.value = false
addOpenid.value = ''
load()
} catch (e) { ElMessage.error(e.message || '操作失败') }
}
onMounted(load)
</script>
<style scoped>.head{display:flex;justify-content:space-between;align-items:center}</style>
<style scoped>
.page { background: #fff; border-radius: 12px; padding: 16px; box-shadow: 0 1px 4px rgba(0,0,0,.06); }
.toolbar { display: flex; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; }
</style>
+1 -1
View File
@@ -27,7 +27,7 @@
</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" />
<el-dialog v-model="dlg" :title="form._id ? '编辑资讯' : '新增资讯'" width="560px">
<el-dialog v-model="dlg" :title="form._id ? '编辑资讯' : '新增资讯'" width="min(560px, 94%)" style="max-width: 560px">
<el-form label-width="76px">
<el-form-item label="标题"><el-input v-model="form.title" /></el-form-item>
<el-form-item label="摘要"><el-input v-model="form.summary" type="textarea" :rows="2" /></el-form-item>
+3 -3
View File
@@ -15,8 +15,8 @@
<el-table-column label="最近登录" width="160">
<template #default="{ row }">{{ fmt(row.lastLoginAt) }}</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="80">
<template #default="{ row }"><el-tag :type="row.status === 'active' ? 'success' : 'info'" size="small">{{ row.status }}</el-tag></template>
<el-table-column label="状态" width="80">
<template #default="{ row }"><el-tag :type="(row.status || 'active') === 'active' ? 'success' : 'info'" size="small">{{ (row.status || 'active') === 'active' ? '正常' : row.status }}</el-tag></template>
</el-table-column>
<el-table-column label="操作" width="110">
<template #default="{ row }">
@@ -25,7 +25,7 @@
</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" />
<el-dialog v-model="quotaDlg" title="增加问答额度" width="360px">
<el-dialog v-model="quotaDlg" title="增加问答额度" width="min(360px, 92%)" style="max-width: 360px">
<el-form label-width="90px">
<el-form-item label="用户">{{ quotaUser?.nickName }}</el-form-item>
<el-form-item label="OpenID">{{ (quotaUser?.openid || '').slice(0, 16) }}…</el-form-item>