Files
zyt/admin/src/views/setting/prescription_ai_visibility/index.vue
T
2026-10-17 16:51:48 +08:00

228 lines
8.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="prescription-ai-visibility">
<el-card v-loading="loading" shadow="never" class="!border-none">
<div class="text-xl font-medium mb-[20px]">处方 AI 一致度可见范围</div>
<el-alert type="info" :closable="false" show-icon class="mb-5">
<template #title>指定用户组或用户可查看一致度</template>
<div class="leading-6">
用户命中任一指定系统角色,或被单独指定,即可查看桌面端“与 AI
一致度”、逐味对照和一致度统计。AI
报告继续按原有权限开放,已有报告不受影响,患者与处方的数据范围保持原有规则。
</div>
</el-alert>
<el-alert
v-if="loadError"
:title="loadError"
type="error"
:closable="false"
show-icon
class="mb-5"
/>
<div v-if="loading" role="status" class="mb-5">正在读取当前可见范围…</div>
<el-form
v-if="hasLoaded"
class="ls-form"
:model="formData"
:disabled="!ready || loading || saving"
label-width="140px"
>
<el-form-item label="指定用户组" prop="role_ids">
<div class="w-full max-w-[640px]">
<el-select
v-model="formData.role_ids"
class="w-full"
multiple
filterable
clearable
placeholder="请选择系统角色,可搜索角色名称"
>
<el-option
v-for="role in roleOptions"
:key="role.id"
:label="role.name"
:value="role.id"
/>
</el-select>
<div class="form-tips">账号拥有任一指定角色即可命中。</div>
</div>
</el-form-item>
<el-form-item label="指定用户" prop="admin_ids">
<div class="w-full max-w-[640px]">
<el-select
v-model="formData.admin_ids"
class="w-full"
multiple
filterable
clearable
placeholder="请选择用户,可搜索姓名或账号"
>
<el-option
v-for="admin in adminOptions"
:key="admin.id"
:label="admin.label"
:value="admin.id"
/>
</el-select>
<div class="form-tips">
单独指定的用户无需同时命中用户组。当前不在可选列表中的已配置 ID
会保留,移除后保存才会取消该项授权。
</div>
</div>
</el-form-item>
<el-form-item label="生效规则">
<div>
<div class="leading-6">指定用户组与指定用户按“或”生效。</div>
<div class="form-tips">
两项均为空时,所有账号(包括超级管理员)均隐藏一致度、对照与统计。
拥有本页管理权限不自动获得一致度查看权,超级管理员也需命中上述名单。
</div>
</div>
</el-form-item>
</el-form>
<el-alert
v-if="ready && !formData.role_ids.length && !formData.admin_ids.length"
title="当前选择为空:保存后所有账号将隐藏一致度、对照与统计,AI 报告仍保留。"
type="warning"
:closable="false"
show-icon
class="mb-5"
/>
<el-alert
v-if="saveError"
:title="saveError"
type="error"
:closable="false"
show-icon
class="mb-5"
/>
<el-button :disabled="loading || saving" @click="loadConfig">
{{ loadError ? '重试加载' : '重新加载' }}
</el-button>
</el-card>
<footer-btns v-if="canManage">
<el-button
type="primary"
:loading="saving"
:disabled="!ready || loading || saving"
@click="handleSubmit"
>
{{ saving ? '正在保存' : '保存' }}
</el-button>
</footer-btns>
</div>
</template>
<script setup lang="ts" name="prescriptionAiVisibility">
import { computed, reactive, ref } from 'vue'
import type {
PrescriptionAiVisibilityConfig,
PrescriptionAiVisibilityOptions
} from '@/api/setting/prescription_ai_visibility'
import {
getPrescriptionAiCapabilities,
getPrescriptionAiVisibilityConfig,
getPrescriptionAiVisibilityOptions,
setPrescriptionAiVisibilityConfig
} from '@/api/setting/prescription_ai_visibility'
import feedback from '@/utils/feedback'
const loading = ref(false)
const saving = ref(false)
const ready = ref(false)
const hasLoaded = ref(false)
const canManage = ref(false)
const loadError = ref('')
const saveError = ref('')
const formData = reactive<PrescriptionAiVisibilityConfig>({ role_ids: [], admin_ids: [] })
const optionsData = reactive<PrescriptionAiVisibilityOptions>({ roles: [], admins: [] })
const roleOptions = computed(() => {
const options = new Map(optionsData.roles.map((role) => [role.id, role]))
for (const id of formData.role_ids) {
if (!options.has(id)) {
options.set(id, { id, name: `已配置角色 #${id}(当前不在可选列表)` })
}
}
return [...options.values()]
})
const adminOptions = computed(() => {
const options = new Map(
optionsData.admins.map((admin) => [
admin.id,
{ id: admin.id, label: `${admin.name || `用户 #${admin.id}`}(${admin.account})` }
])
)
for (const id of formData.admin_ids) {
if (!options.has(id)) {
options.set(id, { id, label: `已配置用户 #${id}(当前不在可选列表)` })
}
}
return [...options.values()]
})
const assignConfig = (config: PrescriptionAiVisibilityConfig) => {
formData.role_ids = [...config.role_ids]
formData.admin_ids = [...config.admin_ids]
}
const loadConfig = async () => {
if (loading.value || saving.value) return
loading.value = true
ready.value = false
canManage.value = false
loadError.value = ''
saveError.value = ''
try {
const capabilities = await getPrescriptionAiCapabilities()
if (capabilities.can_manage_visibility !== true) {
loadError.value = '当前账号无权管理处方 AI 一致度可见范围。'
return
}
canManage.value = true
const [config, options] = await Promise.all([
getPrescriptionAiVisibilityConfig(),
getPrescriptionAiVisibilityOptions()
])
if (!Array.isArray(options?.roles) || !Array.isArray(options?.admins)) {
throw new Error('可选用户组或用户响应格式不正确')
}
// Apply both responses together; an incomplete load cannot overwrite the current policy.
assignConfig(config)
optionsData.roles = options.roles
optionsData.admins = options.admins
hasLoaded.value = true
ready.value = true
} catch {
loadError.value = '可见范围加载失败,尚未读取完整配置。请重试加载后再保存。'
} finally {
loading.value = false
}
}
const handleSubmit = async () => {
if (!ready.value || !canManage.value || loading.value || saving.value) return
saving.value = true
saveError.value = ''
try {
const config = await setPrescriptionAiVisibilityConfig({
role_ids: [...formData.role_ids],
admin_ids: [...formData.admin_ids]
})
assignConfig(config)
feedback.msgSuccess('可见范围已保存')
} catch {
saveError.value = '保存结果未确认,当前选择已保留。请重试保存,或重新加载以确认服务端策略。'
} finally {
saving.value = false
}
}
void loadConfig()
</script>