228 lines
8.8 KiB
Vue
228 lines
8.8 KiB
Vue
<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>
|