Merge branch 'fawney19:main' into main

This commit is contained in:
ZheFox
2026-05-18 13:13:37 +08:00
committed by GitHub
12 changed files with 321 additions and 286 deletions

View File

@@ -58,6 +58,11 @@ ADMIN_USERNAME=admin
# AETHER_GATEWAY_AUTO_PREPARE_DATABASE=true # AETHER_GATEWAY_AUTO_PREPARE_DATABASE=true
# PostgreSQL 连接池配置(默认适合单实例/小型部署;高并发可按需调大) # PostgreSQL 连接池配置(默认适合单实例/小型部署;高并发可按需调大)
# 推荐计算方式(单实例):
# MAX = CPU 核数 × 10AI 网关偏 IO 等待,可激进些;纯 OLTP 用 × 4
# MIN = MAX × 0.2(保留常驻连接应对突发流量,避免冷启动握手开销)
# 多实例部署时请按 实例数 × MAX 控制总和PG 端 max_connections 至少为该总和 + 20 余量
# AETHER_GATEWAY_DATA_POSTGRES_MIN_CONNECTIONS=1 # AETHER_GATEWAY_DATA_POSTGRES_MIN_CONNECTIONS=1
# AETHER_GATEWAY_DATA_POSTGRES_MAX_CONNECTIONS=20 # AETHER_GATEWAY_DATA_POSTGRES_MAX_CONNECTIONS=20
# AETHER_GATEWAY_DATA_POSTGRES_IDLE_TIMEOUT_MS=30000 # AETHER_GATEWAY_DATA_POSTGRES_STATEMENT_CACHE_CAPACITY=100
# AETHER_GATEWAY_DATA_POSTGRES_ACQUIRE_TIMEOUT_MS=3000

View File

@@ -2,10 +2,6 @@
import { PopoverTrigger } from 'radix-vue' import { PopoverTrigger } from 'radix-vue'
import { useAttrs } from 'vue' import { useAttrs } from 'vue'
defineOptions({
inheritAttrs: false,
})
withDefaults(defineProps<{ withDefaults(defineProps<{
asChild?: boolean asChild?: boolean
as?: string as?: string
@@ -14,6 +10,10 @@ withDefaults(defineProps<{
as: 'button', as: 'button',
}) })
defineOptions({
inheritAttrs: false,
})
const attrs = useAttrs() const attrs = useAttrs()
</script> </script>

View File

@@ -211,7 +211,6 @@
两次输入的密码不一致 两次输入的密码不一致
</p> </p>
</div> </div>
</form> </form>
<!-- 登录链接 --> <!-- 登录链接 -->

View File

@@ -17,6 +17,22 @@
<script setup lang="ts"> <script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue' import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
const props = withDefaults(defineProps<{
modelValue?: string
siteKey: string
action?: string
disabled?: boolean
}>(), {
modelValue: '',
action: undefined,
disabled: false,
})
const emit = defineEmits<{
'update:modelValue': [value: string]
error: [message: string]
}>()
const TURNSTILE_SCRIPT_URL = 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit' const TURNSTILE_SCRIPT_URL = 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit'
type TurnstileWidgetId = string type TurnstileWidgetId = string
@@ -46,22 +62,6 @@ declare global {
} }
} }
const props = withDefaults(defineProps<{
modelValue?: string
siteKey: string
action?: string
disabled?: boolean
}>(), {
modelValue: '',
action: undefined,
disabled: false,
})
const emit = defineEmits<{
'update:modelValue': [value: string]
error: [message: string]
}>()
const containerRef = ref<HTMLElement | null>(null) const containerRef = ref<HTMLElement | null>(null)
const widgetId = ref<TurnstileWidgetId | null>(null) const widgetId = ref<TurnstileWidgetId | null>(null)
const errorMessage = ref('') const errorMessage = ref('')

View File

