update: 对接金币相关

This commit is contained in:
2026-08-20 14:37:08 +08:00
parent 82c360f1b1
commit d2571854bc
10 changed files with 494 additions and 158 deletions
+96 -33
View File
@@ -5,22 +5,106 @@ import Container from "@/components/Container.vue";
import CoinHeader from "./components/CoinHeader.vue";
import LocationPermissionState from "./components/LocationPermissionState.vue";
import StoreCard from "./components/StoreCard.vue";
import { nearbyStore } from "./data";
import { getNearbyStoresAPI } from "@/apis";
const PAGE_SIZE = 20;
const DEFAULT_STORE_IMAGE = "/static/coin/store-photo.png";
const showPermissionState = ref(false);
const stores = ref([]);
const location = ref(null);
const page = ref(0);
const total = ref(0);
const loading = ref(false);
const noMore = ref(false);
const loaded = ref(false);
onLoad((options = {}) => {
// 预留未授权态,接口接入后替换为微信定位授权结果。
showPermissionState.value = options.state === "empty";
const getCurrentLocation = () =>
new Promise((resolve, reject) => {
uni.getLocation({
type: "gcj02",
success: resolve,
fail: reject,
});
});
const mapStore = (item = {}) => ({
id: item.id,
name: item.name || "",
address: item.address || "",
phone: item.phone || "",
hours: item.businessHours || "",
image: item.coverImage || DEFAULT_STORE_IMAGE,
});
const authorizeLocation = () => {
showPermissionState.value = false;
const loadStores = async ({ reset = false } = {}) => {
if (!location.value || loading.value || (!reset && noMore.value)) return;
const nextPage = reset ? 1 : page.value + 1;
loading.value = true;
if (reset) noMore.value = false;
try {
const result = await getNearbyStoresAPI({
...location.value,
page: nextPage,
pageSize: PAGE_SIZE,
});
const list = Array.isArray(result?.list) ? result.list : [];
const mappedList = list.map(mapStore);
stores.value = reset ? mappedList : stores.value.concat(mappedList);
page.value = Number(result?.page) || nextPage;
const pageCount = Number(result?.pageCount);
const totalCount = Number(result?.totalCount ?? result?.total);
const responsePageSize = Number(result?.pageSize) || PAGE_SIZE;
total.value = Number.isFinite(totalCount) ? totalCount : 0;
if (Number.isFinite(pageCount) && pageCount >= 0) {
noMore.value = page.value >= pageCount;
} else if (Number.isFinite(totalCount) && totalCount >= 0) {
noMore.value = stores.value.length >= totalCount;
} else {
noMore.value = list.length < responsePageSize;
}
} catch (error) {
if (reset) {
stores.value = [];
page.value = 0;
}
console.error("加载附近门店失败", error);
} finally {
loading.value = false;
loaded.value = true;
}
};
const locateAndLoadStores = async () => {
try {
const position = await getCurrentLocation();
location.value = {
longitude: position.longitude,
latitude: position.latitude,
};
showPermissionState.value = false;
await loadStores({ reset: true });
} catch (error) {
showPermissionState.value = true;
loaded.value = true;
console.error("获取定位失败", error);
}
};
const authorizeLocation = () => {
uni.openSetting({
success: locateAndLoadStores,
fail: locateAndLoadStores,
});
};
onLoad(locateAndLoadStores);
</script>
<template>
<Container :bgType="6" :isHome="true">
<Container :bgType="6" :isHome="true" @scrolltolower="loadStores">
<template #header>
<CoinHeader title="附近门店" />
</template>
@@ -30,15 +114,11 @@ const authorizeLocation = () => {
@authorize="authorizeLocation"
/>
<template v-else>
<StoreCard :store="nearbyStore" />
<view class="store-placeholder">
<image
class="store-placeholder__background"
src="/static/coin/store-placeholder-bg.png"
mode="scaleToFill"
/>
</view>
<text class="stores-page__more">更多门店敬请期待~</text>
<StoreCard v-for="store in stores" :key="store.id" :store="store" />
<text v-if="loaded && !stores.length" class="stores-page__more">
附近暂无门店~
</text>
<text v-else-if="noMore" class="stores-page__more">没有更多门店了~</text>
</template>
</view>
</Container>
@@ -52,23 +132,6 @@ const authorizeLocation = () => {
box-sizing: border-box;
}
.store-placeholder {
position: relative;
width: 650rpx;
height: 324rpx;
margin: 44rpx auto 0;
overflow: hidden;
border-radius: 12rpx;
}
.store-placeholder__background {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.stores-page__more {
display: block;
width: 650rpx;