feat: add new features, update theme and build config

- Add 40+ new UI components including chat modules, discovery cards, photo galleries, FAQ and booking tools
- Standardize brand color across all styles by replacing $theme-color-500 SCSS variables with #0ccd58
- Add sass 1.58.3 dependency and update vite config for modern scss compiler support
- Refactor existing components (AddCarCrad, login page) and remove unused /quick/list router route
- Add utility functions for URL parameter handling
- Add static assets including custom znicons font, component images and icons
- Fix scss syntax issues and deprecation warnings
This commit is contained in:
duanshuwen
2026-05-26 22:49:52 +08:00
parent 548df7020c
commit ac8f5b5f64
159 changed files with 12439 additions and 629 deletions

View File

@@ -0,0 +1,10 @@
export const DETAIL_ROUTE_BY_TYPE = {
longTextCard: "/pages/ChatModule/LongTextGuideCardPrediv/guide",
longTextCardScenicSpot: "/pages/ChatModule/LongTextGuideCardPrediv/poi",
longTextCardRoute: "/pages/ChatModule/LongTextGuideCardPrediv/route",
longTextCardSnap: "/pages/ChatModule/LongTextGuideCardPrediv/photo",
};
export const getLongTextGuideDetailRoute = (type) => {
return DETAIL_ROUTE_BY_TYPE[type] || "";
};

View File

