feat(aigc): implement travel AIGC feature and clean up legacy assets
- Replace all local static AIGC assets with OSS hosted URLs to reduce bundle size - Add travelAIGC command to ChatModel and update quick access menu to link to AIGC home - Implement AIGC user consent flow with local storage persistence for compliance - Refactor Discovery page layout, remove unused HeritageDiscoverySection component - Update ChatTopNavBar to support dynamic navigation bar height based on system info - Restructure ChatMainList layout for better discovery panel interaction - Remove deprecated local asset files and clean up unused imports across codebase
This commit is contained in:
16
src/constant/aigc.js
Normal file
16
src/constant/aigc.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { currentClientType } from "@/constant/base";
|
||||||
|
|
||||||
|
const CLIENT_TYPE = currentClientType();
|
||||||
|
const AIGC_CONSENT_AGREED = `${CLIENT_TYPE}_AIGC_CONSENT_AGREED`;
|
||||||
|
|
||||||
|
export const getAigcConsentAgreed = () => {
|
||||||
|
return uni.getStorageSync(AIGC_CONSENT_AGREED);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setAigcConsentAgreed = (agreed = true) => {
|
||||||
|
return uni.setStorageSync(AIGC_CONSENT_AGREED, agreed);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeAigcConsentAgreed = () => {
|
||||||
|
return uni.removeStorageSync(AIGC_CONSENT_AGREED);
|
||||||
|
};
|
||||||
@@ -99,4 +99,6 @@ export const Command = {
|
|||||||
feedbackCard: "Command.feedbackCard",
|
feedbackCard: "Command.feedbackCard",
|
||||||
// 生成合成图片
|
// 生成合成图片
|
||||||
aigcPhotoGenerator: "Command.aigcPhotoGenerator",
|
aigcPhotoGenerator: "Command.aigcPhotoGenerator",
|
||||||
|
// 旅行AIGC
|
||||||
|
travelAIGC: "Command.travelAIGC",
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import glassBoatPostcard from "../../home/assets/glass-boat-postcard.gif";
|
|
||||||
|
|
||||||
export const aigcDetailResult = {
|
export const aigcDetailResult = {
|
||||||
id: "glass-boat-postcard-result",
|
id: "glass-boat-postcard-result",
|
||||||
title: "鸳鸯湖明信片",
|
title: "鸳鸯湖明信片",
|
||||||
cover: glassBoatPostcard,
|
cover: "https://oss.nianxx.cn/mp/static/xiaoqi/glass-boat-postcard.gif",
|
||||||
accent: "#0a4d46",
|
accent: "#0a4d46",
|
||||||
variantLabel: "图片版",
|
variantLabel: "图片版",
|
||||||
resultLabel: "图片版",
|
resultLabel: "图片版",
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 772 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 MiB |
@@ -1,8 +1,3 @@
|
|||||||
import glassBoatPostcard from "../assets/glass-boat-postcard.gif";
|
|
||||||
import bridgeCover from "../assets/card-bridge.png";
|
|
||||||
import waterfallCover from "../assets/card-waterfall.png";
|
|
||||||
import cultureCover from "../assets/card-culture-1.png";
|
|
||||||
|
|
||||||
export const aigcTemplates = [
|
export const aigcTemplates = [
|
||||||
{
|
{
|
||||||
id: "glass-boat-postcard",
|
id: "glass-boat-postcard",
|
||||||
@@ -11,7 +6,7 @@ export const aigcTemplates = [
|
|||||||
note: "图片版100积分 · 动效视频版200积分/5秒内",
|
note: "图片版100积分 · 动效视频版200积分/5秒内",
|
||||||
badge: "同源双版本",
|
badge: "同源双版本",
|
||||||
buttonText: "选这个模板",
|
buttonText: "选这个模板",
|
||||||
cover: glassBoatPostcard,
|
cover: "https://oss.nianxx.cn/mp/static/xiaoqi/glass-boat-postcard.gif",
|
||||||
tone: "postcard",
|
tone: "postcard",
|
||||||
accent: "#0a4d46",
|
accent: "#0a4d46",
|
||||||
},
|
},
|
||||||
@@ -22,7 +17,7 @@ export const aigcTemplates = [
|
|||||||
note: "图片版100积分 · 动效视频版200积分/5秒内",
|
note: "图片版100积分 · 动效视频版200积分/5秒内",
|
||||||
badge: "同源双版本",
|
badge: "同源双版本",
|
||||||
buttonText: "选这个模板",
|
buttonText: "选这个模板",
|
||||||
cover: bridgeCover,
|
cover: "https://oss.nianxx.cn/mp/static/xiaoqi/card-bridge.png",
|
||||||
tone: "emerald",
|
tone: "emerald",
|
||||||
accent: "#0f7069",
|
accent: "#0f7069",
|
||||||
},
|
},
|
||||||
@@ -33,7 +28,7 @@ export const aigcTemplates = [
|
|||||||
note: "图片版100积分 · 动效视频版200积分/5秒内",
|
note: "图片版100积分 · 动效视频版200积分/5秒内",
|
||||||
badge: "同源双版本",
|
badge: "同源双版本",
|
||||||
buttonText: "选这个模板",
|
buttonText: "选这个模板",
|
||||||
cover: waterfallCover,
|
cover: "https://oss.nianxx.cn/mp/static/xiaoqi/card-waterfall.png",
|
||||||
tone: "aqua",
|
tone: "aqua",
|
||||||
accent: "#155e75",
|
accent: "#155e75",
|
||||||
},
|
},
|
||||||
@@ -44,7 +39,7 @@ export const aigcTemplates = [
|
|||||||
note: "图片版100积分 · 动效视频版200积分/5秒内",
|
note: "图片版100积分 · 动效视频版200积分/5秒内",
|
||||||
badge: "同源双版本",
|
badge: "同源双版本",
|
||||||
buttonText: "选这个模板",
|
buttonText: "选这个模板",
|
||||||
cover: cultureCover,
|
cover: "https://oss.nianxx.cn/mp/static/xiaoqi/card-culture-1.png",
|
||||||
tone: "forest",
|
tone: "forest",
|
||||||
accent: "#36563d",
|
accent: "#36563d",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,10 +3,7 @@
|
|||||||
<AigcTopBar :points="pointBalance" @back="handleBack" @history="handleHistory" @recharge="handleRecharge" />
|
<AigcTopBar :points="pointBalance" @back="handleBack" @history="handleHistory" @recharge="handleRecharge" />
|
||||||
|
|
||||||
<view class="aigc-home-browser">
|
<view class="aigc-home-browser">
|
||||||
<GiftPointsToast
|
<GiftPointsToast :visible="giftToastVisible" @close="handleCloseGiftToast" />
|
||||||
:visible="giftToastVisible"
|
|
||||||
@close="handleCloseGiftToast"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TemplateCarousel v-model="activeIndex" :templates="templates" @select="handleSelectTemplate" />
|
<TemplateCarousel v-model="activeIndex" :templates="templates" @select="handleSelectTemplate" />
|
||||||
|
|
||||||
@@ -29,13 +26,6 @@ const giftToastVisible = ref(true);
|
|||||||
const templates = aigcTemplates;
|
const templates = aigcTemplates;
|
||||||
const steps = aigcFlowSteps;
|
const steps = aigcFlowSteps;
|
||||||
|
|
||||||
const showPlaceholderToast = (title) => {
|
|
||||||
uni.showToast({
|
|
||||||
title,
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
const pages = getCurrentPages();
|
const pages = getCurrentPages();
|
||||||
if (pages.length > 1) {
|
if (pages.length > 1) {
|
||||||
@@ -44,11 +34,15 @@ const handleBack = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleHistory = () => {
|
const handleHistory = () => {
|
||||||
showPlaceholderToast("最近任务");
|
uni.navigateTo({
|
||||||
|
url: "/pages-aigc/record/record"
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRecharge = () => {
|
const handleRecharge = () => {
|
||||||
showPlaceholderToast("积分充值");
|
uni.navigateTo({
|
||||||
|
url: "/pages-aigc/recharge/recharge"
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCloseGiftToast = () => {
|
const handleCloseGiftToast = () => {
|
||||||
@@ -57,8 +51,7 @@ const handleCloseGiftToast = () => {
|
|||||||
|
|
||||||
const handleSelectTemplate = (template) => {
|
const handleSelectTemplate = (template) => {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages-aigc/useTemplate/useTemplate?templateId=${encodeURIComponent(template.id || "")}`,
|
url: `/pages-aigc/useTemplate/useTemplate?templateId=${encodeURIComponent(template.id || "")}`
|
||||||
fail: () => showPlaceholderToast(template.title),
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
import glassBoatPostcard from "@/pages-aigc/home/assets/glass-boat-postcard.gif";
|
|
||||||
|
|
||||||
export const aigcRecords = [
|
export const aigcRecords = [
|
||||||
{
|
{
|
||||||
id: "record-lake-postcard",
|
id: "record-lake-postcard",
|
||||||
title: "鸳鸯湖明信片",
|
title: "鸳鸯湖明信片",
|
||||||
time: "2026-06-29 15:46:12",
|
time: "2026-06-29 15:46:12",
|
||||||
status: "图片版 · 已完成 · 可升级动效视频",
|
status: "图片版 · 已完成 · 可升级动效视频",
|
||||||
image: glassBoatPostcard,
|
image: "https://oss.nianxx.cn/mp/static/xiaoqi/glass-boat-postcard.gif",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "record-lake-postcard-video",
|
id: "record-lake-postcard-video",
|
||||||
title: "鸳鸯湖明信片",
|
title: "鸳鸯湖明信片",
|
||||||
time: "2026-06-29 15:58:40",
|
time: "2026-06-29 15:58:40",
|
||||||
status: "动效视频版 · 5秒内 · 由图片版升级",
|
status: "动效视频版 · 5秒内 · 由图片版升级",
|
||||||
image: glassBoatPostcard,
|
image: "https://oss.nianxx.cn/mp/static/xiaoqi/glass-boat-postcard.gif",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 556 KiB After Width: | Height: | Size: 123 KiB |
@@ -1,13 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<view
|
<uni-popup
|
||||||
v-if="visible"
|
ref="popupRef"
|
||||||
class="aigc-consent-overlay"
|
type="center"
|
||||||
@touchmove.stop.prevent
|
background-color="transparent"
|
||||||
|
mask-background-color="rgba(0, 0, 0, 0.58)"
|
||||||
|
:safe-area="false"
|
||||||
|
:is-mask-click="false"
|
||||||
|
@change="handlePopupChange"
|
||||||
>
|
>
|
||||||
<view class="aigc-consent-dialog">
|
<view
|
||||||
<text class="aigc-consent-title">温馨提示</text>
|
class="aigc-consent-overlay"
|
||||||
|
@touchmove.stop.prevent
|
||||||
|
>
|
||||||
|
<view class="aigc-consent-dialog">
|
||||||
|
<text class="aigc-consent-title">温馨提示</text>
|
||||||
|
|
||||||
<view class="aigc-consent-content">
|
<view class="aigc-consent-content">
|
||||||
<text v-if="content">{{ content }}</text>
|
<text v-if="content">{{ content }}</text>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<text>{{ defaultContentPrefix }}</text>
|
<text>{{ defaultContentPrefix }}</text>
|
||||||
@@ -16,9 +24,9 @@
|
|||||||
</text>
|
</text>
|
||||||
<text>{{ defaultContentSuffix }}</text>
|
<text>{{ defaultContentSuffix }}</text>
|
||||||
</template>
|
</template>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="aigc-consent-actions">
|
<view class="aigc-consent-actions">
|
||||||
<button
|
<button
|
||||||
class="aigc-consent-button aigc-consent-cancel"
|
class="aigc-consent-button aigc-consent-cancel"
|
||||||
type="default"
|
type="default"
|
||||||
@@ -33,13 +41,14 @@
|
|||||||
>
|
>
|
||||||
我同意
|
我同意
|
||||||
</button>
|
</button>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</uni-popup>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from "vue";
|
import { computed, nextTick, onMounted, ref, watch } from "vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
visible: {
|
visible: {
|
||||||
@@ -61,6 +70,7 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(["update:visible", "cancel", "agree", "ruleClick"]);
|
const emit = defineEmits(["update:visible", "cancel", "agree", "ruleClick"]);
|
||||||
|
const popupRef = ref(null);
|
||||||
|
|
||||||
const defaultContentPrefix = computed(
|
const defaultContentPrefix = computed(
|
||||||
() =>
|
() =>
|
||||||
@@ -71,6 +81,7 @@ const defaultContentSuffix =
|
|||||||
",您点击“我同意”等进行下一步操作的行为均视为您同意受本规则约束。如您不同意,您可以直接关闭页面。";
|
",您点击“我同意”等进行下一步操作的行为均视为您同意受本规则约束。如您不同意,您可以直接关闭页面。";
|
||||||
|
|
||||||
const close = () => {
|
const close = () => {
|
||||||
|
popupRef.value?.close();
|
||||||
emit("update:visible", false);
|
emit("update:visible", false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -87,6 +98,34 @@ const handleAgree = () => {
|
|||||||
const handleRuleClick = () => {
|
const handleRuleClick = () => {
|
||||||
emit("ruleClick");
|
emit("ruleClick");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const syncPopupVisible = async (visible) => {
|
||||||
|
await nextTick();
|
||||||
|
if (visible) {
|
||||||
|
popupRef.value?.open();
|
||||||
|
} else {
|
||||||
|
popupRef.value?.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePopupChange = (event) => {
|
||||||
|
const show = event?.show ?? event?.detail?.show;
|
||||||
|
if (show === false && props.visible) {
|
||||||
|
emit("update:visible", false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.visible,
|
||||||
|
(visible) => {
|
||||||
|
syncPopupVisible(visible);
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
syncPopupVisible(props.visible);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -1,18 +1,7 @@
|
|||||||
.aigc-consent-overlay {
|
.aigc-consent-overlay {
|
||||||
position: absolute;
|
width: 100vw;
|
||||||
z-index: 30;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 0 28px;
|
padding: 0 28px;
|
||||||
background: rgba(0, 0, 0, 0.58);
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
-webkit-backdrop-filter: blur(1px);
|
|
||||||
backdrop-filter: blur(1px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.aigc-consent-dialog {
|
.aigc-consent-dialog {
|
||||||
|
|||||||
@@ -2,23 +2,17 @@
|
|||||||
<view class="flex flex-col h-screen relative overflow-hidden">
|
<view class="flex flex-col h-screen relative overflow-hidden">
|
||||||
<!-- 顶部自定义导航栏 -->
|
<!-- 顶部自定义导航栏 -->
|
||||||
<view class="header absolute top-0 left-0 w-full z-10" :style="{ paddingTop: statusBarHeight + 'px' }">
|
<view class="header absolute top-0 left-0 w-full z-10" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||||
<ChatTopNavBar ref="topNavBarRef" :mainPageDataModel="mainPageDataModel" @showDrawer="handleShowDrawer" />
|
<ChatTopNavBar ref="topNavBarRef" :mainPageDataModel="mainPageDataModel" :navHeight="navBarHeight"
|
||||||
|
@showDrawer="handleShowDrawer" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="home-hero relative flex-shrink-0">
|
<view class="home-hero relative flex-shrink-0">
|
||||||
<image class="home-hero-bg w-full block" :src="mainPageDataModel?.initPageImages?.backgroundImageUrl"
|
<image class="home-hero-bg w-full block" :src="mainPageDataModel?.initPageImages?.backgroundImageUrl"
|
||||||
mode="aspectFill" />
|
mode="aspectFill" />
|
||||||
<!-- <SpriteAnimator
|
<SpriteAnimator v-if="homeSpriteStyle.ipLargeImage" class="home-hero-sprite" :src="homeSpriteStyle.ipLargeImage"
|
||||||
v-if="homeSpriteStyle.ipLargeImage"
|
:frameWidth="homeSpriteStyle.frameWidth" :frameHeight="homeSpriteStyle.frameHeight"
|
||||||
class="home-hero-sprite"
|
:totalFrames="homeSpriteStyle.totalFrames" :columns="homeSpriteStyle.columns"
|
||||||
:src="homeSpriteStyle.ipLargeImage"
|
:displayWidth="homeSpriteStyle.displayWidth" :fps="16" />
|
||||||
:frameWidth="homeSpriteStyle.frameWidth"
|
|
||||||
:frameHeight="homeSpriteStyle.frameHeight"
|
|
||||||
:totalFrames="homeSpriteStyle.totalFrames"
|
|
||||||
:columns="homeSpriteStyle.columns"
|
|
||||||
:displayWidth="homeSpriteStyle.displayWidth"
|
|
||||||
:fps="16"
|
|
||||||
/> -->
|
|
||||||
<view class="home-tabs-layer absolute bottom-0 left-0 right-0 flex-full">
|
<view class="home-tabs-layer absolute bottom-0 left-0 right-0 flex-full">
|
||||||
<view style="margin-bottom: -1px;">
|
<view style="margin-bottom: -1px;">
|
||||||
<AiTabSwitch v-model="tabIndex" :list="tabList" @change="handleChange" />
|
<AiTabSwitch v-model="tabIndex" :list="tabList" @change="handleChange" />
|
||||||
@@ -26,16 +20,16 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<scroll-view v-show="tabIndex === 0" class="main-scroll-area flex flex-col flex-full overflow-hidden" scroll-y
|
<view v-show="tabIndex === 0" class="discovery-shell flex-full" @touchstart.capture="handleDiscoveryPanelTouchStart"
|
||||||
@scroll="handleDiscoveryScroll"
|
@touchstart="handleDiscoveryPanelTouchStart" @touchmove="handleDiscoveryPanelTouchMove">
|
||||||
@touchstart.capture="handleScrollAreaTouchStart" @touchstart="handleScrollAreaTouchStart"
|
<view class="home-welcome-panel">
|
||||||
@touchmove="handleScrollAreaTouchMove">
|
|
||||||
<view class="home-welcome-collapse" :class="{ 'is-collapsed': isHomeWelcomeCollapsed }">
|
|
||||||
<HomeWelcome class="flex-shrink-0" :mainPageDataModel="mainPageDataModel" />
|
<HomeWelcome class="flex-shrink-0" :mainPageDataModel="mainPageDataModel" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<Discovery />
|
<view class="discovery-panel" :class="{ 'is-collapsed': isDiscoveryPanelCollapsed }">
|
||||||
</scroll-view>
|
<Discovery @content-scroll="handleDiscoveryContentScroll" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 消息列表(可滚动区域) -->
|
<!-- 消息列表(可滚动区域) -->
|
||||||
<scroll-view v-show="tabIndex === 1" class="main main-scroll-area flex-full overflow-hidden min-height-0" scroll-y
|
<scroll-view v-show="tabIndex === 1" class="main main-scroll-area flex-full overflow-hidden min-height-0" scroll-y
|
||||||
@@ -215,6 +209,7 @@ const emit = defineEmits(["showDrawer"]);
|
|||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
/// 导航栏相关
|
/// 导航栏相关
|
||||||
const statusBarHeight = ref(20);
|
const statusBarHeight = ref(20);
|
||||||
|
const navBarHeight = ref(44);
|
||||||
/// 输入框组件引用
|
/// 输入框组件引用
|
||||||
const inputAreaRef = ref(null);
|
const inputAreaRef = ref(null);
|
||||||
const topNavBarRef = ref();
|
const topNavBarRef = ref();
|
||||||
@@ -230,12 +225,11 @@ const isKeyboardShow = ref(false);
|
|||||||
|
|
||||||
///(控制滚动位置)
|
///(控制滚动位置)
|
||||||
const scrollTop = ref(99999);
|
const scrollTop = ref(99999);
|
||||||
const discoveryScrollTop = ref(0);
|
const discoveryInnerScrollTop = ref(0);
|
||||||
const lastDiscoveryScrollTop = ref(0);
|
const discoveryPanelTouchStartY = ref(0);
|
||||||
const isHomeWelcomeCollapsed = ref(false);
|
const isDiscoveryPanelCollapsed = ref(false);
|
||||||
const DISCOVERY_WELCOME_COLLAPSE_TOP = 12;
|
const DISCOVERY_PANEL_EXPAND_TOP = 4;
|
||||||
const DISCOVERY_WELCOME_EXPAND_TOP = 4;
|
const DISCOVERY_PANEL_TOUCH_DELTA = 16;
|
||||||
const DISCOVERY_SCROLL_DELTA = 2;
|
|
||||||
|
|
||||||
/// 会话列表
|
/// 会话列表
|
||||||
const chatMsgList = ref([]);
|
const chatMsgList = ref([]);
|
||||||
@@ -302,6 +296,9 @@ const homeSpriteStyle = computed(() => {
|
|||||||
|
|
||||||
const handleChange = (i) => {
|
const handleChange = (i) => {
|
||||||
console.log("切换:", i);
|
console.log("切换:", i);
|
||||||
|
if (i === 0) {
|
||||||
|
resetDiscoveryScrollState();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleShowDrawer = () => {
|
const handleShowDrawer = () => {
|
||||||
@@ -389,26 +386,45 @@ const handleScrollAreaTouchMove = () => {
|
|||||||
hideKeyboardByScroll();
|
hideKeyboardByScroll();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const resetDiscoveryScrollState = () => {
|
||||||
|
discoveryInnerScrollTop.value = 0;
|
||||||
|
discoveryPanelTouchStartY.value = 0;
|
||||||
|
isDiscoveryPanelCollapsed.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
// 处理用户滚动事件
|
// 处理用户滚动事件
|
||||||
const handleDiscoveryScroll = (e) => {
|
const getTouchPointY = (e) => {
|
||||||
if (Date.now() - lastScrollTouchAt < 1000) {
|
const touch = e?.touches?.[0] || e?.changedTouches?.[0];
|
||||||
hideKeyboardByScroll();
|
return Number(touch?.clientY ?? touch?.pageY ?? 0);
|
||||||
}
|
};
|
||||||
|
|
||||||
const currentScrollTop = Number(e.detail?.scrollTop || 0);
|
const handleDiscoveryPanelTouchStart = (e) => {
|
||||||
const scrollDelta = currentScrollTop - lastDiscoveryScrollTop.value;
|
handleScrollAreaTouchStart();
|
||||||
discoveryScrollTop.value = currentScrollTop;
|
discoveryPanelTouchStartY.value = getTouchPointY(e);
|
||||||
|
};
|
||||||
|
|
||||||
if (currentScrollTop <= DISCOVERY_WELCOME_EXPAND_TOP) {
|
const handleDiscoveryPanelTouchMove = (e) => {
|
||||||
isHomeWelcomeCollapsed.value = false;
|
handleScrollAreaTouchMove();
|
||||||
|
|
||||||
|
const currentY = getTouchPointY(e);
|
||||||
|
if (!currentY || !discoveryPanelTouchStartY.value) return;
|
||||||
|
|
||||||
|
const touchDelta = currentY - discoveryPanelTouchStartY.value;
|
||||||
|
if (touchDelta < -DISCOVERY_PANEL_TOUCH_DELTA) {
|
||||||
|
isDiscoveryPanelCollapsed.value = true;
|
||||||
} else if (
|
} else if (
|
||||||
currentScrollTop > DISCOVERY_WELCOME_COLLAPSE_TOP ||
|
touchDelta > DISCOVERY_PANEL_TOUCH_DELTA &&
|
||||||
scrollDelta > DISCOVERY_SCROLL_DELTA
|
discoveryInnerScrollTop.value <= DISCOVERY_PANEL_EXPAND_TOP
|
||||||
) {
|
) {
|
||||||
isHomeWelcomeCollapsed.value = true;
|
isDiscoveryPanelCollapsed.value = false;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
lastDiscoveryScrollTop.value = currentScrollTop;
|
const handleDiscoveryContentScroll = ({ scrollTop }) => {
|
||||||
|
discoveryInnerScrollTop.value = Number(scrollTop || 0);
|
||||||
|
if (discoveryInnerScrollTop.value > DISCOVERY_PANEL_TOUCH_DELTA) {
|
||||||
|
isDiscoveryPanelCollapsed.value = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const welcomeHeight = ref(0);
|
const welcomeHeight = ref(0);
|
||||||
@@ -537,11 +553,19 @@ const addNoticeListener = () => {
|
|||||||
|
|
||||||
/// =============生命周期函数↓================
|
/// =============生命周期函数↓================
|
||||||
onLoad(() => {
|
onLoad(() => {
|
||||||
uni.getSystemInfo({
|
const systemInfo = uni.getSystemInfoSync();
|
||||||
success: (res) => {
|
const systemStatusBarHeight = systemInfo.statusBarHeight || 20;
|
||||||
statusBarHeight.value = res.statusBarHeight || 20;
|
statusBarHeight.value = systemStatusBarHeight;
|
||||||
},
|
navBarHeight.value = systemInfo.platform === "ios" ? 44 : 48;
|
||||||
});
|
|
||||||
|
if (typeof uni.getMenuButtonBoundingClientRect === "function") {
|
||||||
|
const menuButton = uni.getMenuButtonBoundingClientRect();
|
||||||
|
|
||||||
|
if (menuButton?.height && typeof menuButton.top === "number") {
|
||||||
|
statusBarHeight.value = Math.max(menuButton.top, systemStatusBarHeight);
|
||||||
|
navBarHeight.value = menuButton.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onReady(() => {
|
onReady(() => {
|
||||||
|
|||||||
@@ -5,23 +5,41 @@
|
|||||||
overscroll-behavior-y: contain;
|
overscroll-behavior-y: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-welcome-collapse {
|
.discovery-shell {
|
||||||
width: 100%;
|
position: relative;
|
||||||
height: 92px;
|
flex-basis: 0;
|
||||||
flex-shrink: 0;
|
height: 0;
|
||||||
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
opacity: 1;
|
background: $theme-color-50;
|
||||||
transform: translateY(0);
|
|
||||||
transition:
|
|
||||||
height 240ms ease,
|
|
||||||
opacity 240ms ease,
|
|
||||||
transform 240ms ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-welcome-collapse.is-collapsed {
|
.home-welcome-panel {
|
||||||
height: 0;
|
position: absolute;
|
||||||
opacity: 0;
|
top: 0;
|
||||||
transform: translateY(-8px);
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1;
|
||||||
|
width: 100%;
|
||||||
|
height: 92px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.discovery-panel {
|
||||||
|
position: absolute;
|
||||||
|
top: 92px;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 2;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: $theme-color-50;
|
||||||
|
transition: top 240ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.discovery-panel.is-collapsed {
|
||||||
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-hero {
|
.home-hero {
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="quick-access flex flex-row ml-12 pt-8 pb-8 scroll-x whitespace-nowrap">
|
<view>
|
||||||
<view class="item border-box rounded-50 flex flex-row items-center" v-for="(item, index) in itemList" :key="index"
|
<view class="quick-access flex flex-row ml-12 pt-8 pb-8 scroll-x whitespace-nowrap">
|
||||||
@click="sendReply(item)">
|
<view class="item border-box rounded-50 flex flex-row items-center" v-for="(item, index) in itemList" :key="index"
|
||||||
<view class="flex items-center justify-center">
|
@click="sendReply(item)">
|
||||||
<image v-if="item.icon" class="icon" :src="item.icon" />
|
<view class="flex items-center justify-center">
|
||||||
<text class="font-size-14 theme-color-500 line-height-20">
|
<image v-if="item.icon" class="icon" :src="item.icon" />
|
||||||
{{ item.title }}
|
<text class="font-size-14 theme-color-500 line-height-20">
|
||||||
</text>
|
{{ item.title }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<AigcConsentDialog
|
||||||
|
v-model:visible="aigcConsentVisible"
|
||||||
|
@agree="handleAigcConsentAgree"
|
||||||
|
/>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -16,7 +23,12 @@
|
|||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { Command } from "@/model/ChatModel";
|
import { Command } from "@/model/ChatModel";
|
||||||
import { SEND_MESSAGE_COMMAND_TYPE } from "@/constant/constant";
|
import { SEND_MESSAGE_COMMAND_TYPE } from "@/constant/constant";
|
||||||
|
import { getAigcConsentAgreed, setAigcConsentAgreed } from "@/constant/aigc";
|
||||||
import { checkToken } from "@/hooks/useGoLogin";
|
import { checkToken } from "@/hooks/useGoLogin";
|
||||||
|
import AigcConsentDialog from "../AigcConsentDialog/index.vue";
|
||||||
|
|
||||||
|
const AIGC_HOME_URL = "/pages-aigc/home/home";
|
||||||
|
const aigcConsentVisible = ref(false);
|
||||||
|
|
||||||
const itemList = ref([
|
const itemList = ref([
|
||||||
{
|
{
|
||||||
@@ -26,8 +38,8 @@ const itemList = ref([
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "",
|
icon: "",
|
||||||
title: "我的订单",
|
title: "旅行记录",
|
||||||
type: Command.myOrder,
|
type: Command.travelAIGC,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "",
|
icon: "",
|
||||||
@@ -64,8 +76,29 @@ const sendReply = (item) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 旅行AIGC
|
||||||
|
if (item.type === Command.travelAIGC) {
|
||||||
|
checkToken().then(() => {
|
||||||
|
if (getAigcConsentAgreed()) {
|
||||||
|
navigateToAigcHome();
|
||||||
|
} else {
|
||||||
|
aigcConsentVisible.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uni.$emit(SEND_MESSAGE_COMMAND_TYPE, item);
|
uni.$emit(SEND_MESSAGE_COMMAND_TYPE, item);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const navigateToAigcHome = () => {
|
||||||
|
uni.navigateTo({ url: AIGC_HOME_URL });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAigcConsentAgree = () => {
|
||||||
|
setAigcConsentAgreed(true);
|
||||||
|
navigateToAigcHome();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="border-box h-44 flex flex-items-center pl-12 pr-12">
|
<view class="border-box h-44 flex flex-items-center pl-12 pr-12" :style="navBarStyle">
|
||||||
<view class="nav-icon-button" @tap.stop="showDrawer">
|
<view class="nav-icon-button" @tap.stop="showDrawer">
|
||||||
<uni-icons type="bars" size="24" color="#ffffff" />
|
<uni-icons type="bars" size="24" color="#ffffff" />
|
||||||
</view>
|
</view>
|
||||||
@@ -29,6 +29,10 @@ import { getCurrentConfig } from "@/constant/base";
|
|||||||
import SpriteAnimator from "@/components/Sprite/SpriteAnimator.vue";
|
import SpriteAnimator from "@/components/Sprite/SpriteAnimator.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
navHeight: {
|
||||||
|
type: Number,
|
||||||
|
default: 44,
|
||||||
|
},
|
||||||
mainPageDataModel: {
|
mainPageDataModel: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({
|
default: () => ({
|
||||||
@@ -60,6 +64,10 @@ const emit = defineEmits(["showDrawer"]);
|
|||||||
|
|
||||||
const showDrawer = () => emit("showDrawer");
|
const showDrawer = () => emit("showDrawer");
|
||||||
|
|
||||||
|
const navBarStyle = computed(() => ({
|
||||||
|
height: `${props.navHeight}px`,
|
||||||
|
}));
|
||||||
|
|
||||||
defineExpose({ show });
|
defineExpose({ show });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,111 +0,0 @@
|
|||||||
<template>
|
|
||||||
<view class="heritage-section">
|
|
||||||
<view class="heritage-carousel">
|
|
||||||
<scroll-view
|
|
||||||
class="heritage-scroll"
|
|
||||||
scroll-x
|
|
||||||
show-scrollbar="false"
|
|
||||||
:scroll-left="carouselScrollLeft"
|
|
||||||
>
|
|
||||||
<view class="heritage-track">
|
|
||||||
<view
|
|
||||||
v-for="(item, index) in normalizedCards"
|
|
||||||
:key="getItemKey(item, index)"
|
|
||||||
class="heritage-card"
|
|
||||||
:class="{
|
|
||||||
'is-featured': index === 1,
|
|
||||||
'is-selected': index === 1,
|
|
||||||
}"
|
|
||||||
hover-class="is-pressed"
|
|
||||||
hover-stay-time="80"
|
|
||||||
@tap="handleCardTap(item.raw, index)"
|
|
||||||
>
|
|
||||||
<view class="heritage-image">
|
|
||||||
<image
|
|
||||||
v-if="item.coverImage"
|
|
||||||
class="heritage-cover"
|
|
||||||
:src="item.coverImage"
|
|
||||||
mode="aspectFill"
|
|
||||||
/>
|
|
||||||
<text class="heritage-badge">{{ item.badge }}</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="heritage-copy">
|
|
||||||
<text class="heritage-tag ellipsis-1">{{ item.tag }}</text>
|
|
||||||
<text class="heritage-title ellipsis-1">{{ item.title }}</text>
|
|
||||||
<text class="heritage-desc ellipsis-1">{{ item.subTitle }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</scroll-view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<HeritageQuickPrompts
|
|
||||||
:list="prompts"
|
|
||||||
@didSelectItem="handlePromptTap"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { computed, ref, watch } from "vue";
|
|
||||||
import HeritageQuickPrompts from "../HeritageQuickPrompts/index.vue";
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
cards: {
|
|
||||||
type: Array,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
prompts: {
|
|
||||||
type: Array,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits(["select-card", "select-prompt"]);
|
|
||||||
|
|
||||||
const carouselScrollLeft = ref(165);
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.cards.length,
|
|
||||||
(length) => {
|
|
||||||
const targetScrollLeft = length > 1 ? 165 : 0;
|
|
||||||
carouselScrollLeft.value = 0;
|
|
||||||
setTimeout(() => {
|
|
||||||
carouselScrollLeft.value = targetScrollLeft;
|
|
||||||
}, 0);
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
const getBadgeText = (item) => {
|
|
||||||
const source = item.jumpDesc || item.tag || item.title || "";
|
|
||||||
return source.slice(0, 2) || "推荐";
|
|
||||||
};
|
|
||||||
|
|
||||||
const normalizedCards = computed(() =>
|
|
||||||
props.cards.map((item) => ({
|
|
||||||
raw: item,
|
|
||||||
id: item.id ?? item.tabContentId,
|
|
||||||
title: item.title || "",
|
|
||||||
subTitle: item.subTitle || "",
|
|
||||||
tag: item.tag || item.jumpDesc || "推荐",
|
|
||||||
badge: getBadgeText(item),
|
|
||||||
coverImage: item.coverImage || "",
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
|
|
||||||
const getItemKey = (item, index) => item.id ?? item.title ?? index;
|
|
||||||
|
|
||||||
const handleCardTap = (item, index) => {
|
|
||||||
emit("select-card", item, index);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePromptTap = (item, index) => {
|
|
||||||
emit("select-prompt", item, index);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
@import "./styles/index.scss";
|
|
||||||
</style>
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
.heritage-section {
|
|
||||||
width: 100%;
|
|
||||||
height: 386px;
|
|
||||||
overflow: hidden;
|
|
||||||
background: $theme-color-50;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heritage-carousel,
|
|
||||||
.heritage-scroll {
|
|
||||||
width: 100%;
|
|
||||||
height: 268px;
|
|
||||||
overflow: hidden;
|
|
||||||
background: $theme-color-50;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heritage-track {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
min-width: 100%;
|
|
||||||
height: 268px;
|
|
||||||
padding: 8px 69px 26px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heritage-card {
|
|
||||||
flex: 0 0 189px;
|
|
||||||
width: 189px;
|
|
||||||
height: 227px;
|
|
||||||
margin-top: 5px;
|
|
||||||
margin-right: 14px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
padding: 8px;
|
|
||||||
border-radius: 28px;
|
|
||||||
border: 1px solid #f1f5f9;
|
|
||||||
background: #ffffff;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
||||||
box-sizing: border-box;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heritage-card:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heritage-card.is-featured {
|
|
||||||
flex-basis: 237px;
|
|
||||||
width: 237px;
|
|
||||||
height: 234px;
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heritage-card.is-selected {
|
|
||||||
border-color: rgba(12, 205, 88, 0.55);
|
|
||||||
box-shadow: 0 8px 18px rgba(12, 205, 88, 0.12);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.heritage-card.is-pressed {
|
|
||||||
opacity: 0.92;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heritage-image {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
height: 138px;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: 20px;
|
|
||||||
background: #f1f5f9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heritage-card.is-featured .heritage-image {
|
|
||||||
height: 145px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heritage-cover {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heritage-badge {
|
|
||||||
position: absolute;
|
|
||||||
top: 8px;
|
|
||||||
right: 8px;
|
|
||||||
width: 34px;
|
|
||||||
height: 32px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
border-radius: 8px;
|
|
||||||
background: rgba(255, 255, 255, 0.8);
|
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
||||||
color: $theme-color-500;
|
|
||||||
font-size: 11px;
|
|
||||||
line-height: 16px;
|
|
||||||
font-weight: 900;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heritage-copy {
|
|
||||||
min-width: 0;
|
|
||||||
margin-top: 8px;
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heritage-tag {
|
|
||||||
display: inline-flex;
|
|
||||||
max-width: 100%;
|
|
||||||
height: 18px;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0 6px;
|
|
||||||
border-radius: 4px;
|
|
||||||
background: #fffbeb;
|
|
||||||
color: #d97706;
|
|
||||||
font-size: 9px;
|
|
||||||
line-height: 14px;
|
|
||||||
font-weight: 800;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heritage-title {
|
|
||||||
display: block;
|
|
||||||
max-width: 100%;
|
|
||||||
margin: 4px 0;
|
|
||||||
color: #1e293b;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 20px;
|
|
||||||
font-weight: 900;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heritage-desc {
|
|
||||||
display: block;
|
|
||||||
max-width: 100%;
|
|
||||||
color: #94a3b8;
|
|
||||||
font-size: 10px;
|
|
||||||
line-height: 15px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
@@ -4,17 +4,18 @@
|
|||||||
<FindTabs v-if="discoveryTabs.length > 0" v-model="activeIndex" :tabs="discoveryTabs" @change="handleTabChange" />
|
<FindTabs v-if="discoveryTabs.length > 0" v-model="activeIndex" :tabs="discoveryTabs" @change="handleTabChange" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<HeritageDiscoverySection :cards="discoveryCards" :prompts="discoveryQuickQuestions" @select-card="handleCardClick"
|
<scroll-view class="discovery-scroll" scroll-y @scroll="handleContentScroll">
|
||||||
@select-prompt="handleQuickQuestionClick" />
|
<view class="discovery-body">
|
||||||
|
<ExploreCards v-if="discoveryCards.length > 0" :list="discoveryCards" @didSelectItem="handleCardClick" />
|
||||||
|
|
||||||
<ExploreCards v-if="discoveryCards.length > 0" :list="discoveryCards" @didSelectItem="handleCardClick" />
|
<QuickQuestions v-if="discoveryQuickQuestions.length > 0" :list="discoveryQuickQuestions"
|
||||||
|
@didSelectItem="handleQuickQuestionClick" />
|
||||||
|
|
||||||
<QuickQuestions v-if="discoveryQuickQuestions.length > 0" :list="discoveryQuickQuestions"
|
<!-- <DiscoveryPhotoToolCard @didSelectItem="handleToolCardClick" @didSelectOption="handleToolOptionClick" />
|
||||||
@didSelectItem="handleQuickQuestionClick" />
|
|
||||||
|
|
||||||
<DiscoveryPhotoToolCard @didSelectItem="handleToolCardClick" @didSelectOption="handleToolOptionClick" />
|
|
||||||
<DiscoveryAudioToolCard @didSelectItem="handleToolCardClick" />
|
<DiscoveryAudioToolCard @didSelectItem="handleToolCardClick" />
|
||||||
<DiscoveryGuideMapToolCard @didSelectItem="handleToolCardClick" />
|
<DiscoveryGuideMapToolCard @didSelectItem="handleToolCardClick" /> -->
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -26,7 +27,6 @@ import { getAccessToken } from "@/constant/token";
|
|||||||
|
|
||||||
import FindTabs from "./components/FindTabs/index.vue";
|
import FindTabs from "./components/FindTabs/index.vue";
|
||||||
import ExploreCards from "./components/ExploreCards/index.vue";
|
import ExploreCards from "./components/ExploreCards/index.vue";
|
||||||
import HeritageDiscoverySection from "./components/HeritageDiscoverySection/index.vue";
|
|
||||||
import QuickQuestions from "./components/QuickQuestions/index.vue";
|
import QuickQuestions from "./components/QuickQuestions/index.vue";
|
||||||
import DiscoveryPhotoToolCard from "./components/DiscoveryPhotoToolCard/index.vue";
|
import DiscoveryPhotoToolCard from "./components/DiscoveryPhotoToolCard/index.vue";
|
||||||
import DiscoveryAudioToolCard from "./components/DiscoveryAudioToolCard/index.vue";
|
import DiscoveryAudioToolCard from "./components/DiscoveryAudioToolCard/index.vue";
|
||||||
@@ -45,7 +45,13 @@ const activeIndex = ref(0);
|
|||||||
const discoveryTabs = ref([]);
|
const discoveryTabs = ref([]);
|
||||||
const discoveryCards = ref([]);
|
const discoveryCards = ref([]);
|
||||||
const discoveryQuickQuestions = ref([]);
|
const discoveryQuickQuestions = ref([]);
|
||||||
const emit = defineEmits(["scroll-touch-start", "scroll-touch"]);
|
const emit = defineEmits(["content-scroll"]);
|
||||||
|
|
||||||
|
const handleContentScroll = (e) => {
|
||||||
|
emit("content-scroll", {
|
||||||
|
scrollTop: Number(e.detail?.scrollTop || 0),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/// tabs 切换事件
|
/// tabs 切换事件
|
||||||
@@ -208,16 +214,30 @@ onMounted(() => {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.discovery-content {
|
.discovery-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 100%;
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
background: $theme-color-50;
|
background: $theme-color-50;
|
||||||
}
|
}
|
||||||
|
|
||||||
.discovery-tabs-sticky {
|
.discovery-tabs-sticky {
|
||||||
position: sticky;
|
flex-shrink: 0;
|
||||||
top: 0;
|
|
||||||
z-index: 12;
|
z-index: 12;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: $theme-color-50;
|
background: $theme-color-50;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.discovery-scroll {
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
height: 0;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.discovery-body {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user