mirror of
https://github.com/ialley-workshop-open/uni-halo.git
synced 2026-09-12 16:40:40 +08:00
refactor: 完成项目多模块优化与功能迭代
本次提交包含多项优化与功能更新: 1. 关闭本地开发模式,准备正式发布 2. 重构空状态按钮,统一使用刷新按钮替代加载按钮 3. 优化导航栏样式与返回按钮细节 4. 为图库页面添加图片标题展示与阴影优化 5. 关闭相册接口缓存,确保数据实时性 6. 重构相册查看组件,改为内部自动请求数据并优化布局 7. 优化投票页面样式与配色 8. 重构搜索页面代码结构与细节样式 9. 优化恋爱相册页面布局与交互体验
This commit is contained in:
+3
-5
@@ -1,10 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* uni-halo 自定义 API 接口定义
|
* uni-halo 自定义 API 接口定义
|
||||||
* 覆盖 plugin-uni-halo(/apis/api.unihalo.ialley.cn)与三方插件接口:
|
|
||||||
* 受限阅读(tools.muyin.site)、友链提交(linkssubmit.muyin.site)、投票(api.vote.kunkunyu.com)、
|
|
||||||
* 豆瓣(api.douban.moony.la)、评论组件(api.commentwidget.halo.run)
|
|
||||||
* 风格参考 src/api/foo-alova.ts:http.Get<IResponse<T>>(url, { params, header, meta })
|
|
||||||
* 源自旧项目 api/v2/all.config.js、all.api.js(三方部分)、love.*.js,按需命名导出
|
|
||||||
*/
|
*/
|
||||||
import { http } from '@/http/alova'
|
import { http } from '@/http/alova'
|
||||||
import { RequestFrom } from '@/http/tools/enum'
|
import { RequestFrom } from '@/http/tools/enum'
|
||||||
@@ -211,6 +206,7 @@ export function getLoveConfig() {
|
|||||||
export function getLoveAlbums(params: ILoveAlbumListReq) {
|
export function getLoveAlbums(params: ILoveAlbumListReq) {
|
||||||
return http.Get<IResponse<ILoveAlbumListRes>>('/apis/api.unihalo.ialley.cn/v1alpha1/plugins/plugin-uni-halo/love-albums', {
|
return http.Get<IResponse<ILoveAlbumListRes>>('/apis/api.unihalo.ialley.cn/v1alpha1/plugins/plugin-uni-halo/love-albums', {
|
||||||
params,
|
params,
|
||||||
|
cacheFor: 0,
|
||||||
meta: { requestFrom: RequestFrom.Halo },
|
meta: { requestFrom: RequestFrom.Halo },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -221,6 +217,7 @@ export function getLoveAlbums(params: ILoveAlbumListReq) {
|
|||||||
export function getLoveAlbumByName(name: string, params: ILoveAlbumListReq) {
|
export function getLoveAlbumByName(name: string, params: ILoveAlbumListReq) {
|
||||||
return http.Get<IResponse<ILoveAlbum>>(`/apis/api.unihalo.ialley.cn/v1alpha1/plugins/plugin-uni-halo/love-albums/${name}`, {
|
return http.Get<IResponse<ILoveAlbum>>(`/apis/api.unihalo.ialley.cn/v1alpha1/plugins/plugin-uni-halo/love-albums/${name}`, {
|
||||||
params,
|
params,
|
||||||
|
cacheFor: 0,
|
||||||
meta: { requestFrom: RequestFrom.Halo },
|
meta: { requestFrom: RequestFrom.Halo },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -249,6 +246,7 @@ export function getLoveDailyItems(params: ILoveDailyItemListReq) {
|
|||||||
'/apis/api.unihalo.ialley.cn/v1alpha1/plugins/plugin-uni-halo/love-daily-items',
|
'/apis/api.unihalo.ialley.cn/v1alpha1/plugins/plugin-uni-halo/love-daily-items',
|
||||||
{
|
{
|
||||||
params,
|
params,
|
||||||
|
cacheFor: 0,
|
||||||
meta: { requestFrom: RequestFrom.Halo },
|
meta: { requestFrom: RequestFrom.Halo },
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref, watch } from 'vue'
|
import { computed, ref, watch } from 'vue'
|
||||||
|
import { getLoveAlbumByName } from '@/api/uni-halo'
|
||||||
import { checkImageUrl } from '@/utils/url'
|
import { checkImageUrl } from '@/utils/url'
|
||||||
|
import { sleep } from '@/utils/common'
|
||||||
|
import { DataLoadingStatusEnum, useDataLoadingStatus } from '@/hooks/useDataLoadingStatus'
|
||||||
|
import type { ILoveAlbum } from '@/api/types/uni-halo'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
show : boolean
|
show : boolean
|
||||||
albumName ?: string
|
albumName ?: string
|
||||||
photos ?: IAlbumPhoto[]
|
/** 相册 key(详情请求参数) */
|
||||||
loading ?: boolean
|
albumKey ?: string
|
||||||
|
/** 解锁 token(加密相册已解锁时传入) */
|
||||||
|
token ?: string
|
||||||
}>(), {
|
}>(), {
|
||||||
albumName: '',
|
albumName: '',
|
||||||
photos: () => [],
|
albumKey: '',
|
||||||
loading: false,
|
token: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
@@ -28,24 +34,39 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isShow = ref(false)
|
const isShow = ref(false)
|
||||||
|
const { loadingStatus, updateLoadingStatus } = useDataLoadingStatus()
|
||||||
watch(() => props.show, (val) => {
|
const photos = ref<IAlbumPhoto[]>([])
|
||||||
isShow.value = val
|
|
||||||
})
|
|
||||||
|
|
||||||
/** 预处理图片路径(相对路径拼接 BASE_API) */
|
/** 预处理图片路径(相对路径拼接 BASE_API) */
|
||||||
const photoList = computed<IAlbumPhoto[]>(() =>
|
const photoList = computed<IAlbumPhoto[]>(() =>
|
||||||
(props.photos || []).map(photo => ({
|
photos.value.map(photo => ({
|
||||||
...photo,
|
...photo,
|
||||||
url: checkImageUrl(photo.url || ''),
|
url: checkImageUrl(photo.url || ''),
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
|
|
||||||
/** 左列(偶数位照片,瀑布流错落) */
|
/** 内部自请求:获取相册详情并填充照片 */
|
||||||
const leftPhotos = computed(() => photoList.value.filter((_, index) => index % 2 === 0))
|
async function handleLoadPhotos() {
|
||||||
|
updateLoadingStatus(DataLoadingStatusEnum.Loading)
|
||||||
|
try {
|
||||||
|
const detail = await getLoveAlbumByName(props.albumKey, { token: props.token })
|
||||||
|
photos.value = (detail.data as unknown as ILoveAlbum)?.photos || []
|
||||||
|
await sleep(600)
|
||||||
|
updateLoadingStatus(photos.value.length === 0 ? DataLoadingStatusEnum.Empty : DataLoadingStatusEnum.Success)
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.error('获取相册照片失败', e)
|
||||||
|
updateLoadingStatus(DataLoadingStatusEnum.Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 右列(奇数位照片) */
|
watch(() => props.show, (val) => {
|
||||||
const rightPhotos = computed(() => photoList.value.filter((_, index) => index % 2 === 1))
|
isShow.value = val
|
||||||
|
if (val) {
|
||||||
|
photos.value = []
|
||||||
|
handleLoadPhotos()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
function handleClose() {
|
function handleClose() {
|
||||||
isShow.value = false
|
isShow.value = false
|
||||||
@@ -71,88 +92,61 @@
|
|||||||
safe-area-inset-bottom @close="handleClose">
|
safe-area-inset-bottom @close="handleClose">
|
||||||
<view class="box-border h-full w-full flex flex-col gap-y-3 p-4">
|
<view class="box-border h-full w-full flex flex-col gap-y-3 p-4">
|
||||||
<!-- 头部 -->
|
<!-- 头部 -->
|
||||||
<view class="w-full shrink-0 flex items-center justify-between">
|
<view class="w-full flex shrink-0 items-center justify-between">
|
||||||
<view class="font-bold flex items-center gap-x-1">
|
<view class="flex items-center gap-x-1 font-bold">
|
||||||
{{ albumName }}
|
{{ albumName }}
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view
|
||||||
class="w-6 h-6 uh-global-card-glass border uh-shadow-xs flex items-center justify-center rounded-lg"
|
class="uh-global-card-glass uh-shadow-xs h-6 w-6 flex items-center justify-center border rounded-lg"
|
||||||
@click="handleClose">
|
@click="handleClose">
|
||||||
<wd-icon name="close" size="32rpx"></wd-icon>
|
<wd-icon name="close" size="32rpx" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 照片列表 -->
|
<!-- 照片列表 -->
|
||||||
<scroll-view class="box-border max-h-[50vh] flex-1" scroll-y :show-scrollbar="false">
|
<scroll-view class="box-border max-h-[50vh] flex-1" scroll-y :show-scrollbar="false">
|
||||||
<view v-if="loading" class="viewer-empty box-border h-full flex items-center justify-center p-10">
|
<!-- 加载/错误/空占位(状态机) -->
|
||||||
<view class="viewer-loading flex flex-col items-center">
|
<uh-data-loading v-if="loadingStatus !== DataLoadingStatusEnum.Success" :use-refresh-button="false"
|
||||||
<view class="loading-text mt-7 text-[28rpx] text-[#56bbf9]">
|
:loading-status="loadingStatus" error-text="照片加载失败,请点击刷新重试" empty-text="这个相册暂时还没有照片~"
|
||||||
照片正在努力加载中啦~
|
min-height="40vh" @refresh="handleLoadPhotos" />
|
||||||
</view>
|
<view v-else class="box-border grid grid-cols-2 gap-2">
|
||||||
</view>
|
<view v-for="photo in photoList" :key="photo.name"
|
||||||
</view>
|
class="relative box-border overflow-hidden uh-global-card-glass rounded-xl">
|
||||||
<view v-else-if="photoList.length === 0"
|
<image class="w-full h-46 block" :src="photo.url" mode="aspectFill" lazy-load
|
||||||
class="viewer-empty box-border h-full flex items-center justify-center p-10">
|
|
||||||
<wd-empty description="这个相册暂时还没有照片~" />
|
|
||||||
</view>
|
|
||||||
<view v-else class="photo-list box-border flex items-start p-5">
|
|
||||||
<!-- 左列 -->
|
|
||||||
<view class="photo-column box-border min-w-0 flex-1 mr-[20rpx]">
|
|
||||||
<view v-for="photo in leftPhotos" :key="photo.name"
|
|
||||||
class="photo-card mb-6 box-border overflow-hidden rounded-xl bg-white shadow-sm">
|
|
||||||
<image class="photo-image w-full" :src="photo.url" mode="widthFix" lazy-load
|
|
||||||
@click="handlePreview(photo.url)" />
|
@click="handlePreview(photo.url)" />
|
||||||
<view class="photo-info box-border px-6 py-5">
|
<view
|
||||||
<view v-if="photo.title" class="photo-title mb-3 text-[30rpx] text-[#333] font-bold">
|
class="absolute bottom-0 w-full box-border p-3 pt-4 z-2 bg-gradient-to-b from-white/0 to-white/60">
|
||||||
|
<view v-if="photo.title" class="mb-1 text-xs text-love font-bold">
|
||||||
{{ photo.title }}
|
{{ photo.title }}
|
||||||
</view>
|
</view>
|
||||||
<view v-if="photo.takenDate || photo.location"
|
<view v-if="photo.description" class="mb-1 text-xs text-white leading-5">
|
||||||
class="photo-meta mb-3 flex flex-wrap items-center">
|
|
||||||
<text v-if="photo.takenDate"
|
|
||||||
class="meta-item mr-8 text-[24rpx] text-[#999]">{{ photo.takenDate }}</text>
|
|
||||||
<text v-if="photo.location"
|
|
||||||
class="meta-item mr-8 text-[24rpx] text-[#999]">{{ photo.location }}</text>
|
|
||||||
</view>
|
|
||||||
<view v-if="photo.description"
|
|
||||||
class="photo-desc text-[26rpx] text-[#666] leading-[1.6]">
|
|
||||||
{{ photo.description }}
|
{{ photo.description }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<!-- 右列 -->
|
|
||||||
<view class="photo-column box-border min-w-0 flex-1">
|
|
||||||
<view v-for="photo in rightPhotos" :key="photo.name"
|
|
||||||
class="photo-card mb-6 box-border overflow-hidden rounded-xl bg-white shadow-sm">
|
|
||||||
<image class="photo-image w-full" :src="photo.url" mode="widthFix" lazy-load
|
|
||||||
@click="handlePreview(photo.url)" />
|
|
||||||
<view class="photo-info box-border px-6 py-5">
|
|
||||||
<view v-if="photo.title" class="photo-title mb-3 text-[30rpx] text-[#333] font-bold">
|
|
||||||
{{ photo.title }}
|
|
||||||
</view>
|
|
||||||
<view v-if="photo.takenDate || photo.location"
|
<view v-if="photo.takenDate || photo.location"
|
||||||
class="photo-meta mb-3 flex flex-wrap items-center">
|
class="flex flex-col gap-y-1">
|
||||||
<text v-if="photo.takenDate"
|
<text v-if="photo.takenDate" class="text-xs text-white">
|
||||||
class="meta-item mr-8 text-[24rpx] text-[#999]">{{ photo.takenDate }}</text>
|
<wd-icon name="time-line"></wd-icon> {{ photo.takenDate }}
|
||||||
<text v-if="photo.location"
|
</text>
|
||||||
class="meta-item mr-8 text-[24rpx] text-[#999]">{{ photo.location }}</text>
|
<text v-if="photo.location" class="text-xs text-white">
|
||||||
</view>
|
<wd-icon name="location"></wd-icon> {{ photo.location }}
|
||||||
<view v-if="photo.description"
|
</text>
|
||||||
class="photo-desc text-[26rpx] text-[#666] leading-[1.6]">
|
|
||||||
{{ photo.description }}
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<!-- 底部关闭 -->
|
<!-- 底部关闭 -->
|
||||||
<view class="w-full shrink-0">
|
<view class="w-full shrink-0 flex items-center justify-center gap-x-2">
|
||||||
<uh-button custom-class="py-2 uh-global-card-glass rounded-xl !bg-love/90 text-white border"
|
<uh-button custom-class="py-2 flex-1 uh-global-card-glass border rounded-xl bg-white/90"
|
||||||
@click="handleClose">
|
@click="handleClose">
|
||||||
关闭
|
关闭
|
||||||
</uh-button>
|
</uh-button>
|
||||||
|
<uh-button custom-class="flex-1 py-2 uh-global-card-glass rounded-xl !bg-love/90 text-white border"
|
||||||
|
@click="handleLoadPhotos">
|
||||||
|
刷新
|
||||||
|
</uh-button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</uh-glass-popup>
|
</uh-glass-popup>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
loadingSubText ?: string
|
loadingSubText ?: string
|
||||||
errorSubText ?: string
|
errorSubText ?: string
|
||||||
emptySubText ?: string
|
emptySubText ?: string
|
||||||
useLoadingButton ?: boolean
|
useRefreshButton ?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<IProps>(), {
|
const props = withDefaults(defineProps<IProps>(), {
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
loadingSubText: '',
|
loadingSubText: '',
|
||||||
errorSubText: '请检查网络连接,或稍后再试',
|
errorSubText: '请检查网络连接,或稍后再试',
|
||||||
emptySubText: '稍后再来看看吧~',
|
emptySubText: '稍后再来看看吧~',
|
||||||
useLoadingButton: true,
|
useRefreshButton: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits<{ (e : 'refresh') : void }>()
|
const emit = defineEmits<{ (e : 'refresh') : void }>()
|
||||||
@@ -106,8 +106,8 @@
|
|||||||
<text v-if="statusScene.subText" class="mt-3 text-xs text-gray-500">
|
<text v-if="statusScene.subText" class="mt-3 text-xs text-gray-500">
|
||||||
{{ statusScene.subText }}
|
{{ statusScene.subText }}
|
||||||
</text>
|
</text>
|
||||||
<view v-if="props.useLoadingButton" class="mt-5 uh-global-card-glass uh-shadow-xs border rounded-lg">
|
<view v-if="props.useRefreshButton" class="mt-5">
|
||||||
<uh-button custom-class="!rounded-lg" @click="emit('refresh')">
|
<uh-button custom-class="!rounded-lg uh-global-card-glass uh-shadow-xs border rounded-lg" @click="emit('refresh')">
|
||||||
刷新试试
|
刷新试试
|
||||||
</uh-button>
|
</uh-button>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -95,11 +95,11 @@
|
|||||||
<!-- 左边 -->
|
<!-- 左边 -->
|
||||||
<view class="shrink-0 min-w-18" @click="handleBack()">
|
<view class="shrink-0 min-w-18" @click="handleBack()">
|
||||||
<view v-if="props.useBack"
|
<view v-if="props.useBack"
|
||||||
class="uh-global-card-glass h-7 px-3 rounded-full border flex items-center gap-x-2 text-sm"
|
class="uh-global-card-glass uh-shadow-xs h-8 px-3 rounded-full border flex items-center gap-x-2 text-sm"
|
||||||
:class="props.backClass" :style="[props.backStyle]">
|
:class="props.backClass" :style="[props.backStyle]">
|
||||||
<wd-icon name="arrow-left" size="32rpx"></wd-icon>
|
<wd-icon name="arrow-left" size="34rpx"></wd-icon>
|
||||||
<view class="w-[1px] h-4 bg-white/60" />
|
<view class="w-[1px] h-4 bg-white/60" />
|
||||||
<text class="text-xs font-bold">返回</text>
|
<text class="text-sm font-bold">返回</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 中间 -->
|
<!-- 中间 -->
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<uh-glass-popup v-model="isShow" position="center" :z-index="9999" radius="24rpx" @close="handleClose">
|
<uh-glass-popup v-model="isShow" position="center" :z-index="9999" custom-class="rounded-xl" @close="handleClose">
|
||||||
<view v-if="notice" class="box-border w-[80vw] p-4">
|
<view v-if="notice" class="box-border w-[80vw] p-4">
|
||||||
<!-- 头部:标题 + 关闭 -->
|
<!-- 头部:标题 + 关闭 -->
|
||||||
<view class="flex items-center justify-between">
|
<view class="flex items-center justify-between">
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ const emptyText = computed(() => (activeKind.value === 'post' ? '还没有收藏
|
|||||||
<!-- 空态(当前 Tab 无收藏):uh-data-loading 统一渲染,视觉与 tabbar 页一致 -->
|
<!-- 空态(当前 Tab 无收藏):uh-data-loading 统一渲染,视觉与 tabbar 页一致 -->
|
||||||
<uh-data-loading
|
<uh-data-loading
|
||||||
v-if="loadingStatus !== 'success'" :loading-status="loadingStatus" min-height="65vh"
|
v-if="loadingStatus !== 'success'" :loading-status="loadingStatus" min-height="65vh"
|
||||||
:use-loading-button="false" :empty-text="emptyText" empty-sub-text="快去阅读文章/瞬间点击收藏吧"
|
:use-refresh-button="false" :empty-text="emptyText" empty-sub-text="快去阅读文章/瞬间点击收藏吧"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 成功态:当前 Tab 列表 -->
|
<!-- 成功态:当前 Tab 列表 -->
|
||||||
|
|||||||
@@ -67,12 +67,14 @@
|
|||||||
/** 图片查看弹窗 */
|
/** 图片查看弹窗 */
|
||||||
const showPhotoViewer = ref(false)
|
const showPhotoViewer = ref(false)
|
||||||
const currentViewerAlbum = ref<ILoveAlbumCard | null>(null)
|
const currentViewerAlbum = ref<ILoveAlbumCard | null>(null)
|
||||||
const viewerLoading = ref(false)
|
|
||||||
|
|
||||||
const unlockAlbumName = computed(() => currentUnlockAlbum.value?.displayName || '')
|
const unlockAlbumName = computed(() => currentUnlockAlbum.value?.displayName || '')
|
||||||
const unlockAlbumKey = computed(() => currentUnlockAlbum.value?.name || '')
|
const unlockAlbumKey = computed(() => currentUnlockAlbum.value?.name || '')
|
||||||
const viewerAlbumName = computed(() => currentViewerAlbum.value?.displayName || '')
|
const viewerAlbumName = computed(() => currentViewerAlbum.value?.displayName || '')
|
||||||
const viewerPhotos = computed(() => currentViewerAlbum.value?.photos || [])
|
const viewerAlbumKey = computed(() => currentViewerAlbum.value?.name || '')
|
||||||
|
const viewerAlbumToken = computed(() => currentViewerAlbum.value
|
||||||
|
? (unlockedAlbums.value[currentViewerAlbum.value.name] || '')
|
||||||
|
: '')
|
||||||
|
|
||||||
/* ---------------- 缓存 ---------------- */
|
/* ---------------- 缓存 ---------------- */
|
||||||
function handleRestoreUnlockedAlbums() {
|
function handleRestoreUnlockedAlbums() {
|
||||||
@@ -151,32 +153,10 @@
|
|||||||
handleOpenPhotoViewer(item)
|
handleOpenPhotoViewer(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleOpenPhotoViewer(item : ILoveAlbumCard) {
|
function handleOpenPhotoViewer(item: ILoveAlbumCard) {
|
||||||
currentViewerAlbum.value = item
|
currentViewerAlbum.value = item
|
||||||
showPhotoViewer.value = true
|
showPhotoViewer.value = true
|
||||||
if (item.photos.length > 0) { return }
|
// 照片数据由 uh-album-photo-viewer 内部自请求(见组件 handleLoadPhotos)
|
||||||
viewerLoading.value = true
|
|
||||||
try {
|
|
||||||
const token = unlockedAlbums.value[item.name] || ''
|
|
||||||
const detail = await getLoveAlbumByName(item.name, { token })
|
|
||||||
if (detail) {
|
|
||||||
if (detail.locked) {
|
|
||||||
delete unlockedAlbums.value[item.name]
|
|
||||||
handleSaveUnlockedAlbums()
|
|
||||||
}
|
|
||||||
else if (detail.photos) {
|
|
||||||
item.photos = detail.photos
|
|
||||||
item.locked = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error('获取相册照片失败', e)
|
|
||||||
uni.showToast({ icon: 'none', title: '照片加载失败,请稍后重试' })
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
viewerLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleOnUnlockSuccess(data: { albumKey: string, token: string, photos: unknown[] }) {
|
function handleOnUnlockSuccess(data: { albumKey: string, token: string, photos: unknown[] }) {
|
||||||
@@ -221,44 +201,70 @@
|
|||||||
<uh-navbar default-title="恋爱相册" title-color="text-love" back-class="text-love" />
|
<uh-navbar default-title="恋爱相册" title-color="text-love" back-class="text-love" />
|
||||||
|
|
||||||
<!-- 加载/错误/空占位(状态机) -->
|
<!-- 加载/错误/空占位(状态机) -->
|
||||||
<uh-data-loading v-if="loadingStatus !== DataLoadingStatusEnum.Success" :loading-status="loadingStatus"
|
<uh-data-loading
|
||||||
min-height="75vh" empty-text="相册暂时还没有数据~" @refresh="handleGetData" />
|
v-if="loadingStatus !== DataLoadingStatusEnum.Success" :loading-status="loadingStatus"
|
||||||
|
min-height="75vh" empty-text="相册暂时还没有数据~" @refresh="handleGetData"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 相册列表(两列网格) -->
|
<!-- 相册列表(两列网格) -->
|
||||||
<view v-else class="box-border grid grid-cols-2 p-3 pt-2 gap-3">
|
<view v-else class="grid grid-cols-2 box-border gap-3 p-3 pt-2">
|
||||||
<view v-for="(item) in dataList" :key="item.name"
|
|
||||||
class="uh-global-card-glass box-border overflow-hidden rounded-xl" @click="handleOnAlbumClick(item)">
|
|
||||||
<view class="relative h-24 w-full">
|
|
||||||
<image class="h-full w-full" :src="item.image" mode="aspectFill" lazy-load />
|
|
||||||
<view v-if="item.locked && !unlockedAlbums[item.name]"
|
|
||||||
class="absolute left-0 top-0 h-full w-full flex flex-col items-center justify-center gap-1 bg-black/45">
|
|
||||||
<wd-icon name="lock" size="52rpx" class="text-white" />
|
|
||||||
<view class="text-xs text-white"> 已加密 </view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="album-info box-border p-3">
|
|
||||||
<view
|
<view
|
||||||
class="album-name overflow-hidden text-ellipsis whitespace-nowrap text-[30rpx] text-[#333] font-bold">
|
v-for="(item) in dataList" :key="item.name"
|
||||||
|
class="uh-global-card-glass box-border overflow-hidden rounded-xl" @click="handleOnAlbumClick(item)"
|
||||||
|
>
|
||||||
|
<view class="relative h-36 w-full">
|
||||||
|
<image class="h-full w-full" :src="item.image" mode="aspectFill" lazy-load />
|
||||||
|
<view
|
||||||
|
v-if="item.locked && !unlockedAlbums[item.name]"
|
||||||
|
class="absolute right-0 top-0 px-2 py-1 rounded-lb-md flex items-center justify-center gap-1 bg-black/30"
|
||||||
|
>
|
||||||
|
<wd-icon name="lock" size="30rpx" class="text-white" />
|
||||||
|
<view class="text-xs text-white">
|
||||||
|
已加密
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="absolute left-0 right-0 bottom-0 box-border p-3 pt-6 bg-gradient-to-b from-white/0 to-white/60">
|
||||||
|
<view
|
||||||
|
class="truncate text-sm text-love font-bold"
|
||||||
|
>
|
||||||
{{ item.displayName }}
|
{{ item.displayName }}
|
||||||
</view>
|
</view>
|
||||||
<view class="album-count mt-1 text-xs text-gray-500">
|
<view class="album-count mt-1 text-xs text-white">
|
||||||
{{ item.photoCount }} 张照片
|
{{ item.photoCount }} 张照片
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 密码解锁弹窗 -->
|
<!-- 密码解锁弹窗 -->
|
||||||
<uh-album-unlock-popup v-if="currentUnlockAlbum" v-model="showUnlockModal" :show="showUnlockModal" :album-name="unlockAlbumName"
|
<uh-album-unlock-popup
|
||||||
:album-key="unlockAlbumKey" @update:show="showUnlockModal = $event" @success="handleOnUnlockSuccess" />
|
v-if="currentUnlockAlbum" v-model="showUnlockModal" :show="showUnlockModal" :album-name="unlockAlbumName"
|
||||||
|
:album-key="unlockAlbumKey" @update:show="showUnlockModal = $event" @success="handleOnUnlockSuccess"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 相册图片查看弹窗 -->
|
<!-- 相册图片查看弹窗(数据在组件内部自请求) -->
|
||||||
<uh-album-photo-viewer v-if="currentViewerAlbum" v-model="showPhotoViewer" :show="showPhotoViewer" :album-name="viewerAlbumName"
|
<uh-album-photo-viewer
|
||||||
:photos="viewerPhotos" :loading="viewerLoading" @update:show="showPhotoViewer = $event" />
|
v-if="currentViewerAlbum" v-model="showPhotoViewer" :show="showPhotoViewer"
|
||||||
|
:album-name="viewerAlbumName" :album-key="viewerAlbumKey" :token="viewerAlbumToken"
|
||||||
|
@update:show="showPhotoViewer = $event"
|
||||||
|
/>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.app-page {
|
.app-page {
|
||||||
background: linear-gradient(-135deg, rgb(247 149 51 / 10%), rgb(243 112 85 / 10%) 15%, rgb(239 78 123 / 10%) 30%, rgb(161 102 171 / 10%) 44%, rgb(80 115 184 / 10%) 58%, rgb(16 152 173 / 10%) 72%, rgb(7 179 155 / 10%) 86%, rgb(109 186 130 / 10%));
|
background: linear-gradient(
|
||||||
|
-135deg,
|
||||||
|
rgb(247 149 51 / 10%),
|
||||||
|
rgb(243 112 85 / 10%) 15%,
|
||||||
|
rgb(239 78 123 / 10%) 30%,
|
||||||
|
rgb(161 102 171 / 10%) 44%,
|
||||||
|
rgb(80 115 184 / 10%) 58%,
|
||||||
|
rgb(16 152 173 / 10%) 72%,
|
||||||
|
rgb(7 179 155 / 10%) 86%,
|
||||||
|
rgb(109 186 130 / 10%)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -350,7 +350,7 @@
|
|||||||
|
|
||||||
</view>
|
</view>
|
||||||
<uh-data-loading v-if="showList.length === 0" :loading-status="DataLoadingStatusEnum.Empty"
|
<uh-data-loading v-if="showList.length === 0" :loading-status="DataLoadingStatusEnum.Empty"
|
||||||
min-height="42vh" empty-text="该筛选条件下暂无清单~" :use-loading-button="false" />
|
min-height="42vh" empty-text="该筛选条件下暂无清单~" :use-refresh-button="false" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 筛选弹层(状态/排序;排序附方向选择) -->
|
<!-- 筛选弹层(状态/排序;排序附方向选择) -->
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
/**
|
|
||||||
* 内容搜索页(源自旧项目 pagesA/articles,新建复刻)
|
|
||||||
* 功能:关键词搜索文章/瞬间,结果列表展示
|
|
||||||
*/
|
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app'
|
import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app'
|
||||||
import { getPostListByKeyword } from '@/api/halo'
|
import { getPostListByKeyword } from '@/api/halo'
|
||||||
|
import { sleep } from '@/utils/common'
|
||||||
import { useAppConfigStore } from '@/store/appConfig'
|
import { useAppConfigStore } from '@/store/appConfig'
|
||||||
import { DataLoadingStatusEnum, useDataLoadingStatus } from '@/hooks/useDataLoadingStatus'
|
import { DataLoadingStatusEnum, useDataLoadingStatus } from '@/hooks/useDataLoadingStatus'
|
||||||
import { NeedPluginIds } from '@/hooks/usePluginAvailable'
|
import { NeedPluginIds } from '@/hooks/usePluginAvailable'
|
||||||
@@ -23,16 +20,13 @@ definePage({
|
|||||||
const appConfigStore = useAppConfigStore()
|
const appConfigStore = useAppConfigStore()
|
||||||
const calcAuditModeEnabled = computed(() => appConfigStore.auditModeEnabled)
|
const calcAuditModeEnabled = computed(() => appConfigStore.auditModeEnabled)
|
||||||
|
|
||||||
/** 依赖插件(plugin-search-widget,参考 gallery 对象传参模式) */
|
|
||||||
const { pluginId, checking, tips, available: uniHaloPluginAvailable, check: checkPluginAvailable } = usePluginAvailable({
|
const { pluginId, checking, tips, available: uniHaloPluginAvailable, check: checkPluginAvailable } = usePluginAvailable({
|
||||||
pluginId: NeedPluginIds.PluginSearchWidget,
|
pluginId: NeedPluginIds.PluginSearchWidget,
|
||||||
tips: '检测到当前插件没有安装或者启用,无法使用搜索功能哦,请联系管理员',
|
tips: '啊偶,当前功能未开放!',
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 重新检测插件:可用则重新搜索(供 uh-plugin-unavailable 刷新按钮) */
|
|
||||||
async function handlePluginRefresh() {
|
async function handlePluginRefresh() {
|
||||||
if (await checkPluginAvailable())
|
if (await checkPluginAvailable()) { handleOnSearch() }
|
||||||
handleOnSearch()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------- 状态 ---------------- */
|
/* ---------------- 状态 ---------------- */
|
||||||
@@ -70,11 +64,12 @@ const emptyText = computed(() =>
|
|||||||
/* ---------------- 搜索 ---------------- */
|
/* ---------------- 搜索 ---------------- */
|
||||||
async function handleGetData() {
|
async function handleGetData() {
|
||||||
if (calcAuditModeEnabled.value)
|
if (calcAuditModeEnabled.value)
|
||||||
return
|
{return}
|
||||||
updateLoadingStatus(DataLoadingStatusEnum.Loading)
|
updateLoadingStatus(DataLoadingStatusEnum.Loading)
|
||||||
try {
|
try {
|
||||||
const res = await getPostListByKeyword({ ...queryParams.value })
|
const res = await getPostListByKeyword({ ...queryParams.value })
|
||||||
dataList.value = (res.data as unknown as { hits ?: typeof dataList.value }).hits || []
|
dataList.value = (res.data as unknown as { hits ?: typeof dataList.value }).hits || []
|
||||||
|
await sleep(600)
|
||||||
updateLoadingStatus(
|
updateLoadingStatus(
|
||||||
dataList.value.length === 0 ? DataLoadingStatusEnum.Empty : DataLoadingStatusEnum.Success,
|
dataList.value.length === 0 ? DataLoadingStatusEnum.Empty : DataLoadingStatusEnum.Success,
|
||||||
)
|
)
|
||||||
@@ -110,8 +105,7 @@ function isArticle(item: { type?: string }): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleToDetail(item : { metadataName ?: string, type ?: string }) {
|
function handleToDetail(item : { metadataName ?: string, type ?: string }) {
|
||||||
if (calcAuditModeEnabled.value)
|
if (calcAuditModeEnabled.value) { return }
|
||||||
return
|
|
||||||
if (isArticle(item)) {
|
if (isArticle(item)) {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages-blog/article-detail/article-detail?name=${item.metadataName}`,
|
url: `/pages-blog/article-detail/article-detail?name=${item.metadataName}`,
|
||||||
@@ -126,14 +120,9 @@ function handleToDetail(item: { metadataName?: string, type?: string }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleToTopPage(duration = 500) {
|
function handleResetSearch() {
|
||||||
uni.pageScrollTo({
|
queryParams.value.keyword = '';
|
||||||
scrollTop: 0,
|
handleOnSearch()
|
||||||
duration,
|
|
||||||
fail: (err) => {
|
|
||||||
console.error('回顶失败', err)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------- 生命周期 ---------------- */
|
/* ---------------- 生命周期 ---------------- */
|
||||||
@@ -166,80 +155,49 @@ onPullDownRefresh(() => {
|
|||||||
<!-- 自定义导航 -->
|
<!-- 自定义导航 -->
|
||||||
<uh-navbar default-title="内容搜索" title-color="text-gray-900" />
|
<uh-navbar default-title="内容搜索" title-color="text-gray-900" />
|
||||||
|
|
||||||
<uh-plugin-unavailable
|
<uh-plugin-unavailable v-if="!uniHaloPluginAvailable" :plugin-id="pluginId" :error-text="tips"
|
||||||
v-if="!uniHaloPluginAvailable"
|
:checking="checking" @on-refresh="handlePluginRefresh" />
|
||||||
:plugin-id="pluginId"
|
|
||||||
:error-text="tips"
|
|
||||||
:checking="checking"
|
|
||||||
@on-refresh="handlePluginRefresh"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<!-- 顶部搜索框-->
|
<!-- 顶部搜索框-->
|
||||||
<wd-sticky class="">
|
<wd-sticky class="">
|
||||||
<view class="w-screen box-border px-3 py-2">
|
<view class="w-screen box-border px-3 py-2">
|
||||||
<view class="uh-global-card-glass h-9 flex items-center gap-3 rounded-full px-5">
|
<view class="box-border uh-global-card-glass h-9 flex items-center gap-3 rounded-full pl-1 pr-3">
|
||||||
<wd-icon name="search" size="16px" />
|
<wd-icon name="search" size="16px" />
|
||||||
<input
|
<input v-model="queryParams.keyword" class="flex-1 text-sm text-gray-900"
|
||||||
v-model="queryParams.keyword"
|
placeholder="哈喽,想看些什么呢~" placeholder-class="text-gray-400" confirm-type="search"
|
||||||
class="flex-1 text-[26rpx] text-gray-900"
|
@input="handleOnInput" @confirm="handleOnSearch">
|
||||||
placeholder="哈喽,想看些什么呢~"
|
<view v-if="queryParams.keyword" class="clear-btn flex items-center"
|
||||||
placeholder-class="text-gray-400"
|
@click="handleResetSearch()">
|
||||||
confirm-type="search"
|
<wd-icon name="close" size="28rpx" />
|
||||||
@input="handleOnInput"
|
|
||||||
@confirm="handleOnSearch"
|
|
||||||
>
|
|
||||||
<view v-if="queryParams.keyword" class="clear-btn flex items-center" @click="queryParams.keyword = ''; handleOnSearch()">
|
|
||||||
<wd-icon name="close" size="14px" />
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</wd-sticky>
|
</wd-sticky>
|
||||||
|
|
||||||
<!-- 加载/错误/空占位(状态机) -->
|
<!-- 加载/错误/空占位(状态机) -->
|
||||||
<uh-data-loading
|
<uh-data-loading v-if="loadingStatus !== DataLoadingStatusEnum.Success" :loading-status="loadingStatus"
|
||||||
v-if="loadingStatus !== 'success'"
|
min-height="70vh" error-text="搜索异常" :empty-text="emptyText" @refresh="handleOnSearch" />
|
||||||
:loading-status="loadingStatus"
|
|
||||||
min-height="65vh"
|
|
||||||
error-text="搜索异常"
|
|
||||||
:empty-text="emptyText"
|
|
||||||
@refresh="handleOnSearch"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 内容区域(成功态) -->
|
<!-- 内容区域(成功态) -->
|
||||||
<view v-else class="box-border pt-2 px-3 flex flex-col gap-y-3">
|
<view v-else class="box-border pt-2 px-3 flex flex-col gap-y-3">
|
||||||
<block v-if="dataList.length !== 0">
|
<block v-if="dataList.length !== 0">
|
||||||
<view
|
<view v-for="(item, index) in dataList" :key="index"
|
||||||
v-for="(item, index) in dataList"
|
|
||||||
:key="index"
|
|
||||||
class="uh-global-card-glass uh-shadow-xs border flex flex-col overflow-hidden rounded-2xl p-4"
|
class="uh-global-card-glass uh-shadow-xs border flex flex-col overflow-hidden rounded-2xl p-4"
|
||||||
:style="{ animationDelay: `${calcAniDelays[index]}ms` }"
|
:style="{ animationDelay: `${calcAniDelays[index]}ms` }" @click="handleToDetail(item)">
|
||||||
@click="handleToDetail(item)"
|
|
||||||
>
|
|
||||||
<view class="card-head mb-3 flex items-center">
|
<view class="card-head mb-3 flex items-center">
|
||||||
<view
|
<view class="type-tag mr-3 shrink-0 rounded-md px-1.5 py-1 text-xs leading-none"
|
||||||
class="type-tag mr-3 shrink-0 rounded-md px-1.5 py-1 text-xs leading-none"
|
:class="isArticle(item) ? 'bg-secondary text-gray-900' : 'bg-blue-500 text-gray-50'">
|
||||||
:class="isArticle(item) ? 'bg-secondary text-gray-900' : 'bg-blue-500 text-gray-50'"
|
|
||||||
>
|
|
||||||
{{ isArticle(item) ? '文章' : '瞬间' }}
|
{{ isArticle(item) ? '文章' : '瞬间' }}
|
||||||
</view>
|
</view>
|
||||||
<text class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap text-sm text-gray-900 font-bold">{{ item.title }}</text>
|
<text
|
||||||
|
class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap text-sm text-gray-900 font-bold">{{ item.title }}</text>
|
||||||
</view>
|
</view>
|
||||||
<mp-html
|
<mp-html class="evan-markdown" lazy-load :domain="markdownConfig.domain ?? ''"
|
||||||
class="evan-markdown"
|
:loading-img="markdownConfig.loadingGif" scroll-table selectable
|
||||||
lazy-load
|
:tag-style="markdownConfig.tagStyle" :container-style="markdownConfig.containStyle"
|
||||||
:domain="markdownConfig.domain ?? ''"
|
:content="item.description || item.content || ''" :markdown="true" :show-line-number="true"
|
||||||
:loading-img="markdownConfig.loadingGif"
|
:show-language-name="true" copy-by-long-press />
|
||||||
scroll-table
|
|
||||||
selectable
|
|
||||||
:tag-style="markdownConfig.tagStyle"
|
|
||||||
:container-style="markdownConfig.containStyle"
|
|
||||||
:content="item.description || item.content || ''"
|
|
||||||
:markdown="true"
|
|
||||||
:show-line-number="true"
|
|
||||||
:show-language-name="true"
|
|
||||||
copy-by-long-press
|
|
||||||
/>
|
|
||||||
</view>
|
</view>
|
||||||
</block>
|
</block>
|
||||||
</view>
|
</view>
|
||||||
@@ -248,7 +206,6 @@ onPullDownRefresh(() => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
/* 列表项入场动画(对应旧版 tm-translate fadeUp):@keyframes 无法用原子类表达,保留 scoped 样式 */
|
|
||||||
.fade-up {
|
.fade-up {
|
||||||
animation: fade-up 0.4s ease-out both;
|
animation: fade-up 0.4s ease-out both;
|
||||||
|
|
||||||
@@ -257,6 +214,7 @@ onPullDownRefresh(() => {
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(24rpx);
|
transform: translateY(24rpx);
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ onShareTimeline(() => ({
|
|||||||
<!-- 投票信息 -->
|
<!-- 投票信息 -->
|
||||||
<view class="uh-global-card-glass box-border flex flex-col gap-y-3 rounded-2xl p-3">
|
<view class="uh-global-card-glass box-border flex flex-col gap-y-3 rounded-2xl p-3">
|
||||||
<uh-section-title> 投票信息 </uh-section-title>
|
<uh-section-title> 投票信息 </uh-section-title>
|
||||||
<view class="flex flex-col gap-3 rounded-xl bg-gray-100 p-4 text-sm text-gray-600">
|
<view class="flex flex-col gap-2 rounded-xl bg-gray-100 px-4 py-3 text-sm text-gray-900">
|
||||||
<view class="info-row">
|
<view class="info-row">
|
||||||
<text>投票类型:</text>
|
<text>投票类型:</text>
|
||||||
<text class="tag">{{ vote.spec?._uh_type }}</text>
|
<text class="tag">{{ vote.spec?._uh_type }}</text>
|
||||||
@@ -290,7 +290,7 @@ onShareTimeline(() => ({
|
|||||||
</view>
|
</view>
|
||||||
<view class="info-row">
|
<view class="info-row">
|
||||||
<text>投票方式:</text>
|
<text>投票方式:</text>
|
||||||
<text class="tag" :class="vote.spec?.canAnonymously ? 'text-primary' : 'text-[#f44336]'">
|
<text class="tag" :class="vote.spec?.canAnonymously ? 'text-primary' : 'text-red-400'">
|
||||||
{{ vote.spec?.canAnonymously ? '匿名' : '不匿名' }}
|
{{ vote.spec?.canAnonymously ? '匿名' : '不匿名' }}
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -307,7 +307,7 @@ onShareTimeline(() => ({
|
|||||||
<!-- 投票内容 -->
|
<!-- 投票内容 -->
|
||||||
<view class="uh-global-card-glass box-border flex flex-col gap-3 rounded-2xl p-3">
|
<view class="uh-global-card-glass box-border flex flex-col gap-3 rounded-2xl p-3">
|
||||||
<uh-section-title> 投票内容 </uh-section-title>
|
<uh-section-title> 投票内容 </uh-section-title>
|
||||||
<view class="box-border flex flex-col gap-y-2 rounded-xl bg-gray-100 p-4">
|
<view class="box-border flex flex-col gap-y-2 rounded-xl bg-gray-100 px-4 py-3">
|
||||||
<view class="text-sm text-gray-900 font-bold">
|
<view class="text-sm text-gray-900 font-bold">
|
||||||
{{ vote.spec?.title }}
|
{{ vote.spec?.title }}
|
||||||
</view>
|
</view>
|
||||||
@@ -326,12 +326,12 @@ onShareTimeline(() => ({
|
|||||||
{{ vote.spec?.maxVotes }} 项)
|
{{ vote.spec?.maxVotes }} 项)
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="options flex flex-col gap-3">
|
<view class="options flex flex-col gap-3 w-full">
|
||||||
<!-- PK 对抗条(与旧项目 pk-container 一致;样式需顶层定义,勿嵌套在 .vote-card 下) -->
|
<!-- PK 对抗条(与旧项目 pk-container 一致;样式需顶层定义,勿嵌套在 .vote-card 下) -->
|
||||||
<view v-if="vote.spec?.type === 'pk'" class="pk-container box-border w-full flex">
|
<view v-if="vote.spec?.type === 'pk'" class="pk-container box-border w-full flex">
|
||||||
<view
|
<view
|
||||||
v-for="(option, optionIndex) in vote.spec?.options" :key="optionIndex"
|
v-for="(option, optionIndex) in vote.spec?.options" :key="optionIndex"
|
||||||
class="radio-item" :class="optionIndex === 0 ? 'radio-left' : 'radio-right'"
|
class="flex-1 radio-item" :class="optionIndex === 0 ? 'radio-left' : 'radio-right'"
|
||||||
:style="{ width: `${option._uh_percent}%` }"
|
:style="{ width: `${option._uh_percent}%` }"
|
||||||
>
|
>
|
||||||
<view
|
<view
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
const articleDetailPath = '/pages-blog/article-detail/article-detail'
|
const articleDetailPath = '/pages-blog/article-detail/article-detail'
|
||||||
|
|
||||||
// 本地开发快速跳转页面,发布请置为 false
|
// 本地开发快速跳转页面,发布请置为 false
|
||||||
const DEV_MODE = true
|
const DEV_MODE = false
|
||||||
const DEV_TO_TYPE = 'page' as 'page' | 'tabbar'
|
const DEV_TO_TYPE = 'page' as 'page' | 'tabbar'
|
||||||
const DEV_TO_PATH = `/pages-blog/love/love`
|
const DEV_TO_PATH = `/pages-blog/love/love`
|
||||||
|
|
||||||
|
|||||||
@@ -217,9 +217,13 @@
|
|||||||
<view v-else class="box-border w-full p-3">
|
<view v-else class="box-border w-full p-3">
|
||||||
<view class="grid grid-cols-2 gap-2.5">
|
<view class="grid grid-cols-2 gap-2.5">
|
||||||
<view v-for="(item, index) in dataList" :key="index"
|
<view v-for="(item, index) in dataList" :key="index"
|
||||||
class="uh-global-card-glass h-38 w-full overflow-hidden rounded-xl">
|
class="relative uh-global-card-glass h-38 w-full overflow-hidden rounded-xl">
|
||||||
<image class="h-full w-full" :src="item.spec.url" mode="aspectFill" lazy-load
|
<image class="h-full w-full" :src="item.spec.url" mode="aspectFill" lazy-load
|
||||||
@click="handlePreview(item)" />
|
@click="handlePreview(item)" />
|
||||||
|
<view v-if="item.spec.displayName"
|
||||||
|
class="absolute bottom-0 w-full box-border p-3 pt-6 z-2 bg-gradient-to-b from-white/0 to-black/40 text-xs text-white">
|
||||||
|
{{item.spec.displayName}}
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="load-text w-full py-4 text-center text-xs text-gray-500">
|
<view class="load-text w-full py-4 text-center text-xs text-gray-500">
|
||||||
|
|||||||
Reference in New Issue
Block a user