From 48510739a7a77e0b858580b88e6166ca608e34f9 Mon Sep 17 00:00:00 2001 From: eafonyang Date: Mon, 10 Aug 2026 14:56:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=98=E7=BD=91=E5=BC=80=E5=8F=91=200810?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dashboard/backend/src/routes/www/sections.ts | 13 +- .../frontend/src/router/elegant/routes.ts | 2 +- .../frontend/src/service/api/www-sections.ts | 4 +- dashboard/frontend/src/typings/api/www.d.ts | 2 + .../views/www/components/SectionManager.vue | 81 ++++- .../src/views/www/components/SpecManager.vue | 306 ++++++++++++++++++ db/migrations/x8_balanced_headphone_specs.sql | 9 + db/migrations/x8_basic_specs.sql | 20 ++ db/migrations/x8_io_specs.sql | 15 + db/migrations/x8_rca_output_specs.sql | 9 + db/migrations/x8_se_headphone_specs.sql | 8 + db/migrations/x8_section_sort_fix.sql | 11 + db/migrations/x8_xlr_output_specs.sql | 12 + tmp_home_check.png | Bin 0 -> 40881 bytes www/app/assets/css/main.css | 11 + .../components/section/SectionRenderer.vue | 8 + .../section/layouts/LayoutSpecTable.vue | 145 ++++++--- .../section/layouts/LayoutSplitContent.vue | 19 +- www/package.json | 1 + www/pnpm-lock.yaml | 13 + 20 files changed, 636 insertions(+), 53 deletions(-) create mode 100644 dashboard/frontend/src/views/www/components/SpecManager.vue create mode 100644 db/migrations/x8_balanced_headphone_specs.sql create mode 100644 db/migrations/x8_basic_specs.sql create mode 100644 db/migrations/x8_io_specs.sql create mode 100644 db/migrations/x8_rca_output_specs.sql create mode 100644 db/migrations/x8_se_headphone_specs.sql create mode 100644 db/migrations/x8_section_sort_fix.sql create mode 100644 db/migrations/x8_xlr_output_specs.sql create mode 100644 tmp_home_check.png diff --git a/dashboard/backend/src/routes/www/sections.ts b/dashboard/backend/src/routes/www/sections.ts index b3aadbc..fb708cc 100644 --- a/dashboard/backend/src/routes/www/sections.ts +++ b/dashboard/backend/src/routes/www/sections.ts @@ -1,5 +1,5 @@ import { Router, type Request, type Response } from 'express'; -import { eq, and } from 'drizzle-orm'; +import { eq, and, max } from 'drizzle-orm'; import { db } from '../../config/database.js'; import { wwwSectionBlocks, wwwSpecGroups, wwwSpecItems } from '../../schemas/index.js'; import logger from '../../config/logger.js'; @@ -77,6 +77,15 @@ router.post('/api/www/sections', async (req: Request, res: Response) => { return; } + // 未指定排序时,自动追加到同 page_type(及同产品)已有区块的最后,避免默认 0 导致乱序 + let sortOrder = Number(b.sort_order) || 0; + if (b.sort_order === undefined || b.sort_order === null) { + const scope = [eq(wwwSectionBlocks.pageType, b.page_type)]; + if (b.product_id) scope.push(eq(wwwSectionBlocks.productId, b.product_id)); + const [agg] = await db.select({ max: max(wwwSectionBlocks.sortOrder) }).from(wwwSectionBlocks).where(and(...scope)); + sortOrder = (agg?.max ?? -1) + 1; + } + const result = await db.insert(wwwSectionBlocks).values({ pageType: b.page_type, productId: b.product_id || null, @@ -108,7 +117,7 @@ router.post('/api/www/sections', async (req: Request, res: Response) => { videoUrl: b.video_url || '', config: b.config || null, isVisible: b.is_visible !== undefined ? (b.is_visible ? 1 : 0) : 1, - sortOrder: b.sort_order || 0, + sortOrder, }); const newId = result[0].insertId; diff --git a/dashboard/frontend/src/router/elegant/routes.ts b/dashboard/frontend/src/router/elegant/routes.ts index 965c50f..c85cf44 100644 --- a/dashboard/frontend/src/router/elegant/routes.ts +++ b/dashboard/frontend/src/router/elegant/routes.ts @@ -246,7 +246,7 @@ export const generatedRoutes: GeneratedRoute[] = [ meta: { title: 'www', i18nKey: 'route.www', - icon: 'mdi:globe-model', + icon: 'iconoir:www', order: 7 }, children: [ diff --git a/dashboard/frontend/src/service/api/www-sections.ts b/dashboard/frontend/src/service/api/www-sections.ts index df34ec6..eb32025 100644 --- a/dashboard/frontend/src/service/api/www-sections.ts +++ b/dashboard/frontend/src/service/api/www-sections.ts @@ -35,7 +35,7 @@ export function fetchDuplicateSection(id: number) { // ===== 参数分组 ===== export function fetchGetSpecGroups(sectionId: number) { - return request({ url: `/www/sections/${sectionId}/spec-groups`, method: 'get' }); + return request<{ items: Api.Www.SpecGroup[]; total: number }>({ url: `/www/sections/${sectionId}/spec-groups`, method: 'get' }); } export function fetchCreateSpecGroup(sectionId: number, data: { title_zh: string; title_en: string; default_visible?: number }) { @@ -56,7 +56,7 @@ export function fetchSortSpecGroups(sectionId: number, data: Array<{ id: number; // ===== 参数项 ===== export function fetchGetSpecItems(groupId: number) { - return request({ url: `/www/spec-groups/${groupId}/items`, method: 'get' }); + return request<{ items: Api.Www.SpecItem[]; total: number }>({ url: `/www/spec-groups/${groupId}/items`, method: 'get' }); } export function fetchCreateSpecItem(groupId: number, data: { name_zh: string; name_en: string; value_zh: string; value_en: string }) { diff --git a/dashboard/frontend/src/typings/api/www.d.ts b/dashboard/frontend/src/typings/api/www.d.ts index 0c4aa42..7123f4d 100644 --- a/dashboard/frontend/src/typings/api/www.d.ts +++ b/dashboard/frontend/src/typings/api/www.d.ts @@ -147,6 +147,8 @@ declare namespace Api { title_en: string; default_visible: number; sort_order: number; + /** GET spec-groups 列表接口内联返回的参数项 */ + items?: SpecItem[]; } interface SpecItem { diff --git a/dashboard/frontend/src/views/www/components/SectionManager.vue b/dashboard/frontend/src/views/www/components/SectionManager.vue index 6b05306..0ff7ed3 100644 --- a/dashboard/frontend/src/views/www/components/SectionManager.vue +++ b/dashboard/frontend/src/views/www/components/SectionManager.vue @@ -4,6 +4,7 @@ import { NButton, NSpace, NSwitch, NTag, type DataTableColumns, type FormInst, t import ColorInput from '../page/home/components/ColorInput.vue'; import MediaSelectInput from './MediaSelectInput.vue'; import RichTextEditor from './RichTextEditor.vue'; +import SpecManager from './SpecManager.vue'; import { fetchCreateSection, fetchDeleteSection, @@ -110,7 +111,7 @@ const formData = reactive({ media_url_en: '', video_url: '', is_visible: true, - config: { text_position: 'middle_left', width_percent: 100, container_width: '1200', border_radius: 0, padding_y: null, title_font_size: null, bg_fit: 'cover', media_position: 'left', mosaic_pattern: 'big_3', mosaic_items: emptyMosaicItems(4), min_height: null } as Record + config: { text_position: 'middle_left', width_percent: 100, container_width: '1200', border_radius: 0, padding_y: null, margin_y: null, title_font_size: null, bg_fit: 'cover', media_position: 'left', split_ratio: 50, mosaic_pattern: 'big_3', mosaic_items: emptyMosaicItems(4), min_height: null } as Record }); // 背景图/视频显示模式选项(bg_type 为图片/视频时生效) @@ -128,6 +129,20 @@ const containerWidthOptions = [ { label: '全宽', value: 'full' } ]; +// 图文分栏比例选项(值为素材栏宽占比);标签顺序随「媒体位置」联动: +// 素材在左 → 「素材 : 文案」,素材在右 → 「文案 : 素材」(与视觉左右顺序一致,底层存值不变) +const splitRatioOptions = computed(() => { + const mediaRight = formData.config.media_position === 'right'; + const label = (media: number) => (mediaRight ? `${100 - media} : ${media}` : `${media} : ${100 - media}`); + return [ + { label: `${label(30)}`, value: 30 }, + { label: `${label(40)}`, value: 40 }, + { label: `${label(50)}(默认)`, value: 50 }, + { label: `${label(60)}`, value: 60 }, + { label: `${label(70)}`, value: 70 } + ]; +}); + // ===== 马赛克拼贴(layout=mosaic):固定版式 + 槽位素材,存 config.mosaic_pattern / config.mosaic_items ===== interface MosaicItemForm { type: 'image' | 'video'; @@ -247,11 +262,15 @@ const columns = computed((): DataTableColumns => [ { title: '操作', key: 'actions', - width: 240, + width: 290, fixed: 'right', render(row) { return h('div', { class: 'flex-y-center gap-8px' }, [ h(NButton, { size: 'small', type: 'primary', onClick: () => handleEdit(row) }, { default: () => '编辑' }), + // spec_table 布局:管理参数分组与参数项 + row.layout === 'spec_table' + ? h(NButton, { size: 'small', type: 'info', onClick: () => handleSpecManage(row) }, { default: () => '参数' }) + : null, h(NButton, { size: 'small', onClick: () => handleCopy(row) }, { default: () => '复制' }), h(NButton, { size: 'small', type: 'error', onClick: () => handleDelete(row) }, { default: () => '删除' }) ]); @@ -315,7 +334,7 @@ function handleAdd() { formData.media_url_en = ''; formData.video_url = ''; formData.is_visible = true; - formData.config = { text_position: 'middle_left', width_percent: 100, container_width: '1200', border_radius: 0, padding_y: null, title_font_size: null, bg_fit: 'cover', media_position: 'left', mosaic_pattern: 'big_3', mosaic_items: emptyMosaicItems(4), min_height: null }; + formData.config = { text_position: 'middle_left', width_percent: 100, container_width: '1200', border_radius: 0, padding_y: null, margin_y: null, title_font_size: null, bg_fit: 'cover', media_position: 'left', split_ratio: 50, mosaic_pattern: 'big_3', mosaic_items: emptyMosaicItems(4), min_height: null }; dialogVisible.value = true; } @@ -356,9 +375,11 @@ function fillFormFromRow(row: Api.Www.SectionBlock) { container_width: ['1400', '1600', 'full'].includes(String(cfg.container_width)) ? String(cfg.container_width) : '1200', border_radius: typeof cfg.border_radius === 'number' && cfg.border_radius > 0 ? cfg.border_radius : 0, padding_y: typeof cfg.padding_y === 'number' && cfg.padding_y >= 0 ? cfg.padding_y : null, + margin_y: typeof cfg.margin_y === 'number' && cfg.margin_y >= 0 ? cfg.margin_y : null, title_font_size: typeof cfg.title_font_size === 'number' && cfg.title_font_size > 0 ? cfg.title_font_size : null, bg_fit: cfg.bg_fit === 'contain' || cfg.bg_fit === 'auto' ? cfg.bg_fit : 'cover', media_position: cfg.media_position === 'right' ? 'right' : 'left', + split_ratio: [30, 40, 50, 60, 70].includes(Number(cfg.split_ratio)) ? Number(cfg.split_ratio) : 50, min_height: typeof cfg.min_height === 'number' && cfg.min_height >= 0 ? cfg.min_height : null, mosaic_pattern: ['big_3', 'half_2', 'big_4', 'big_2'].includes(String(cfg.mosaic_pattern)) ? String(cfg.mosaic_pattern) : 'big_3' }; @@ -404,7 +425,14 @@ function handleDelete(row: Api.Www.SectionBlock) { }); } -async function handleSubmit() { +// 参数管理(spec_table 布局):唤起 SpecManager +const specManagerRef = ref | null>(null); + +function handleSpecManage(row: Api.Www.SectionBlock) { + specManagerRef.value?.open(row); +} + +async function handleSubmit(closeAfter = true) { submitLoading.value = true; const { id, ...payload } = formData; const reqData = { @@ -412,13 +440,15 @@ async function handleSubmit() { page_type: props.pageType, product_id: props.productId || null }; - const { error } = id + const { data, error } = id ? await fetchUpdateSection(id, reqData) : await fetchCreateSection(reqData); submitLoading.value = false; if (!error) { + // 「应用」新建后回填新 id,后续保存走更新接口,避免重复创建 + if (!id && data?.id) formData.id = data.id; window.$message?.success(id ? '更新成功' : '创建成功'); - dialogVisible.value = false; + if (closeAfter) dialogVisible.value = false; loadData(); } } @@ -447,6 +477,8 @@ onMounted(loadData); :title="dialogTitle" class="w-1000px" :mask-closable="false" + :segmented="{ content: true, footer: 'soft' }" + content-style="max-height: calc(85vh - 130px); overflow-y: auto;" > 基础配置 @@ -515,6 +547,23 @@ onMounted(loadData); 内容区与区块上下边缘的间距。留空 = 布局默认(多数 96px / 全幅横幅 120px / 主视觉分屏 64px);0 = 完全贴边 + +
+ + + + 区块与上下相邻区块之间的间隙,露出页面背景色;适合「区块宽度 < 100 + 圆角」的卡片式区块。留空/0 = 紧贴(默认) +
+
- 图片/视频在左 - 图片/视频在右 + 素材|文案 + 文案|素材 + +
+ + 按页面视觉左右顺序标注({{ formData.config.media_position === 'right' ? '文案 : 素材' : '素材 : 文案' }}),默认五五等分;移动端(小屏)始终单列堆叠不受影响 +
+
@@ -700,10 +759,14 @@ onMounted(loadData); + + +
diff --git a/dashboard/frontend/src/views/www/components/SpecManager.vue b/dashboard/frontend/src/views/www/components/SpecManager.vue new file mode 100644 index 0000000..b550363 --- /dev/null +++ b/dashboard/frontend/src/views/www/components/SpecManager.vue @@ -0,0 +1,306 @@ + + + diff --git a/db/migrations/x8_balanced_headphone_specs.sql b/db/migrations/x8_balanced_headphone_specs.sql new file mode 100644 index 0000000..551fe7d --- /dev/null +++ b/db/migrations/x8_balanced_headphone_specs.sql @@ -0,0 +1,9 @@ +-- 产品详情(product_id=1)参数区块「平衡耳机输出性能参数(4.4mm/XLR4输出)」参数项 +-- 区块:www_section_blocks.id=28(spec_table),分组已预建:gid=5 + +INSERT INTO www_spec_items (spec_group_id, name_zh, name_en, value_zh, value_en, sort_order) VALUES +(5, '高增益', 'High Gain', 'L+R≥4840mW+4840mW(16Ω, THD+N<1%)', 'L+R≥4840mW+4840mW (16Ω, THD+N < 1%)', 0), +(5, '输出阻抗', 'Output Impedance', '<1Ω', '< 1Ω', 1), +(5, '总谐波失真', 'THD+N', '<−117dB (1kHz/0dB@32Ω)', '< -117dB (1kHz / 0dB @ 32Ω)', 2), +(5, '信噪比', 'SNR', '≥123dB', '≥123dB', 3), +(5, '声道分离度', 'Crosstalk', '≥119dB (1kHz@32Ω)', '≥119dB (1kHz @ 32Ω)', 4); diff --git a/db/migrations/x8_basic_specs.sql b/db/migrations/x8_basic_specs.sql new file mode 100644 index 0000000..8fa38c9 --- /dev/null +++ b/db/migrations/x8_basic_specs.sql @@ -0,0 +1,20 @@ +-- 产品详情(product_id=1)参数区块「基本规格」补充参数项 +-- 区块:www_section_blocks.id=28(spec_table),分组:www_spec_groups.id=1(基本规格) +-- 已存在:型号 / 尺寸 / 重量(手工新增,sort_order 均为 0,此处一并规范化) + +-- 1) 规范化已有 3 项排序 +UPDATE www_spec_items SET sort_order = 0 WHERE id = 1; +UPDATE www_spec_items SET sort_order = 1 WHERE id = 2; +UPDATE www_spec_items SET sort_order = 2 WHERE id = 3; + +-- 2) 按图片补充剩余 9 项 +INSERT INTO www_spec_items (spec_group_id, name_zh, name_en, value_zh, value_en, sort_order) VALUES +(1, '电源输入', 'Input Power', 'AC 100–120V/220–240V~50/60Hz', 'AC 100-120V/220-240V~50/60Hz', 3), +(1, '屏幕', 'Display', '4英寸 LCD(480×960)触摸屏', '4" LCD (480*960) Touchscreen', 4), +(1, '解码', 'DAC', 'Cirrus Logic CS43198 × 8', 'Cirrus Logic CS43198 × 8', 5), +(1, '内部电源', 'Power Supply', '超低底噪可调电压线性电源', 'Ultra-low-noise, voltage-adjustable Linear Power Supply', 6), +(1, 'WiFi', 'WiFi', '支持2.4G/5G双频WiFi', 'Wi-Fi 2.4GHz / 5GHz', 7), +(1, '蓝牙接收', 'Bluetooth', 'Qualcomm SXW5125 (BT 5.1)', 'Qualcomm SXW5125 (BT 5.1)', 8), +(1, '控制方式', 'Control Methods', '触控屏, 移动设备 APP (Android/iOS), 电脑浏览器, 红外遥控器(选购配件)', 'Touchscreen, Mobile APP (Android/iOS), Web Browser, IR Remote(Optional)', 9), +(1, '额定功率', 'Rated Power', '25W', '25W', 10), +(1, '包装清单', 'Packing List', '电源线×1,USB-B线×1, 3.5mm转6.35mm适配器×1', 'Power Cable ×1, USB-B cable ×1, 3.5mm to 6.35mm adapter ×1', 11); diff --git a/db/migrations/x8_io_specs.sql b/db/migrations/x8_io_specs.sql new file mode 100644 index 0000000..1bb6a2a --- /dev/null +++ b/db/migrations/x8_io_specs.sql @@ -0,0 +1,15 @@ +-- 产品详情(product_id=1)参数区块「输入 / 输出」参数项 +-- 区块:www_section_blocks.id=28(spec_table),分组:www_spec_groups.id=2(输入 / 输出) + +INSERT INTO www_spec_items (spec_group_id, name_zh, name_en, value_zh, value_en, sort_order) VALUES +(2, 'USB-A 输入', 'USB-A Input', '用于本地固件更新', 'For local firmware update', 0), +(2, 'USB-B 输入', 'USB-B Input', '最高支持 PCM 768kHz/32bit; DSD512(Native)', 'Up to PCM 768kHz/32bit; DSD512(Native)', 1), +(2, 'USB-C 输入', 'USB-C Input', '最高支持 PCM 768kHz/32bit; DSD512(Native)', 'Up to PCM 768kHz/32bit; DSD512(Native)', 2), +(2, 'IIS 输入', 'IIS Input', '最高支持 PCM 768kHz/32bit; DSD512(Native)', 'Up to PCM 768kHz/32bit; DSD512(Native)', 3), +(2, '同轴输入', 'Coaxial Input', '最高支持 PCM 192kHz/24bit', 'Up to PCM 192kHz/24bit', 4), +(2, '光纤输入', 'Optical Input', '最高支持 PCM 192kHz/24bit', 'Up to PCM 192kHz/24bit', 5), +(2, 'TRIGGER IN', 'TRIGGER IN', '标准3.5mm耳机插座', 'Standard 3.5mm headphone jack', 6), +(2, 'TRIGGER OUT', 'TRIGGER OUT', '标准3.5mm耳机插座', 'Standard 3.5mm headphone jack', 7), +(2, '模拟输出接口', 'Analog Output', 'RCA', 'RCA', 8), +(2, '数字输出接口', 'Balanced Output', 'XLR', 'XLR', 9), +(2, '耳机输出接口', 'Headphone Output', '6.35mm(非平衡),4.4mm(平衡),4 pin XLR(平衡)', '6.35mm (Unbalanced), 4.4mm (Balanced), 4 pin XLR (Balanced)', 10); diff --git a/db/migrations/x8_rca_output_specs.sql b/db/migrations/x8_rca_output_specs.sql new file mode 100644 index 0000000..46c126f --- /dev/null +++ b/db/migrations/x8_rca_output_specs.sql @@ -0,0 +1,9 @@ +-- 产品详情(product_id=1)参数区块「RCA 输出音频特性」参数项 +-- 区块:www_section_blocks.id=28(spec_table),分组已预建:gid=4 + +INSERT INTO www_spec_items (spec_group_id, name_zh, name_en, value_zh, value_en, sort_order) VALUES +(4, '信噪比', 'SNR', '≥124.5dB', '≥124.5dB', 0), +(4, '总谐波失真', 'THD+N', '<−120dB @不加权', '< -120dB @ unweighted', 1), +(4, '声道分离度', 'Crosstalk', '≥125dB (1kHz@100kΩ)', '≥125dB (1kHz@100kΩ)', 2), +(4, '底噪', 'Noise Floor', '<1.3uVrms', '< 1.3uVrms', 3), +(4, '线路输出电平', 'Output Level', '2.1Vrms (1kHz@100kΩ)', '2.1Vrms (1kHz@100kΩ)', 4); diff --git a/db/migrations/x8_se_headphone_specs.sql b/db/migrations/x8_se_headphone_specs.sql new file mode 100644 index 0000000..30d3b82 --- /dev/null +++ b/db/migrations/x8_se_headphone_specs.sql @@ -0,0 +1,8 @@ +-- 产品详情(product_id=1)参数区块「单端耳机输出性能参数(6.35mm输出)」参数项 +-- 区块:www_section_blocks.id=28(spec_table),分组已预建:gid=6 + +INSERT INTO www_spec_items (spec_group_id, name_zh, name_en, value_zh, value_en, sort_order) VALUES +(6, '高增益', 'High Gain', 'L+R≥2900mW+2900mW(16Ω,THD+N<1%)', 'L+R≥2900mW+2900mW (16Ω, THD+N < 1%)', 0), +(6, '输出阻抗', 'Output Impedance', '<1Ω', '< 1Ω', 1), +(6, '总谐波失真', 'THD+N', '<−115dB (1kHz/0dB@32Ω)', '< -115dB (1kHz/0dB@32Ω)', 2), +(6, '信噪比', 'SNR', '≥121dB', '≥121dB', 3); diff --git a/db/migrations/x8_section_sort_fix.sql b/db/migrations/x8_section_sort_fix.sql new file mode 100644 index 0000000..5948323 --- /dev/null +++ b/db/migrations/x8_section_sort_fix.sql @@ -0,0 +1,11 @@ +-- Luxsin X8(product_id=1)区块排序修复 +-- 背景:所有区块 sort_order 均为 0,前台按 sort_order 排序导致顺序混乱。 +-- 已确认 www_section_blocks.id 为自增主键,按 id 升序(即创建顺序)重新分配 sort_order(0 起)。 +-- 同时后端 POST /api/www/sections 已改为:未指定 sort_order 时取同 page_type(+product_id) +-- 下现有区块的 max(sort_order)+1 自动追加,不再默认 0。 + +SET @row := -1; +UPDATE www_section_blocks +SET sort_order = (@row := @row + 1) +WHERE page_type = 'product_detail' AND product_id = 1 +ORDER BY id; diff --git a/db/migrations/x8_xlr_output_specs.sql b/db/migrations/x8_xlr_output_specs.sql new file mode 100644 index 0000000..b7a6bf1 --- /dev/null +++ b/db/migrations/x8_xlr_output_specs.sql @@ -0,0 +1,12 @@ +-- 产品详情(product_id=1)参数区块「XLR 输出音频特性」参数项 +-- 区块:www_section_blocks.id=28(spec_table) +-- 说明:分组「XLR 输出音频特性」已预先存在(gid=3),本脚本仅补参数项; +-- 执行中发现重复建组(gid=7)已清理:参数项改挂 gid=3,重复组已删除。 +-- 顺带规范了各分组 sort_order:基本规格=0、输入/输出=1、XLR=2、RCA=3、平衡耳机=4、单端耳机=5 + +INSERT INTO www_spec_items (spec_group_id, name_zh, name_en, value_zh, value_en, sort_order) VALUES +(3, '信噪比', 'SNR', '≥129.5dB', '≥129.5dB', 0), +(3, '总谐波失真', 'THD+N', '<−121.8dB @不加权', '< -121.8dB @ unweighted', 1), +(3, '声道分离度', 'Crosstalk', '≥133dB (1kHz@200kΩ)', '≥133dB (1kHz@200kΩ)', 2), +(3, '底噪', 'Noise Floor', '<1.1uVrms', '< 1.1uVrms', 3), +(3, '线路输出电平', 'Output Level', '4.2Vrms (1kHz@200kΩ)', '4.2Vrms (1kHz@200kΩ)', 4); diff --git a/tmp_home_check.png b/tmp_home_check.png new file mode 100644 index 0000000000000000000000000000000000000000..d8bd5b3c721247ba8e6529affb4ba43b5410821e GIT binary patch literal 40881 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 literal 0 HcmV?d00001 diff --git a/www/app/assets/css/main.css b/www/app/assets/css/main.css index cb69dbc..1c19697 100644 --- a/www/app/assets/css/main.css +++ b/www/app/assets/css/main.css @@ -4,6 +4,17 @@ html { -moz-osx-font-smoothing: grayscale; } +/* UnoCSS wind3 preflight 未含 Tailwind 标准的 border 重置:浏览器默认 border-style 为 none, + 导致 border-b / border 等宽度工具类不可见,此处补上(宽度默认 0,不影响未显式设置边框的元素) */ +*, +::before, +::after { + box-sizing: border-box; + border-width: 0; + border-style: solid; + border-color: currentColor; +} + body { margin: 0; font-family: diff --git a/www/app/components/section/SectionRenderer.vue b/www/app/components/section/SectionRenderer.vue index 0e35d8d..a355e9d 100644 --- a/www/app/components/section/SectionRenderer.vue +++ b/www/app/components/section/SectionRenderer.vue @@ -72,6 +72,13 @@ const paddingY = computed(() => { return typeof v === 'number' && v >= 0 ? `${v}px` : ''; }); +// 区块上下外边距(config.margin_y):单位 px,区块与相邻区块的间隙(露出页面背景); +// 未设置或 0 = 紧贴相邻区块(默认,全宽无缝拼接设计) +const marginY = computed(() => { + const v = props.section.config?.margin_y; + return typeof v === 'number' && v > 0 ? `${v}px` : ''; +}); + // 标题字号(config.title_font_size):桌面端 px,未设置时不下发变量(main.css 的 section h2 规则兜底 36px); // 移动端按桌面值 62.5% 等比缩小(--sec-title-fs-m) const titleFontSize = computed(() => { @@ -89,6 +96,7 @@ const sectionStyleVars = computed(() => { '--sec-cw': containerWidth, borderRadius: borderRadius.value, ...(paddingY.value ? { '--sec-py': paddingY.value } : {}), + ...(marginY.value ? { marginTop: marginY.value, marginBottom: marginY.value } : {}), ...(titleFontSize.value ? { '--sec-title-fs': titleFontSize.value.desktop, '--sec-title-fs-m': titleFontSize.value.mobile } : {}) } as CSSProperties; }); diff --git a/www/app/components/section/layouts/LayoutSpecTable.vue b/www/app/components/section/layouts/LayoutSpecTable.vue index 0e2e8e2..777e6e8 100644 --- a/www/app/components/section/layouts/LayoutSpecTable.vue +++ b/www/app/components/section/layouts/LayoutSpecTable.vue @@ -1,13 +1,14 @@