chore: initialize frontend miniapp repository

This commit is contained in:
lyf
2026-06-09 21:08:45 +08:00
commit a90f63cef0
107 changed files with 60454 additions and 0 deletions

View File

@@ -0,0 +1,268 @@
<template>
<GuideMapShell
:search-text="facility.name"
floor-top="164px"
tools-top="406px"
:tools="['回正', '2D']"
@search-tap="handleSearchTap"
@mode-change="handleModeChange"
@floor-change="handleFloorChange"
@tool-click="handleToolClick"
>
<view class="detail-sheet">
<view class="detail-title-row">
<text class="detail-title">{{ facility.name }}</text>
<text class="open-status">{{ facility.status }}</text>
</view>
<view class="detail-lines">
<text class="detail-line">所在区域{{ facility.location }}</text>
<text class="detail-line">最近垂直交通{{ facility.traffic }}</text>
</view>
<view class="tag-row">
<view
v-for="(tag, index) in facility.tags"
:key="tag"
class="detail-tag"
:class="{ active: index === 0 }"
>
<text class="detail-tag-text">{{ tag }}</text>
</view>
</view>
<view class="action-row">
<view class="action-btn secondary" @tap="handleChooseStart">
<text class="action-text">选择起点</text>
</view>
<view class="action-btn primary" @tap="handleStartNavigation">
<text class="action-text">查看位置</text>
</view>
</view>
</view>
</GuideMapShell>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import GuideMapShell from '@/components/navigation/GuideMapShell.vue'
import {
NAV_ROUTE_UNAVAILABLE_MESSAGE,
formatNavFloorLabel,
isPoiAccessible,
loadCleanNavPoiById
} from '@/services/navAssets'
const facility = ref({
id: '',
name: '目标位置',
status: '可预览',
location: 'clean 导览数据点位',
traffic: NAV_ROUTE_UNAVAILABLE_MESSAGE,
tags: ['三维位置', 'clean 数据']
})
onLoad(async (options: any) => {
if (options.id) {
facility.value.id = options.id
}
if (options.target) {
facility.value.name = decodeURIComponent(options.target)
}
if (!facility.value.id) return
try {
const poi = await loadCleanNavPoiById(facility.value.id)
if (!poi) return
const floor = formatNavFloorLabel(poi.floorId)
facility.value = {
id: poi.id,
name: poi.name,
status: '可预览',
location: `${floor} · ${poi.primaryCategoryZh}`,
traffic: NAV_ROUTE_UNAVAILABLE_MESSAGE,
tags: [
floor,
poi.primaryCategoryZh,
isPoiAccessible(poi) ? '无障碍相关' : '展示点位'
]
}
} catch (error) {
console.error('加载 clean 设施详情失败:', error)
}
})
const handleSearchTap = () => {
uni.navigateTo({
url: `/pages/search/index?keyword=${encodeURIComponent(facility.value.name)}`
})
}
const handleChooseStart = () => {
uni.showToast({
title: '请选择当前位置',
icon: 'none'
})
}
const handleStartNavigation = () => {
uni.navigateTo({
url: `/pages/route/detail?facilityId=${facility.value.id}&target=${encodeURIComponent(facility.value.name)}&state=planning`
})
}
const handleModeChange = (mode: '2d' | '3d') => {
console.log('设施详情切换导览模式:', mode)
}
const handleFloorChange = (floor: string) => {
console.log('设施详情切换楼层:', floor)
}
const handleToolClick = (tool: string) => {
console.log('设施详情工具:', tool)
}
</script>
<style scoped lang="scss">
.detail-sheet {
position: absolute;
left: 0;
right: 0;
bottom: calc(env(safe-area-inset-bottom) + 34px);
height: 252px;
padding: 22px 20px 20px;
box-sizing: border-box;
background: #ffffff;
border: 0;
border-radius: 20px;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.14);
z-index: 45;
}
.detail-title-row {
height: 28px;
display: flex;
align-items: center;
justify-content: space-between;
}
.detail-title {
flex: 1;
min-width: 0;
font-size: 18px;
line-height: 24px;
font-weight: 700;
color: #000000;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.open-status {
width: 60px;
flex-shrink: 0;
text-align: right;
font-size: 13px;
line-height: 18px;
font-weight: 500;
color: #1a7f37;
}
.detail-lines {
margin-top: 17px;
display: flex;
flex-direction: column;
gap: 8px;
}
.detail-line {
font-size: 13px;
line-height: 18px;
color: #6b7178;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.tag-row {
margin-top: 21px;
display: flex;
gap: 8px;
}
.detail-tag {
height: 28px;
min-width: 88px;
padding: 0 15px;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
background: #ffffff;
border: 1px solid #d9d9d9;
border-radius: 14px;
}
.detail-tag.active {
background: #000000;
border-color: #000000;
}
.detail-tag-text {
font-size: 12px;
line-height: 16px;
font-weight: 500;
color: #1f2329;
}
.detail-tag.active .detail-tag-text {
color: var(--museum-accent);
}
.action-row {
position: absolute;
left: 20px;
right: 20px;
bottom: 20px;
display: flex;
gap: 16px;
}
.action-btn {
height: 44px;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
border-radius: 8px;
}
.action-btn.secondary {
width: 151px;
background: #ffffff;
border: 1px solid #000000;
}
.action-btn.primary {
width: 168px;
background: #000000;
border: 1px solid #000000;
}
.action-text {
font-size: 14px;
line-height: 19px;
font-weight: 500;
color: #000000;
}
.action-btn.primary .action-text {
color: var(--museum-accent);
}
</style>