feat: add admin permissions voice input analytics and feedback
This commit is contained in:
@@ -49,10 +49,26 @@ const SsoIntegrationView = defineAsyncComponent(
|
||||
const SystemConfigView = defineAsyncComponent(
|
||||
() => import("./components/SystemConfigView.vue"),
|
||||
);
|
||||
const AdminManagementView = defineAsyncComponent(
|
||||
() => import("./components/AdminManagementView.vue"),
|
||||
);
|
||||
const FeedbackManagementView = defineAsyncComponent(() => import("./components/FeedbackManagementView.vue"));
|
||||
|
||||
const admin = ref<AdminProfile | null>(null);
|
||||
const activeMenu = ref("dashboard");
|
||||
const loading = ref(false);
|
||||
const passwordDialogVisible = ref(false);
|
||||
const passwordSaving = ref(false);
|
||||
const passwordForm = reactive({ currentPassword: "", newPassword: "", confirmPassword: "" });
|
||||
|
||||
const can = (permission: string) => Boolean(admin.value?.isSuperAdmin || admin.value?.permissions.includes(permission));
|
||||
const menuPermissions: Record<string, string> = {
|
||||
dashboard: "dashboard.view", users: "users.view", entitlements: "entitlements.view",
|
||||
knowledge: "knowledge.view", prompt: "prompt.view", models: "models.view",
|
||||
"content-generation": "content-generation.view", configs: "configs.view", sso: "sso.view",
|
||||
records: "records.view", retrievals: "retrievals.view", attention: "attention.view", admins: "admins.view",
|
||||
feedback: "feedback.view",
|
||||
};
|
||||
|
||||
const entitlementPlans = ref<EntitlementPlan[]>([]);
|
||||
const models = ref<ModelItem[]>([]);
|
||||
@@ -190,7 +206,8 @@ onMounted(async () => {
|
||||
if (!getToken()) return;
|
||||
try {
|
||||
admin.value = await api.profile();
|
||||
await loadCurrentMenu();
|
||||
passwordDialogVisible.value = admin.value.mustChangePassword;
|
||||
if (!admin.value.mustChangePassword) await enterFirstAvailableMenu();
|
||||
} catch {
|
||||
clearToken();
|
||||
}
|
||||
@@ -202,7 +219,8 @@ async function login(credentials: { username: string; password: string }) {
|
||||
const result = await api.login(credentials.username, credentials.password);
|
||||
saveToken(result.token);
|
||||
admin.value = result.admin;
|
||||
await loadCurrentMenu();
|
||||
passwordDialogVisible.value = result.admin.mustChangePassword;
|
||||
if (!result.admin.mustChangePassword) await enterFirstAvailableMenu();
|
||||
} catch (error) {
|
||||
ElMessage.error(error instanceof Error ? error.message : "登录失败");
|
||||
} finally {
|
||||
@@ -220,10 +238,32 @@ async function logout() {
|
||||
}
|
||||
|
||||
async function switchMenu(menu: string) {
|
||||
if (!can(menuPermissions[menu])) return;
|
||||
activeMenu.value = menu;
|
||||
await loadCurrentMenu();
|
||||
}
|
||||
|
||||
async function enterFirstAvailableMenu() {
|
||||
const first = Object.keys(menuPermissions).find((menu) => can(menuPermissions[menu]));
|
||||
activeMenu.value = first ?? "dashboard";
|
||||
if (first) await loadCurrentMenu();
|
||||
}
|
||||
|
||||
async function changeInitialPassword() {
|
||||
if (passwordForm.newPassword.length < 8) return ElMessage.warning("新密码至少 8 位");
|
||||
if (passwordForm.newPassword !== passwordForm.confirmPassword) return ElMessage.warning("两次输入的新密码不一致");
|
||||
passwordSaving.value = true;
|
||||
try {
|
||||
await api.changeAdminPassword({ currentPassword: passwordForm.currentPassword, newPassword: passwordForm.newPassword });
|
||||
if (admin.value) admin.value.mustChangePassword = false;
|
||||
passwordDialogVisible.value = false;
|
||||
Object.assign(passwordForm, { currentPassword: "", newPassword: "", confirmPassword: "" });
|
||||
ElMessage.success("密码已修改,请使用新密码登录");
|
||||
await logout();
|
||||
} catch (error) { ElMessage.error(error instanceof Error ? error.message : "密码修改失败"); }
|
||||
finally { passwordSaving.value = false; }
|
||||
}
|
||||
|
||||
async function previewKnowledge(knowledgeId: number) {
|
||||
previewKnowledgeId.value = knowledgeId;
|
||||
await switchMenu("prompt");
|
||||
@@ -596,77 +636,99 @@ async function clearFeishuCache() {
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-title">大本营千问千答</div>
|
||||
<button
|
||||
v-if="can('dashboard.view')"
|
||||
:class="{ active: activeMenu === 'dashboard' }"
|
||||
@click="switchMenu('dashboard')"
|
||||
>
|
||||
数据看板
|
||||
</button>
|
||||
<button
|
||||
v-if="can('users.view')"
|
||||
:class="{ active: activeMenu === 'users' }"
|
||||
@click="switchMenu('users')"
|
||||
>
|
||||
用户管理
|
||||
</button>
|
||||
<button
|
||||
v-if="can('entitlements.view')"
|
||||
:class="{ active: activeMenu === 'entitlements' }"
|
||||
@click="switchMenu('entitlements')"
|
||||
>
|
||||
权益管理
|
||||
</button>
|
||||
<button
|
||||
v-if="can('knowledge.view')"
|
||||
:class="{ active: activeMenu === 'knowledge' }"
|
||||
@click="switchMenu('knowledge')"
|
||||
>
|
||||
知识库管理
|
||||
</button>
|
||||
<button
|
||||
v-if="can('prompt.view')"
|
||||
:class="{ active: activeMenu === 'prompt' }"
|
||||
@click="switchMenu('prompt')"
|
||||
>
|
||||
Agent 管理
|
||||
</button>
|
||||
<button
|
||||
v-if="can('models.view')"
|
||||
:class="{ active: activeMenu === 'models' }"
|
||||
@click="switchMenu('models')"
|
||||
>
|
||||
模型管理
|
||||
</button>
|
||||
<button
|
||||
v-if="can('content-generation.view')"
|
||||
:class="{ active: activeMenu === 'content-generation' }"
|
||||
@click="switchMenu('content-generation')"
|
||||
>
|
||||
内容生成
|
||||
</button>
|
||||
<button
|
||||
v-if="can('configs.view')"
|
||||
:class="{ active: activeMenu === 'configs' }"
|
||||
@click="switchMenu('configs')"
|
||||
>
|
||||
系统配置
|
||||
</button>
|
||||
<button
|
||||
v-if="can('sso.view')"
|
||||
:class="{ active: activeMenu === 'sso' }"
|
||||
@click="switchMenu('sso')"
|
||||
>
|
||||
应用接入
|
||||
</button>
|
||||
<button
|
||||
v-if="can('records.view')"
|
||||
:class="{ active: activeMenu === 'records' }"
|
||||
@click="switchMenu('records')"
|
||||
>
|
||||
记录审计
|
||||
</button>
|
||||
<button
|
||||
v-if="can('retrievals.view')"
|
||||
:class="{ active: activeMenu === 'retrievals' }"
|
||||
@click="switchMenu('retrievals')"
|
||||
>
|
||||
检索日志
|
||||
</button>
|
||||
<button
|
||||
v-if="can('feedback.view')"
|
||||
:class="{ active: activeMenu === 'feedback' }"
|
||||
@click="switchMenu('feedback')"
|
||||
>反馈管理</button>
|
||||
<button
|
||||
v-if="can('attention.view')"
|
||||
:class="{ active: activeMenu === 'attention' }"
|
||||
@click="switchMenu('attention')"
|
||||
>
|
||||
人工关注
|
||||
</button>
|
||||
<button
|
||||
v-if="admin.isSuperAdmin"
|
||||
:class="{ active: activeMenu === 'admins' }"
|
||||
@click="switchMenu('admins')"
|
||||
>管理员与权限</button>
|
||||
</aside>
|
||||
|
||||
<section class="workspace">
|
||||
@@ -1057,8 +1119,20 @@ async function clearFeishuCache() {
|
||||
|
||||
<RetrievalLogView v-if="activeMenu === 'retrievals'" />
|
||||
<AttentionManagementView v-if="activeMenu === 'attention'" />
|
||||
<FeedbackManagementView v-if="activeMenu === 'feedback'" :can-delete="can('feedback.delete')" />
|
||||
<RecordAuditView v-if="activeMenu === 'records'" />
|
||||
<AdminManagementView v-if="activeMenu === 'admins'" />
|
||||
</section>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<el-dialog v-model="passwordDialogVisible" title="首次登录,请修改初始密码" width="460px" :close-on-click-modal="false" :close-on-press-escape="false" :show-close="false">
|
||||
<el-alert title="为保障账号安全,修改密码后需要重新登录。" type="warning" :closable="false" show-icon />
|
||||
<el-form label-position="top" class="password-form">
|
||||
<el-form-item label="当前初始密码"><el-input v-model="passwordForm.currentPassword" type="password" show-password /></el-form-item>
|
||||
<el-form-item label="新密码"><el-input v-model="passwordForm.newPassword" type="password" show-password placeholder="至少 8 位" /></el-form-item>
|
||||
<el-form-item label="确认新密码"><el-input v-model="passwordForm.confirmPassword" type="password" show-password /></el-form-item>
|
||||
</el-form>
|
||||
<template #footer><el-button @click="logout">退出登录</el-button><el-button type="primary" :loading="passwordSaving" @click="changeInitialPassword">确认修改</el-button></template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user