feat: 管理后台全面升级——修复菜单无数据根因(items字段不匹配+trends接口缺失),新增知识管理(审核/检测题编辑)/访问日志/看板v2(最近访问+点亮分布+全量指标),trends CRUD,用户/反馈列表修正
This commit is contained in:
+65
-14
@@ -1,23 +1,74 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="head"><h2>用户管理</h2><el-input v-model="q" placeholder="搜索昵称" style="width:200px" clearable @change="page=1;load()" /></div>
|
||||
<el-table :data="list">
|
||||
<el-table-column prop="nickname" label="昵称" width="140" />
|
||||
<el-table-column label="手机号" width="130"><template #default="{row}">{{ row.phone || '-' }}</template></el-table-column>
|
||||
<el-table-column label="注册时间" width="160"><template #default="{row}">{{ row.createdAt?.slice(0,10) }}</template></el-table-column>
|
||||
<el-table-column label="操作"><template #default="{row}"><el-tag size="small">{{ row._id?.slice(-6) }}</el-tag></template></el-table-column>
|
||||
<div class="page">
|
||||
<div class="toolbar">
|
||||
<el-input v-model="q" placeholder="搜索昵称" style="width: 220px" clearable @keyup.enter="search" />
|
||||
<el-button type="primary" @click="search">搜索</el-button>
|
||||
</div>
|
||||
<el-table :data="list" stripe v-loading="loading">
|
||||
<el-table-column prop="nickName" label="昵称" min-width="110" />
|
||||
<el-table-column label="OpenID" min-width="150">
|
||||
<template #default="{ row }">{{ (row.openid || '').slice(0, 14) }}…</template>
|
||||
</el-table-column>
|
||||
<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.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>
|
||||
<el-table-column label="操作" width="110">
|
||||
<template #default="{ row }">
|
||||
<el-button size="small" @click="openQuota(row)">加问答额度</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination v-model:current-page="page" layout="prev,pager,next,total" :total="total" :page-size="20" style="margin-top:14px" @current-change="load" />
|
||||
<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-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>
|
||||
<el-form-item label="增加次数">
|
||||
<el-input-number v-model="quotaAmount" :min="1" :max="100" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="quotaDlg = false">取消</el-button>
|
||||
<el-button type="primary" @click="addQuota">确认</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { apiGet } from '../api'
|
||||
const list = ref([]); const total = ref(0); const page = ref(1); const q = ref('')
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { apiGet, apiPost } from '../api'
|
||||
const list = ref([]), total = ref(0), page = ref(1), pageSize = 20, q = ref(''), loading = ref(false)
|
||||
const quotaDlg = ref(false), quotaUser = ref(null), quotaAmount = ref(5)
|
||||
function fmt(t) { return t ? new Date(t).toLocaleString('zh-CN', { hour12: false }) : '—' }
|
||||
function search() { page.value = 1; load() }
|
||||
async function load() {
|
||||
const r = await apiGet(`/api/admin/users?q=${q.value}&page=${page.value}`)
|
||||
list.value = r.users || []; total.value = r.total || 0
|
||||
loading.value = true
|
||||
try {
|
||||
const r = await apiGet(`/api/admin/users?page=${page.value}&limit=${pageSize}&search=${encodeURIComponent(q.value)}`)
|
||||
list.value = r.items || []
|
||||
total.value = r.pagination?.total || 0
|
||||
} finally { loading.value = false }
|
||||
}
|
||||
function openQuota(row) { quotaUser.value = row; quotaAmount.value = 5; quotaDlg.value = true }
|
||||
async function addQuota() {
|
||||
try {
|
||||
await apiPost('/api/admin/ai-chat/add-quota', { openid: quotaUser.value.openid, amount: quotaAmount.value })
|
||||
ElMessage.success('已增加')
|
||||
quotaDlg.value = false
|
||||
} 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; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user