Commit de4a9da9 authored by caoxu's avatar caoxu

Add: 新增城市介绍页面

parent 19ad2be1
Pipeline #508 canceled with stages
......@@ -16,6 +16,11 @@ const router = createRouter({
path: '/museum-night',
name: 'museumNight',
component: () => import('../views/MuseumNightView.vue')
},
{
path: '/city-introduction',
name: 'cityIntroduction',
component: () => import('../views/CityIntroductionView.vue')
}
]
})
......
<template>
<div class="city-introduction">
<div class="header">
<button class="back-button" @click="goBack"></button>
<h1 class="page-title">墨鱼旅行城市介绍</h1>
</div>
<div class="main-content">
<div class="city-banner">
<img src="https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?w=1200&h=400&fit=crop" alt="城市风景" class="banner-image" />
</div>
<div class="city-info-section">
<h2 class="section-title">城市介绍</h2>
<div class="city-description">
<p>
欢迎来到这座充满魅力的城市!这里融合了古老的历史文化与现代都市的繁华,
每一个角落都散发着独特的魅力。漫步在古老的街道上,感受历史的沉淀;
探索现代化的建筑群,体验都市的活力。无论是历史文化爱好者,
还是美食探索者,都能在这里找到属于自己的精彩。
</p>
</div>
</div>
<div class="attractions-section">
<h2 class="section-title">热门景点</h2>
<div class="attractions-grid">
<div v-for="attraction in attractions" :key="attraction.id" class="attraction-card">
<img :src="attraction.image" :alt="attraction.name" class="attraction-image" />
<div class="attraction-info">
<h3 class="attraction-name">{{ attraction.name }}</h3>
<p class="attraction-description">{{ attraction.description }}</p>
<div class="attraction-meta">
<span class="attraction-rating">{{ attraction.rating }}</span>
<span class="attraction-price">¥{{ attraction.price }}</span>
</div>
</div>
</div>
</div>
</div>
<div class="nearby-users-section">
<h2 class="section-title">附近的用户</h2>
<div class="users-list">
<div v-for="user in nearbyUsers" :key="user.id" class="user-card">
<img :src="user.avatar" :alt="user.name" class="user-avatar" />
<div class="user-info">
<h4 class="user-name">{{ user.name }}</h4>
<p class="user-location">{{ user.location }}</p>
<span class="user-status" :class="user.status">{{ user.statusText }}</span>
</div>
</div>
</div>
</div>
<div class="destination-dynamics-section">
<h2 class="section-title">当前目的地动态</h2>
<div class="dynamics-list">
<div v-for="dynamic in dynamics" :key="dynamic.id" class="dynamic-card">
<div class="dynamic-header">
<img :src="dynamic.userAvatar" :alt="dynamic.userName" class="dynamic-avatar" />
<div class="dynamic-user-info">
<h4 class="dynamic-user-name">{{ dynamic.userName }}</h4>
<span class="dynamic-time">{{ dynamic.time }}</span>
</div>
</div>
<p class="dynamic-content">{{ dynamic.content }}</p>
<div class="dynamic-actions">
<button class="action-btn like-btn">
<span>❤️</span>
<span>{{ dynamic.likes }}</span>
</button>
<button class="action-btn comment-btn">
<span>💬</span>
<span>{{ dynamic.comments }}</span>
</button>
</div>
</div>
</div>
</div>
<div class="food-section">
<h2 class="section-title">特色美食</h2>
<div class="food-grid">
<div v-for="food in foods" :key="food.id" class="food-card">
<img :src="food.image" :alt="food.name" class="food-image" />
<div class="food-info">
<h3 class="food-name">{{ food.name }}</h3>
<p class="food-description">{{ food.description }}</p>
<div class="food-meta">
<span class="food-type">{{ food.type }}</span>
<span class="food-price">¥{{ food.price }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const attractions = ref([
{
id: 1,
name: '古城博物馆',
description: '收藏着千年历史的珍贵文物,展示着古代文明的辉煌成就。',
image: 'https://images.unsplash.com/photo-1554907984-15263bfd63bd?w=400&h=300&fit=crop',
rating: 4.8,
price: 80
},
{
id: 2,
name: '现代艺术中心',
description: '当代艺术的殿堂,定期举办国际艺术展览。',
image: 'https://images.unsplash.com/photo-1561214115-f2f73c5b4d8c?w=400&h=300&fit=crop',
rating: 4.6,
price: 120
},
{
id: 3,
name: '中央公园',
description: '城市绿肺,休闲娱乐的理想去处。',
image: 'https://images.unsplash.com/photo-1496417263034-01ec0d5c7b5e?w=400&h=300&fit=crop',
rating: 4.9,
price: 0
},
{
id: 4,
name: '历史街区',
description: '保存完好的古建筑群,体验传统生活方式。',
image: 'https://images.unsplash.com/photo-1548625361-98a0b2c3a1d?w=400&h=300&fit=crop',
rating: 4.7,
price: 0
}
])
const nearbyUsers = ref([
{
id: 1,
name: '张三',
avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop',
location: '距离您 500m',
status: 'online',
statusText: '在线'
},
{
id: 2,
name: '李四',
avatar: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100&h=100&fit=crop',
location: '距离您 1.2km',
status: 'traveling',
statusText: '旅行中'
},
{
id: 3,
name: '王五',
avatar: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=100&h=100&fit=crop',
location: '距离您 2.5km',
status: 'offline',
statusText: '离线'
},
{
id: 4,
name: '赵六',
avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=100&h=100&fit=crop',
location: '距离您 3.8km',
status: 'online',
statusText: '在线'
}
])
const dynamics = ref([
{
id: 1,
userName: '小明',
userAvatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop',
time: '10分钟前',
content: '今天参观了古城博物馆,真的太震撼了!强烈推荐大家去看看。',
likes: 128,
comments: 32
},
{
id: 2,
userName: '小红',
userAvatar: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100&h=100&fit=crop',
time: '30分钟前',
content: '在中央公园野餐,天气真好,心情超棒!',
likes: 89,
comments: 15
},
{
id: 3,
userName: '大伟',
userAvatar: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=100&h=100&fit=crop',
time: '1小时前',
content: '历史街区的夜景太美了,拍了很多照片!',
likes: 256,
comments: 48
}
])
const foods = ref([
{
id: 1,
name: '特色烤鸭',
description: '百年老店,皮脆肉嫩,香气四溢。',
image: 'https://images.unsplash.com/photo-1544025162-d566946569f2?w=400&h=300&fit=crop',
type: '传统美食',
price: 88
},
{
id: 2,
name: '手工拉面',
description: '劲道爽滑,汤底浓郁,回味无穷。',
image: 'https://images.unsplash.com/photo-1569718212165-3a8278d5f71f?w=400&h=300&fit=crop',
type: '面食',
price: 35
},
{
id: 3,
name: '传统糕点',
description: '精致可口,甜而不腻,送礼佳品。',
image: 'https://images.unsplash.com/photo-1509368959836-f7801b4d6c1a?w=400&h=300&fit=crop',
type: '甜品',
price: 45
},
{
id: 4,
name: '本地海鲜',
description: '新鲜捕捞,烹饪精良,营养丰富。',
image: 'https://images.unsplash.com/photo-1534604973900-85bd99082946?w=400&h=300&fit=crop',
type: '海鲜',
price: 168
}
])
const goBack = () => {
router.back()
}
</script>
<style scoped>
.city-introduction {
min-height: 100vh;
background-color: #f5f5f5;
}
.header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px;
background-color: white;
position: sticky;
top: 0;
z-index: 10;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.back-button {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
padding: 0;
color: #333;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
}
.page-title {
font-size: 18px;
font-weight: 600;
margin: 0;
color: #333;
flex: 1;
text-align: center;
}
.main-content {
padding: 16px;
}
.city-banner {
width: 100%;
height: 200px;
overflow: hidden;
border-radius: 12px;
margin-bottom: 24px;
}
.banner-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.city-info-section,
.attractions-section,
.nearby-users-section,
.destination-dynamics-section,
.food-section {
background-color: white;
border-radius: 12px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.section-title {
font-size: 20px;
font-weight: 600;
color: #333;
margin: 0 0 16px 0;
padding-bottom: 12px;
border-bottom: 2px solid #42b883;
}
.city-description p {
font-size: 15px;
line-height: 1.8;
color: #666;
margin: 0;
}
.attractions-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 16px;
}
.attraction-card {
border: 1px solid #e0e0e0;
border-radius: 12px;
overflow: hidden;
transition: all 0.3s ease;
}
.attraction-card:hover {
transform: translateY(-4px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.attraction-image {
width: 100%;
height: 180px;
object-fit: cover;
}
.attraction-info {
padding: 16px;
}
.attraction-name {
font-size: 18px;
font-weight: 600;
color: #333;
margin: 0 0 8px 0;
}
.attraction-description {
font-size: 14px;
color: #666;
margin: 0 0 12px 0;
line-height: 1.6;
}
.attraction-meta {
display: flex;
justify-content: space-between;
align-items: center;
}
.attraction-rating {
font-size: 14px;
color: #ff9800;
font-weight: 500;
}
.attraction-price {
font-size: 18px;
font-weight: 700;
color: #ff6b35;
}
.users-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 12px;
}
.user-card {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
background-color: #f8f8f8;
border-radius: 8px;
}
.user-avatar {
width: 50px;
height: 50px;
border-radius: 50%;
object-fit: cover;
}
.user-info {
flex: 1;
}
.user-name {
font-size: 16px;
font-weight: 600;
color: #333;
margin: 0 0 4px 0;
}
.user-location {
font-size: 13px;
color: #999;
margin: 0 0 4px 0;
}
.user-status {
display: inline-block;
padding: 4px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
}
.user-status.online {
background-color: #e8f5e9;
color: #4caf50;
}
.user-status.traveling {
background-color: #e3f2fd;
color: #2196f3;
}
.user-status.offline {
background-color: #f5f5f5;
color: #9e9e9e;
}
.dynamics-list {
display: flex;
flex-direction: column;
gap: 16px;
}
.dynamic-card {
border: 1px solid #e0e0e0;
border-radius: 12px;
padding: 16px;
background-color: #fafafa;
}
.dynamic-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 12px;
}
.dynamic-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
object-fit: cover;
}
.dynamic-user-info {
flex: 1;
}
.dynamic-user-name {
font-size: 15px;
font-weight: 600;
color: #333;
margin: 0;
}
.dynamic-time {
font-size: 12px;
color: #999;
margin-left: 8px;
}
.dynamic-content {
font-size: 15px;
line-height: 1.6;
color: #666;
margin: 0 0 12px 0;
}
.dynamic-actions {
display: flex;
gap: 16px;
}
.action-btn {
display: flex;
align-items: center;
gap: 4px;
background: none;
border: none;
font-size: 14px;
cursor: pointer;
color: #666;
padding: 8px 12px;
border-radius: 20px;
transition: all 0.3s ease;
}
.action-btn:hover {
background-color: #f0f0f0;
color: #42b883;
}
.food-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 16px;
}
.food-card {
border: 1px solid #e0e0e0;
border-radius: 12px;
overflow: hidden;
transition: all 0.3s ease;
}
.food-card:hover {
transform: translateY(-4px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.food-image {
width: 100%;
height: 180px;
object-fit: cover;
}
.food-info {
padding: 16px;
}
.food-name {
font-size: 18px;
font-weight: 600;
color: #333;
margin: 0 0 8px 0;
}
.food-description {
font-size: 14px;
color: #666;
margin: 0 0 12px 0;
line-height: 1.6;
}
.food-meta {
display: flex;
justify-content: space-between;
align-items: center;
}
.food-type {
font-size: 13px;
color: #42b883;
background-color: #e8f5e9;
padding: 4px 8px;
border-radius: 4px;
}
.food-price {
font-size: 18px;
font-weight: 700;
color: #ff6b35;
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment