From a403393c1190994b473e679e1751794d9a1b9502 Mon Sep 17 00:00:00 2001 From: cloudroam <cloudroam> Date: 星期二, 01 七月 2025 10:36:07 +0800 Subject: [PATCH] add: 分享+景点管理 --- components/card/localtion-card.vue | 95 +++++++ pages/home/home.vue | 2 static/common/parking.png | 0 static/common/wechat.png | 0 components/title/section-title.vue | 1 pages/home/home-main.vue | 65 ++++ pages.json | 26 + static/common/visit.png | 0 sub-pages/hot-spot/index.vue | 100 +++++++ components/share-popup.vue | 46 +++ types/index.ts | 51 +++ sub-pages/film-list/film-detail.vue | 10 sub-pages/film-list/film-list.vue | 1 static/common/link.png | 0 sub-pages/hot-spot/spot-detail.vue | 366 ++++++++++++++++++++++++++++ sub-pages/utils/api.ts | 15 + static/common/wechat-moments.png | 0 17 files changed, 755 insertions(+), 23 deletions(-) diff --git a/components/card/localtion-card.vue b/components/card/localtion-card.vue new file mode 100644 index 0000000..32a9584 --- /dev/null +++ b/components/card/localtion-card.vue @@ -0,0 +1,95 @@ +<template> + <view class="card" @click="handleClick(item)"> + <view class="image-wrapper"> + <image :src="item.locationUrl" mode="widthFix" class="card-image" /> + </view> + <view class="card-title"> + <up-text :lines="2" size="14px" :text="item.locationName" bold></up-text> + </view> + <view class="card-footer"> + <view class="user-info"> + <view class="user-text"> + <text class="nickname">{{ item.address }}</text> + </view> + </view> + <view class="opera-info"> + <up-icon name="heart" size="30rpx" color="#999" /> + <text>{{ item.locationWeight }}</text> + </view> + </view> + </view> +</template> + +<script setup lang="ts"> +defineProps<{ + item: any +}>() + +const emit = defineEmits(['click']) +const handleClick = (item: any) => { + emit('click', item) +} +</script> + +<style scoped lang="scss"> +.card { + border-radius: 10rpx; + background-color: #ffffff; + font-size: 14px; + line-height: 20px; + color: rgb(51, 51, 51); + margin: 10rpx; + + .image-wrapper { + width: 100%; + position: relative; + display: inline-block; + + .card-image { + width: 100%; + border-radius: inherit; + } + + } + + + .card-title { + padding: 10rpx; + font-weight: 500; + } + + .card-footer { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10rpx; + } + + .user-info { + display: flex; + align-items: center; + + .user-text { + font-size: 18rpx; + line-height: 14px; + margin-left: 10rpx; + + .nickname { + font-weight: bold; + display: block; + color: #646464; + } + } + } + + .opera-info { + display: flex; + align-items: center; + + text { + margin-left: 10rpx; + font-size: 12px; + } + } +} +</style> \ No newline at end of file diff --git a/components/share-popup.vue b/components/share-popup.vue index 9cd2ef9..f316f4d 100644 --- a/components/share-popup.vue +++ b/components/share-popup.vue @@ -4,14 +4,16 @@ <view class="share-content"> <view class="share-title">分享到</view> <view class="share-options"> - <button class="share-item" open-type="share" @click="handleShare('wechat')"> + <!-- 分享给好友 --> + <button class="share-item" open-type="share"> <image src="/static/common/wechat.png" class="share-icon" /> <text>微信好友</text> </button> - <button class="share-item" open-type="share" @click="handleShare('moments')"> + <!-- 分享到朋友圈 --> + <view class="share-item" @click="handleShareTimeline"> <image src="/static/common/wechat-moments.png" class="share-icon" /> <text>朋友圈</text> - </button> + </view> <view class="share-item" @click="handleCopyLink"> <image src="/static/common/link.png" class="share-icon" /> <text>复制链接</text> @@ -48,10 +50,40 @@ emit('update:show', false) } -// 处理分享 -const handleShare = (type: 'wechat' | 'moments') => { - // 小程序分享通过页面配置和按钮的 open-type="share" 实现 - // 分享内容在页面的 onShareAppMessage 中配置 +// 处理分享到朋友圈 +const handleShareTimeline = () => { + // #ifdef MP-WEIXIN + // 使用微信原生朋友圈分享 + wx.openChannelsActivity({ + finderUserName: '', // 视频号用户名,可选 + success: (res) => { + console.log('打开朋友圈成功', res) + uni.showToast({ + title: '已打开朋友圈', + icon: 'success' + }) + }, + fail: (err) => { + console.error('打开朋友圈失败', err) + // 如果打开失败,尝试使用小程序分享 + uni.showModal({ + title: '提示', + content: '无法直接打开朋友圈,请点击右上角分享到朋友圈', + showCancel: false + }) + } + }) + // #endif + + // #ifndef MP-WEIXIN + // 非微信小程序环境 + uni.showToast({ + title: '请点击右上角分享到朋友圈', + icon: 'none', + duration: 2000 + }) + // #endif + closePopup() } diff --git a/components/title/section-title.vue b/components/title/section-title.vue index d3fbf41..8e101ac 100644 --- a/components/title/section-title.vue +++ b/components/title/section-title.vue @@ -53,6 +53,7 @@ }) function go(url: string) { + console.log("url",url) if (url) { uni.navigateTo({ url diff --git a/pages.json b/pages.json index 1ebaad6..6a19d6c 100644 --- a/pages.json +++ b/pages.json @@ -52,7 +52,9 @@ "path": "film-detail", "style": { "navigationBarTitleText": "", - "enablePullDownRefresh": true + "enablePullDownRefresh": true, + "enableShareTimeline": true, + "enableShareAppMessage": true } } ,{ @@ -122,6 +124,28 @@ } ] } + ,{ + "root": "sub-pages/hot-spot", + "pages": [ + { + "path": "index", + "style": { + "navigationBarTitleText": "场景博物馆", + "enablePullDownRefresh": true + } + } + ,{ + "path": "spot-detail", + "style": { + "navigationBarTitleText": "", + "enablePullDownRefresh": true, + "enableShareTimeline": true, + "enableShareAppMessage": true + } + } + ] + } + ], "globalStyle": { "navigationBarTextStyle": "black", diff --git a/pages/home/home-main.vue b/pages/home/home-main.vue index 3e545c6..e809a9b 100644 --- a/pages/home/home-main.vue +++ b/pages/home/home-main.vue @@ -2,23 +2,26 @@ <view> <!-- <view class="card" v-if="!showVideo"> --> <view class="card"> - <view class="main-title">每一帧画面,都藏着一个等待探索的世界</view> + <view class="main-title">{{ config.mainTitle }}</view> <view class="sub-title"> - 从经典场景到幕后故事,开启你的专属影视朝圣之旅 + {{ config.subTitle }} </view> <view class="btn-group"> <view class="custom-btn explore-btn" @click="startExplore"> - <text class="btn-text">开始探索</text> - <up-icon name="play-right-fill" size="34rpx" color="black" class="btn-icon" /> + <text class="btn-text">{{ config.btnText1 }}</text> + <up-icon + :name="config.btnIcon1" + :color="config.iconColor1" + size="34rpx" class="btn-icon" /> </view> <view class="custom-btn route-btn" @click="hotRoute"> - <text class="btn-text">热门路线</text> + <text class="btn-text">{{ config.btnText2 }}</text> <up-icon - name="/static/common/road-map-fill.png" + :name="config.btnIcon2" + :color="config.iconColor2" size="34rpx" - color="white" class="btn-icon" /> </view> @@ -54,7 +57,9 @@ <script setup lang="ts"> import { ref, computed } from 'vue' - + import { onLoad } from '@dcloudio/uni-app' + import { useGlobal } from '@/composables/useGlobal' + const { $http, $message, $store } = useGlobal() const showVideo = ref(false) const currentIndex = ref(0) @@ -70,7 +75,17 @@ ] const currentVideo = computed(() => videoList[currentIndex.value]) - + // 添加配置响应式对象 + const config = ref({ + mainTitle: '每一帧画面,都藏着一个等待探索的世界', + subTitle: '从经典场景到幕后故事,开启你的专属影视朝圣之旅', + btnText1: '开始探索', + btnText2: '热门路线', + btnIcon1: 'play-right-fill', + btnIcon2: '/static/common/road-map-fill.png', + iconColor1: 'black', + iconColor2: 'white' + }) function startExplore() { // 跳转到具体页面 uni.navigateTo({ @@ -89,6 +104,38 @@ icon: 'none', }) } + + onLoad((options: any) => { + getHomeConfig() + }) + + // 获取首页配置信息 + const getHomeConfig = async () => { + try { + const { code, data } = await $http.request( + 'get', + '/api/home/homeConfig/info', + {} + ) + if (code == 0) { + console.log("接口返回数据:", data); + // 只更新接口返回的有效字段 + Object.keys(config.value).forEach(key => { + const newValue = data[key]; + console.log(`字段 ${key}: 接口值=${newValue}, 本地值=${config.value[key]}`); + if (newValue !== undefined && newValue !== null && newValue !== '') { + config.value[key] = newValue; + } + }); + console.log("首页配置加载成功", config.value) + } else { + } + } catch (error) { + console.error('配置请求失败', error) + } + } + + </script> <style scoped> .card { diff --git a/pages/home/home.vue b/pages/home/home.vue index a1f260e..7095440 100644 --- a/pages/home/home.vue +++ b/pages/home/home.vue @@ -35,7 +35,7 @@ <SectionTitle title="全球影视地标" optitle="查看全部" goUrl="/pages/home/home-more" /> <GlobalGeo /> - <SectionTitle title="场景博物馆" optitle="查看全部" goUrl="/pages/home/home-more" /> + <SectionTitle title="场景博物馆" optitle="查看全部" goUrl="/sub-pages/hot-spot/index" /> <SceneMuseumCard v-for="(item, index) in cardList" :key="index" :image="item.image" :title="item.title" :subtitle="item.subtitle" :readTime="item.readTime" /> diff --git a/static/common/link.png b/static/common/link.png new file mode 100644 index 0000000..a08c7a1 --- /dev/null +++ b/static/common/link.png Binary files differ diff --git a/static/common/parking.png b/static/common/parking.png new file mode 100644 index 0000000..1425c94 --- /dev/null +++ b/static/common/parking.png Binary files differ diff --git a/static/common/visit.png b/static/common/visit.png new file mode 100644 index 0000000..614b53b --- /dev/null +++ b/static/common/visit.png Binary files differ diff --git a/static/common/wechat-moments.png b/static/common/wechat-moments.png new file mode 100644 index 0000000..cb131fb --- /dev/null +++ b/static/common/wechat-moments.png Binary files differ diff --git a/static/common/wechat.png b/static/common/wechat.png new file mode 100644 index 0000000..68bbedb --- /dev/null +++ b/static/common/wechat.png Binary files differ diff --git a/sub-pages/film-list/film-detail.vue b/sub-pages/film-list/film-detail.vue index 3d89490..2d73253 100644 --- a/sub-pages/film-list/film-detail.vue +++ b/sub-pages/film-list/film-detail.vue @@ -183,7 +183,8 @@ title: filmInfo.value?.coverTitle || '分享内容', desc: filmInfo.value?.filmContent?.substring(0, 50) || '', image: filmPictureList.value[0] || '', - url: `https://您的域名/sub-pages/film-list/film-detail?id=${filmInfo.value?.id}` + // url: `http://您的域名/sub-pages/film-list/film-detail?id=${filmInfo.value?.id}` + url: `/sub-pages/film-list/film-detail?id=${filmInfo.value?.id}` } showSharePopup.value = true } @@ -193,7 +194,9 @@ const copyLink = () => { sharePopupShow.value = false uni.setClipboardData({ - data: `https://你的域名/sub-pages/film-list/film-detail?id=${filmInfo.value?.id}`, + // data: `http://14.103.144.28/sub-pages/film-list/film-detail?id=${filmInfo.value?.id}`, + // 此处应该是一个小程序的外链 + data: `http://14.103.144.28/sub-pages/film-list/film-detail?id=${filmInfo.value?.id}`, success: () => $message.showToast('链接已复制') }) } @@ -426,7 +429,8 @@ return { title: filmInfo.value?.coverTitle || '分享内容', query: `id=${filmInfo.value?.id}`, - imageUrl: filmPictureList.value[0] || '' + imageUrl: filmPictureList.value[0] || '', + desc: filmInfo.value?.filmContent?.substring(0, 50) || '' } } }) diff --git a/sub-pages/film-list/film-list.vue b/sub-pages/film-list/film-list.vue index 3987c0d..3257cd1 100644 --- a/sub-pages/film-list/film-list.vue +++ b/sub-pages/film-list/film-list.vue @@ -119,6 +119,7 @@ type: '', current: filmPage.value, size: filmSize, + status: 'published', keywords: keywords.value // 关键修改 }; const records = await getFilmWorksBase(query) diff --git a/sub-pages/hot-spot/index.vue b/sub-pages/hot-spot/index.vue new file mode 100644 index 0000000..b6ac4cf --- /dev/null +++ b/sub-pages/hot-spot/index.vue @@ -0,0 +1,100 @@ +<template> + <view :class="['app', theme]"> + <view style="padding-top: 10rpx;"> + <up-search height="70rpx" placeholder="搜索" search-icon-size="40rpx" margin="0rpx 30rpx" v-model="search" + :show-action="true" @search="onSearch" /> + </view> + <view class="list-view"> + <up-waterfall v-model="films"> + <template #left="{ leftList }"> + <LocaltionCard v-for="(item, index) in leftList" :key="index" :item="item" @click="handleDetailClick(item)" /> + </template> + <template #right="{ rightList }"> + <LocaltionCard v-for="(item, index) in rightList" :key="index" :item="item" @click="handleDetailClick(item)" /> + </template> + </up-waterfall> + <up-loadmore :status="filmStatus" :line="true" /> + </view> + </view> +</template> + +<script setup lang="ts"> +import { ref } from 'vue' +import { onLoad, onShow, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app' +import { FilmLocationVO, FilmLocationQueryDTO } from '@/types/index' +import { useGlobal } from '@/composables/useGlobal' +const { $http, $message } = useGlobal() +import { useNavigator } from '@/composables/useNavigator' +const { navigateTo } = useNavigator() +import { getFilmLocationBase } from '@/sub-pages/utils/api' +import LocaltionCard from "../../components/card/localtion-card.vue"; + +const theme = ref('light') +const search = ref('') +const films = ref<FilmLocationVO[]>([]) +const filmPage = ref(1) +const filmSize = 10 +const filmStatus = ref('loading') + +const onSearch = () => { + filmPage.value = 1 + films.value = [] + filmStatus.value = 'loadmore' + getFilmLocation(search.value) +} + +const handleDetailClick = (item: FilmLocationVO) => { + const url = `/sub-pages/hot-spot/spot-detail?id=${item.id}` + navigateTo(url) +} + +onLoad(() => { + const storedTheme = uni.getStorageSync('theme') || 'light' + theme.value = storedTheme +}) + +onShow(() => { + getFilmLocation() +}) + +onPullDownRefresh(async () => { + filmPage.value = 1 + getFilmLocation() + uni.stopPullDownRefresh() +}) + +onReachBottom(() => { + getFilmLocation() +}) + +const getFilmLocation = async (keyword = '') => { + if (filmStatus.value === 'nomore') return + filmStatus.value = 'loading' + + try { + const query: FilmLocationQueryDTO = { + locationName: keyword, + current: filmPage.value, + size: filmSize, + isEnabled: 1 + } + const records = await getFilmLocationBase(query) + if (records && records.length > 0) { + const existingIds = new Set(films.value.map(item => item.id)) + const uniqueRecords = records.filter(item => !existingIds.has(item.id)) + films.value = [...films.value, ...uniqueRecords] + if (records.length < filmSize) { + filmStatus.value = 'noMore' + } + filmPage.value++ + } else { + filmStatus.value = 'noMore' + } + } catch (e) { + filmStatus.value = 'loadmore' // 重置状态允许重试 + $message.error('加载失败,请重试') + } +} +</script> + +<style lang="scss" scoped></style> \ No newline at end of file diff --git a/sub-pages/hot-spot/spot-detail.vue b/sub-pages/hot-spot/spot-detail.vue new file mode 100644 index 0000000..ff20930 --- /dev/null +++ b/sub-pages/hot-spot/spot-detail.vue @@ -0,0 +1,366 @@ +<template> + <view class="spot-detail-page"> + <!-- 顶部信息 --> + <view class="header"> + <view class="header-info"> + <view class="geo-row"> + <view class="geo-path">{{ geoPath }}</view> + <image src="/static/common/earth.png" class="earth-icon" /> + </view> + <view class="title-row"> + <view class="title">{{ location?.locationName || '景点详情' }}</view> + <up-icon name="heart" size="40rpx" :color="collected ? '#FF4D4F' : '#ccc'" @click="toggleCollect" /> + </view> + </view> + </view> + + <!-- 主图 --> + <view class="main-image"> + <image :src="mainImage" mode="aspectFill" class="main-img" /> + </view> + + <!-- 地址、类型、电话、身份准入等 --> + <view class="info-list"> + <view class="info-item">{{ location?.address }}</view> + <view class="info-item"><up-icon name="/static/common/marker.png" size="32rpx" /> {{ location?.sceneType || '类型未知' }}</view> + <view class="info-item"><up-icon name="/static/common/parking.png" size="32rpx" /> {{ location?.parkingInfo || '无电话' }}</view> + <view class="info-item"><up-icon name="/static/common/visit.png" size="32rpx" /> {{ location?.isOpenVisitStr === '是' ? '允许参观' : '不允许参观' }}</view> + </view> + + <!-- 介绍描述 --> + <view class="divider-line"></view> + <view class="desc-block"> + <text>{{ location?.landmarkDesc || location?.visitInfo || '暂无介绍' }}</text> + </view> + + <!-- 地图 --> + <view class="map-block" v-if="showMap"> + <!-- 腾讯地图小程序组件(uni-app中需配置腾讯地图key) --> + <map + :latitude="location?.gpsLat" + :longitude="location?.gpsLng" + :markers="mapMarkers" + style="width: 100%; height: 300rpx;" + v-if="location?.gpsLat && location?.gpsLng" + /> + <image v-else src="/static/common/geo-earth.png" class="map-placeholder" /> + </view> + + <!-- 实景图 --> + <view class="scene-block" v-if="sceneImages.length"> + <view class="scene-title">实景图 <text class="scene-count">{{ sceneImages.length }}</text></view> + <view class="scene-list"> + <image + v-for="(img, idx) in sceneImages" + :key="idx" + :src="img" + mode="aspectFill" + class="scene-image" + @tap="previewScene(idx)" + /> + </view> + </view> + + <!-- 关联影视作品 --> + <view class="film-block" v-if="relatedFilms.length"> + <view class="film-title">关联影视作品</view> + <view class="film-list"> + <view class="film-item" v-for="film in relatedFilms" :key="film.id"> + <image :src="film.coverUrl" class="film-cover" /> + <view class="film-info"> + <view class="film-name">{{ film.nameCn }}</view> + <view class="film-en">{{ film.nameEn }}</view> + <view class="film-meta"> + <text>{{ film.typeStr }}</text> + <text v-if="film.country"> / {{ film.country }}</text> + <text v-if="film.releaseYear"> / {{ film.releaseYear }}</text> + </view> + </view> + </view> + </view> + </view> + </view> +</template> + +<script setup lang="ts"> +import { ref } from 'vue' +import { onLoad } from '@dcloudio/uni-app' +import { useGlobal } from '@/composables/useGlobal' +const { $http, $message } = useGlobal() +import { FilmLocationVO, FilmWorks } from '@/types/index' + +const location = ref<FilmLocationVO>() +const collected = ref(false) +const geoPath = ref('亚洲-中国-海南省-海口市') +const mainImage = ref('') +const sceneImages = ref<string[]>([]) +const relatedFilms = ref<FilmWorks[]>([]) +const showMap = ref(true) + + +onLoad(async (options: any) => { + const id = options.id + if (id) { + await getLocationDetail(id) + await getRelatedFilms(id) + } +}) + +const getLocationDetail = async (id: string) => { + const { code, data } = await $http.request('get', '/api/filmLocation/list/view', { + params: { id } + }) + if (code === 0) { + location.value = data + // 主图优先locationUrl,其次visitorPhotos + if (data.locationUrl) { + mainImage.value = data.locationUrl + console.log(data.locationUrl) + console.log( mainImage.value) + } else if (data.visitorPhotos) { + try { + const arr = JSON.parse(data.visitorPhotos) + mainImage.value = arr[0]?.url || '' + } catch { + mainImage.value = '' + } + } + // 实景图 + if (data.visitorPhotos) { + try { + const arr = JSON.parse(data.visitorPhotos) + sceneImages.value = arr.map((item: any) => item.url) + } catch { + sceneImages.value = [] + } + } else { + sceneImages.value = [] + } + // 拼接地理层级 + geoPath.value = [ + '亚洲', + '中国', + data.province, + data.city + ].filter(Boolean).join('-') + } else { + $message.showToast('获取景点信息失败') + } +} + +// 地图标记 +const mapMarkers = ref([ + { + id: 1, + latitude: location.value?.gpsLat, + longitude: location.value?.gpsLng, + iconPath: '/static/common/marker.png', + width: 40, + height: 40 + } +]) + +const previewScene = (idx: number) => { + uni.previewImage({ + current: sceneImages.value[idx], + urls: sceneImages.value + }) +} + +// 影视作品接口示例 +const getRelatedFilms = async (locationId: string) => { + // 假设接口 /api/filmWorks/related?locationId=xxx + const { code, data } = await $http.request('get', '/api/filmLocation/related', { + params: { locationId } + }) + if (code === 0 && Array.isArray(data)) { + relatedFilms.value = data + } else { + relatedFilms.value = [] + } +} + +const toggleCollect = () => { + collected.value = !collected.value + $message.showToast(collected.value ? '已收藏' : '已取消收藏') +} +</script> + +<style scoped> +.spot-detail-page { + background: #fff; + min-height: 100vh; +} +.header { + display: flex; + align-items: flex-start; + padding: 30rpx 20rpx 10rpx 20rpx; +} +.header-info { + flex: 1; + margin-left: 20rpx; +} +.geo-path { + color: #6c8fc5; + font-size: 22rpx; + margin-bottom: 10rpx; +} +.title-row { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 30rpx; /* 增加名称与上方的间距 */ +} +.title { + font-size: 36rpx; + font-weight: bold; + margin-right: 16rpx; +} +.earth-icon { + width: 144rpx; /* 放大三倍 */ + height: 144rpx; +} +.main-image { + width: 100%; + height: 320rpx; + margin-top: 40rpx; /* 增加名称和图片之间的间隔 */ + margin-bottom: 40rpx; +} +.main-img { + width: 100%; + height: 100%; + object-fit: cover; + border-radius: 10rpx; +} +/*.info-list {*/ +/* padding: 0 20rpx;*/ +/* margin-bottom: 20rpx;*/ +/*}*/ +/*.info-item {*/ +/* font-size: 28rpx;*/ +/* color: #333;*/ +/* margin-bottom: 16rpx;*/ +/* display: flex;*/ +/* align-items: center;*/ +/*}*/ +/*.desc-block {*/ +/* padding: 0 20rpx 30rpx 20rpx;*/ +/* color: #666;*/ +/* font-size: 26rpx;*/ +/*}*/ +.info-list { + padding: 20rpx; /* 增加内边距 */ + margin: 20rpx 0; /* 调整上下外边距 */ + background-color: #f9f9f9; + border-radius: 12rpx; +} + +.info-item { + font-size: 28rpx; + color: #333; + margin-bottom: 20rpx; /* 调整间距 */ + display: flex; + align-items: center; + line-height: 1.6; +} + +.info-item:last-child { + margin-bottom: 0; +} + +/* 添加分割线样式 */ +.divider-line { + height: 1px; + background-color: #eee; + margin: 30rpx 20rpx 20rpx 20rpx; +} + +/* 调整描述区块的间距 */ +.desc-block { + padding: 0 20rpx 30rpx 20rpx; + color: #666; + font-size: 26rpx; + line-height: 1.8; + margin-top: 20rpx; +} +.map-block { + margin: 20rpx 0; +} +.map-placeholder { + width: 100%; + height: 300rpx; + object-fit: cover; + border-radius: 10rpx; +} +.scene-block { + padding: 0 20rpx 30rpx 20rpx; +} +.scene-title { + font-size: 28rpx; + font-weight: bold; + margin-bottom: 10rpx; +} +.scene-count { + color: #888; + font-size: 22rpx; + margin-left: 10rpx; +} +.scene-list { + display: flex; + gap: 20rpx; + flex-wrap: wrap; +} +.scene-image { + width: 45vw; + height: 140rpx; + object-fit: cover; + border-radius: 8rpx; + margin-bottom: 10rpx; +} +.film-block { + padding: 0 20rpx 30rpx 20rpx; +} +.film-title { + font-size: 28rpx; + font-weight: bold; + margin-bottom: 10rpx; +} +.film-list { + display: flex; + flex-direction: column; + gap: 20rpx; +} +.film-item { + display: flex; + align-items: flex-start; + gap: 20rpx; +} +.film-cover { + width: 120rpx; + height: 160rpx; + object-fit: cover; + border-radius: 8rpx; +} +.film-info { + flex: 1; +} +.film-name { + font-size: 28rpx; + font-weight: bold; +} +.film-en { + font-size: 22rpx; + color: #888; + margin-bottom: 6rpx; +} +.film-meta { + font-size: 22rpx; + color: #888; +} +.geo-row { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 15rpx; +} +</style> \ No newline at end of file diff --git a/sub-pages/utils/api.ts b/sub-pages/utils/api.ts index 4dcc8a9..0316dea 100644 --- a/sub-pages/utils/api.ts +++ b/sub-pages/utils/api.ts @@ -83,4 +83,17 @@ message.showToast('系统异常,无法获取数据'); return null; } - } \ No newline at end of file + } + +export const getFilmLocationBase = async (query: FilmWorksQueryDTO) => { + const { code, data } = await http.request('get', '/api/filmLocation/list', { + params: query + }); + + if (code === 0) { + return data.records; + } else { + message.showToast('系统异常,无法获取数据'); + return null; + } +} \ No newline at end of file diff --git a/types/index.ts b/types/index.ts index f214c6d..7ba6aaa 100644 --- a/types/index.ts +++ b/types/index.ts @@ -304,4 +304,53 @@ size: number; url: string; status: string; - } \ No newline at end of file + } + + +export interface FilmLocationVO { + address?: string, + arEntry?: string, + checkinCount?: number, + city?: string, + classicScene?: string, + endDate?: string, + filmId?: number, + gpsLat?: number, + gpsLng?: number, + id?: number, + isEnabled?: boolean, + isOpenVisit?: string, + isOpenVisitStr?: string, + landmarkDesc?: string, + locationName?: string, + locationUrl?: string, + locationWeight?: number, + operationWeight?: number, + parkingInfo?: string, + province?: string, + region?: string, + sceneType?: string, + startDate?: string, + surroundingFacilities?: string, + transportGuide?: string, + visitInfo?: string, + visitorPhotos?: string +} + +export interface FilmWorksQueryDTO extends PaginationQuery { + + /** 拍摄地点名称 */ + locationName?: string; + + /** 所在省 */ + province?: string; + + /** 所在市 */ + city?: string; + + /** 所在区 */ + region?: string; + + /** 启用/禁用(USER_ENABLED_OR_DISABLED) */ + isEnabled?: boolean; +} -- Gitblit v1.9.3