From 902faa70e73d87d9f1cc2c5876523cc302005f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E8=8E=AB=E5=94=90=E5=B0=BC?= Date: Thu, 3 Sep 2026 22:36:26 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E9=A1=B5=E9=80=BB=E8=BE=91=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=85=A8=E5=B1=80=E7=BB=84=E4=BB=B6=E4=B8=8E=E5=81=8F=E5=A5=BD?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 移除旧版启动页分流逻辑,直接跳转首页 2. 新增返回顶部、章节标题、导航栏等全局组件 3. 重构偏好设置系统,实现站点默认与本地差异分层管理 4. 删除冗余的测试mock、插件模块与样式文件 5. 优化文章卡片与评论组件样式,更新全局主题色 6. 清理废弃的请求参数与配置项 --- src/App.ku.vue | 5 +- src/api/halo.ts | 4 +- src/api/types/halo.ts | 41 +- src/api/types/uni-halo.ts | 17 +- src/api/uni-halo.ts | 9 - .../uh-article-card/uh-article-card.vue | 292 +--- .../uh-category-mini-card.vue | 54 - .../uh-comment-item/uh-comment-item.vue | 226 ++- .../uh-comment-list/uh-comment-list.vue | 348 +++-- .../uh-home-banner - 副本/uh-home-banner.vue | 269 ++++ .../uh-home-banner/uh-home-banner.vue | 132 ++ .../uh-home-category/uh-home-category.vue | 102 ++ .../uh-home-quick-nav/uh-home-quick-nav.vue | 88 ++ src/components/uh-navbar/uh-navbar.vue | 85 ++ .../uh-scroll-top/uh-scroll-top.vue | 22 + .../uh-section-title/uh-section-title.vue | 20 + src/components/uh-swiper/uh-swiper.vue | 421 ------ src/config/appConfig.ts | 4 - src/config/appSettings.ts | 13 - src/config/markdown.ts | 23 +- src/hooks/useDataLoadingStatus.ts | 4 +- src/http/interceptor.ts | 1 - src/http/types.ts | 1 - .../article-detail/article-detail.vue | 1252 ++++++++--------- .../moment-detail/moment-detail.vue | 41 +- src/pages-blog/setting/setting.vue | 490 ++++--- src/pages/index/index.vue | 40 +- src/pages/start/start.vue | 299 ---- src/pages/tabbar/about/about.vue | 9 + src/pages/tabbar/category/category.vue | 517 +++---- src/pages/tabbar/gallery/gallery.vue | 490 +++---- src/pages/tabbar/home/home.vue | 577 +++----- src/pages/tabbar/moments/moments.vue | 167 ++- src/store/appConfig.ts | 6 + src/store/setting.ts | 59 +- src/style/index.scss | 39 +- src/style/uni-components/audio.css | 12 - src/style/uni-components/video.css | 6 - src/test-mocks/pages.json | 10 - src/uni.scss | 75 +- src/uni_modules/liu-poster/changelog.md | 22 - .../components/liu-poster/liu-poster.vue | 377 ----- src/uni_modules/liu-poster/license.md | 6 - src/uni_modules/liu-poster/package.json | 100 -- src/uni_modules/liu-poster/readme.md | 260 ---- src/utils/page.ts | 5 +- src/utils/preference.test.ts | 193 +++ src/utils/preference.ts | 221 +++ uno.config.ts | 4 +- 49 files changed, 3170 insertions(+), 4288 deletions(-) delete mode 100644 src/components/uh-category-mini-card/uh-category-mini-card.vue create mode 100644 src/components/uh-home-banner - 副本/uh-home-banner.vue create mode 100644 src/components/uh-home-banner/uh-home-banner.vue create mode 100644 src/components/uh-home-category/uh-home-category.vue create mode 100644 src/components/uh-home-quick-nav/uh-home-quick-nav.vue create mode 100644 src/components/uh-navbar/uh-navbar.vue create mode 100644 src/components/uh-scroll-top/uh-scroll-top.vue create mode 100644 src/components/uh-section-title/uh-section-title.vue delete mode 100644 src/components/uh-swiper/uh-swiper.vue delete mode 100644 src/pages/start/start.vue delete mode 100644 src/style/uni-components/audio.css delete mode 100644 src/style/uni-components/video.css delete mode 100644 src/test-mocks/pages.json delete mode 100644 src/uni_modules/liu-poster/changelog.md delete mode 100644 src/uni_modules/liu-poster/components/liu-poster/liu-poster.vue delete mode 100644 src/uni_modules/liu-poster/license.md delete mode 100644 src/uni_modules/liu-poster/package.json delete mode 100644 src/uni_modules/liu-poster/readme.md create mode 100644 src/utils/preference.test.ts create mode 100644 src/utils/preference.ts diff --git a/src/App.ku.vue b/src/App.ku.vue index 5bf77d6..b7975fb 100644 --- a/src/App.ku.vue +++ b/src/App.ku.vue @@ -28,10 +28,7 @@ defineExpose({ \ No newline at end of file diff --git a/src/components/uh-comment-list/uh-comment-list.vue b/src/components/uh-comment-list/uh-comment-list.vue index ca1638b..ae2bfeb 100644 --- a/src/components/uh-comment-list/uh-comment-list.vue +++ b/src/components/uh-comment-list/uh-comment-list.vue @@ -1,206 +1,176 @@ + + + + + + \ No newline at end of file diff --git a/src/components/uh-home-banner - 副本/uh-home-banner.vue b/src/components/uh-home-banner - 副本/uh-home-banner.vue new file mode 100644 index 0000000..1988987 --- /dev/null +++ b/src/components/uh-home-banner - 副本/uh-home-banner.vue @@ -0,0 +1,269 @@ + + + \ No newline at end of file diff --git a/src/components/uh-home-banner/uh-home-banner.vue b/src/components/uh-home-banner/uh-home-banner.vue new file mode 100644 index 0000000..80b0ebf --- /dev/null +++ b/src/components/uh-home-banner/uh-home-banner.vue @@ -0,0 +1,132 @@ + + + \ No newline at end of file diff --git a/src/components/uh-home-category/uh-home-category.vue b/src/components/uh-home-category/uh-home-category.vue new file mode 100644 index 0000000..69ad8d1 --- /dev/null +++ b/src/components/uh-home-category/uh-home-category.vue @@ -0,0 +1,102 @@ + + + \ No newline at end of file diff --git a/src/components/uh-home-quick-nav/uh-home-quick-nav.vue b/src/components/uh-home-quick-nav/uh-home-quick-nav.vue new file mode 100644 index 0000000..5a10646 --- /dev/null +++ b/src/components/uh-home-quick-nav/uh-home-quick-nav.vue @@ -0,0 +1,88 @@ + + + \ No newline at end of file diff --git a/src/components/uh-navbar/uh-navbar.vue b/src/components/uh-navbar/uh-navbar.vue new file mode 100644 index 0000000..0130bb1 --- /dev/null +++ b/src/components/uh-navbar/uh-navbar.vue @@ -0,0 +1,85 @@ + + + \ No newline at end of file diff --git a/src/components/uh-scroll-top/uh-scroll-top.vue b/src/components/uh-scroll-top/uh-scroll-top.vue new file mode 100644 index 0000000..8306e6c --- /dev/null +++ b/src/components/uh-scroll-top/uh-scroll-top.vue @@ -0,0 +1,22 @@ + + + \ No newline at end of file diff --git a/src/components/uh-section-title/uh-section-title.vue b/src/components/uh-section-title/uh-section-title.vue new file mode 100644 index 0000000..eb23017 --- /dev/null +++ b/src/components/uh-section-title/uh-section-title.vue @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/src/components/uh-swiper/uh-swiper.vue b/src/components/uh-swiper/uh-swiper.vue deleted file mode 100644 index 7a031ac..0000000 --- a/src/components/uh-swiper/uh-swiper.vue +++ /dev/null @@ -1,421 +0,0 @@ - - - - - diff --git a/src/config/appConfig.ts b/src/config/appConfig.ts index d665a2f..8332e78 100644 --- a/src/config/appConfig.ts +++ b/src/config/appConfig.ts @@ -45,9 +45,5 @@ export const DefaultAppConfigs: IAppConfig = { }, auditConfig: { auditModeEnabled: false, - auditModeData: { - jsonUrl: '', - jsonData: '', - }, }, } diff --git a/src/config/appSettings.ts b/src/config/appSettings.ts index af06aa2..4ce32f8 100644 --- a/src/config/appSettings.ts +++ b/src/config/appSettings.ts @@ -3,8 +3,6 @@ */ export interface IAppSettings { - /** 是否每次启动都显示启动页 */ - showStartPage: boolean /** 评论头像是否圆形 */ isAvatarRadius: boolean banner: { @@ -25,12 +23,6 @@ export interface IAppSettings { /** 是否屏蔽广告 */ disabled: boolean } - /** 评论弹幕(文章详情) */ - barrage: { - use: boolean - /** 弹幕位置(rightToLeft / leftBottom) */ - type: string - } gallery: { /** 是否使用瀑布流 */ useWaterfull: boolean @@ -55,7 +47,6 @@ export interface IAppSettings { } export const DefaultAppSettings: IAppSettings = { - showStartPage: false, isAvatarRadius: false, banner: { useDot: true, @@ -69,10 +60,6 @@ export const DefaultAppSettings: IAppSettings = { timeout: 3, disabled: false, }, - barrage: { - use: false, - type: 'leftBottom', - }, gallery: { useWaterfull: true, }, diff --git a/src/config/markdown.ts b/src/config/markdown.ts index a92afb8..5985a22 100644 --- a/src/config/markdown.ts +++ b/src/config/markdown.ts @@ -5,6 +5,8 @@ */ import { checkImageUrl } from '@/utils/url' +const primaryColor = '#B9E424' + export const markdownConfig = { /** 图片域名前缀(mp-html 相对路径补全,源自旧配置 domain: BASE_API) */ domain: import.meta.env.VITE_SERVER_BASEURL || '', @@ -34,52 +36,55 @@ export const markdownConfig = { blockquote: ` padding: 8px 15px; color: #606266; - background: #f2f6fc; - border-left: 5px solid #50bfff; + background-color: rgb(255 255 255 / 55%); + backdrop-filter: blur(24rpx) saturate(160%); + -webkit-backdrop-filter: blur(24rpx) saturate(160%); + border-left: 5px solid ${primaryColor}; border-radius: 4px; line-height: 26px; margin-bottom: 18px; + box-shadow: 0 0px 12px rgba(0, 0, 0, 0.035); `, ul: 'padding-left: 15px;line-height: 1.85;', ol: 'padding-left: 15px;line-height: 1.85;', li: 'margin-bottom: 12px;line-height: 1.85;', h1: ` margin: 30px 0 20px; - color: var(--main); + color: ${primaryColor}; line-height: 24px; position: relative; font-size:1.2em; `, h2: ` - color: var(--main); + color: ${primaryColor}; line-height: 24px; position: relative; margin: 22px 0 16px; font-size: 1.16em; `, h3: ` - color: var(--main); + color: ${primaryColor}; line-height: 24px; position: relative; margin: 26px 0 18px; font-size: 1.14em; `, h4: ` - color: var(--main); + color: ${primaryColor}; line-height: 24px; margin-bottom: 18px; position: relative; font-size: 1.12em; `, h5: ` - color: var(--main); + color: ${primaryColor}; line-height: 24px; margin-bottom: 14px; position: relative; font-size: 1.1em; `, h6: ` - color: #303133; + color: ${primaryColor}; line-height: 24px; margin-bottom: 14px; position: relative; @@ -95,7 +100,7 @@ export const markdownConfig = { video: 'width: 100%', }, /** 容器样式 */ - containStyle: 'font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;padding:12px;font-size: 14px;color: #606266;word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 6px;background-color:#FFFFFF;', + containStyle: 'font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;padding:12px;font-size: 14px;color: #606266;word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 0px;background-color:transparent;', /** 加载图 / 空图(来自应用配置 imagesConfig) */ loadingGif: checkImageUrl(undefined), emptyGif: checkImageUrl(undefined), diff --git a/src/hooks/useDataLoadingStatus.ts b/src/hooks/useDataLoadingStatus.ts index eccfee2..ff5f8c5 100644 --- a/src/hooks/useDataLoadingStatus.ts +++ b/src/hooks/useDataLoadingStatus.ts @@ -5,8 +5,8 @@ export enum DataLoadingStatusEnum { Success = 'success', } -export function useDataLoadingStatus() { - const loadingStatus = ref(DataLoadingStatusEnum.Loading) +export function useDataLoadingStatus(status?:DataLoadingStatusEnum) { + const loadingStatus = ref(status??DataLoadingStatusEnum.Loading) function resetLoadingStatus() { loadingStatus.value = DataLoadingStatusEnum.Loading diff --git a/src/http/interceptor.ts b/src/http/interceptor.ts index 9ec7d3f..1e39b23 100644 --- a/src/http/interceptor.ts +++ b/src/http/interceptor.ts @@ -2,7 +2,6 @@ import type { CustomRequestOptions } from '@/http/types'; import { useTokenStore } from '@/store'; import { getEnvBaseUrl } from '@/utils'; import { stringifyQuery } from './tools/queryString'; -import qs from 'qs'; // 请求基准地址 const baseUrl = getEnvBaseUrl(); diff --git a/src/http/types.ts b/src/http/types.ts index 7096c34..690044a 100644 --- a/src/http/types.ts +++ b/src/http/types.ts @@ -3,7 +3,6 @@ */ export type CustomRequestOptions = UniApp.RequestOptions & { query?: Record - params?: Record /** 出错时是否隐藏错误提示 */ hideErrorToast?: boolean } & IUniUploadFileOptions // 添加uni.uploadFile参数类型 diff --git a/src/pages-blog/article-detail/article-detail.vue b/src/pages-blog/article-detail/article-detail.vue index 9669270..661d2ce 100644 --- a/src/pages-blog/article-detail/article-detail.vue +++ b/src/pages-blog/article-detail/article-detail.vue @@ -1,740 +1,626 @@ + + + + + + + - + + + + \ No newline at end of file diff --git a/src/pages-blog/moment-detail/moment-detail.vue b/src/pages-blog/moment-detail/moment-detail.vue index af217d1..7821709 100644 --- a/src/pages-blog/moment-detail/moment-detail.vue +++ b/src/pages-blog/moment-detail/moment-detail.vue @@ -35,7 +35,11 @@ const bloggerInfo = computed(() => { const calcUseTagRandomColor = computed(() => !!haloConfigs.value.pageConfig?.momentConfig?.useTagRandomColor) -const startConfig = computed(() => haloConfigs.value.appConfig?.startConfig as { title?: string } | undefined) +/** 站点名称(原 startConfig.title 已随启动页下线,改读 appConfig.appInfo.name) */ +const siteName = computed(() => { + const appInfo = haloConfigs.value.appConfig?.appInfo as { name?: string } | undefined + return appInfo?.name || bloggerInfo.value.nickname || 'uni-halo' +}) /* ---------------- 状态 ---------------- */ const loading = ref<'loading' | 'success' | 'error'>('loading') @@ -73,16 +77,18 @@ async function handleGetData() { const res = await getMomentByName(queryName.value) uni.setNavigationBarTitle({ title: '瞬间详情' }) - const medium = (res.data.spec as unknown as { medium?: { type?: string, url: string }[] }).medium || [] + const medium = (res.data.spec.content?.medium || []) + .map(x => ({ ...x, url: x.url || '' })) + const owner = res.data.owner const tempResult = { ...res.data, + // 无顶层 owner(如个别历史接口)时兜底为博主信息 + owner: owner?.displayName + ? owner + : { displayName: bloggerInfo.value.nickname || '', name: bloggerInfo.value.nickname || '', avatar: bloggerInfo.value.avatar }, spec: { ...res.data.spec, - owner: { - displayName: bloggerInfo.value.nickname, - avatar: bloggerInfo.value.avatar, - }, - newHtml: removeTagLinksCompletely((res.data.spec as unknown as { content?: { html?: string } }).content?.html || ''), + newHtml: removeTagLinksCompletely(res.data.spec.content?.html || ''), }, images: medium.filter(x => x.type === 'PHOTO').map(x => ({ ...x, url: checkThumbnailUrl(x.url, true) })), videos: medium.filter(x => x.type === 'VIDEO').map(x => ({ ...x, id: generateUUID() })), @@ -170,11 +176,11 @@ onPullDownRefresh(() => { onShareAppMessage(() => ({ path: `/pages-blog/moment-detail/moment-detail?name=${moment.value?.metadata.name}`, - title: moment.value?.spec.owner?.displayName || '', + title: moment.value?.owner?.displayName || '', })) onShareTimeline(() => ({ - title: moment.value?.spec.owner?.displayName || '', + title: moment.value?.owner?.displayName || '', query: moment.value ? `name=${moment.value.metadata.name}` : '', })) @@ -189,14 +195,25 @@ onShareTimeline(() => ({ - + - {{ moment.spec.owner?.displayName || bloggerInfo.nickname }} + {{ moment.owner?.displayName || bloggerInfo.nickname }} {{ formatTime(moment.spec.releaseTime) }} + + + + + {{ moment.stats.upvote || 0 }} + + + + {{ moment.stats.totalComment || 0 }} + + @@ -255,7 +272,7 @@ onShareTimeline(() => ({ :key="audio.url" :src="audio.url" :poster="bloggerInfo.avatar" - :name="`来自${startConfig?.title || bloggerInfo.nickname}的声音`" + :name="`来自${siteName}的声音`" :author="bloggerInfo.nickname" /> diff --git a/src/pages-blog/setting/setting.vue b/src/pages-blog/setting/setting.vue index 443ba51..42bbf5a 100644 --- a/src/pages-blog/setting/setting.vue +++ b/src/pages-blog/setting/setting.vue @@ -1,260 +1,338 @@ diff --git a/src/pages/tabbar/about/about.vue b/src/pages/tabbar/about/about.vue index 521675c..2896028 100644 --- a/src/pages/tabbar/about/about.vue +++ b/src/pages/tabbar/about/about.vue @@ -159,6 +159,15 @@ async function handleGetNavList() { path: '/pages-blog/about/about', show: !!basicConfig.value?.showAboutSystem, }, + { + key: 'setting', + title: '偏好设置', + icon: 'settings', + iconColor: '#03a9f4', + rightText: '首页布局、卡片样式等本地偏好', + path: '/pages-blog/setting/setting', + show: true, + }, ] } diff --git a/src/pages/tabbar/category/category.vue b/src/pages/tabbar/category/category.vue index 2a3728f..e57f189 100644 --- a/src/pages/tabbar/category/category.vue +++ b/src/pages/tabbar/category/category.vue @@ -1,384 +1,183 @@ - - diff --git a/src/pages/tabbar/gallery/gallery.vue b/src/pages/tabbar/gallery/gallery.vue index 697ea0c..f0f41bb 100644 --- a/src/pages/tabbar/gallery/gallery.vue +++ b/src/pages/tabbar/gallery/gallery.vue @@ -1,292 +1,250 @@ + + \ No newline at end of file diff --git a/src/pages/tabbar/home/home.vue b/src/pages/tabbar/home/home.vue index b11b461..284f6a5 100644 --- a/src/pages/tabbar/home/home.vue +++ b/src/pages/tabbar/home/home.vue @@ -1,419 +1,228 @@ + + + 最新内容 + + + + + + + + + + + + {{ loadMoreText }} + + + + + + + + \ No newline at end of file diff --git a/src/pages/tabbar/moments/moments.vue b/src/pages/tabbar/moments/moments.vue index e89d88c..5f57c3e 100644 --- a/src/pages/tabbar/moments/moments.vue +++ b/src/pages/tabbar/moments/moments.vue @@ -20,6 +20,8 @@ definePage({ style: { navigationBarTitleText: '瞬间', enablePullDownRefresh: true, + // 玻璃拟态试验:下拉/回弹露出的窗口底色对齐壁纸底部色调 + backgroundColor: '#f4efff', }, }) @@ -36,7 +38,11 @@ const bloggerInfo = computed(() => { } }) -const startConfig = computed(() => haloConfigs.value.appConfig?.startConfig as { title?: string } | undefined) +/** 站点名称(原 startConfig.title 已随启动页下线,改读 appConfig.appInfo.name) */ +const siteName = computed(() => { + const appInfo = haloConfigs.value.appConfig?.appInfo as { name?: string } | undefined + return appInfo?.name || bloggerInfo.value.nickname || 'uni-halo' +}) /** 依赖插件(plugin-moments) */ const uniHaloPluginId = 'plugin-moments' @@ -46,7 +52,14 @@ const uniHaloPluginAvailable = ref(true) const loading = ref<'loading' | 'success' | 'error'>('loading') const queryParams = ref({ size: 10, page: 1 }) const hasNext = ref(false) -const dataList = ref<(IMoment & { images?: { type?: string, url: string }[], videos?: { id?: string, url: string }[], audios?: { type?: string, url: string }[], spec: { newHtml?: string } })[]>([]) +/** 列表卡片:medium 已按类型拆为 images/videos/audios + 正文 tag 清理 */ +type MomentCard = IMoment & { + images?: { type?: string, url: string }[] + videos?: { id?: string, url: string }[] + audios?: { type?: string, url: string }[] + spec: IMoment['spec'] & { newHtml?: string } +} +const dataList = ref([]) const isLoadMore = ref(false) const loadMoreText = ref(t('common.loading')) const videoContexts = ref>({}) @@ -58,18 +71,20 @@ function removeTagLinksCompletely(htmlString: string): string { return htmlString.replace(regex, '') } -/** 瞬间项映射(medium 拆分为 images/videos/audios + 内容 tag 清理) */ -function mapMomentItem(item: IMoment) { - const medium = (item.spec as unknown as { medium?: { type?: string, url: string }[] }).medium || [] +/** 瞬间项映射(spec.content.medium 拆分为 images/videos/audios + 内容 tag 清理 + 作者兜底) */ +function mapMomentItem(item: IMoment): MomentCard { + const medium = (item.spec.content?.medium || []) + .map(x => ({ ...x, url: x.url || '' })) + const owner = item.owner return { ...item, + // 无顶层 owner(如个别历史接口)时兜底为博主信息 + owner: owner?.displayName + ? owner + : { displayName: bloggerInfo.value.nickname || '', name: bloggerInfo.value.nickname || '', avatar: bloggerInfo.value.avatar }, spec: { ...item.spec, - owner: { - displayName: bloggerInfo.value.nickname, - avatar: bloggerInfo.value.avatar, - }, - newHtml: removeTagLinksCompletely((item.spec as unknown as { content?: { html?: string } }).content?.html || ''), + newHtml: removeTagLinksCompletely(item.spec.content?.html || ''), }, images: medium.filter(x => x.type === 'PHOTO').map(x => ({ ...x, url: checkThumbnailUrl(x.url, true) })), videos: medium.filter(x => x.type === 'VIDEO').map(x => ({ ...x, id: generateUUID() })), @@ -251,7 +266,15 @@ onReachBottom(() => { + + diff --git a/src/store/appConfig.ts b/src/store/appConfig.ts index 6b65d0a..3a919e3 100644 --- a/src/store/appConfig.ts +++ b/src/store/appConfig.ts @@ -12,6 +12,8 @@ import type { IAppConfig, IAuditDataResult } from '@/api/types/uni-halo' /** 个人令牌存储 key(与 src/store/token.ts 的 getPersonalToken 保持一致) */ const APP_TOKENS_KEY = 'APP_TOKENS' +/** 合并后配置缓存 key(与 utils/url.ts / api/uni-halo.ts 的 APP_GLOBAL_CONFIGS 读取保持一致) */ +const APP_GLOBAL_CONFIGS_KEY = 'APP_GLOBAL_CONFIGS' export const useAppConfigStore = defineStore( 'appConfig', @@ -36,6 +38,10 @@ export const useAppConfigStore = defineStore( if (body) { configs.value = deepMerge(JSON.parse(JSON.stringify(DefaultAppConfigs)), body) + // 合并结果写入 APP_GLOBAL_CONFIGS 缓存,供 utils/url.ts 图片兜底与 + // api/uni-halo.ts 第三方插件授权头等按 storage 路径读取 + setCache(APP_GLOBAL_CONFIGS_KEY, configs.value) + // 存储个人令牌(供 getPersonalToken 使用,如非匿名投票) if (body?.basicConfig?.tokenConfig) { setCache(APP_TOKENS_KEY, body.basicConfig.tokenConfig) diff --git a/src/store/setting.ts b/src/store/setting.ts index 7d613ec..3b434c5 100644 --- a/src/store/setting.ts +++ b/src/store/setting.ts @@ -1,23 +1,68 @@ /** - * 应用设置 store(源自旧项目 store/setting.js) + * 应用设置 store(两层偏好:站点默认 L0 + 本地差异 L1-L) + * + * - settings:合并结果缓存(= L0 站点默认 + 本地差异,本地优先),persist 持久化供离线兜底; + * - applySiteDefaults(site):启动 fetchConfigs 后把 getConfigs 收集的 L0 与本地差异合并(含旧数据迁移); + * - savePreference(patch):写本地差异(uh_pref_local_v1)并立即重合并; + * - resetPreferences:清本地差异,立即回退「站点默认」(无 L0 时回退内置默认)。 + * + * 设计依据:插件仓库 .docs/config-system-v2-redesign.md §3-4(v2.2:远端=站点默认,无用户级远端层)。 */ import { defineStore } from 'pinia' import { ref } from 'vue' import { DefaultAppSettings } from '@/config/appSettings' import type { IAppSettings } from '@/config/appSettings' +import { + clearLocalPrefs, + mergeWithDefaults, + migrateLegacyLocalPrefs, + readLocalPrefs, + updateLocalPrefs, +} from '@/utils/preference' +import type { LocalPrefs } from '@/utils/preference' export const useSettingStore = defineStore( 'setting', () => { + /** 合并结果缓存(站点默认 + 本地差异;页面消费点不变) */ const settings = ref(JSON.parse(JSON.stringify(DefaultAppSettings))) + /** 最近一次站点默认(L0,collectSiteDefaults 结果),非持久化 */ + const siteDefaults = ref(null) - /** 重置为默认设置 */ - const updateDefaultAppSettings = () => { - settings.value = JSON.parse(JSON.stringify(DefaultAppSettings)) + /** 重算合并结果(统一出口:写 settings 缓存) */ + function recompute(): void { + settings.value = mergeWithDefaults(siteDefaults.value, readLocalPrefs()) + } + + /** + * 应用站点默认并合并本地差异(启动 fetchConfigs 成功后调用;site 为 null/空时仅本地差异覆盖内置默认) + * 首次运行时顺带迁移旧版全量 persist(见 utils/preference.migrateLegacyLocalPrefs) + */ + const applySiteDefaults = (site: LocalPrefs | null): void => { + siteDefaults.value = site && typeof site === 'object' ? site : null + migrateLegacyLocalPrefs() + recompute() + } + + /** 保存偏好:写本地差异并立即重合并(改偏好即时生效) */ + const savePreference = (patch: LocalPrefs): void => { + updateLocalPrefs(patch) + recompute() + } + + /** 重置为站点默认:清本地差异(重置=删除本地,回退 getConfigs 下发值) */ + const resetPreferences = (): void => { + clearLocalPrefs() + recompute() + } + + /** 兼容旧调用点:恢复默认(新语义=重置回站点默认) */ + const updateDefaultAppSettings = (): void => { + resetPreferences() } /** 检查并设置默认设置(启动时调用,persist 已保证有值,兜底处理) */ - const checkAndSetDefaultAppSettings = () => { + const checkAndSetDefaultAppSettings = (): void => { if (!settings.value) { settings.value = JSON.parse(JSON.stringify(DefaultAppSettings)) } @@ -25,6 +70,10 @@ export const useSettingStore = defineStore( return { settings, + siteDefaults, + applySiteDefaults, + savePreference, + resetPreferences, updateDefaultAppSettings, checkAndSetDefaultAppSettings, } diff --git a/src/style/index.scss b/src/style/index.scss index 1ee7de9..bf44221 100644 --- a/src/style/index.scss +++ b/src/style/index.scss @@ -1,21 +1,34 @@ // 测试用的 iconfont,可生效 -// @import './iconfont.css'; - -.test { - // 可以通过 @apply 多个样式封装整体样式 - @apply mt-4 ml-4; - - padding-top: 4px; - color: red; -} +@import './iconfont.css'; :root, page { - // 修改按主题色 - // --wot-color-theme: #37c2bc; + // 修改按主题色 + --wot-color-theme: #B9E424; - // 修改按钮背景色 - // --wot-button-primary-bg-color: green; + // 修改按钮背景色 + --wot-button-primary-bg-color: #B9E424; +} + +.uh-global-page { +} + +.uh-global-card-glass { + box-sizing: border-box; + background-color: rgb(255 255 255 / 55%); + border: 4rpx solid rgb(255 255 255 / 65%); + box-shadow: inset 0 1rpx 0 rgb(255 255 255 / 75%), 0 8rpx 32rpx rgb(90 105 200 / 14%); + backdrop-filter: blur(24rpx) saturate(160%); + -webkit-backdrop-filter: blur(24rpx) saturate(160%); + + /* 低端安卓 WebView 不支持 backdrop-filter 的兜底:提高不透明度保证可读性 */ + @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { + background-color: rgb(255 255 255 / 88%); + } +} + +.uh-shadow-xs { + box-shadow: inset 0 1rpx 0 rgb(255 255 255 / 75%), 0 8rpx 32rpx rgb(90 105 200 / 7%); } /* diff --git a/src/style/uni-components/audio.css b/src/style/uni-components/audio.css deleted file mode 100644 index 0579b65..0000000 --- a/src/style/uni-components/audio.css +++ /dev/null @@ -1,12 +0,0 @@ -/** - * audio 组件默认样式补件 - * 说明:@dcloudio/uni-components 3.0.0-4070620250821001 的 style/ 目录未提供 audio.css, - * vite 编译