优化项目结构
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { computed, h, onMounted, reactive, ref } from 'vue';
|
||||
import { NButton, NSpace, NSwitch, NTag, type DataTableColumns, type FormInst, type SelectOption, type SelectRenderOption } from 'naive-ui';
|
||||
import ColorInput from '../page/home/components/ColorInput.vue';
|
||||
import GradientInput from './GradientInput.vue';
|
||||
import MediaSelectInput from './MediaSelectInput.vue';
|
||||
import RichTextEditor from './RichTextEditor.vue';
|
||||
import SpecManager from './SpecManager.vue';
|
||||
@@ -89,8 +90,6 @@ const formData = reactive({
|
||||
body_color: '',
|
||||
bg_type: 'color',
|
||||
bg_value: '',
|
||||
overlay_enabled: false,
|
||||
overlay_opacity: 0,
|
||||
overline_zh: '',
|
||||
overline_en: '',
|
||||
title_zh: '',
|
||||
@@ -349,8 +348,6 @@ function handleAdd() {
|
||||
formData.body_color = '';
|
||||
formData.bg_type = 'color';
|
||||
formData.bg_value = '';
|
||||
formData.overlay_enabled = false;
|
||||
formData.overlay_opacity = 0;
|
||||
formData.overline_zh = '';
|
||||
formData.overline_en = '';
|
||||
formData.title_zh = '';
|
||||
@@ -382,8 +379,6 @@ function fillFormFromRow(row: Api.Www.SectionBlock) {
|
||||
formData.body_color = row.body_color || '';
|
||||
formData.bg_type = row.bg_type;
|
||||
formData.bg_value = row.bg_value;
|
||||
formData.overlay_enabled = Boolean(row.overlay_enabled);
|
||||
formData.overlay_opacity = Number(row.overlay_opacity);
|
||||
formData.overline_zh = row.overline_zh;
|
||||
formData.overline_en = row.overline_en;
|
||||
formData.title_zh = row.title_zh;
|
||||
@@ -519,146 +514,170 @@ onMounted(loadData);
|
||||
>
|
||||
<NForm ref="formRef" :model="formData" label-placement="left" label-width="120">
|
||||
<NDivider>基础配置</NDivider>
|
||||
<NFormItem label="布局类型">
|
||||
<NSelect v-model:value="formData.layout" :options="layoutOptions" :render-label="renderLayoutLabel" :render-option="renderLayoutOption" />
|
||||
</NFormItem>
|
||||
<NFormItem label="主题">
|
||||
<NRadioGroup v-model:value="formData.theme">
|
||||
<NRadio v-for="opt in themeOptions" :key="opt.value" :value="opt.value">{{ opt.label }}</NRadio>
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
<NFormItem label="区块宽度">
|
||||
<div class="w-full flex flex-col gap-8px">
|
||||
<NInputNumber
|
||||
:value="(formData.config.width_percent as number) ?? 100"
|
||||
:min="30"
|
||||
:max="100"
|
||||
:step="5"
|
||||
class="w-full"
|
||||
@update:value="v => (formData.config.width_percent = v ?? 100)"
|
||||
>
|
||||
<template #suffix>%</template>
|
||||
</NInputNumber>
|
||||
<span class="text-12px opacity-60">占视口宽度百分比,居中显示;100 = 全宽。移动端(小屏)始终全宽</span>
|
||||
</div>
|
||||
</NFormItem>
|
||||
<NFormItem label="内容区宽度">
|
||||
<div class="w-full flex flex-col gap-8px">
|
||||
<NSelect
|
||||
:value="(formData.config.container_width as string) ?? '1200'"
|
||||
:options="containerWidthOptions"
|
||||
@update:value="v => (formData.config.container_width = v)"
|
||||
/>
|
||||
<span class="text-12px opacity-60">区块内容容器的最大宽度,居中于区块内;全宽 = 内容占满整个区块</span>
|
||||
</div>
|
||||
</NFormItem>
|
||||
<NFormItem label="区块圆角">
|
||||
<div class="w-full flex flex-col gap-8px">
|
||||
<NInputNumber
|
||||
:value="(formData.config.border_radius as number) ?? 0"
|
||||
:min="0"
|
||||
:max="60"
|
||||
:step="4"
|
||||
class="w-full"
|
||||
@update:value="v => (formData.config.border_radius = v ?? 0)"
|
||||
>
|
||||
<template #suffix>px</template>
|
||||
</NInputNumber>
|
||||
<span class="text-12px opacity-60">区块四角圆角大小;0 = 直角(默认)。建议与「区块宽度」小于 100 搭配使用,全宽时圆角不可见</span>
|
||||
</div>
|
||||
</NFormItem>
|
||||
<NFormItem label="上下内边距">
|
||||
<div class="w-full flex flex-col gap-8px">
|
||||
<NInputNumber
|
||||
:value="(formData.config.padding_y as number | null) ?? null"
|
||||
:min="0"
|
||||
:max="240"
|
||||
:step="8"
|
||||
class="w-full"
|
||||
clearable
|
||||
placeholder="留空 = 布局默认值"
|
||||
@update:value="v => (formData.config.padding_y = v)"
|
||||
>
|
||||
<template #suffix>px</template>
|
||||
</NInputNumber>
|
||||
<span class="text-12px opacity-60">内容区与区块上下边缘的间距。留空 = 布局默认(多数 96px / 全幅横幅 120px / 主视觉分屏 64px);0 = 完全贴边</span>
|
||||
</div>
|
||||
</NFormItem>
|
||||
<NFormItem label="上下外边距">
|
||||
<div class="w-full flex flex-col gap-8px">
|
||||
<NInputNumber
|
||||
:value="(formData.config.margin_y as number | null) ?? null"
|
||||
:min="0"
|
||||
:max="240"
|
||||
:step="8"
|
||||
class="w-full"
|
||||
clearable
|
||||
placeholder="留空 = 紧贴相邻区块"
|
||||
@update:value="v => (formData.config.margin_y = v)"
|
||||
>
|
||||
<template #suffix>px</template>
|
||||
</NInputNumber>
|
||||
<span class="text-12px opacity-60">区块与上下相邻区块之间的间隙,露出页面背景色;适合「区块宽度 < 100 + 圆角」的卡片式区块。留空/0 = 紧贴(默认)</span>
|
||||
</div>
|
||||
</NFormItem>
|
||||
<NFormItem label="标题字号">
|
||||
<div class="w-full flex flex-col gap-8px">
|
||||
<NInputNumber
|
||||
:value="(formData.config.title_font_size as number | null) ?? null"
|
||||
:min="16"
|
||||
:max="96"
|
||||
:step="2"
|
||||
class="w-full"
|
||||
clearable
|
||||
placeholder="留空 = 36px(兜底)"
|
||||
@update:value="v => (formData.config.title_font_size = v)"
|
||||
>
|
||||
<template #suffix>px</template>
|
||||
</NInputNumber>
|
||||
<span class="text-12px opacity-60">桌面端标题字号;移动端自动按约 62.5% 缩小(如填 48 → 移动端 30px)。留空 = 兜底 36px;引言布局无标题字段不受影响</span>
|
||||
</div>
|
||||
</NFormItem>
|
||||
<NFormItem v-if="formData.layout === 'hero_split' || formData.layout === 'mosaic'" :label="formData.layout === 'mosaic' ? '网格高度' : '最小高度'">
|
||||
<div class="w-full flex flex-col gap-8px">
|
||||
<NInputNumber
|
||||
:value="(formData.config.min_height as number | null) ?? null"
|
||||
:min="0"
|
||||
:max="1200"
|
||||
:step="20"
|
||||
class="w-full"
|
||||
clearable
|
||||
:placeholder="formData.layout === 'mosaic' ? '留空 = 默认 16:9 宽高比' : '留空 = 首屏高度(默认)'"
|
||||
@update:value="v => (formData.config.min_height = v)"
|
||||
>
|
||||
<template #suffix>px</template>
|
||||
</NInputNumber>
|
||||
<span class="text-12px opacity-60">
|
||||
<div class="grid grid-cols-2 gap-x-16px">
|
||||
<NFormItem label="布局类型" label-placement="top">
|
||||
<NSelect v-model:value="formData.layout" :options="layoutOptions" :render-label="renderLayoutLabel" :render-option="renderLayoutOption" />
|
||||
</NFormItem>
|
||||
<NFormItem label="主题" label-placement="top">
|
||||
<NRadioGroup v-model:value="formData.theme">
|
||||
<NRadio v-for="opt in themeOptions" :key="opt.value" :value="opt.value">{{ opt.label }}</NRadio>
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-x-16px">
|
||||
<NFormItem label="区块宽度" label-placement="top">
|
||||
<NTooltip trigger="focus" placement="top">
|
||||
<template #trigger>
|
||||
<NInputNumber
|
||||
:value="(formData.config.width_percent as number) ?? 100"
|
||||
:min="30"
|
||||
:max="100"
|
||||
:step="5"
|
||||
class="w-full"
|
||||
@update:value="v => (formData.config.width_percent = v ?? 100)"
|
||||
>
|
||||
<template #suffix>%</template>
|
||||
</NInputNumber>
|
||||
</template>
|
||||
占视口宽度百分比,居中显示;100 = 全宽。移动端(小屏)始终全宽
|
||||
</NTooltip>
|
||||
</NFormItem>
|
||||
<NFormItem label="内容区宽度" label-placement="top">
|
||||
<NTooltip trigger="focus" placement="top">
|
||||
<template #trigger>
|
||||
<NSelect
|
||||
:value="(formData.config.container_width as string) ?? '1200'"
|
||||
:options="containerWidthOptions"
|
||||
@update:value="v => (formData.config.container_width = v)"
|
||||
/>
|
||||
</template>
|
||||
区块内容容器的最大宽度,居中于区块内;全宽 = 内容占满整个区块
|
||||
</NTooltip>
|
||||
</NFormItem>
|
||||
<NFormItem label="区块圆角" label-placement="top">
|
||||
<NTooltip trigger="focus" placement="top">
|
||||
<template #trigger>
|
||||
<NInputNumber
|
||||
:value="(formData.config.border_radius as number) ?? 0"
|
||||
:min="0"
|
||||
:max="60"
|
||||
:step="4"
|
||||
class="w-full"
|
||||
@update:value="v => (formData.config.border_radius = v ?? 0)"
|
||||
>
|
||||
<template #suffix>px</template>
|
||||
</NInputNumber>
|
||||
</template>
|
||||
区块四角圆角大小;0 = 直角(默认)。建议与「区块宽度」小于 100 搭配使用,全宽时圆角不可见
|
||||
</NTooltip>
|
||||
</NFormItem>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-x-16px">
|
||||
<NFormItem label="上下内边距" label-placement="top">
|
||||
<NTooltip trigger="focus" placement="top">
|
||||
<template #trigger>
|
||||
<NInputNumber
|
||||
:value="(formData.config.padding_y as number | null) ?? null"
|
||||
:min="0"
|
||||
:max="240"
|
||||
:step="8"
|
||||
class="w-full"
|
||||
clearable
|
||||
placeholder="留空 = 布局默认值"
|
||||
@update:value="v => (formData.config.padding_y = v)"
|
||||
>
|
||||
<template #suffix>px</template>
|
||||
</NInputNumber>
|
||||
</template>
|
||||
内容区与区块上下边缘的间距。留空 = 布局默认(多数 96px / 全幅横幅 120px / 主视觉分屏 64px);0 = 完全贴边
|
||||
</NTooltip>
|
||||
</NFormItem>
|
||||
<NFormItem label="上下外边距" label-placement="top">
|
||||
<NTooltip trigger="focus" placement="top">
|
||||
<template #trigger>
|
||||
<NInputNumber
|
||||
:value="(formData.config.margin_y as number | null) ?? null"
|
||||
:min="0"
|
||||
:max="240"
|
||||
:step="8"
|
||||
class="w-full"
|
||||
clearable
|
||||
placeholder="留空 = 紧贴相邻区块"
|
||||
@update:value="v => (formData.config.margin_y = v)"
|
||||
>
|
||||
<template #suffix>px</template>
|
||||
</NInputNumber>
|
||||
</template>
|
||||
区块与上下相邻区块之间的间隙,露出页面背景色;适合「区块宽度 < 100 + 圆角」的卡片式区块。留空/0 = 紧贴(默认)
|
||||
</NTooltip>
|
||||
</NFormItem>
|
||||
<NFormItem v-if="formData.layout === 'hero_split' || formData.layout === 'mosaic'" :label="formData.layout === 'mosaic' ? '网格高度' : '最小高度'" label-placement="top">
|
||||
<NTooltip trigger="focus" placement="top">
|
||||
<template #trigger>
|
||||
<NInputNumber
|
||||
:value="(formData.config.min_height as number | null) ?? null"
|
||||
:min="0"
|
||||
:max="1200"
|
||||
:step="20"
|
||||
class="w-full"
|
||||
clearable
|
||||
:placeholder="formData.layout === 'mosaic' ? '留空 = 默认 16:9 宽高比' : '留空 = 首屏高度(默认)'"
|
||||
@update:value="v => (formData.config.min_height = v)"
|
||||
>
|
||||
<template #suffix>px</template>
|
||||
</NInputNumber>
|
||||
</template>
|
||||
<template v-if="formData.layout === 'mosaic'">仅桌面端生效。留空 = 默认 16:9 宽高比;填数值 = 网格固定高度(px),素材自动裁剪填充,可调低区块高度;移动端保持单列堆叠不变</template>
|
||||
<template v-else>仅主视觉分屏布局生效。留空 = 沿用首屏高度(至少 680px 约一屏);0 = 完全自适应内容(去上下内边距,区块高度严格等于内容高度);填数值 = 自定义最小高度</template>
|
||||
</span>
|
||||
</div>
|
||||
</NFormItem>
|
||||
<NDivider>文案颜色(留空=跟随主题默认色)</NDivider>
|
||||
<NFormItem label="Overline 颜色">
|
||||
<ColorInput v-model:value="formData.overline_color" />
|
||||
</NFormItem>
|
||||
<NFormItem label="标题颜色">
|
||||
<ColorInput v-model:value="formData.title_color" />
|
||||
</NFormItem>
|
||||
<NFormItem label="副标题/正文颜色">
|
||||
<ColorInput v-model:value="formData.body_color" />
|
||||
</NFormItem>
|
||||
<NFormItem label="背景类型">
|
||||
<NRadioGroup v-model:value="formData.bg_type">
|
||||
<NRadioButton value="color">纯色</NRadioButton>
|
||||
<NRadioButton value="image">图片</NRadioButton>
|
||||
<NRadioButton value="gradient">渐变</NRadioButton>
|
||||
<NRadioButton value="video">视频</NRadioButton>
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
<NFormItem label="背景值">
|
||||
<MediaSelectInput v-model:value="formData.bg_value" placeholder="颜色值或图片/视频路径(支持 /uploads/... 相对路径)" />
|
||||
</NFormItem>
|
||||
</NTooltip>
|
||||
</NFormItem>
|
||||
</div>
|
||||
<div class="flex items-start gap-x-16px">
|
||||
<NFormItem label="背景类型" label-placement="top" class="shrink-0">
|
||||
<NRadioGroup v-model:value="formData.bg_type">
|
||||
<NRadioButton value="color">纯色</NRadioButton>
|
||||
<NRadioButton value="gradient">渐变</NRadioButton>
|
||||
<NRadioButton value="image">图片</NRadioButton>
|
||||
<NRadioButton value="video">视频</NRadioButton>
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
<NFormItem label="背景值" label-placement="top" class="min-w-0 flex-1">
|
||||
<ColorInput v-if="formData.bg_type === 'color'" v-model:value="formData.bg_value" placeholder="留空则无背景色" />
|
||||
<GradientInput v-else-if="formData.bg_type === 'gradient'" v-model:value="formData.bg_value" />
|
||||
<MediaSelectInput v-else v-model:value="formData.bg_value" placeholder="图片/视频路径(支持 /uploads/... 相对路径)" />
|
||||
</NFormItem>
|
||||
</div>
|
||||
<NDivider>文案样式</NDivider>
|
||||
<div class="grid grid-cols-4 gap-x-16px">
|
||||
<NFormItem label="标题字号" label-placement="top">
|
||||
<NTooltip trigger="focus" placement="top">
|
||||
<template #trigger>
|
||||
<NInputNumber
|
||||
:value="(formData.config.title_font_size as number | null) ?? null"
|
||||
:min="16"
|
||||
:max="96"
|
||||
:step="2"
|
||||
class="w-full"
|
||||
clearable
|
||||
placeholder="留空 = 36px(兜底)"
|
||||
@update:value="v => (formData.config.title_font_size = v)"
|
||||
>
|
||||
<template #suffix>px</template>
|
||||
</NInputNumber>
|
||||
</template>
|
||||
桌面端标题字号;移动端自动按约 62.5% 缩小(如填 48 → 移动端 30px)。留空 = 兜底 36px;引言布局无标题字段不受影响
|
||||
</NTooltip>
|
||||
</NFormItem>
|
||||
<NFormItem label="Overline 颜色" label-placement="top">
|
||||
<ColorInput v-model:value="formData.overline_color" />
|
||||
</NFormItem>
|
||||
<NFormItem label="标题颜色" label-placement="top">
|
||||
<ColorInput v-model:value="formData.title_color" />
|
||||
</NFormItem>
|
||||
<NFormItem label="副标题/正文颜色" label-placement="top">
|
||||
<ColorInput v-model:value="formData.body_color" />
|
||||
</NFormItem>
|
||||
</div>
|
||||
<NFormItem v-if="formData.bg_type === 'image' || formData.bg_type === 'video'" label="背景显示模式">
|
||||
<NRadioGroup :value="(formData.config.bg_fit as string) ?? 'cover'" @update:value="v => (formData.config.bg_fit = v)">
|
||||
<NRadio v-for="opt in bgFitOptions" :key="opt.value" :value="opt.value">{{ opt.label }}</NRadio>
|
||||
@@ -704,14 +723,6 @@ onMounted(loadData);
|
||||
<span class="text-12px opacity-60">固定版式;切换版式会同步下方槽位数量(已填素材按顺序保留)</span>
|
||||
</div>
|
||||
</NFormItem>
|
||||
<NFormItem label="遮罩">
|
||||
<NSpace align="center">
|
||||
<NSwitch v-model:value="formData.overlay_enabled" />
|
||||
<span>透明度</span>
|
||||
<NSlider v-model:value="formData.overlay_opacity" :min="0" :max="1" :step="0.05" class="w-200px" />
|
||||
<span>{{ formData.overlay_opacity.toFixed(2) }}</span>
|
||||
</NSpace>
|
||||
</NFormItem>
|
||||
|
||||
<NDivider>文案内容</NDivider>
|
||||
<NFormItem label="Overline(中)">
|
||||
|
||||
Reference in New Issue
Block a user