From 004bac175eea3bb0c55ae19a88904a87b1d5ead9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E8=8E=AB=E5=94=90=E5=B0=BC?= Date: Wed, 9 Sep 2026 13:22:50 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E6=8A=95?= =?UTF-8?q?=E7=A5=A8=E7=9B=B8=E5=85=B3=E7=BB=84=E4=BB=B6=E4=B8=8E=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E4=BB=A3=E7=A0=81=E6=A0=BC=E5=BC=8F=E4=B8=8E=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 统一uh-article-vote与uh-article-vote-item组件代码缩进与格式 2. 更新投票提示文案与文章卡片样式适配 3. 规范vote.ts工具类代码格式与分号使用 4. 调整文章卡片布局与置顶样式 --- .../uh-article-card/uh-article-card.vue | 60 +- .../uh-article-vote-item.vue | 758 +++++++++--------- .../uh-article-vote/uh-article-vote.vue | 80 +- src/utils/vote.ts | 124 +-- 4 files changed, 509 insertions(+), 513 deletions(-) diff --git a/src/components/uh-article-card/uh-article-card.vue b/src/components/uh-article-card/uh-article-card.vue index e8471d0..d7a862e 100644 --- a/src/components/uh-article-card/uh-article-card.vue +++ b/src/components/uh-article-card/uh-article-card.vue @@ -13,9 +13,13 @@ contentWrapper: string footer: string authorGroup: string + avatar: string + nickname: string + infoCol: string time: string tagCategory: string visits: string + pinned: string } /** 旧版全局 cardType → 新版 layout;未知值(如 only_text)由 effectiveLayout 兜底 image_top */ @@ -34,19 +38,27 @@ contentWrapper: 'w-full', footer: 'flex items-center', authorGroup: 'flex-1 items-center justify-start gap-x-1', + avatar: '', + nickname: '', + infoCol: 'items-center gap-x-1', time: 'flex-1 text-center', tagCategory: '', visits: 'flex-1 justify-end', + pinned: 'right-4 top-4', }, image_bottom: { container: 'flex flex-col gap-y-2', cover: 'order-2', contentWrapper: 'w-full', - footer: 'flex items-center', - authorGroup: 'flex-1 items-center justify-center gap-x-1', - time: 'flex-1 text-center', + footer: 'order-first flex items-center mb-1', + authorGroup: 'items-center gap-x-2', + avatar: '!h-9 !w-9 !rounded-xl', + nickname: '!text-sm', + infoCol: 'flex-col items-start leading-tight', + time: '', tagCategory: '', - visits: 'flex-1 justify-center', + visits: '', + pinned: 'right-3 top-3', }, image_left: { container: 'flex gap-x-3 !p-2', @@ -54,9 +66,13 @@ contentWrapper: 'w-0 flex-1 justify-between', footer: 'flex items-center justify-between', authorGroup: 'items-center gap-x-1', + avatar: '', + nickname: '', + infoCol: 'items-center gap-x-1', time: '!hidden', tagCategory: '!hidden', visits: '', + pinned: 'left-3 top-3', }, image_right: { container: 'flex gap-x-3 !p-2', @@ -64,9 +80,13 @@ contentWrapper: 'order-1 w-0 flex-1 justify-between', footer: 'flex items-center justify-between', authorGroup: 'items-center gap-x-1', + avatar: '', + nickname: '', + infoCol: 'items-center gap-x-1', time: '!hidden', tagCategory: '!hidden', visits: '', + pinned: 'right-3 top-3', }, } @@ -104,6 +124,9 @@ const cardLayout = computed(() => CARD_LAYOUTS[effectiveLayout.value]) + /** 社交卡片形态(封面在下):左上用户信息(头像 + 昵称/日期垂直)、右上浏览数 */ + const isSocialCard = computed(() => effectiveLayout.value === 'image_bottom') + const publishTimeText = computed(() => { const time = props.article.spec.publishTime return time ? formatTime({ d: time, f: 'yyyy/MM/dd' }) : '' @@ -137,7 +160,8 @@ + class="box-border uh-global-card-glass border text-gray-900 absolute z-1 rounded-md bg-secondary px-1.5 py-0.5 text-xs" + :class="cardLayout.pinned"> 置顶 @@ -166,11 +190,25 @@ - {{ article.owner.displayName }} + :class="cardLayout.avatar" mode="aspectFill" /> + + {{ article.owner.displayName }} - {{ publishTimeText }} - + {{ publishTimeText }} + 浏览 {{ visitCount }} 次 diff --git a/src/components/uh-article-vote-item/uh-article-vote-item.vue b/src/components/uh-article-vote-item/uh-article-vote-item.vue index 5e0f3f5..ab3f8cc 100644 --- a/src/components/uh-article-vote-item/uh-article-vote-item.vue +++ b/src/components/uh-article-vote-item/uh-article-vote-item.vue @@ -1,435 +1,397 @@ + .is-voted-item { + &::before { + content: ''; + width: var(--percent); + position: absolute; + left: 0; + top: 0; + bottom: 0; + background-color: #d0d0d0; + z-index: 0; + border-radius: 6rpx; + } + } + \ No newline at end of file diff --git a/src/components/uh-article-vote/uh-article-vote.vue b/src/components/uh-article-vote/uh-article-vote.vue index a3309b9..c6eba28 100644 --- a/src/components/uh-article-vote/uh-article-vote.vue +++ b/src/components/uh-article-vote/uh-article-vote.vue @@ -1,54 +1,46 @@ + + 投票已收起,点击展开 {{ voteIds.length }} 个投票项 + + + + \ No newline at end of file diff --git a/src/utils/vote.ts b/src/utils/vote.ts index a84dda9..ec69535 100644 --- a/src/utils/vote.ts +++ b/src/utils/vote.ts @@ -2,46 +2,46 @@ * 投票工具(源自旧项目 utils/vote.js,按需命名导出) * 投票状态计算、UID 缓存、投票周期判断 */ -import { getCache, setCache } from './storage' +import { getCache, setCache } from './storage'; /** 投票 UID 缓存 key */ -const UnihaloVoteUid = 'unihalo_vote_uid' +const UnihaloVoteUid = 'unihalo_vote_uid'; -export type VoteType = 'single' | 'multiple' | 'pk' -export type VoteState = 'not-voted' | 'voting' | 'voted' | 'vote-ended' +export type VoteType = 'single' | 'multiple' | 'pk'; +export type VoteState = 'not-voted' | 'voting' | 'voted' | 'vote-ended'; /** 投票类型中文映射(与旧项目一致:key 为插件小写 type) */ export const VOTE_TYPES: Record = { - pk: '双选PK', - multiple: '多选', - single: '单选', -} + pk: '双选PK', + multiple: '多选', + single: '单选' +}; /** 投票状态常量(内部状态机) */ -export const VOTE_STATES: { NOT_VOTED: VoteState, VOTING: VoteState, VOTED: VoteState, VOTE_ENDED: VoteState } = { - NOT_VOTED: 'not-voted', - VOTING: 'voting', - VOTED: 'voted', - VOTE_ENDED: 'vote-ended', -} +export const VOTE_STATES: { NOT_VOTED: VoteState; VOTING: VoteState; VOTED: VoteState; VOTE_ENDED: VoteState } = { + NOT_VOTED: 'not-voted', + VOTING: 'voting', + VOTED: 'voted', + VOTE_ENDED: 'vote-ended' +}; /** 投票展示状态(与旧项目 VOTE_STATES 一致:中文 + 颜色) */ -export const VOTE_STATE_LABELS: Record = { - 未开始: { state: '未开始', color: 'orange' }, - 进行中: { state: '进行中', color: 'green' }, - 已结束: { state: '已结束', color: 'red' }, -} +export const VOTE_STATE_LABELS: Record = { + 未开始: { state: '未开始', color: 'orange' }, + 进行中: { state: '进行中', color: 'green' }, + 已结束: { state: '已结束', color: 'red' } +}; /** * 获取投票 UID(不存在则生成) */ export function getOrCreateVoteUid(): string { - let uid = getCache(UnihaloVoteUid) - if (!uid) { - uid = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}` - setCache(UnihaloVoteUid, uid) - } - return uid + let uid = getCache(UnihaloVoteUid); + if (!uid) { + uid = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`; + setCache(UnihaloVoteUid, uid); + } + return uid; } /** @@ -50,22 +50,25 @@ export function getOrCreateVoteUid(): string { * @param vote 投票对象(含 spec.timeLimit/hasEnded/startDate/endDate) * @returns { state: '未开始' | '进行中' | '已结束', color: 'orange' | 'green' | 'red' } */ -export function calcVoteState( - vote: { spec?: { timeLimit?: string, hasEnded?: boolean, startDate?: string, endDate?: string, [key: string]: unknown } }, -): { state: string, color: string } { - if (vote.spec?.timeLimit !== 'custom') { - return vote.spec?.hasEnded ? VOTE_STATE_LABELS['已结束'] : VOTE_STATE_LABELS['进行中'] - } +export function calcVoteState(vote: { spec?: { timeLimit?: string; hasEnded?: boolean; startDate?: string; endDate?: string; [key: string]: unknown } }): { + state: string; + color: string; +} { + if (vote.spec?.timeLimit !== 'custom') { + return vote.spec?.hasEnded ? VOTE_STATE_LABELS['已结束'] : VOTE_STATE_LABELS['进行中']; + } - const nowTime = new Date().getTime() - const startTime = vote.spec?.startDate ? new Date(vote.spec.startDate).getTime() : nowTime - const endTime = vote.spec?.endDate ? new Date(vote.spec.endDate).getTime() : nowTime + const nowTime = new Date().getTime(); + const startTime = vote.spec?.startDate ? new Date(vote.spec.startDate).getTime() : nowTime; + const endTime = vote.spec?.endDate ? new Date(vote.spec.endDate).getTime() : nowTime; - if (nowTime < startTime) - return VOTE_STATE_LABELS['未开始'] - if (nowTime < endTime) - return VOTE_STATE_LABELS['进行中'] - return vote.spec?.hasEnded ? VOTE_STATE_LABELS['已结束'] : VOTE_STATE_LABELS['进行中'] + if (nowTime < startTime) { + return VOTE_STATE_LABELS['未开始']; + } + if (nowTime < endTime) { + return VOTE_STATE_LABELS['进行中']; + } + return vote.spec?.hasEnded ? VOTE_STATE_LABELS['已结束'] : VOTE_STATE_LABELS['进行中']; } /** @@ -74,35 +77,36 @@ export function calcVoteState( * @param option 选项(含 count) */ export function calcVotePercent(vote: { stats?: { voteCount?: number } }, option: { count?: number }): number { - const total = vote.stats?.voteCount || 0 - const count = option.count || 0 - if (total === 0) - return 0 - return Math.round((count / total) * 100) + const total = vote.stats?.voteCount || 0; + const count = option.count || 0; + if (total === 0) { + return 0; + } + return Math.round((count / total) * 100); } /** 投票缓存 key 前缀 */ -const VOTE_CACHE_KEY = 'unihalo_vote_' +const VOTE_CACHE_KEY = 'unihalo_vote_'; interface IVoteCacheData { - selected: string[] - data: unknown + selected: string[]; + data: unknown; } /** * 投票缓存工具(源自旧项目 utils/vote.js 的 voteCacheUtil) */ export const voteCacheUtil = { - /** 是否已缓存(已投票) */ - has(name: string): boolean { - return !!getCache(VOTE_CACHE_KEY + name) - }, - /** 获取缓存数据 */ - get(name: string): IVoteCacheData | null { - return getCache(VOTE_CACHE_KEY + name) || null - }, - /** 写入缓存 */ - set(name: string, data: IVoteCacheData): void { - setCache(VOTE_CACHE_KEY + name, data) - }, -} + /** 是否已缓存(已投票) */ + has(name: string): boolean { + return !!getCache(VOTE_CACHE_KEY + name); + }, + /** 获取缓存数据 */ + get(name: string): IVoteCacheData | null { + return getCache(VOTE_CACHE_KEY + name) || null; + }, + /** 写入缓存 */ + set(name: string, data: IVoteCacheData): void { + setCache(VOTE_CACHE_KEY + name, data); + } +};