fix(前端): 兼容非安全上下文的任务请求键生成

crypto.randomUUID 仅在 HTTPS 或 localhost 下存在,客户内网
以 http://<内网IP> 访问时该 API 为 undefined,而新建任务
对话框在页面挂载即调用,会直接 TypeError 导致整页白屏。

新增 newRequestKey 工具:优先 randomUUID,不可用时降级为
getRandomValues 拼 v4 格式(非安全上下文仍可用)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
liuwenxin 2026-10-30 09:56:41 +08:00
parent ee801652e3
commit 37eb51513f
2 changed files with 15 additions and 3 deletions

View File

@ -0,0 +1,11 @@
// crypto.randomUUID 仅在安全上下文(HTTPS 或 localhost)存在;客户内网常以
// http://<内网IP> 访问,此时该 API 为 undefined。降级用 getRandomValues 拼
// v4 格式(getRandomValues 在非安全上下文仍然可用)。
export function newRequestKey(): string {
if (typeof crypto.randomUUID === 'function') return crypto.randomUUID()
const bytes = crypto.getRandomValues(new Uint8Array(16))
bytes[6] = (bytes[6] & 0x0f) | 0x40 // version 4
bytes[8] = (bytes[8] & 0x3f) | 0x80 // variant 10x
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0'))
return `${hex.slice(0, 4).join('')}-${hex.slice(4, 6).join('')}-${hex.slice(6, 8).join('')}-${hex.slice(8, 10).join('')}-${hex.slice(10, 16).join('')}`
}

View File

@ -3,6 +3,7 @@ import { ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import * as api from '@/api/tplus'
import { handledError } from '@/utils/error'
import { newRequestKey } from '@/utils/uuid'
import { entities } from './labels'
const visible = defineModel<boolean>({ required: true })
@ -11,9 +12,9 @@ const emit = defineEmits<{ created: [batch: api.TPlusDetail] }>()
const taskType = ref<api.TaskType>('READ')
const selected = ref<api.EntityType[]>(['personnel'])
const pending = ref(false)
let requestKey = crypto.randomUUID()
let requestKey = newRequestKey()
// 请求失败后保留键,只有意图改变或成功后才换键。
watch([taskType, selected], () => { requestKey = crypto.randomUUID() }, { deep: true, flush: 'sync' })
watch([taskType, selected], () => { requestKey = newRequestKey() }, { deep: true, flush: 'sync' })
async function submit(): Promise<void> {
if (pending.value || !props.configured) return
@ -21,7 +22,7 @@ async function submit(): Promise<void> {
try {
const batch = await api.createTask({ task_type: taskType.value,
entity_types: taskType.value === 'AUDIT' ? [] : [...selected.value], request_key: requestKey })
requestKey = crypto.randomUUID()
requestKey = newRequestKey()
visible.value = false
ElMessage.success('任务已排队,处理完成后可刷新查看')
emit('created', batch)