@@ -28,7 +28,10 @@
{{ manualGlobalModelMode ? '选择已有模型' : '手动添加' }} {{ manualGlobalModelMode ? '选择已有模型' : '手动添加' }}
</Button> </Button>
</div> </div>
<div v-if="!manualGlobalModelMode" class="space-y-2"> <div
v-if="!manualGlobalModelMode"
class="space-y-2"
>
<Select <Select
:model-value="form.global_model_id" :model-value="form.global_model_id"
:disabled="loadingGlobalModels" :disabled="loadingGlobalModels"
@@ -48,10 +51,16 @@
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
<div v-else class="rounded-lg border border-border/60 bg-muted/20 p-3 space-y-3"> <div
v-else
class="rounded-lg border border-border/60 bg-muted/20 p-3 space-y-3"
>
<div class="grid grid-cols-2 gap-3"> <div class="grid grid-cols-2 gap-3">
<div class="space-y-1.5"> <div class="space-y-1.5">
<Label for="manual-global-model-name" class="text-xs">模型ID *</Label> <Label
for="manual-global-model-name"
class="text-xs"
>模型ID *</Label>
<Input <Input
id="manual-global-model-name" id="manual-global-model-name"
v-model="form.manual_global_model_name" v-model="form.manual_global_model_name"
@@ -60,7 +69,10 @@
/> />
</div> </div>
<div class="space-y-1.5"> <div class="space-y-1.5">
<Label for="manual-global-model-display-name" class="text-xs">显示名称</Label> <Label
for="manual-global-model-display-name"
class="text-xs"
>显示名称</Label>
<Input <Input
id="manual-global-model-display-name" id="manual-global-model-display-name"
v-model="form.manual_global_model_display_name" v-model="form.manual_global_model_display_name"
@@ -79,7 +91,10 @@
没有可选择的本地全局模型可以切换到手动添加继续保存 没有可选择的本地全局模型可以切换到手动添加继续保存
</p> </p>
<div class="space-y-1.5"> <div class="space-y-1.5">
<Label for="provider-model-name" class="text-xs">Provider 模型名 *</Label> <Label
for="provider-model-name"
class="text-xs"
>Provider 模型名 *</Label>
<Input <Input
id="provider-model-name" id="provider-model-name"
v-model="form.provider_model_name" v-model="form.provider_model_name"

View File

@@ -293,7 +293,10 @@
</div> </div>
<!-- 桌面端表格视图 --> <!-- 桌面端表格视图 -->
<Table :class="['hidden md:table table-fixed w-full', isAdmin ? 'min-w-[1120px]' : 'min-w-[960px]']"> <Table
class="hidden md:table table-fixed w-full"
:class="[isAdmin ? 'min-w-[1120px]' : 'min-w-[960px]']"
>
<colgroup v-if="isAdmin"> <colgroup v-if="isAdmin">
<col class="w-[8%]"> <col class="w-[8%]">
<col class="w-[12%]"> <col class="w-[12%]">
@@ -346,7 +349,8 @@
密钥 密钥
</TableHead> </TableHead>
<SortableTableHead <SortableTableHead
:class="['h-12 font-semibold', isAdmin ? 'w-[14%]' : 'w-[22%]']" class="h-12 font-semibold"
:class="[isAdmin ? 'w-[14%]' : 'w-[22%]']"
column-key="model" column-key="model"
:sortable="false" :sortable="false"
:filter-active="filterModel !== '__all__'" :filter-active="filterModel !== '__all__'"
@@ -383,7 +387,8 @@
</template> </template>
</SortableTableHead> </SortableTableHead>
<SortableTableHead <SortableTableHead
:class="['h-12 font-semibold', isAdmin ? 'w-[15%]' : 'w-[14%]']" class="h-12 font-semibold"
:class="[isAdmin ? 'w-[15%]' : 'w-[14%]']"
column-key="api_format" column-key="api_format"
:sortable="false" :sortable="false"
:filter-active="filterApiFormat !== '__all__'" :filter-active="filterApiFormat !== '__all__'"
@@ -495,7 +500,8 @@
</div> </div>
</TableCell> </TableCell>
<TableCell <TableCell
:class="['font-medium py-4', isAdmin ? 'w-[14%]' : 'w-[22%]']" class="font-medium py-4"
:class="[isAdmin ? 'w-[14%]' : 'w-[22%]']"
:title="getModelTooltip(record)" :title="getModelTooltip(record)"
> >
<div <div
@@ -582,7 +588,8 @@
</div> </div>
</TableCell> </TableCell>
<TableCell <TableCell
:class="['py-4', isAdmin ? 'w-[15%]' : 'w-[14%]']" class="py-4"
:class="[isAdmin ? 'w-[15%]' : 'w-[14%]']"
:title="getApiFormatTooltip(record)" :title="getApiFormatTooltip(record)"
> >
<!-- 有格式转换或同族格式差异两行显示 --> <!-- 有格式转换或同族格式差异两行显示 -->
@@ -682,8 +689,8 @@
</div> </div>
<div class="mt-0.5 grid w-full min-w-0 grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] gap-x-1 text-xs leading-tight tabular-nums text-muted-foreground"> <div class="mt-0.5 grid w-full min-w-0 grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] gap-x-1 text-xs leading-tight tabular-nums text-muted-foreground">
<span <span
class="justify-self-end whitespace-nowrap text-right"
:class="[ :class="[
'justify-self-end whitespace-nowrap text-right',
hasPositiveTokens(getRecordCacheReadTokens(record)) ? 'text-foreground/70' : '' hasPositiveTokens(getRecordCacheReadTokens(record)) ? 'text-foreground/70' : ''
]" ]"
> >
@@ -693,8 +700,8 @@
/ /
</span> </span>
<span <span
class="justify-self-start whitespace-nowrap text-left"
:class="[ :class="[
'justify-self-start whitespace-nowrap text-left',
hasPositiveTokens(getRecordCacheCreationTokens(record)) ? 'text-foreground/70' : '' hasPositiveTokens(getRecordCacheCreationTokens(record)) ? 'text-foreground/70' : ''
]" ]"
> >

