feat(usage): 记录并展示失败请求(用户端+管理端)
- 记录失败请求并在用户端/管理端展示;分类下拉改用统一 Select 组件 - 模型过滤改后端 ILIKE 模糊匹配;新增「Key 名称」列(含已删除标记)与按 Key 过滤;时间列移至末列 - 用户可见「已删除 key 失败请求」:OpsErrorLogFilter 加 MatchDeletedKeyOwner,用户侧归属 放宽为 (user_id OR deleted_key_owner_user_id),让 key 原所有者能看到删除 key 后继续请求 导致的认证失败记录(他人仍 NotFound,不泄露存在性) - 迁移 148:ops_error_logs 用户+时间索引 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
QTom
co-authored by
Claude Opus 4.8
parent
ddf063352a
commit
cfb195c7b2
@@ -22,6 +22,18 @@
|
||||
{{ selectedLabel }}
|
||||
</slot>
|
||||
</span>
|
||||
<span
|
||||
v-if="clearable && hasValue && !disabled"
|
||||
class="select-clear"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
aria-label="Clear selection"
|
||||
@click.stop="clearSelection"
|
||||
@mousedown.stop
|
||||
@keydown.enter.stop.prevent="clearSelection"
|
||||
>
|
||||
<Icon name="x" size="sm" />
|
||||
</span>
|
||||
<span class="select-icon">
|
||||
<Icon
|
||||
name="chevronDown"
|
||||
@@ -135,6 +147,7 @@ interface Props {
|
||||
labelKey?: string
|
||||
creatable?: boolean
|
||||
creatablePrefix?: string
|
||||
clearable?: boolean
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
@@ -148,6 +161,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
searchable: 'auto',
|
||||
creatable: false,
|
||||
creatablePrefix: '',
|
||||
clearable: false,
|
||||
valueKey: 'value',
|
||||
labelKey: 'label'
|
||||
})
|
||||
@@ -239,6 +253,10 @@ const selectedLabel = computed(() => {
|
||||
return placeholderText.value
|
||||
})
|
||||
|
||||
const hasValue = computed(
|
||||
() => props.modelValue !== null && props.modelValue !== undefined && props.modelValue !== ''
|
||||
)
|
||||
|
||||
const filteredOptions = computed(() => {
|
||||
let opts = props.options as any[]
|
||||
if (isSearchable.value && searchQuery.value) {
|
||||
@@ -355,6 +373,12 @@ const selectOption = (option: any) => {
|
||||
triggerRef.value?.focus()
|
||||
}
|
||||
|
||||
const clearSelection = () => {
|
||||
if (props.disabled) return
|
||||
emit('update:modelValue', null)
|
||||
emit('change', null, null)
|
||||
}
|
||||
|
||||
// Keyboards
|
||||
const onTriggerKeyDown = () => {
|
||||
if (!isOpen.value) {
|
||||
@@ -461,6 +485,12 @@ onUnmounted(() => {
|
||||
.select-icon {
|
||||
@apply flex-shrink-0 text-gray-400 dark:text-dark-400;
|
||||
}
|
||||
|
||||
.select-clear {
|
||||
@apply flex flex-shrink-0 cursor-pointer items-center justify-center;
|
||||
@apply rounded text-gray-400 transition-colors;
|
||||
@apply hover:text-gray-600 dark:hover:text-gray-200;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user