fix:修复bug

This commit is contained in:
2025-10-30 15:41:25 +08:00
parent c5277af28f
commit c77e3fa94d
10 changed files with 98 additions and 68 deletions
+2 -4
View File
@@ -38,11 +38,9 @@
<script setup> <script setup>
import { computed } from 'vue' import { computed } from 'vue'
import { useI18n } from '@/utils/i18n.js'
import { getCurrentInstance } from 'vue'
const instance = getCurrentInstance() const { t: $t } = useI18n()
const $t = instance?.proxy?.$t || ((key) => key)
const props = defineProps({ const props = defineProps({
show: { type: Boolean, default: false }, show: { type: Boolean, default: false },
+28 -23
View File
@@ -7,16 +7,16 @@
:markers="mapMarkers" :scale="mapZoom" :show-location="false" @regionchange="onMapRegionChange" :markers="mapMarkers" :scale="mapZoom" :show-location="false" @regionchange="onMapRegionChange"
@markertap="onMapMarkerTap" @callouttap="onCalloutTap" @updated="onMapUpdated" @error="onMapError"> @markertap="onMapMarkerTap" @callouttap="onCalloutTap" @updated="onMapUpdated" @error="onMapError">
<!-- 覆盖在地图上的可点击控件使用 cover-view 以兼容小程序原生组件层级 --> <!-- 覆盖在地图上的可点击控件使用 cover-view 以兼容小程序原生组件层级 -->
<cover-view class="index-swiper" v-if="!props.hideControls" @tap="handleJoinTap"> <cover-view class="index-swiper" v-if="!props.hideControls && !props.hideMapOverlays" @tap="handleJoinTap">
<cover-image src="/static/index_swiper.png" class="index-swiper-img" mode="aspectFit"></cover-image> <cover-image src="/static/index_swiper.png" class="index-swiper-img" mode="aspectFit"></cover-image>
</cover-view> </cover-view>
<!-- 地图中心固定定位图标 --> <!-- 地图中心固定定位图标 -->
<cover-view class="center-location-marker"> <cover-view class="center-location-marker" v-if="!props.hideMapOverlays">
<cover-image src="/static/location-icon.png" class="center-marker-icon"></cover-image> <cover-image src="/static/location-icon.png" class="center-marker-icon"></cover-image>
</cover-view> </cover-view>
<cover-view class="map-side-controls" v-if="!props.hideControls"> <cover-view class="map-side-controls" v-if="!props.hideControls && !props.hideMapOverlays">
<cover-view class="side-btn service" @tap="handleService"> <cover-view class="side-btn service" @tap="handleService">
<cover-image class="side-icon" src="/static/customer-service.png"></cover-image> <cover-image class="side-icon" src="/static/customer-service.png"></cover-image>
<!-- <cover-view class="side-text">客服</cover-view> --> <!-- <cover-view class="side-text">客服</cover-view> -->
@@ -57,10 +57,11 @@
import { import {
calculateDistanceSync calculateDistanceSync
} from '../utils/mapUtils.js' } from '../utils/mapUtils.js'
// 导入国际化
import { useI18n } from '../utils/i18n.js'
// 获取 i18n 实例 // 获取 i18n 实例
const instance = getCurrentInstance() const { t: $t } = useI18n()
const $t = instance?.proxy?.$t || ((key) => key)
// 引用折叠面板组件的ref // 引用折叠面板组件的ref
const collapseRef = ref(null) const collapseRef = ref(null)
@@ -99,11 +100,15 @@
type: Boolean, type: Boolean,
default: false // 是否隐藏侧边控制按钮 default: false // 是否隐藏侧边控制按钮
}, },
fullWidth: { fullWidth: {
type: Boolean, type: Boolean,
default: false // 是否全宽显示(去掉 margin 和固定宽度) default: false // 是否全宽显示(去掉 margin 和固定宽度)
} },
}) hideMapOverlays: {
type: Boolean,
default: false // 是否隐藏地图上的覆盖层元素(如中心定位图标、轮播图等)
}
})
// Emits // Emits
const emit = defineEmits([ const emit = defineEmits([
@@ -484,18 +489,18 @@ const handleSearch = () => {
} }
} }
/* 地图中心定位图标(固定在屏幕中心) */ /* 地图中心定位图标(固定在屏幕中心) */
.center-location-marker { .center-location-marker {
position: absolute; position: absolute;
left: 50%; left: 50%;
top: 50%; top: 50%;
z-index: 100; z-index: 1;
width: 60rpx; width: 60rpx;
height: 80rpx; height: 80rpx;
margin-left: -30rpx; margin-left: -30rpx;
margin-top: -80rpx; margin-top: -80rpx;
pointer-events: none; pointer-events: none;
} }
.center-marker-icon { .center-marker-icon {
width: 60rpx; width: 60rpx;
@@ -567,7 +572,7 @@ const handleSearch = () => {
width: 90vw; width: 90vw;
height: 120rpx; height: 120rpx;
border-radius: 20rpx; border-radius: 20rpx;
z-index: 1000; z-index: 1;
position: absolute; position: absolute;
// top: 10rpx; // top: 10rpx;
left: 50%; left: 50%;
+4 -4
View File
@@ -80,10 +80,10 @@
</template> </template>
<script setup> <script setup>
import { computed, getCurrentInstance } from 'vue'; import { computed } from 'vue';
import { useI18n } from '@/utils/i18n.js'
const instance = getCurrentInstance()
const $t = instance?.proxy?.$t || ((key) => key) const { t: $t } = useI18n()
const props = defineProps({ const props = defineProps({
order: { type: Object, required: true }, order: { type: Object, required: true },
+1 -1
View File
@@ -3,4 +3,4 @@ export const URL = "https://fansdev.gxfs123.com/api" //测试服务器
// export const URL = "http://192.168.5.120:8080" //本地调试 // export const URL = "http://192.168.5.120:8080" //本地调试
// export const URL = "http://127.0.0.1:8080" //本地调试 // export const URL = "http://127.0.0.1:8080" //本地调试
export const appid = "wx2165f0be356ae7a9" //小程序appid export const appid = "wx2165f0be356ae7a9" //小程序appid
+11 -11
View File
@@ -1,26 +1,26 @@
// 帮助中心文案配置 // 帮助中心文案配置
export const HELP_CONTENT = { export const HELP_CONTENT = {
// FAQ列表 // FAQ列表(存储翻译键,由组件动态翻译)
FAQ_LIST: [ FAQ_LIST: [
{ {
question: '如何租借风扇?', question: 'help.faq1Question',
answer: '点击首页"扫码租借"按钮,使用微信扫描设备上的二维码,按提示完成支付即可使用。' answer: 'help.faq1Answer'
}, },
{ {
question: '收费标准是怎样的?', question: 'help.faq2Question',
answer: '本产品租界风扇采用免押金租借形式,无需支付押金,具体计费方式以场地机柜扫码提示为准。' answer: 'help.faq2Answer'
}, },
{ {
question: '如何归还风扇?', question: 'help.faq3Question',
answer: '将风扇带到任意归还点,点击首页"扫码归还"按钮,扫描归还点二维码即可完成归还。' answer: 'help.faq3Answer'
}, },
{ {
question: '押金多久能退还?', question: 'help.faq4Question',
answer: '归还设备后押金将自动发起退款,预计0-7个工作日到账。' answer: 'help.faq4Answer'
}, },
{ {
question: '设备无法正常使用怎么办?', question: 'help.faq5Question',
answer: '您可以通过"我的-投诉与建议"提交故障反馈,或直接拨打客服电话处理。' answer: 'help.faq5Answer'
} }
], ],
+11 -1
View File
@@ -349,7 +349,17 @@ export default {
phone: 'Phone', phone: 'Phone',
email: 'Email', email: 'Email',
workingHours: 'Working Hours', workingHours: 'Working Hours',
functionDeveloping: 'Feature in development' functionDeveloping: 'Feature in development',
faq1Question: 'How to rent a fan?',
faq1Answer: 'Click "Scan to Rent" on the homepage, scan the QR code on the device with WeChat, and complete payment as prompted.',
faq2Question: 'What are the charges?',
faq2Answer: 'Our fan rental is deposit-free. Specific billing is shown when scanning the device QR code.',
faq3Question: 'How to return the fan?',
faq3Answer: 'Bring the fan to any return point, click "Scan to Return" on homepage, and scan the return point QR code.',
faq4Question: 'When will deposit be refunded?',
faq4Answer: 'Deposit refund is automatically initiated after returning. It takes 0-7 business days.',
faq5Question: 'What if device doesn\'t work?',
faq5Answer: 'Submit feedback via "My - Feedback", or call customer service directly.'
}, },
settings: { settings: {
+11 -1
View File
@@ -349,7 +349,17 @@ export default {
phone: '电话', phone: '电话',
email: '邮箱', email: '邮箱',
workingHours: '工作时间', workingHours: '工作时间',
functionDeveloping: '功能开发中' functionDeveloping: '功能开发中',
faq1Question: '如何租借风扇?',
faq1Answer: '点击首页"扫码租借"按钮,使用微信扫描设备上的二维码,按提示完成支付即可使用。',
faq2Question: '收费标准是怎样的?',
faq2Answer: '本产品租界风扇采用免押金租借形式,无需支付押金,具体计费方式以场地机柜扫码提示为准。',
faq3Question: '如何归还风扇?',
faq3Answer: '将风扇带到任意归还点,点击首页"扫码归还"按钮,扫描归还点二维码即可完成归还。',
faq4Question: '押金多久能退还?',
faq4Answer: '归还设备后押金将自动发起退款,预计0-7个工作日到账。',
faq5Question: '设备无法正常使用怎么办?',
faq5Answer: '您可以通过"我的-投诉与建议"提交故障反馈,或直接拨打客服电话处理。'
}, },
settings: { settings: {
+11 -11
View File
@@ -4,13 +4,13 @@
<!-- 问题类型选择 --> <!-- 问题类型选择 -->
<view class="type-section"> <view class="type-section">
<view class="section-title">{{ $t('feedback.issueType') }}</view> <view class="section-title">{{ $t('feedback.issueType') }}</view>
<view class="type-grid"> <view class="type-grid">
<view v-for="(type, index) in types" :key="index" class="type-item" <view v-for="(type, index) in types" :key="index" class="type-item"
:class="{ active: selectedType === index }" @click="selectType(index)"> :class="{ active: selectedType === index }" @click="selectType(index)">
{{ type }} {{ $t(type) }}
</view>
</view> </view>
</view> </view>
</view>
<!-- 问题描述 --> <!-- 问题描述 -->
<view class="description-section"> <view class="description-section">
@@ -76,7 +76,7 @@
}) })
// 响应式数据 // 响应式数据
const types = ref([$t('feedback.deviceFault'), $t('feedback.chargingIssue'), $t('feedback.usageSuggestion'), $t('feedback.other')]) const types = ref(['feedback.deviceFault', 'feedback.chargingIssue', 'feedback.usageSuggestion', 'feedback.other'])
const selectedType = ref(-1) const selectedType = ref(-1)
const paramsType = ref('') const paramsType = ref('')
const description = ref('') const description = ref('')
@@ -145,11 +145,11 @@
return return
} }
if (types.value[selectedType.value] == $t('feedback.deviceFault') || types.value[selectedType.value] == $t('feedback.chargingIssue')) { if (types.value[selectedType.value] === 'feedback.deviceFault' || types.value[selectedType.value] === 'feedback.chargingIssue') {
paramsType.value = 'complain' paramsType.value = 'complain'
} else { } else {
paramsType.value = 'suggestion' paramsType.value = 'suggestion'
} }
// 构建反馈数据 // 构建反馈数据
const feedbackData = { const feedbackData = {
+2 -2
View File
@@ -9,11 +9,11 @@
@click="toggleFaq(index)" @click="toggleFaq(index)"
> >
<view class="faq-header"> <view class="faq-header">
<text class="question">{{ item.question }}</text> <text class="question">{{ $t(item.question) }}</text>
<view class="arrow" :class="{ open: item.isOpen }"></view> <view class="arrow" :class="{ open: item.isOpen }"></view>
</view> </view>
<view class="answer" v-show="item.isOpen"> <view class="answer" v-show="item.isOpen">
{{ item.answer }} {{ $t(item.answer) }}
</view> </view>
</view> </view>
</view> </view>
+17 -10
View File
@@ -18,12 +18,13 @@
<!-- 内容区域 --> <!-- 内容区域 -->
<view class="main-content" :style="{ paddingTop: (statusBarHeight + navBarHeight + noticeHeight) + 'px' }"> <view class="main-content" :style="{ paddingTop: (statusBarHeight + navBarHeight + noticeHeight) + 'px' }">
<!-- 全屏地图组件 --> <!-- 全屏地图组件 -->
<MapComponent v-if="!isLoading && userLocation" ref="mapRef" :userLocation="userLocation" <MapComponent v-if="!isLoading && userLocation" ref="mapRef" :userLocation="userLocation"
:positionList="positionList" :filteredPositions="filteredPositions" :searchKeyword="searchKeyword" :positionList="positionList" :filteredPositions="filteredPositions" :searchKeyword="searchKeyword"
:enableMarkers="true" :enableMarkers="true"
@relocate="handleRelocate" @scan="handleScan" @showList="showLocationList" @markerTap="selectPosition" :hideMapOverlays="showGuidePopup || showNoticePopup"
@mapCenterChange="onMapCenterChange" /> @relocate="handleRelocate" @scan="handleScan" @showList="showLocationList" @markerTap="selectPosition"
@mapCenterChange="onMapCenterChange" />
<!-- 地图加载状态 --> <!-- 地图加载状态 -->
<view v-if="isLoading || !userLocation" class="map-loading-placeholder"> <view v-if="isLoading || !userLocation" class="map-loading-placeholder">
@@ -209,11 +210,13 @@
const isLoading = ref(false) const isLoading = ref(false)
const showPhoneAuthPopup = ref(false) const showPhoneAuthPopup = ref(false)
const isLocationInitialized = ref(false) const isLocationInitialized = ref(false)
const showLocationPopup = ref(false) const showLocationPopup = ref(false)
const isRelocating = ref(false) // 防抖标志:是否正在重新定位 const isRelocating = ref(false) // 防抖标志:是否正在重新定位
const showGuidePopup = ref(false) // 使用指南弹窗显示状态
const showNoticePopup = ref(false) // 通知详情弹窗显示状态
// 导航栏高度相关 // 导航栏高度相关
const statusBarHeight = ref(0) const statusBarHeight = ref(0)
const navBarHeight = ref(44) // 默认导航栏内容高度 const navBarHeight = ref(44) // 默认导航栏内容高度
const noticeHeight = ref(0) // 通知栏高度 const noticeHeight = ref(0) // 通知栏高度
@@ -814,12 +817,14 @@ const noticePopup = ref(null)
// 使用指南弹窗控制 // 使用指南弹窗控制
const openPopup = () => { const openPopup = () => {
try { try {
showGuidePopup.value = true
guidePopup.value && typeof guidePopup.value.open === 'function' && guidePopup.value.open() guidePopup.value && typeof guidePopup.value.open === 'function' && guidePopup.value.open()
} catch (e) {} } catch (e) {}
} }
const closeGuidePopup = () => { const closeGuidePopup = () => {
try { try {
showGuidePopup.value = false
guidePopup.value && typeof guidePopup.value.close === 'function' && guidePopup.value.close() guidePopup.value && typeof guidePopup.value.close === 'function' && guidePopup.value.close()
} catch (e) {} } catch (e) {}
} }
@@ -827,12 +832,14 @@ const closeGuidePopup = () => {
// 通知弹窗控制 // 通知弹窗控制
const openNoticePopup = () => { const openNoticePopup = () => {
try { try {
showNoticePopup.value = true
noticePopup.value && typeof noticePopup.value.open === 'function' && noticePopup.value.open() noticePopup.value && typeof noticePopup.value.open === 'function' && noticePopup.value.open()
} catch (e) {} } catch (e) {}
} }
const closeNoticePopup = () => { const closeNoticePopup = () => {
try { try {
showNoticePopup.value = false
noticePopup.value && typeof noticePopup.value.close === 'function' && noticePopup.value.close() noticePopup.value && typeof noticePopup.value.close === 'function' && noticePopup.value.close()
} catch (e) {} } catch (e) {}
} }