View File

@@ -25,11 +25,11 @@ describe('parseDateLike', () => {
describe('datetime-local conversion', () => { describe('datetime-local conversion', () => {
it('formats RFC3339 instants for datetime-local inputs using local clock fields', () => { it('formats RFC3339 instants for datetime-local inputs using local clock fields', () => {
const date = new Date('2026-04-12T15:30:00Z') const date = new Date('2026-04-12T15:30:00Z')
const expected = [ const expected = `${[
date.getFullYear(), date.getFullYear(),
padDatePart(date.getMonth() + 1), padDatePart(date.getMonth() + 1),
padDatePart(date.getDate()), padDatePart(date.getDate()),
].join('-') + `T${padDatePart(date.getHours())}:${padDatePart(date.getMinutes())}` ].join('-') }T${padDatePart(date.getHours())}:${padDatePart(date.getMinutes())}`
expect(formatDateTimeLocalInput('2026-04-12T15:30:00Z')).toBe(expected) expect(formatDateTimeLocalInput('2026-04-12T15:30:00Z')).toBe(expected)
}) })

View File

@@ -41,12 +41,19 @@
:class="selectedType === '__new__' ? 'bg-primary/10 text-primary' : 'text-foreground hover:bg-muted'" :class="selectedType === '__new__' ? 'bg-primary/10 text-primary' : 'text-foreground hover:bg-muted'"
@click="selectNewConfig()" @click="selectNewConfig()"
> >
<div class="w-7 h-7 rounded-md flex items-center justify-center text-xs font-semibold shrink-0" <div
class="w-7 h-7 rounded-md flex items-center justify-center text-xs font-semibold shrink-0"
:class="selectedType === '__new__' ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'" :class="selectedType === '__new__' ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'"
>+</div> >
+
</div>
<div class="flex-1 min-w-0 text-left"> <div class="flex-1 min-w-0 text-left">
<div class="truncate font-medium text-sm">新配置</div> <div class="truncate font-medium text-sm">
<div class="text-[10px] text-muted-foreground">未保存</div> 新配置
</div>
<div class="text-[10px] text-muted-foreground">
未保存
</div>
</div> </div>
</button> </button>
@@ -70,10 +77,12 @@
src="https://cdn.linux.do/uploads/default/optimized/3X/9/d/9dd49731091ce8656243f3c2b6e5d5e5a7e3e3e3_2_32x32.png" src="https://cdn.linux.do/uploads/default/optimized/3X/9/d/9dd49731091ce8656243f3c2b6e5d5e5a7e3e3e3_2_32x32.png"
class="absolute inset-0 w-full h-full object-cover" class="absolute inset-0 w-full h-full object-cover"
@error="($event.target as HTMLImageElement).remove()" @error="($event.target as HTMLImageElement).remove()"
/> >
</div> </div>
<div class="flex-1 min-w-0 text-left"> <div class="flex-1 min-w-0 text-left">
<div class="truncate font-medium text-sm">{{ item.display_name }}</div> <div class="truncate font-medium text-sm">
{{ item.display_name }}
</div>
<div class="text-[10px] text-muted-foreground"> <div class="text-[10px] text-muted-foreground">
{{ item.configured ? (item.is_enabled ? '已启用' : '已禁用') : '未配置' }} {{ item.configured ? (item.is_enabled ? '已启用' : '已禁用') : '未配置' }}
</div> </div>
@@ -96,7 +105,6 @@
<!-- 右侧内容区 --> <!-- 右侧内容区 -->
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">
<!-- 配置表单 --> <!-- 配置表单 -->
<CardSection <CardSection
v-if="selectedType" v-if="selectedType"

View File

@@ -822,7 +822,6 @@
</div> </div>
</Card> </Card>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -23,7 +23,9 @@
<div>API 端点</div> <div>API 端点</div>
<div>推理程度</div> <div>推理程度</div>
<div>映射参数</div> <div>映射参数</div>
<div class="md:text-right">状态</div> <div class="md:text-right">
状态
</div>
</div> </div>
<div class="divide-y"> <div class="divide-y">
<div <div