@@ -0,0 +1,124 @@
<template>
<div class="long-text-detail-page flex flex-col">
<TopNavBar title="漂流攻略" background="#E5EFE9" />
<div class="long-text-detail-scroll" scroll-y>
<div class="long-text-detail-content">
<div class="long-text-detail-card">
<div class="long-text-detail-header">
<div class="long-text-detail-title">下水之前先听小七唠两句</div>
<div class="long-text-detail-badge is-amber">漂流攻略</div>
</div>
<div class="long-text-detail-body">
<div class="detail-paragraph">
卧龙潭的水是那种一眼就让人想跳进去的绿
<text class="detail-highlight">皮筏艇漂流</text>
全程约两公里三段激流接连而下水花会结结实实拍在脸上这趟值得冲但晕水的朋友得先掂量掂量
</div>
<img class="detail-main-image"
src="https://one-feel-config-images-bucket.oss-cn-chengdu.aliyuncs.com/comp1.jpg" mode="aspectFill" />
<div class="detail-section-title">下水前这几样别落下</div>
<div class="detail-tip-block">
换洗衣服塞进防水袋手机一定要封好<br />
穿凉鞋或防滑鞋拖鞋是真的不让下<br />
贵重东西先存好寄存柜别揣身上
</div>
<div class="detail-paragraph">
小七的私心建议
<span class="detail-highlight">上午九点到十一点</span>
这一场水量足太阳还没毒漂下来浑身舒坦不会被晒得发昏
</div>
<div class="detail-section-title">这些坑提前绕开</div>
<div class="detail-tip-block is-warn">
雨后水量猛涨可能临时停漂出发前先问一句开放状态现场拖鞋不补租光脚更危险
</div>
</div>
<div class="detail-action-zone">
<div class="detail-action-label">相关票务</div>
<div class="detail-product-scroll">
<div class="detail-product-row">
<div v-for="product in products" :key="product.name" class="detail-product-card">
<img class="detail-product-image" :src="product.img" mode="aspectFill" />
<div class="detail-product-body">
<div v-if="product.saleTag" class="detail-product-tag">
{{ product.saleTag }}
</div>
<div class="detail-product-name">{{ product.name }}</div>
<div class="detail-product-price">
<span class="detail-product-currency">¥</span>{{ product.price }}
<span v-if="product.original" class="detail-product-original">
¥{{ product.original }}
</span>
</div>
<button class="detail-buy-button" @click="goodsDetail(product)">
立即购买
</button>
</div>
</div>
</div>
</div>
<div class="detail-action-label">继续追问</div>
<div class="detail-faq-wrap">
<div v-for="question in faq" :key="question" class="detail-faq-chip" @click="sendReply(question)">
{{ question }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import TopNavBar from "@/components/TopNavBar/index.vue";
import { SEND_MESSAGE_CONTENT_TEXT } from "@/constant/constant";
const products = [
{
name: "卧龙潭皮筏艇漂流",
img: "https://one-feel-config-images-bucket.oss-cn-chengdu.aliyuncs.com/comp1.jpg",
price: "50",
commodityId: "1032119438058270721",
},
{
name: "鸳鸯湖玻璃船",
img: "https://one-feel-config-images-bucket.oss-cn-chengdu.aliyuncs.com/comp12.jpg",
price: "50",
saleTag: "漂完顺路",
commodityId: "1032121733894451202",
},
];
const faq = ["几岁的孩子能玩", "会不会全身湿透", "漂完去哪儿歇脚"];
const showToast = (title) => {
uni.showToast({
title,
icon: "none",
});
};
const goodsDetail = (item) => {
uni.navigateTo({
url: `/pages/goods/index?commodityId=${item.commodityId}`,
});
};
const sendReply = (item) => {
uni.navigateBack();
uni.$emit(SEND_MESSAGE_CONTENT_TEXT, item);
};
</script>
<style scoped lang="scss">
@import "./styles/detail.scss";
</style>

View File

@@ -0,0 +1,105 @@
<template>
<div class="w-full bg-white border-box border-ff overflow-hidden rounded-20 flex flex-col">
<!-- 占位撑开 -->
<div class="w-vw"></div>
<div class="flex flex-col px-16 pt-16 pb-12 border-box" @click="openDetail(item)">
<div class="long-text-guide-card__badge font-size-12 font-900" :class="`is-${item.badgeTone}`">
{{ item.badge }}
</div>
<div class="long-text-guide-card__summary-title color-1E293B font-size-18 font-900">
{{ item.title }}
</div>
<div class="long-text-guide-card__summary-text color-94A3B8 font-size-14 font-500 ellipsis-2">
{{ item.summary }}
</div>
<div class="long-text-guide-card__summary-footer flex flex-items-center flex-justify-between">
<span class="color-CBD5E1 font-size-12 font-800">{{ item.footer }}</span>
<uni-icons type="right" size="16" color="#CBD5E1"></uni-icons>
</div>
</div>
</div>
</template>
<script setup>
import { defineProps, computed } from "vue";
import { getLongTextGuideDetailRoute } from "./detailRoutes.mjs";
const props = defineProps({
componentName: {
type: String,
default: 'longTextCard',
},
});
const longTextCard = {
type: 'longTextCard',
badge: "漂流攻略",
badgeTone: "amber",
title: "下水之前,先听小七唠两句",
summary: "卧龙潭漂流值得冲,全程四十分钟、三段激流,但晕水的人要掂量…",
footer: "点击查看完整攻略",
}
const longTextCardScenicSpot = {
type: 'longTextCardScenicSpot',
badge: "景点故事",
badgeTone: "green",
title: "小七孔古桥 · 走了三百年的石拱",
summary: "小七孔古桥是一座三百岁的七孔石桥,小七孔的名字就从这儿来…",
footer: "点击查看完整介绍",
}
const longTextCardRoute = {
type: 'longTextCardRoute',
badge: "路线指引",
badgeTone: "violet",
title: "漂完卧龙潭,顺道去鸳鸯湖",
summary: "卧龙潭到鸳鸯湖坐观光车约二十分钟。要紧的是鸳鸯湖分上下湖…",
footer: "点击查看完整路线",
}
const longTextCardSnap = {
type: 'longTextCardSnap',
badge: "拍照攻略",
badgeTone: "blue",
title: "鸳鸯湖玻璃船,这样拍才不亏",
summary: "玻璃船拍照,关键是拍水下那抹通透的绿,顺光时段最出片…",
footer: "点击查看完整攻略",
}
const item = computed(() => {
switch (props.componentName) {
case 'longTextCard':
return longTextCard;
case 'longTextCardSnap':
return longTextCardSnap;
case 'longTextCardRoute':
return longTextCardRoute;
case 'longTextCardScenicSpot':
return longTextCardScenicSpot;
default:
return longTextCard;
}
});
const openDetail = (item) => {
const url = getLongTextGuideDetailRoute(item.type);
if (!url) {
uni.showToast({
title: "暂未配置详情页",
icon: "none",
});
return;
}
uni.navigateTo({ url });
};
</script>
<style scoped lang="scss">
@import "./styles/index.scss";
</style>

View File

@@ -0,0 +1,127 @@
<template>
<div class="long-text-detail-page flex flex-col">
<TopNavBar title="拍照攻略" background="#E5EFE9" />
<div class="long-text-detail-scroll" scroll-y>
<div class="long-text-detail-content">
<div class="long-text-detail-card">
<div class="long-text-detail-header">
<div class="long-text-detail-title">鸳鸯湖玻璃船这样拍才不亏</div>
<div class="long-text-detail-badge is-blue">拍照攻略</div>
</div>
<div class="long-text-detail-body">
<div class="detail-paragraph">
鸳鸯湖的玻璃船船底是透明的水下世界看得清清楚楚拍照的关键就一句话
<span class="detail-highlight">别只顾着拍人把水下那抹通透的绿一起收进来</span>
</div>
<div class="detail-section-title">三个不会错的机位</div>
<div class="detail-tip-block">
蹲低贴着透明船底拍水草和光斑会铺满整个画面<br />
船头回拍人物背景是大片湖光人物站三分之一处<br />
把手伸进光里拍水面波纹和指尖是很灵的细节
</div>
<div class="detail-paragraph">
时间上
<text class="detail-highlight">上午十点到下午两点</text>
的顺光时段阳光直直照进水里那种绿才透得出来阴天和傍晚水色会闷差很多
</div>
<div class="detail-section-title">手机党看这里</div>
<div class="detail-tip-block">
手机开 0.5x 广角水面和船一起进画隔着玻璃拍记得擦干净船底逆光时手动点一下水面降曝光
</div>
</div>
<div class="detail-action-zone">
<div class="detail-action-label">查看机位图</div>
<div class="photo-card" @click="predivPhoto">
<img class="photo-card-image" :src="photo.thumb" mode="aspectFill" />
<div class="photo-card-caption">
<div class="photo-card-title">{{ photo.title }}</div>
<div class="photo-card-subtitle">{{ photo.sub }}</div>
</div>
<div class="photo-card-expand"></div>
</div>
<div class="detail-action-label">AIGC 合影</div>
<div class="detail-action-card">
<div class="aigc-cover">
<img class="aigc-image" :src="aigc.img" mode="aspectFill" />
<div class="aigc-badge">AI 生成</div>
</div>
<div class="aigc-body">
<div class="aigc-title">{{ aigc.name }}</div>
<div class="aigc-desc">{{ aigc.desc }}</div>
<button class="detail-solid-button aigc-button" @click="jumpAigcClick">
生成我的合影
</button>
</div>
</div>
<div class="detail-action-label">继续追问</div>
<div class="detail-faq-wrap">
<div v-for="question in faq" :key="question" class="detail-faq-chip" @click="sendReply(question)">
{{ question }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import TopNavBar from "@/components/TopNavBar/index.vue";
import { SEND_MESSAGE_CONTENT_TEXT } from "@/constant/constant";
import { getAccessToken } from "@/constant/token";
import { navigateTo } from "@/router";
const photo = {
thumb: "https://one-feel-config-images-bucket.oss-cn-chengdu.aliyuncs.com/comp4.jpg",
full: "https://one-feel-config-images-bucket.oss-cn-chengdu.aliyuncs.com/comp4.jpg",
title: "玻璃船底机位",
sub: "蹲低贴船底 · 上午顺光",
};
const aigc = {
name: "鸳鸯湖玻璃船 AIGC 合影",
img: "https://one-feel-config-images-bucket.oss-cn-chengdu.aliyuncs.com/20260526101238_396_809.png",
desc: "上船拍一张,小七帮你一键生成专属合影,不用求人也不用自拍杆。",
};
const faq = ["几点光线最好", "船上能站起来拍吗", "穿什么颜色上镜"];
const predivPhoto = () => {
uni.predivImage({
current: photo.full,
urls: [photo.full],
});
};
const showToast = (title) => {
uni.showToast({
title,
icon: "none",
});
};
const jumpAigcClick = () => {
const token = getAccessToken();
navigateTo('https://onefeel.brother7.cn/aigc/#/home', { token: token });
};
const sendReply = (item) => {
uni.navigateBack();
uni.$emit(SEND_MESSAGE_CONTENT_TEXT, item);
};
</script>
<style scoped lang="scss">
@import "./styles/detail.scss";
</style>

View File

@@ -0,0 +1,115 @@
<template>
<div class="long-text-detail-page flex flex-col">
<TopNavBar title="景点故事" background="#E5EFE9" />
<div class="long-text-detail-scroll" scroll-y>
<div class="long-text-detail-content">
<div class="long-text-detail-card">
<div class="long-text-detail-header">
<div class="long-text-detail-title">小七孔古桥 · 走了三百年的石拱</div>
<div class="long-text-detail-badge is-emerald">景点故事</div>
</div>
<div class="long-text-detail-body">
<div class="detail-paragraph">
小七孔古桥静静卧在响水河上七个石拱挨着排开桥身爬满青苔藤蔓它建于清道光年间
<text class="detail-highlight">三百多岁</text>
整个景区的名字就是从这座桥来的
</div>
<img class="detail-main-image"
src="https://one-feel-config-images-bucket.oss-cn-chengdu.aliyuncs.com/comp2.jpg" mode="aspectFill" />
<div class="detail-section-title">站在这儿看什么</div>
<div class="detail-tip-block">
桥拱与水面倒影合成完整的圆这是古桥最经典的一眼<br />
桥身的青苔和藤蔓是三百年时间慢慢长出来的<br />
桥下水浅处清澈见底能看见鹅卵石和游鱼
</div>
<div class="detail-paragraph">
小七的建议别急着走过去先在桥侧站一会儿古桥不是用来打卡的是用来
<span class="detail-highlight">慢慢看</span>
光线斜下来的时候石桥绿水倒影会一起把你框进画里
</div>
<div class="detail-section-title">顺带一提</div>
<div class="detail-tip-block is-warn">
桥面是三百年的老石头雨后偏滑慢点走别翻护栏到桥下浅滩既危险也伤桥
</div>
</div>
<div class="detail-action-zone">
<div class="detail-action-label">查看景点详情</div>
<div class="detail-action-card is-raised" @click="showToast('跳转 H5 景点详情页:小七孔古桥')">
<div class="poi-mini-tag">核心地标</div>
<div class="poi-mini-body">
<div class="poi-mini-title">小七孔古桥</div>
<div class="poi-mini-desc">
清道光年间建的七孔石桥响水河上的镇景之宝小七孔之名由此而来桥畔可观涵碧潭
</div>
<button class="detail-solid-button" @click.stop="openMap">
带我去
</button>
</div>
</div>
<div class="detail-action-label">继续追问</div>
<div class="detail-faq-wrap">
<div v-for="question in faq" :key="question" class="detail-faq-chip" @click="sendReply(question)">
{{ question }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import TopNavBar from "@/components/TopNavBar/index.vue";
import { SEND_MESSAGE_CONTENT_TEXT } from "@/constant/constant";
const faq = ["古桥有什么传说", "最佳观赏时间", "旁边还有什么景点"];
const showToast = (title) => {
uni.showToast({
title,
icon: "none",
});
};
// 打开地图
const openMap = () => {
const address = '小七孔古桥';
const latitude = 25.248714;
const longitude = 107.745735;
uni.getLocation({
type: "gcj02", //返回可以用于uni.openLocation的经纬度
success: (res) => {
console.log("当前经纬度", latitude, longitude);
uni.openLocation({
latitude: latitude,
longitude: longitude,
address: address,
success: () => {
console.log("success");
},
});
},
});
};
const sendReply = (item) => {
uni.navigateBack();
uni.$emit(SEND_MESSAGE_CONTENT_TEXT, item);
};
</script>
<style scoped lang="scss">
@import "./styles/detail.scss";
</style>

View File

@@ -0,0 +1,143 @@
<template>
<div class="long-text-detail-page flex flex-col">
<TopNavBar title="路线指引" background="#E5EFE9" />
<div class="long-text-detail-scroll" scroll-y>
<div class="long-text-detail-content">
<div class="long-text-detail-card">
<div class="long-text-detail-header">
<div class="long-text-detail-title">漂完卧龙潭顺道去鸳鸯湖</div>
<div class="long-text-detail-badge is-violet">路线指引</div>
</div>
<div class="long-text-detail-body">
<div class="detail-paragraph">
漂完卧龙潭人多半是湿着累着的这时候去鸳鸯湖刚刚好坐观光车顺路不绕二十分钟左右就到
</div>
<div class="detail-section-title">鸳鸯湖分上下湖先选好玩哪个</div>
<div class="detail-paragraph">
鸳鸯湖不是一个码头它分成上下两个湖玩的船不一样
<span class="detail-highlight">下车站点也不同</span>
上车前先选好
</div>
<div class="route-vs-wrap">
<div class="route-vs-col">
<div class="route-vs-head">上湖 · 鸳湖</div>
<div class="route-vs-boat" style="color: #2563eb">玻璃船 ¥50</div>
<div class="route-vs-row">
透明船底<span class="route-vs-bold">适合拍照</span>
</div>
<div class="route-vs-row">带老人孩子图轻松</div>
<div class="route-vs-row">
<span class="route-vs-bold">鸳鸯湖上湖站</span> 下车
</div>
</div>
<div class="route-vs-col">
<div class="route-vs-head">下湖 · 鸯湖</div>
<div class="route-vs-boat" style="color: #059669">铁皮船 ¥30</div>
<div class="route-vs-row">自己划1-6 人一船</div>
<div class="route-vs-row">
<span class="route-vs-bold">水上迷宫</span>穿林更有乐趣
</div>
<div class="route-vs-row">
<span class="route-vs-bold">鸳鸯湖站</span> 下车再走 4 分钟
</div>
</div>
</div>
<div class="detail-paragraph">时间够的话两个湖都能玩中间有观光车接驳</div>
<div class="detail-section-title">路上留个心</div>
<div class="detail-tip-block is-warn">
旺季观光车要排队上午人最多<br />
下湖枯水期水位低水上迷宫游线可能关闭购票前先问一句<br />
雨天石板路偏滑带孩子老人慢一点
</div>
</div>
<div class="detail-action-zone">
<div class="detail-action-label">完整路线</div>
<div class="route-step-card">
<div class="route-step-title">卧龙潭 鸳鸯湖 · 看准上下湖</div>
<div v-for="(step, index) in steps" :key="step.act" class="route-step">
<div class="route-step-index">{{ index + 1 }}</div>
<div class="route-step-main">
<div class="route-step-act">{{ step.act }}</div>
<div class="route-step-meta">{{ step.meta }}</div>
</div>
</div>
</div>
<div class="route-step-card">
<div class="route-step-title">沿途设施</div>
<div v-for="facility in facilities" :key="facility.label" class="facility-row">
<div class="facility-label">{{ facility.label }}</div>
<div>{{ facility.text }}</div>
</div>
</div>
<div class="detail-action-label">继续追问</div>
<div class="detail-faq-wrap">
<div v-for="question in faq" :key="question" class="detail-faq-chip" @click="sendReply(question)">
{{ question }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import TopNavBar from "@/components/TopNavBar/index.vue";
import { SEND_MESSAGE_CONTENT_TEXT } from "@/constant/constant";
const steps = [
{
act: "卧龙潭码头 → 卧龙潭站",
meta: "步行约 5 分钟 · 认准观光车乘车点",
},
{
act: "上车前先认准方向:去上湖 or 下湖",
meta: "两个湖站点不同,排队通道也不同,别走错",
},
{
act: "A·去上湖玩玻璃船 → 鸳鸯湖上湖站下车",
meta: "车程约 6 分钟 · 玻璃船 ¥50/人",
},
{
act: "B·去下湖玩铁皮船 → 鸳鸯湖站下车",
meta: "车程约 12 分钟 · 下车再步行 4 分钟 · 铁皮船 ¥30/人",
},
];
const facilities = [
{ label: "换洗", text: "卧龙潭站 · 洗手间 + 换洗寄存点" },
{ label: "休息", text: "鸳鸯湖上湖 · 美食驿站 + 休息亭" },
{ label: "补给", text: "鸳鸯湖站 · 美食驿站 + 充电宝租赁" },
{ label: "卫生间", text: "下湖卫生间在景点处,上湖卫生间在售票处前 150m" },
];
const faq = ["上湖下湖哪个好玩", "玻璃船和铁皮船怎么选", "两个湖都玩来得及吗"];
const showToast = (title) => {
uni.showToast({
title,
icon: "none",
});
};
const sendReply = (item) => {
uni.navigateBack();
uni.$emit(SEND_MESSAGE_CONTENT_TEXT, item);
};
</script>
<style scoped lang="scss">
@import "./styles/detail.scss";
</style>

View File

@@ -0,0 +1,530 @@
.long-text-detail-page {
height: 100vh;
overflow: hidden;
background: #e5efe9;
}
.long-text-detail-scroll {
flex: 1;
min-height: 0;
}
.long-text-detail-content {
box-sizing: border-box;
}
.long-text-detail-card {
overflow: hidden;
}
.long-text-detail-header {
padding: 16px 18px 14px;
border-bottom: 1px solid rgba(15, 23, 42, 0.06);
}
.long-text-detail-title {
color: #1e293b;
font-size: 18px;
font-weight: 900;
line-height: 26px;
}
.long-text-detail-badge {
display: inline-flex;
width: fit-content;
min-height: 24px;
margin-top: 10px;
padding: 0 10px;
align-items: center;
border: 1px solid transparent;
border-radius: 999px;
font-size: 11px;
font-weight: 900;
line-height: 18px;
}
.long-text-detail-badge.is-amber {
color: #d97706;
background: #fffbeb;
border-color: #fde68a;
}
.long-text-detail-badge.is-emerald {
color: #047857;
background: #ecfdf5;
border-color: #a7f3d0;
}
.long-text-detail-badge.is-violet {
color: #7c3aed;
background: #f5f3ff;
border-color: #ddd6fe;
}
.long-text-detail-badge.is-blue {
color: #2563eb;
background: #eff6ff;
border-color: #bfdbfe;
}
.long-text-detail-body {
padding: 18px 18px 4px;
}
.detail-paragraph {
margin-bottom: 14px;
color: #475569;
font-size: 13px;
font-weight: 500;
line-height: 24px;
}
.detail-highlight {
padding: 1px 5px;
border-radius: 4px;
color: #065f46;
background: #ecfdf5;
font-weight: 900;
}
.detail-section-title {
margin: 18px 0 8px;
color: #1e293b;
font-size: 13px;
font-weight: 900;
line-height: 20px;
}
.detail-main-image {
width: 100%;
height: 160px;
margin: 4px 0 16px;
border-radius: 14px;
background: #f1f5f9;
}
.detail-tip-block {
margin: 4px 0 16px;
padding: 10px 14px;
border-left: 3px solid #34d399;
border-radius: 12px;
color: #065f46;
background: #f0fdf4;
font-size: 12px;
font-weight: 800;
line-height: 22px;
}
.detail-tip-block.is-warn {
color: #92400e;
background: #fffbeb;
border-left-color: #fbbf24;
}
.detail-action-zone {
margin-top: 4px;
padding-bottom: 20px;
border-top: 1px solid rgba(15, 23, 42, 0.06);
}
.detail-action-label {
padding: 12px 18px 8px;
color: #94a3b8;
font-size: 10px;
font-weight: 900;
letter-spacing: 0.6px;
line-height: 16px;
}
.detail-action-card {
margin: 0 16px 12px;
overflow: hidden;
border: 1px solid #f1f5f9;
border-radius: 16px;
background: #fff;
}
.detail-action-card.is-raised {
border-radius: 24px;
box-shadow: 0 4px 20px rgba(15, 23, 42, 0.04);
}
.poi-mini-tag {
display: inline-flex;
width: fit-content;
margin: 14px 0 0 14px;
padding: 4px 10px;
align-items: center;
border-radius: 8px;
color: #059669;
background: rgba(255, 255, 255, 0.9);
box-shadow: 0 1px 4px rgba(15, 23, 42, 0.08);
font-size: 10px;
font-weight: 900;
}
.poi-mini-body {
padding: 10px 20px 16px;
}
.poi-mini-title {
margin-bottom: 10px;
color: #1e293b;
font-size: 19px;
font-weight: 900;
line-height: 26px;
}
.poi-mini-desc {
margin-bottom: 12px;
padding: 10px 12px;
border: 1px solid rgba(167, 243, 208, 0.5);
border-radius: 12px;
color: #065f46;
background: linear-gradient(to right, #ecfdf5, rgba(240, 253, 250, 0.5));
font-size: 12px;
font-weight: 800;
line-height: 20px;
}
.detail-solid-button {
width: 100%;
height: 42px;
padding: 0;
border: 0;
border-radius: 14px;
color: #fff;
background: #0f172a;
font-size: 13px;
font-weight: 900;
line-height: 42px;
}
.detail-solid-button::after {
border: 0;
}
.detail-product-scroll {
width: 100%;
white-space: nowrap;
}
.detail-product-row {
display: flex;
gap: 10px;
padding: 0 16px 2px;
}
.detail-product-card {
width: 220px;
flex-shrink: 0;
overflow: hidden;
border: 1px solid #f1f5f9;
border-radius: 20px;
background: #fff;
box-shadow: 0 2px 12px rgba(15, 23, 42, 0.04);
}
.detail-product-image {
width: 100%;
height: 110px;
background: #f1f5f9;
}
.detail-product-body {
padding: 10px 12px 12px;
}
.detail-product-tag {
display: inline-flex;
width: fit-content;
margin-bottom: 4px;
padding: 2px 6px;
border-radius: 6px;
color: #f43f5e;
background: #fef2f2;
font-size: 9px;
font-weight: 900;
}
.detail-product-name {
overflow: hidden;
color: #1e293b;
font-size: 13px;
font-weight: 900;
line-height: 20px;
text-overflow: ellipsis;
white-space: nowrap;
}
.detail-product-price {
margin: 4px 0 8px;
color: #f43f5e;
font-size: 20px;
font-weight: 900;
line-height: 26px;
}
.detail-product-currency {
font-size: 12px;
}
.detail-product-original {
margin-left: 4px;
color: #cbd5e1;
font-size: 11px;
font-weight: 700;
text-decoration: line-through;
}
.detail-buy-button {
width: 100%;
height: 34px;
padding: 0;
border: 0;
border-radius: 12px;
color: #451a03;
background: #fbbf24;
font-size: 12px;
font-weight: 900;
line-height: 34px;
}
.detail-buy-button::after {
border: 0;
}
.detail-faq-wrap {
margin: 0 16px;
}
.detail-faq-chip {
display: inline-flex;
margin: 0 6px 8px 0;
padding: 8px 13px;
border: 1px solid #e2e8f0;
border-radius: 20px;
color: #475569;
background: #fff;
font-size: 11.5px;
font-weight: 800;
line-height: 16px;
}
.route-vs-wrap {
display: flex;
gap: 8px;
margin: 6px 0 16px;
}
.route-vs-col {
flex: 1;
padding: 11px 12px;
border: 1px solid #e8edf2;
border-radius: 12px;
background: #f8fafc;
}
.route-vs-head {
margin-bottom: 8px;
padding-bottom: 7px;
border-bottom: 1px dashed #d8e0e8;
color: #1e293b;
font-size: 12px;
font-weight: 900;
line-height: 18px;
}
.route-vs-boat {
margin-bottom: 7px;
font-size: 13px;
font-weight: 900;
line-height: 18px;
}
.route-vs-row {
margin-bottom: 5px;
color: #64748b;
font-size: 11px;
font-weight: 600;
line-height: 17px;
}
.route-vs-bold {
color: #334155;
font-weight: 900;
}
.route-step-card {
margin: 0 16px 12px;
padding: 14px 16px;
border: 1px solid rgba(15, 23, 42, 0.07);
border-radius: 16px;
background: #fff;
}
.route-step-title {
margin-bottom: 12px;
color: #1e293b;
font-size: 13px;
font-weight: 900;
line-height: 20px;
}
.route-step {
display: flex;
gap: 10px;
margin-bottom: 10px;
}
.route-step:last-child {
margin-bottom: 0;
}
.route-step-index {
width: 18px;
height: 18px;
flex-shrink: 0;
border-radius: 50%;
color: #fff;
background: #8b5cf6;
font-size: 10px;
font-weight: 900;
line-height: 18px;
text-align: center;
}
.route-step-main {
flex: 1;
}
.route-step-act {
color: #334155;
font-size: 12px;
font-weight: 800;
line-height: 18px;
}
.route-step-meta {
margin-top: 1px;
color: #94a3b8;
font-size: 10.5px;
font-weight: 700;
line-height: 16px;
}
.facility-row {
display: flex;
gap: 8px;
padding: 5px 0;
color: #475569;
font-size: 11.5px;
font-weight: 700;
line-height: 18px;
}
.facility-label {
width: 52px;
flex-shrink: 0;
color: #7c3aed;
font-weight: 900;
}
.photo-card {
position: relative;
margin: 0 16px 12px;
overflow: hidden;
border-radius: 16px;
background: #f8fafc;
}
.photo-card-image {
width: 100%;
height: 200px;
background: #f1f5f9;
}
.photo-card-caption {
position: absolute;
right: 0;
bottom: 0;
left: 0;
padding: 28px 14px 12px;
background: linear-gradient(to top, rgba(15, 23, 42, 0.58), rgba(15, 23, 42, 0));
}
.photo-card-title {
color: #fff;
font-size: 13px;
font-weight: 900;
line-height: 18px;
}
.photo-card-subtitle {
margin-top: 2px;
color: rgba(255, 255, 255, 0.78);
font-size: 11px;
font-weight: 700;
line-height: 16px;
}
.photo-card-expand {
position: absolute;
top: 10px;
right: 10px;
width: 30px;
height: 30px;
border-radius: 50%;
color: #fff;
background: rgba(15, 23, 42, 0.38);
font-size: 18px;
font-weight: 800;
line-height: 30px;
text-align: center;
}
.aigc-image {
width: 100%;
height: 160px;
background: #f1f5f9;
}
.aigc-cover {
position: relative;
}
.aigc-badge {
position: absolute;
top: 10px;
left: 10px;
padding: 4px 10px;
border-radius: 10px;
color: #fff;
background: linear-gradient(135deg, #8b5cf6, #6366f1);
box-shadow: 0 2px 8px rgba(99, 102, 241, 0.35);
font-size: 10px;
font-weight: 900;
}
.aigc-body {
padding: 12px 14px 14px;
}
.aigc-title {
color: #1e293b;
font-size: 15px;
font-weight: 900;
line-height: 22px;
}
.aigc-desc {
margin: 5px 0 12px;
color: #64748b;
font-size: 11.5px;
font-weight: 700;
line-height: 18px;
}
.aigc-button {
background: linear-gradient(135deg, #8b5cf6, #6366f1);
}

View File

@@ -0,0 +1,192 @@
.long-text-guide-card__summary-card {
min-height: 178px;
margin-bottom: 16px;
padding: 28px 26px 22px;
border: 1px solid rgba(15, 23, 42, 0.04);
box-shadow: 0 12px 28px rgba(15, 23, 42, 0.04);
transition: transform 0.15s ease, opacity 0.15s ease;
}
.long-text-guide-card__summary-card:active {
transform: scale(0.985);
}
.long-text-guide-card__summary-card.is-disabled {
opacity: 0.55;
}
.long-text-guide-card__badge {
display: inline-flex;
width: fit-content;
align-items: center;
justify-content: center;
min-height: 26px;
padding: 0 10px;
border: 1px solid transparent;
border-radius: 999px;
line-height: 18px;
}
.long-text-guide-card__badge.is-amber {
color: #d97706;
background: #fffbeb;
border-color: #fde68a;
}
.long-text-guide-card__badge.is-green {
color: #059669;
background: #ecfdf5;
border-color: #a7f3d0;
}
.long-text-guide-card__badge.is-violet {
color: #7c3aed;
background: #f5f3ff;
border-color: #ddd6fe;
}
.long-text-guide-card__badge.is-blue {
color: #2563eb;
background: #eff6ff;
border-color: #bfdbfe;
}
.long-text-guide-card__summary-title {
margin-top: 18px;
line-height: 24px;
}
.long-text-guide-card__summary-text {
margin-top: 10px;
line-height: 22px;
}
.long-text-guide-card__summary-footer {
margin-top: 24px;
}
.long-text-guide-card__arrow {
font-size: 26px;
line-height: 1;
}
.long-text-guide-card__detail-card {
border: 1px solid rgba(15, 23, 42, 0.04);
}
.long-text-guide-card__detail-header {
min-height: 70px;
padding: 0 18px 0 20px;
}
.long-text-guide-card__back {
width: 34px;
height: 34px;
margin-right: 12px;
color: #64748b;
background: #f2f4f6;
font-size: 24px;
line-height: 1;
}
.long-text-guide-card__detail-title {
flex: 1;
min-width: 0;
}
.long-text-guide-card__detail-badge {
margin-left: 12px;
}
.long-text-guide-card__rich-body {
padding: 24px 22px 26px;
}
.long-text-guide-card__paragraph {
margin-bottom: 20px;
line-height: 30px;
}
.long-text-guide-card__highlight {
color: #065f46;
background: #ecfdf5;
padding: 1px 6px;
border-radius: 4px;
}
.long-text-guide-card__main-image {
height: 198px;
margin-bottom: 24px;
}
.long-text-guide-card__section-title {
margin-bottom: 12px;
line-height: 22px;
}
.long-text-guide-card__tip-block {
margin-bottom: 22px;
padding: 12px 18px;
border-left: 3px solid #34d399;
border-radius: 12px;
}
.long-text-guide-card__tip {
line-height: 24px;
}
.long-text-guide-card__action-zone {
border-top: 1px solid #f1f5f9;
padding: 16px 20px 20px;
}
.long-text-guide-card__action-label {
margin-bottom: 10px;
letter-spacing: 0.6px;
}
.long-text-guide-card__map-card {
border: 1px solid #f1f5f9;
}
.long-text-guide-card__map-image {
height: 138px;
}
.long-text-guide-card__map-tag {
position: absolute;
left: 14px;
bottom: 12px;
padding: 4px 8px;
border-radius: 999px;
background: rgba(15, 23, 42, 0.72);
}
.long-text-guide-card__map-bar {
padding: 14px 16px;
}
.long-text-guide-card__nav-btn {
padding: 12px 18px;
border-radius: 14px;
}
.long-text-guide-card__photo-card {
min-height: 178px;
overflow: hidden;
border-radius: 16px;
background: #f8fafc;
}
.long-text-guide-card__photo-image {
height: 178px;
}
.long-text-guide-card__expand {
position: absolute;
right: 14px;
bottom: 14px;
width: 38px;
height: 38px;
background: rgba(15, 23, 42, 0.36);
}