官网开发中 0803
This commit is contained in:
+6
@@ -76,6 +76,9 @@ declare namespace Api {
|
||||
product_id: number | null;
|
||||
layout: string;
|
||||
theme: string;
|
||||
overline_color: string;
|
||||
title_color: string;
|
||||
body_color: string;
|
||||
bg_type: string;
|
||||
bg_value: string;
|
||||
overlay_enabled: boolean;
|
||||
@@ -109,6 +112,9 @@ declare namespace Api {
|
||||
product_id?: number | null;
|
||||
layout: string;
|
||||
theme?: string;
|
||||
overline_color?: string;
|
||||
title_color?: string;
|
||||
body_color?: string;
|
||||
bg_type?: string;
|
||||
bg_value?: string;
|
||||
overlay_enabled?: boolean;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
import { NColorPicker, NInput } from 'naive-ui';
|
||||
|
||||
defineOptions({ name: 'ColorInput' });
|
||||
|
||||
const props = defineProps<{ value: string }>();
|
||||
const emit = defineEmits<{ (e: 'update:value', value: string): void }>();
|
||||
|
||||
// 空值 = 跟随主题默认色
|
||||
const model = computed({
|
||||
get: () => props.value,
|
||||
set: v => emit('update:value', v || '')
|
||||
});
|
||||
|
||||
// 输入框获取焦点后在下方显示取色器(default-show 自动展开面板);面板关闭后自动收起。
|
||||
// 注意:不能把 NColorPicker 塞进 NPopover,双层弹层嵌套会导致取色面板位置跑出框外。
|
||||
const showPicker = ref(false);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full flex flex-col gap-8px">
|
||||
<NInput
|
||||
v-model:value="model"
|
||||
placeholder="留空则跟随主题默认色"
|
||||
clearable
|
||||
@focus="showPicker = true"
|
||||
/>
|
||||
<!-- 空值时取色器内部以白色兜底展示,选中任意颜色即写回 -->
|
||||
<NColorPicker
|
||||
v-if="showPicker"
|
||||
:value="model || '#FFFFFF'"
|
||||
:show-alpha="false"
|
||||
:modes="['hex']"
|
||||
default-show
|
||||
class="w-full"
|
||||
@update:value="v => (model = v)"
|
||||
@update:show="v => !v && (showPicker = false)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
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 './components/ColorInput.vue';
|
||||
import {
|
||||
fetchCreateSection,
|
||||
fetchDeleteSection,
|
||||
@@ -64,6 +65,9 @@ const formData = reactive({
|
||||
id: null as number | null,
|
||||
layout: 'hero_split',
|
||||
theme: 'light',
|
||||
overline_color: '',
|
||||
title_color: '',
|
||||
body_color: '',
|
||||
bg_type: 'color',
|
||||
bg_value: '',
|
||||
overlay_enabled: false,
|
||||
@@ -85,9 +89,23 @@ const formData = reactive({
|
||||
media_url_zh: '',
|
||||
media_url_en: '',
|
||||
video_url: '',
|
||||
is_visible: true
|
||||
is_visible: true,
|
||||
config: { text_position: 'middle_left' } as Record<string, unknown>
|
||||
});
|
||||
|
||||
// 九宫格文案位置(hero_split 专用)
|
||||
const textPositionOptions = [
|
||||
{ label: '左上', value: 'top_left' },
|
||||
{ label: '中上', value: 'top_center' },
|
||||
{ label: '右上', value: 'top_right' },
|
||||
{ label: '左中', value: 'middle_left' },
|
||||
{ label: '正中', value: 'middle_center' },
|
||||
{ label: '右中', value: 'middle_right' },
|
||||
{ label: '左下', value: 'bottom_left' },
|
||||
{ label: '中下', value: 'bottom_center' },
|
||||
{ label: '右下', value: 'bottom_right' }
|
||||
];
|
||||
|
||||
const columns = computed((): DataTableColumns<Api.Www.SectionBlock> => [
|
||||
{
|
||||
title: '排序',
|
||||
@@ -177,6 +195,9 @@ function handleAdd() {
|
||||
formData.id = null;
|
||||
formData.layout = 'hero_split';
|
||||
formData.theme = 'light';
|
||||
formData.overline_color = '';
|
||||
formData.title_color = '';
|
||||
formData.body_color = '';
|
||||
formData.bg_type = 'color';
|
||||
formData.bg_value = '';
|
||||
formData.overlay_enabled = false;
|
||||
@@ -199,6 +220,7 @@ function handleAdd() {
|
||||
formData.media_url_en = '';
|
||||
formData.video_url = '';
|
||||
formData.is_visible = true;
|
||||
formData.config = { text_position: 'middle_left' };
|
||||
dialogVisible.value = true;
|
||||
}
|
||||
|
||||
@@ -207,6 +229,9 @@ function handleEdit(row: Api.Www.SectionBlock) {
|
||||
formData.id = row.id;
|
||||
formData.layout = row.layout;
|
||||
formData.theme = row.theme;
|
||||
formData.overline_color = row.overline_color || '';
|
||||
formData.title_color = row.title_color || '';
|
||||
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);
|
||||
@@ -229,6 +254,8 @@ function handleEdit(row: Api.Www.SectionBlock) {
|
||||
formData.media_url_en = row.media_url_en;
|
||||
formData.video_url = row.video_url;
|
||||
formData.is_visible = Boolean(row.is_visible);
|
||||
const cfg = (row.config || {}) as Record<string, unknown>;
|
||||
formData.config = { ...cfg, text_position: cfg.text_position || 'middle_left' };
|
||||
dialogVisible.value = true;
|
||||
}
|
||||
|
||||
@@ -306,6 +333,16 @@ onMounted(loadData);
|
||||
<NRadio v-for="opt in themeOptions" :key="opt.value" :value="opt.value">{{ opt.label }}</NRadio>
|
||||
</NRadioGroup>
|
||||
</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>
|
||||
@@ -315,7 +352,20 @@ onMounted(loadData);
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
<NFormItem label="背景值">
|
||||
<NInput v-model:value="formData.bg_value" placeholder="颜色值或图片路径" />
|
||||
<NInput v-model:value="formData.bg_value" placeholder="颜色值或图片/视频路径" />
|
||||
</NFormItem>
|
||||
<NFormItem v-if="formData.layout === 'hero_split'" label="文案位置">
|
||||
<div class="grid grid-cols-3 gap-4px">
|
||||
<NButton
|
||||
v-for="pos in textPositionOptions"
|
||||
:key="pos.value"
|
||||
size="tiny"
|
||||
:type="formData.config.text_position === pos.value ? 'primary' : 'default'"
|
||||
@click="formData.config.text_position = pos.value"
|
||||
>
|
||||
{{ pos.label }}
|
||||
</NButton>
|
||||
</div>
|
||||
</NFormItem>
|
||||
<NFormItem label="遮罩">
|
||||
<NSpace align="center">
|
||||
|
||||
Reference in New Issue
Block a user