feat(channel): 对话框 Tab 布局 — 基础设置 + 平台独立 Tab + 固定高度
This commit is contained in:
parent
14e565a004
commit
95751d8009
@ -1808,6 +1808,7 @@ export default {
|
||||
defaultPerRequestPrice: 'Default per-request price (fallback when no tier matches)',
|
||||
defaultImagePrice: 'Default image price (fallback when no tier matches)',
|
||||
platformConfig: 'Platform Configuration',
|
||||
basicSettings: 'Basic Settings',
|
||||
addPlatform: 'Add Platform',
|
||||
noPlatforms: 'Click "Add Platform" to start configuring the channel',
|
||||
mappingCount: 'mappings',
|
||||
|
||||
@ -1888,6 +1888,7 @@ export default {
|
||||
defaultPerRequestPrice: '默认单次价格(未命中层级时使用)',
|
||||
defaultImagePrice: '默认图片价格(未命中层级时使用)',
|
||||
platformConfig: '平台配置',
|
||||
basicSettings: '基础设置',
|
||||
addPlatform: '添加平台',
|
||||
noPlatforms: '点击"添加平台"开始配置渠道',
|
||||
mappingCount: '条映射',
|
||||
|
||||
@ -143,7 +143,42 @@
|
||||
width="extra-wide"
|
||||
@close="closeDialog"
|
||||
>
|
||||
<form id="channel-form" @submit.prevent="handleSubmit" class="space-y-5">
|
||||
<div class="channel-dialog-body">
|
||||
<!-- Tab Bar -->
|
||||
<div class="flex items-center border-b border-gray-200 dark:border-dark-700 flex-shrink-0 -mx-4 sm:-mx-6 px-4 sm:px-6 -mt-3 sm:-mt-4">
|
||||
<!-- Basic Settings Tab -->
|
||||
<button
|
||||
type="button"
|
||||
@click="activeTab = 'basic'"
|
||||
class="channel-tab"
|
||||
:class="activeTab === 'basic' ? 'channel-tab-active' : 'channel-tab-inactive'"
|
||||
>
|
||||
{{ t('admin.channels.form.basicSettings', '基础设置') }}
|
||||
</button>
|
||||
<!-- Platform Tabs -->
|
||||
<button
|
||||
v-for="(section, sIdx) in form.platforms"
|
||||
:key="section.platform"
|
||||
type="button"
|
||||
@click="activeTab = section.platform"
|
||||
class="channel-tab group"
|
||||
:class="activeTab === section.platform ? 'channel-tab-active' : 'channel-tab-inactive'"
|
||||
>
|
||||
<PlatformIcon :platform="section.platform" size="xs" :class="getPlatformTextColor(section.platform)" />
|
||||
<span :class="getPlatformTextColor(section.platform)">{{ t('admin.groups.platforms.' + section.platform, section.platform) }}</span>
|
||||
<span
|
||||
@click.stop="removePlatformSection(sIdx)"
|
||||
class="ml-1 rounded-full p-0.5 opacity-0 group-hover:opacity-100 hover:bg-gray-200 dark:hover:bg-dark-600 transition-opacity"
|
||||
>
|
||||
<Icon name="x" size="xs" class="text-gray-400 hover:text-red-500" />
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Tab Content -->
|
||||
<form id="channel-form" @submit.prevent="handleSubmit" class="flex-1 overflow-y-auto pt-4">
|
||||
<!-- Basic Settings Tab -->
|
||||
<div v-show="activeTab === 'basic'" class="space-y-5">
|
||||
<!-- Name -->
|
||||
<div>
|
||||
<label class="input-label">{{ t('admin.channels.form.name', 'Name') }} <span class="text-red-500">*</span></label>
|
||||
@ -197,11 +232,10 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Platform Sections -->
|
||||
<!-- Platform Management -->
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<label class="input-label mb-0">{{ t('admin.channels.form.platformConfig', '平台配置') }}</label>
|
||||
<!-- Add Platform -->
|
||||
<div class="relative" v-if="availablePlatformsToAdd.length > 0">
|
||||
<button type="button" @click="showPlatformMenu = !showPlatformMenu" class="btn btn-secondary btn-sm">
|
||||
<Icon name="plus" size="sm" class="mr-1" />
|
||||
@ -232,29 +266,19 @@
|
||||
{{ t('admin.channels.form.noPlatforms', '点击"添加平台"开始配置渠道') }}
|
||||
</div>
|
||||
|
||||
<!-- Each Platform Section -->
|
||||
<!-- Platform summary list -->
|
||||
<div v-else class="space-y-2">
|
||||
<div
|
||||
v-for="(section, sIdx) in form.platforms"
|
||||
:key="section.platform"
|
||||
class="rounded-lg border border-gray-200 bg-white dark:border-dark-600 dark:bg-dark-800"
|
||||
>
|
||||
<!-- Platform Header -->
|
||||
<div
|
||||
class="flex cursor-pointer select-none items-center justify-between rounded-t-lg border-b border-gray-100 px-3 py-2 dark:border-dark-700"
|
||||
:class="section.collapsed ? 'rounded-b-lg border-b-0' : ''"
|
||||
@click="section.collapsed = !section.collapsed"
|
||||
@click="activeTab = section.platform"
|
||||
class="flex cursor-pointer items-center justify-between rounded-lg border border-gray-200 px-3 py-2 transition-colors hover:bg-gray-50 dark:border-dark-600 dark:hover:bg-dark-700"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<Icon
|
||||
:name="section.collapsed ? 'chevronRight' : 'chevronDown'"
|
||||
size="sm"
|
||||
class="text-gray-400"
|
||||
/>
|
||||
<PlatformIcon :platform="section.platform" size="xs" :class="getPlatformTextColor(section.platform)" />
|
||||
<span :class="['text-sm font-semibold', getPlatformTextColor(section.platform)]">
|
||||
<span :class="['text-sm font-medium', getPlatformTextColor(section.platform)]">
|
||||
{{ t('admin.groups.platforms.' + section.platform, section.platform) }}
|
||||
</span>
|
||||
<!-- Summary badges -->
|
||||
<span class="text-xs text-gray-400">
|
||||
{{ section.group_ids.length }} {{ t('admin.channels.groupsUnit', 'groups') }}
|
||||
</span>
|
||||
@ -274,9 +298,17 @@
|
||||
<Icon name="trash" size="sm" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Platform Content -->
|
||||
<div v-show="!section.collapsed" class="space-y-4 p-3">
|
||||
<!-- Platform Tab Content -->
|
||||
<div
|
||||
v-for="(section, sIdx) in form.platforms"
|
||||
:key="'tab-' + section.platform"
|
||||
v-show="activeTab === section.platform"
|
||||
class="space-y-4"
|
||||
>
|
||||
<!-- Groups -->
|
||||
<div>
|
||||
<label class="input-label text-xs">
|
||||
@ -394,9 +426,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-3">
|
||||
@ -514,6 +545,7 @@ const submitting = ref(false)
|
||||
const showDeleteDialog = ref(false)
|
||||
const deletingChannel = ref<Channel | null>(null)
|
||||
const showPlatformMenu = ref(false)
|
||||
const activeTab = ref<string>('basic')
|
||||
|
||||
// Groups
|
||||
const allGroups = ref<AdminGroup[]>([])
|
||||
@ -578,10 +610,15 @@ function addPlatformSection(platform: GroupPlatform) {
|
||||
model_pricing: []
|
||||
})
|
||||
showPlatformMenu.value = false
|
||||
activeTab.value = platform
|
||||
}
|
||||
|
||||
function removePlatformSection(idx: number) {
|
||||
const removed = form.platforms[idx]
|
||||
form.platforms.splice(idx, 1)
|
||||
if (activeTab.value === removed.platform) {
|
||||
activeTab.value = 'basic'
|
||||
}
|
||||
}
|
||||
|
||||
function getGroupsForPlatform(platform: GroupPlatform): AdminGroup[] {
|
||||
@ -837,6 +874,7 @@ function resetForm() {
|
||||
form.billing_model_source = 'requested'
|
||||
form.platforms = []
|
||||
showPlatformMenu.value = false
|
||||
activeTab.value = 'basic'
|
||||
}
|
||||
|
||||
async function openCreateDialog() {
|
||||
@ -955,3 +993,24 @@ onUnmounted(() => {
|
||||
abortController?.abort()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.channel-dialog-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 70vh;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.channel-tab {
|
||||
@apply flex items-center gap-1.5 px-3 py-2.5 text-sm font-medium border-b-2 transition-colors whitespace-nowrap;
|
||||
}
|
||||
|
||||
.channel-tab-active {
|
||||
@apply border-primary-600 text-primary-600 dark:border-primary-400 dark:text-primary-400;
|
||||
}
|
||||
|
||||
.channel-tab-inactive {
|
||||
@apply border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300;
|
||||
}
|
||||
</style>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user