diff --git a/frontend/pages.json b/frontend/pages.json index 2b0f39e..20f21e6 100644 --- a/frontend/pages.json +++ b/frontend/pages.json @@ -92,6 +92,15 @@ } } }, + { + "path": "pages/profile/myWorks", + "style": { + "navigationStyle": "custom", + "app-plus": { + "bounce": "none" + } + } + }, { "path": "pages/exhibition/exhibition", "style": { diff --git a/frontend/pages/components/BannerTop3.vue b/frontend/pages/components/BannerTop3.vue index 82ce969..b6826b6 100644 --- a/frontend/pages/components/BannerTop3.vue +++ b/frontend/pages/components/BannerTop3.vue @@ -1,47 +1,7 @@ @@ -49,17 +9,8 @@ import { ref, onMounted } from 'vue'; import { getHotRankingApi, getOssPresignedUrlApi } from '@/utils/api.js'; -const top3 = ref([]); -const loading = ref(true); +const emit = defineEmits(['dataLoaded']); -const formatScore = (score) => { - if (typeof score !== 'number' || isNaN(score) || score < 0) return '0'; - if (score >= 1000000) return (score / 1000000).toFixed(1) + 'M'; - if (score >= 1000) return (score / 1000).toFixed(1) + 'K'; - return score.toString(); -}; - -// 获取 OSS 预签名 URL,失败时降级返回原值 const resolveOssUrl = async (fileName, type) => { if (!fileName) return ''; try { @@ -72,199 +23,45 @@ const resolveOssUrl = async (fileName, type) => { }; const loadTop3 = async () => { - loading.value = true; try { const res = await getHotRankingApi('total', null, 1, 3); if (res.code === 200 && res.data?.items) { const items = res.data.items.slice(0, 3); - // 并发解析所有封面图和头像的 OSS 预签名 URL - top3.value = await Promise.all(items.map(async (item) => { + const resolved = await Promise.all(items.map(async (item) => { const [coverUrl, avatarUrl] = await Promise.all([ resolveOssUrl(item.cover_url || '', 'asset'), resolveOssUrl(item.avatar_url || '', 'avatar'), ]); return { ...item, cover_url: coverUrl, avatar_url: avatarUrl }; })); + emit('dataLoaded', resolved); } } catch (e) { console.error('[BannerTop3] 加载失败', e?.message ?? e); - } finally { - loading.value = false; } }; +const onBannerTap = () => { + uni.navigateTo({ url: '/pages/rank/rank' }); +}; + onMounted(loadTop3); defineExpose({ reload: loadTop3 }); diff --git a/frontend/pages/components/Header.vue b/frontend/pages/components/Header.vue index e682832..aed5133 100644 --- a/frontend/pages/components/Header.vue +++ b/frontend/pages/components/Header.vue @@ -12,7 +12,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -40,7 +40,7 @@ - + @@ -58,13 +58,14 @@ + - + {{ crystalBalance }} - + 收益 27.1/H @@ -454,14 +455,14 @@ defineExpose({ /* --- 上层图标样式 --- */ .task-icon-box { position: absolute; - top: 0; + top: 8rpx; /* 固定在顶部 */ left: 50%; transform: translateX(-50%); /* 水平居中 */ - width: 90rpx; + width: 88rpx; /* 图标宽度 */ - height: 90rpx; + height: 88rpx; /* 图标高度 */ z-index: 10; /* 确保图标在文字块上面 */ @@ -475,13 +476,10 @@ defineExpose({ /* 红点样式 */ .task-red-dot { position: absolute; - top: 6rpx; - right: 6rpx; + top: 8rpx; + right: 12rpx; width: 16rpx; height: 16rpx; - background-color: red; - border-radius: 50%; - border: 2rpx solid #fff; } /* --- 下层文字背景块 --- */ @@ -493,42 +491,22 @@ defineExpose({ transform: translateX(-50%); width: 88rpx; height: 80rpx; - background: linear-gradient(to bottom right, - #F0E4B1 0%, - /* 左:浅橙粉 */ - #F08399 50%, - #B94E73 100% - /* 右:柔粉红 */ - ); - - - /* 立体感核心:多层阴影 + 内阴影模拟凸起 */ - box-shadow: - /* 外层投影 - 让按钮浮起 */ - 0 4rpx 12rpx rgba(255, 143, 158, 0.2), - 0 2rpx 6rpx rgba(255, 143, 158, 0.15), - - /* 内阴影 - 模拟顶部受光 + 底部凹陷 */ - inset 0 2rpx 4rpx rgba(255, 255, 255, 0.4), - /* 顶部高光 */ - inset 0 -2rpx 4rpx rgba(0, 0, 0, 0.05); - /* 底部暗部 */ - /* 粉色渐变背景,可微调 */ + background-image: url('/static/square/gerenzhongxincangpinkuang.png'); + background-size: 100% 100%; + background-repeat: no-repeat; border-radius: 20rpx; display: flex; align-items: center; justify-content: center; z-index: 5; /* 必须比图标小,才能被覆盖 */ - box-shadow: 0 4rpx 10rpx rgba(255, 107, 187, 0.3); - /* 可选:增加一点阴影层次感 */ } .task-text-label { - font-size: 18rpx; + font-size: 16rpx; color: #fff; text-shadow: 1rpx 1rpx 2rpx rgba(255, 255, 255, 0.5); - margin-top: 24rpx; + margin-top: 32rpx; } @@ -564,17 +542,23 @@ defineExpose({ /* --- 右侧容器 --- */ .crystal-info-container { position: relative; - /* 自动撑开宽度 */ height: 56rpx; width: 80rpx; - /* 容器高度 */ border-radius: 16rpx; - background: rgba(0, 0, 0, 0.5); bottom: 4rpx; padding-right: 28rpx; padding-left: 56rpx; } +.crystal-bg-img { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 0; +} + /* --- 上层:文字内容 --- */ .crystal-text-layer { position: relative; @@ -618,30 +602,19 @@ defineExpose({ width: 100%; height: 65%; z-index: 1; - /* 关键:层级低于文字,高于透明底色 */ background: linear-gradient(to bottom right, #F0E4B1 0%, - /* 左:浅橙粉 */ #F08399 50%, #B94E7399 100% - /* 右:柔粉红 */ ); - - /* 立体感核心:多层阴影 + 内阴影模拟凸起 */ box-shadow: - /* 外层投影 - 让按钮浮起 */ 0 4rpx 12rpx rgba(255, 143, 158, 0.2), 0 2rpx 6rpx rgba(255, 143, 158, 0.15), - - /* 内阴影 - 模拟顶部受光 + 底部凹陷 */ inset 0 2rpx 4rpx rgba(255, 255, 255, 0.4), - /* 顶部高光 */ inset 0 -2rpx 4rpx rgba(0, 0, 0, 0.05); - /* 底部暗部 */ border-radius: 10rpx; - } .icon-item { diff --git a/frontend/pages/profile/myWorks.vue b/frontend/pages/profile/myWorks.vue new file mode 100644 index 0000000..447a081 --- /dev/null +++ b/frontend/pages/profile/myWorks.vue @@ -0,0 +1,589 @@ + + + + + diff --git a/frontend/pages/square/components/BannerCarousel.vue b/frontend/pages/square/components/BannerCarousel.vue index 37a21e7..14eccd5 100644 --- a/frontend/pages/square/components/BannerCarousel.vue +++ b/frontend/pages/square/components/BannerCarousel.vue @@ -1,15 +1,16 @@ diff --git a/frontend/pages/square/components/ContentTabs.vue b/frontend/pages/square/components/ContentTabs.vue new file mode 100644 index 0000000..276a0ef --- /dev/null +++ b/frontend/pages/square/components/ContentTabs.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/frontend/pages/square/components/WaterfallGrid.vue b/frontend/pages/square/components/WaterfallGrid.vue new file mode 100644 index 0000000..ef07590 --- /dev/null +++ b/frontend/pages/square/components/WaterfallGrid.vue @@ -0,0 +1,457 @@ + + + + + diff --git a/frontend/pages/square/composables/useSwipe.js b/frontend/pages/square/composables/useSwipe.js index eb8e2d9..059a659 100644 --- a/frontend/pages/square/composables/useSwipe.js +++ b/frontend/pages/square/composables/useSwipe.js @@ -88,7 +88,7 @@ export function useSwipe() { inertiaRaf = rafFn(step) } - const getBannerBottom = () => (screenWidth.value / 750) * 496 + const getBannerBottom = () => (screenWidth.value / 750) * 632 const onBgTouchStart = (e) => { const touchY = e.touches[0].clientY diff --git a/frontend/pages/square/square.vue b/frontend/pages/square/square.vue index e00fbb2..96f9477 100644 --- a/frontend/pages/square/square.vue +++ b/frontend/pages/square/square.vue @@ -1,40 +1,16 @@ @@ -340,29 +230,38 @@ onUnmounted(() => { overflow: hidden; } -.background-strip { - position: absolute; - top: 0; - left: 50%; - height: 150%; +/* .fall-bg{ + background: rgba(255, 180, 180, 0.25); + border-radius: 48rpx; +} */ + +.banner-tabs-wrapper { + position: fixed; + top: 216rpx; + left: 0; + right: 0; + z-index: 100; display: flex; - z-index: 0; - will-change: transform; + flex-direction: column; + min-height: 448rpx; + justify-content: space-between; + background: rgb(249 159 192 / 45%);; + /* background: rgba(212, 127, 127, 0.8); */ + border-radius: 48rpx; + overflow: visible; } -.background-tile { - flex-shrink: 0; - height: 100%; -} +/* .tabs{ + margin-bottom: 8rpx; +} */ -.cabin-layer { +.background-fixed { position: absolute; top: 0; - left: 50%; + left: 0; width: 100%; height: 100%; - z-index: 1; - pointer-events: none; + z-index: 0; } .nav-mask {