1
0
mirror of https://github.com/ialley-workshop-open/uni-halo.git synced 2026-09-12 16:40:40 +08:00

feat: 实现全站布局偏好系统,支持多页面独立配置

本次提交完成了完整的偏好设置体系重构:
1. 新增preferences.md文档说明布局偏好设计与映射规则
2. 重构布局配置结构,按页面分组管理列表布局与卡片样式
3. 实现后端preferences字段到本地配置的自动映射转换
4. 完成首页、文章列表、归档页的布局动态切换逻辑
5. 重构投票组件样式绑定,改用unocss类名实现样式分离
6. 新增偏好设置页面,支持按页面配置布局参数
7. 兼容旧版布局参数的自动归一化转换
8. 补充完整的单元测试用例覆盖新旧数据迁移场景
This commit is contained in:
小莫唐尼
2026-09-09 14:48:55 +08:00
parent 004bac175e
commit beaf2c39ca
15 changed files with 319 additions and 135 deletions
+88 -58
View File
@@ -56,36 +56,49 @@
siteLabelOf ?: (value : string) => string
}
const layoutPrefs : PrefDef[] = [
{
key: 'home',
label: '首页文章布局',
kind: 'enum',
path: ['layout', 'home'],
options: [
{ label: '一行一列', value: 'h_row_col1' },
{ label: '一行两列', value: 'h_row_col2' },
],
},
{
key: 'cardType',
label: '文章卡片样式',
kind: 'enum',
path: ['layout', 'cardType'],
options: [
{ label: '左图右文', value: 'lr_image_text' },
{ label: '左文右图', value: 'lr_text_image' },
{ label: '上图下文', value: 'tb_image_text' },
{ label: '上文下图', value: 'tb_text_image' },
{ label: '只有文字', value: 'only_text' },
],
},
/** 布局设置按页面分组(每组:列表布局 + 卡片样式) */
const PAGE_GROUPS = [
{ key: 'home', label: '首页' },
{ key: 'articles', label: '文章列表' },
{ key: 'archives', label: '文章归档' },
]
const layoutPrefs : PrefDef[] = PAGE_GROUPS.flatMap(group => [
{
key: `${group.key}ListLayout`,
label: '列表布局',
kind: 'enum',
path: ['layout', group.key, 'listLayout'],
options: [
{ label: '单列', value: 'single' },
{ label: '双列', value: 'double' },
],
},
{
key: `${group.key}CardType`,
label: '卡片样式',
kind: 'enum',
path: ['layout', group.key, 'cardType'],
options: [
{ label: '上图下文', value: 'image_top' },
{ label: '左文右图', value: 'image_right' },
{ label: '上文下图', value: 'image_bottom' },
{ label: '左图右文', value: 'image_left' },
],
},
])
const featurePrefs : PrefDef[] = [
{ key: 'isAvatarRadius', label: '是否圆形头像', kind: 'bool', path: ['isAvatarRadius'] },
]
/* ---------------- 顶部分段器(布局 / 功能) ---------------- */
const settingTabs : { key : 'layout' | 'feature', label : string }[] = [
{ key: 'layout', label: '布局' },
{ key: 'feature', label: '功能' },
]
const activeTab = ref<'layout' | 'feature'>('layout')
/* ---------------- 状态读取 ---------------- */
function prefValueOf(path : Path) : unknown {
return getByPath(settingStore.settings, path)
@@ -216,6 +229,13 @@
const layoutRows = computed(() => buildRows(layoutPrefs))
const featureRows = computed(() => buildRows(featurePrefs))
/** 布局设置按页面分组的展示行 */
const layoutGroups = computed(() => PAGE_GROUPS.map(group => ({
key: group.key,
label: group.label,
rows: layoutRows.value.filter(row => row.path[1] === group.key),
})))
/* ---------------- 重置全部 ---------------- */
function handleResetAll() {
uni.showModal({
@@ -243,45 +263,54 @@
<!-- 内容区域 -->
<view class="box-border flex flex-col gap-y-6 p-3">
<!-- 布局设置 -->
<view class="flex flex-col gap-y-3">
<uh-section-title>
布局
<template #right>
<text class="text-2xs text-gray-400">应用以及文章列表布局设置</text>
</template>
</uh-section-title>
<view class="uh-global-card-glass overflow-hidden rounded-2xl">
<view v-for="(row, index) in layoutRows" :key="row.key"
class="pick-row flex items-center justify-between px-4 py-4"
:class="index < layoutRows.length - 1 ? 'border-b border-black/5' : ''"
@click="handleOpenEnum(row)">
<view class="row-left flex flex-col gap-1">
<text class="row-label text-[28rpx] text-gray-900 font-bold">{{ row.label }}</text>
<view class="flex items-center gap-2">
<text v-if="row.following" class="row-sub text-2xs text-gray-400">跟随站点默认</text>
<view v-else
class="rounded-full bg-secondary px-2 py-0.5 text-[20rpx] text-[#4d7c0f] leading-none">
已自定义
<!-- 顶部分段器:布局 / 功能 -->
<view class="uh-global-card-glass flex rounded-full p-1">
<view v-for="tab in settingTabs" :key="tab.key"
class="flex-1 rounded-full py-1.5 text-center text-sm"
:class="activeTab === tab.key ? 'bg-primary font-bold' : 'text-gray-500'"
@click="activeTab = tab.key">
{{ tab.label }}
</view>
</view>
<!-- 布局:按页面分组(首页/文章列表/文章归档 × 列表布局/卡片样式) -->
<template v-if="activeTab === 'layout'">
<view v-for="group in layoutGroups" :key="group.key" class="flex flex-col gap-y-3">
<uh-section-title>{{ group.label }}</uh-section-title>
<view class="uh-global-card-glass overflow-hidden rounded-2xl">
<view v-for="(row, index) in group.rows" :key="row.key"
class="pick-row flex items-center justify-between px-4 py-4"
:class="index < group.rows.length - 1 ? 'border-b border-black/5' : ''"
@click="handleOpenEnum(row)">
<view class="row-left flex flex-col gap-1">
<text class="row-label text-[28rpx] text-gray-900 font-bold">{{ row.label }}</text>
<view class="flex items-center gap-2">
<text v-if="row.following" class="row-sub text-2xs text-gray-400">跟随站点默认</text>
<view v-else
class="rounded-full bg-secondary px-2 py-0.5 text-[20rpx] text-[#4d7c0f] leading-none">
已自定义
</view>
</view>
</view>
</view>
<view class="row-value flex items-center gap-2">
<text class="value-text text-[26rpx] text-gray-400">{{ row.displayValue }}</text>
<wd-icon name="arrow-right" size="12px" color="#c8c2b4" />
<view class="row-value flex items-center gap-2">
<text class="value-text text-[26rpx] text-gray-400">{{ row.displayValue }}</text>
<wd-icon name="arrow-right" size="12px" color="#c8c2b4" />
</view>
</view>
</view>
</view>
</view>
</template>
<!-- 功能设置 -->
<view class="flex flex-col gap-y-3">
<uh-section-title>
功能
<template #right>
<text class="text-2xs text-gray-400">一些常用的功能性设置</text>
</template>
</uh-section-title>
<view class="setting-sheet uh-global-card-glass overflow-hidden rounded-2xl">
<template v-else>
<view class="flex flex-col gap-y-3">
<uh-section-title>
功能
<template #right>
<text class="text-2xs text-gray-400">一些常用的功能性设置</text>
</template>
</uh-section-title>
<view class="setting-sheet uh-global-card-glass overflow-hidden rounded-2xl">
<template v-for="(row, index) in featureRows" :key="row.key">
<!-- 布尔开关 -->
<view v-if="row.kind === 'bool'" class="switch-row flex items-center justify-between px-4 py-4"
@@ -332,7 +361,8 @@
</template>
</view>
</view>
<!-- 底部操作栏-->
</template>
<!-- 底部操作栏-->
<view class="box-border w-full">
<uh-button custom-class="uh-global-card-glass py-2 !rounded-xl" @click="handleResetAll">
恢复默认