fix: 管理后台空值修复(users无status字段兜底正常/adminlog时间字段timestamp/知识分类中文/额度列表字段全面修正)+ 弹窗移动端宽度自适应
This commit is contained in:
@@ -14,7 +14,7 @@
|
|||||||
<el-table-column label="维度" width="90">
|
<el-table-column label="维度" width="90">
|
||||||
<template #default="{ row }">{{ DIMS[row.dim - 1] || row.dim }}</template>
|
<template #default="{ row }">{{ DIMS[row.dim - 1] || row.dim }}</template>
|
||||||
</el-table-column>
|
</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">
|
<el-table-column label="检测题" width="80">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag :type="(row.options || []).length ? 'success' : 'info'" size="small">{{ (row.options || []).length ? '有' : '无' }}</el-tag>
|
<el-tag :type="(row.options || []).length ? 'success' : 'info'" size="small">{{ (row.options || []).length ? '有' : '无' }}</el-tag>
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
</el-table>
|
</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-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 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.title" /></el-form-item>
|
||||||
<el-form-item label="维度/分类">
|
<el-form-item label="维度/分类">
|
||||||
|
|||||||
@@ -19,13 +19,13 @@
|
|||||||
<el-table-column prop="userAgent" label="UA" min-width="180" show-overflow-tooltip />
|
<el-table-column prop="userAgent" label="UA" min-width="180" show-overflow-tooltip />
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<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="adminName" label="管理员" width="100" />
|
||||||
<el-table-column prop="action" label="动作" width="90" />
|
<el-table-column prop="action" label="动作" width="90" />
|
||||||
<el-table-column prop="resource" label="对象" width="120" />
|
<el-table-column prop="resource" label="对象" width="120" />
|
||||||
<el-table-column prop="ip" label="IP" width="120" />
|
<el-table-column prop="ip" label="IP" width="120" />
|
||||||
<el-table-column label="详情" min-width="200">
|
<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>
|
</el-table-column>
|
||||||
</template>
|
</template>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -38,6 +38,7 @@ import { ref, onMounted } from 'vue'
|
|||||||
import { apiGet } from '../api'
|
import { apiGet } from '../api'
|
||||||
const tab = ref('login'), list = ref([]), total = ref(0), page = ref(1), pageSize = 20, loading = ref(false)
|
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 }) : '—' }
|
function fmt(t) { return t ? new Date(t).toLocaleString('zh-CN', { hour12: false }) : '—' }
|
||||||
|
// adminlog 的时间字段是 timestamp,loginlog 是 createdAt
|
||||||
async function load() {
|
async function load() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
|
|||||||
+69
-23
@@ -1,36 +1,82 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="page">
|
||||||
<div class="head"><h2>问答额度管理</h2>
|
<div class="toolbar">
|
||||||
<el-button type="primary" @click="addQuota">新增额度</el-button>
|
<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>
|
</div>
|
||||||
<el-table :data="list">
|
<el-table :data="list" stripe v-loading="loading">
|
||||||
<el-table-column prop="user" label="用户" width="160" />
|
<el-table-column label="OpenID" min-width="160">
|
||||||
<el-table-column prop="total" label="总额度" width="90" />
|
<template #default="{ row }">
|
||||||
<el-table-column prop="used" label="已用" width="80" />
|
<span :title="row.openid">{{ openidShort(row.openid) }}</span>
|
||||||
<el-table-column prop="remaining" label="剩余" width="80" />
|
</template>
|
||||||
<el-table-column prop="date" label="日期" width="120" />
|
</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-table>
|
||||||
<el-dialog v-model="dialog" title="增加额度" width="400">
|
<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-form label-width="80">
|
|
||||||
<el-form-item label="用户ID"><el-input v-model="form.userId" /></el-form-item>
|
<el-dialog v-model="addDlg" title="增加问答额度" width="min(380px, 92%)" style="max-width: 380px">
|
||||||
<el-form-item label="增加次数"><el-input-number v-model="form.amount" :min="1" :max="100" /></el-form-item>
|
<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>
|
</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>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, reactive } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { apiGet, apiPost } from '../api'
|
import { apiGet, apiPost } from '../api'
|
||||||
const list = ref([]); const dialog = ref(false)
|
const list = ref([]), total = ref(0), page = ref(1), pageSize = 20, kw = ref(''), loading = ref(false)
|
||||||
const form = reactive({ userId: '', amount: 5 })
|
const addDlg = ref(false), addOpenid = ref(''), addAmount = ref(5)
|
||||||
async function load() { const r = await apiGet('/api/admin/ai-chat/quota-list'); list.value = r.list || r.data || [] }
|
function openidShort(o) { return o && o.length > 18 ? o.slice(0, 16) + '…' : (o || '—') }
|
||||||
function addQuota() { dialog.value = true }
|
function fmt(t) { return t ? new Date(t).toLocaleString('zh-CN', { hour12: false }) : '—' }
|
||||||
async function save() {
|
function remaining(row) {
|
||||||
try { await apiPost('/api/admin/ai-chat/add-quota', { userId: form.userId, amount: form.amount }); ElMessage.success('已增加'); dialog.value = false; load() }
|
const todayUsed = row.lastUsedDate && new Date(row.lastUsedDate).toDateString() === new Date().toDateString() ? row.dailyUsed : 0
|
||||||
catch (e) { ElMessage.error(e.message) }
|
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)
|
onMounted(load)
|
||||||
</script>
|
</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>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
</el-table>
|
</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-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 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.title" /></el-form-item>
|
||||||
<el-form-item label="摘要"><el-input v-model="form.summary" type="textarea" :rows="2" /></el-form-item>
|
<el-form-item label="摘要"><el-input v-model="form.summary" type="textarea" :rows="2" /></el-form-item>
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
<el-table-column label="最近登录" width="160">
|
<el-table-column label="最近登录" width="160">
|
||||||
<template #default="{ row }">{{ fmt(row.lastLoginAt) }}</template>
|
<template #default="{ row }">{{ fmt(row.lastLoginAt) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="status" label="状态" width="80">
|
<el-table-column label="状态" width="80">
|
||||||
<template #default="{ row }"><el-tag :type="row.status === 'active' ? 'success' : 'info'" size="small">{{ row.status }}</el-tag></template>
|
<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>
|
||||||
<el-table-column label="操作" width="110">
|
<el-table-column label="操作" width="110">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</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-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 label-width="90px">
|
||||||
<el-form-item label="用户">{{ quotaUser?.nickName }}</el-form-item>
|
<el-form-item label="用户">{{ quotaUser?.nickName }}</el-form-item>
|
||||||
<el-form-item label="OpenID">{{ (quotaUser?.openid || '').slice(0, 16) }}…</el-form-item>
|
<el-form-item label="OpenID">{{ (quotaUser?.openid || '').slice(0, 16) }}…</el-form-item>
|
||||||
|
|||||||
Reference in New Issue
Block a user