Files
mp-pilates/packages/app/src/components/StudioInfo.vue
2026-09-08 14:20:43 +08:00

102 lines
3.3 KiB
Vue

<template>
<view class="studio-info">
<text class="section-title">来工作室坐坐</text>
<!-- Address + Chat row -->
<view class="location-row">
<view class="location-left" @tap="handleAddressTap">
<view class="location-content">
<text class="location-label">场馆地址</text>
<text class="location-text">
{{ studioInfo?.address || '深圳市宝安区西乡街道财富港 D 座 1203D' }}
</text>
</view>
</view>
<button class="chat-btn" open-type="contact">
<text>联系老师</text>
</button>
</view>
<!-- Horizontal gallery -->
<view class="gallery-block">
<scroll-view scroll-x class="gallery-scroll" :show-scrollbar="false" enhanced>
<view class="gallery-track">
<view
v-for="(photo, idx) in galleryPhotos"
:key="photo"
class="gallery-item"
@tap="previewPhoto(idx)"
>
<image class="gallery-image" :src="photo" mode="aspectFill" />
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import {
DEFAULT_STUDIO_GALLERY_PHOTOS,
type StudioConfig,
} from '@mp-pilates/shared'
const props = defineProps<{
studioInfo: StudioConfig | null
}>()
const galleryPhotos = computed(() => {
const photos = props.studioInfo?.photos?.filter(Boolean) ?? []
return photos.length ? photos : [...DEFAULT_STUDIO_GALLERY_PHOTOS]
})
function previewPhoto(index: number) {
uni.previewImage({
current: index,
urls: galleryPhotos.value,
})
}
function handleAddressTap() {
const latitude = props.studioInfo?.latitude ?? 22.567048
const longitude = props.studioInfo?.longitude ?? 113.867227
const address = props.studioInfo?.address || '深圳市宝安区西乡街道财富港 D 座 1203D'
const name = props.studioInfo?.name || 'Focus Core'
uni.openLocation({
latitude,
longitude,
name,
address,
fail() {
copyAddress()
},
})
}
function copyAddress() {
const address = props.studioInfo?.address
if (!address) return
uni.setClipboardData({
data: address,
success() {
uni.showToast({ title: '地址已复制', icon: 'none' })
},
})
}
</script>
<style lang="scss" scoped>
.studio-info { margin: 36rpx 32rpx 0; }
.section-title { display: block; margin-bottom: 20rpx; font-size: 30rpx; font-weight: 500; color: #514943; }
.location-row { display: flex; align-items: center; justify-content: space-between; gap: 20rpx; margin-bottom: 20rpx; }
.location-left, .location-content { flex: 1; min-width: 0; }
.location-label { display: block; font-size: 21rpx; color: #8b817b; margin-bottom: 6rpx; }
.location-text { font-size: 24rpx; color: #6f655e; line-height: 1.7; overflow-wrap: anywhere; }
.chat-btn { flex-shrink: 0; margin: 0; padding: 0 20rpx; line-height: 64rpx; font-size: 23rpx; border: none; border-radius: 999rpx; background: #f0eae4; color: #78675c; &::after { border: none; } }
.gallery-scroll { width: 100%; }
.gallery-track { display: inline-flex; gap: 16rpx; }
.gallery-item { width: 264rpx; height: 180rpx; border-radius: 20rpx; overflow: hidden; flex-shrink: 0; background: #e9e1d8; }
.gallery-image { width: 100%; height: 100%; }
</style>