fix(frontend): quota notify UI improvements

- QuotaNotifyToggle: add $ or % suffix to threshold input based on type
- QuotaLimitCard: combine reset mode and notify toggle on same row
  to reduce vertical height for daily/weekly sections
- Remove redundant ml-4 indentation from QuotaNotifyToggle
This commit is contained in:
erio
2026-04-13 16:52:02 +08:00
parent 98c9d51791
commit 2066c478ab
3 changed files with 56 additions and 52 deletions

View File

@@ -1 +1 @@
0.1.110.27 0.1.110.28

View File

@@ -203,28 +203,28 @@ const onWeeklyModeChange = (e: Event) => {
:placeholder="t('admin.accounts.quotaLimitPlaceholder')" :placeholder="t('admin.accounts.quotaLimitPlaceholder')"
/> />
</div> </div>
<!-- 日配额重置模式 --> <!-- 日配额重置方式 + 告警阈值同行 -->
<div class="mt-2 flex items-center gap-2"> <div class="mt-2 flex items-center gap-2 flex-wrap">
<label class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">{{ t('admin.accounts.quotaResetMode') }}</label> <label class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">{{ t('admin.accounts.quotaResetMode') }}</label>
<select <select
:value="dailyResetMode || 'rolling'" :value="dailyResetMode || 'rolling'"
@change="onDailyModeChange" @change="onDailyModeChange"
class="input py-1 text-xs" class="input py-1 text-xs w-auto"
> >
<option value="rolling">{{ t('admin.accounts.quotaResetModeRolling') }}</option> <option value="rolling">{{ t('admin.accounts.quotaResetModeRolling') }}</option>
<option value="fixed">{{ t('admin.accounts.quotaResetModeFixed') }}</option> <option value="fixed">{{ t('admin.accounts.quotaResetModeFixed') }}</option>
</select> </select>
</div> <!-- 固定模式小时选择 -->
<!-- 固定模式小时选择 --> <template v-if="dailyResetMode === 'fixed'">
<div v-if="dailyResetMode === 'fixed'" class="mt-2 flex items-center gap-2"> <label class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">{{ t('admin.accounts.quotaResetHour') }}</label>
<label class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">{{ t('admin.accounts.quotaResetHour') }}</label> <select
<select :value="dailyResetHour ?? 0"
:value="dailyResetHour ?? 0" @change="emit('update:dailyResetHour', Number(($event.target as HTMLSelectElement).value))"
@change="emit('update:dailyResetHour', Number(($event.target as HTMLSelectElement).value))" class="input py-1 text-xs w-24"
class="input py-1 text-xs w-24" >
> <option v-for="h in hourOptions" :key="h" :value="h">{{ String(h).padStart(2, '0') }}:00</option>
<option v-for="h in hourOptions" :key="h" :value="h">{{ String(h).padStart(2, '0') }}:00</option> </select>
</select> </template>
</div> </div>
<p class="input-hint"> <p class="input-hint">
<template v-if="dailyResetMode === 'fixed'"> <template v-if="dailyResetMode === 'fixed'">
@@ -234,7 +234,6 @@ const onWeeklyModeChange = (e: Event) => {
{{ t('admin.accounts.quotaDailyLimitHint') }} {{ t('admin.accounts.quotaDailyLimitHint') }}
</template> </template>
</p> </p>
<!-- 日配额告警 -->
<QuotaNotifyToggle <QuotaNotifyToggle
v-if="quotaNotifyGlobalEnabled && dailyLimit && dailyLimit > 0" v-if="quotaNotifyGlobalEnabled && dailyLimit && dailyLimit > 0"
:enabled="props.quotaNotifyDailyEnabled" :enabled="props.quotaNotifyDailyEnabled"
@@ -261,36 +260,36 @@ const onWeeklyModeChange = (e: Event) => {
:placeholder="t('admin.accounts.quotaLimitPlaceholder')" :placeholder="t('admin.accounts.quotaLimitPlaceholder')"
/> />
</div> </div>
<!-- 周配额重置模式 --> <!-- 周配额重置方式 + 告警阈值同行 -->
<div class="mt-2 flex items-center gap-2"> <div class="mt-2 flex items-center gap-2 flex-wrap">
<label class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">{{ t('admin.accounts.quotaResetMode') }}</label> <label class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">{{ t('admin.accounts.quotaResetMode') }}</label>
<select <select
:value="weeklyResetMode || 'rolling'" :value="weeklyResetMode || 'rolling'"
@change="onWeeklyModeChange" @change="onWeeklyModeChange"
class="input py-1 text-xs" class="input py-1 text-xs w-auto"
> >
<option value="rolling">{{ t('admin.accounts.quotaResetModeRolling') }}</option> <option value="rolling">{{ t('admin.accounts.quotaResetModeRolling') }}</option>
<option value="fixed">{{ t('admin.accounts.quotaResetModeFixed') }}</option> <option value="fixed">{{ t('admin.accounts.quotaResetModeFixed') }}</option>
</select> </select>
</div> <!-- 固定模式星期几 + 小时 -->
<!-- 固定模式星期几 + 小时 --> <template v-if="weeklyResetMode === 'fixed'">
<div v-if="weeklyResetMode === 'fixed'" class="mt-2 flex items-center gap-2 flex-wrap"> <label class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">{{ t('admin.accounts.quotaWeeklyResetDay') }}</label>
<label class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">{{ t('admin.accounts.quotaWeeklyResetDay') }}</label> <select
<select :value="weeklyResetDay ?? 1"
:value="weeklyResetDay ?? 1" @change="emit('update:weeklyResetDay', Number(($event.target as HTMLSelectElement).value))"
@change="emit('update:weeklyResetDay', Number(($event.target as HTMLSelectElement).value))" class="input py-1 text-xs w-28"
class="input py-1 text-xs w-28" >
> <option v-for="d in dayOptions" :key="d.value" :value="d.value">{{ t('admin.accounts.dayOfWeek.' + d.key) }}</option>
<option v-for="d in dayOptions" :key="d.value" :value="d.value">{{ t('admin.accounts.dayOfWeek.' + d.key) }}</option> </select>
</select> <label class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">{{ t('admin.accounts.quotaResetHour') }}</label>
<label class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">{{ t('admin.accounts.quotaResetHour') }}</label> <select
<select :value="weeklyResetHour ?? 0"
:value="weeklyResetHour ?? 0" @change="emit('update:weeklyResetHour', Number(($event.target as HTMLSelectElement).value))"
@change="emit('update:weeklyResetHour', Number(($event.target as HTMLSelectElement).value))" class="input py-1 text-xs w-24"
class="input py-1 text-xs w-24" >
> <option v-for="h in hourOptions" :key="h" :value="h">{{ String(h).padStart(2, '0') }}:00</option>
<option v-for="h in hourOptions" :key="h" :value="h">{{ String(h).padStart(2, '0') }}:00</option> </select>
</select> </template>
</div> </div>
<p class="input-hint"> <p class="input-hint">
<template v-if="weeklyResetMode === 'fixed'"> <template v-if="weeklyResetMode === 'fixed'">
@@ -300,7 +299,6 @@ const onWeeklyModeChange = (e: Event) => {
{{ t('admin.accounts.quotaWeeklyLimitHint') }} {{ t('admin.accounts.quotaWeeklyLimitHint') }}
</template> </template>
</p> </p>
<!-- 周配额告警 -->
<QuotaNotifyToggle <QuotaNotifyToggle
v-if="quotaNotifyGlobalEnabled && weeklyLimit && weeklyLimit > 0" v-if="quotaNotifyGlobalEnabled && weeklyLimit && weeklyLimit > 0"
:enabled="props.quotaNotifyWeeklyEnabled" :enabled="props.quotaNotifyWeeklyEnabled"

View File

@@ -21,7 +21,7 @@ function toggleType(current: string | null) {
</script> </script>
<template> <template>
<div class="ml-4 mt-2 flex items-center gap-3"> <div class="flex items-center gap-2">
<label class="text-sm text-gray-500 whitespace-nowrap">{{ t('admin.accounts.quotaNotify.alert') }}</label> <label class="text-sm text-gray-500 whitespace-nowrap">{{ t('admin.accounts.quotaNotify.alert') }}</label>
<button <button
type="button" type="button"
@@ -38,7 +38,7 @@ function toggleType(current: string | null) {
]" ]"
/> />
</button> </button>
<div v-if="enabled" class="flex items-center gap-1 flex-1"> <template v-if="enabled">
<button <button
type="button" type="button"
class="px-1.5 py-0.5 text-xs font-medium rounded border transition-colors" class="px-1.5 py-0.5 text-xs font-medium rounded border transition-colors"
@@ -55,16 +55,22 @@ function toggleType(current: string | null) {
> >
% %
</button> </button>
<input <div class="relative flex-1">
:value="threshold" <input
@input="emit('update:threshold', parseFloat(($event.target as HTMLInputElement).value) || null)" :value="threshold"
type="number" @input="emit('update:threshold', parseFloat(($event.target as HTMLInputElement).value) || null)"
min="0" type="number"
:max="thresholdType === 'percentage' ? 100 : undefined" min="0"
:step="thresholdType === 'percentage' ? 1 : 0.01" :max="thresholdType === 'percentage' ? 100 : undefined"
class="input py-1 text-sm flex-1" :step="thresholdType === 'percentage' ? 1 : 0.01"
:placeholder="thresholdType === 'percentage' ? t('admin.accounts.quotaNotify.thresholdPlaceholder') : t('admin.accounts.quotaNotify.threshold')" class="input py-1 text-sm w-full"
/> :class="thresholdType === 'percentage' ? 'pr-7' : 'pr-7'"
</div> :placeholder="thresholdType === 'percentage' ? t('admin.accounts.quotaNotify.thresholdPlaceholder') : t('admin.accounts.quotaNotify.threshold')"
/>
<span class="absolute right-2.5 top-1/2 -translate-y-1/2 text-xs text-gray-400 pointer-events-none">
{{ thresholdType === 'percentage' ? '%' : '$' }}
</span>
</div>
</template>
</div> </div>
</template> </template>