提交 4847926a 作者: anergin00

update init

父级 a39267af
import CollectionApi from "./apis/CollectionApi"; import CollectionApi from "./apis/CollectionApi";
import PhotoApi from "./apis/PhotoApi"; import PhotoApi from "./apis/PhotoApi";
import ItineraryApi from "./apis/ItineraryApi"; import ItineraryApi from "./apis/ItineraryApi";
export { CollectionApi, PhotoApi, ItineraryApi }; import CardApi from "./apis/CardApi";
import PoiApi from "./apis/PoiApi";
export { CollectionApi, PhotoApi, ItineraryApi, CardApi, PoiApi };
export default class CardApi {
constructor(app) {
this.app = app;
}
async getByZone(zoneCode) {
const { qmurl, post } = this.app;
try {
const {
data: { code, data },
} = await post(`${qmurl}/api/v1/applet/getActivityByZone`, {
zoneCode,
});
if (code === 200) {
return data?.activityId;
}
return null;
} catch (error) {
console.error(error);
return null;
}
}
async get(activityId) {
const { qmurl, post, globalData } = this.app;
if (!globalData.user) return null;
try {
const {
data: { code, data },
} = await post(`${qmurl}/api/v1/applet/getActivityInfo`, {
userId: globalData.user.user.userId,
activityId,
});
if (code === 200) {
return data;
}
return null;
} catch (error) {
console.error(error);
return null;
}
}
async check(poi) {
const { qmurl, post, globalData } = this.app;
if (!globalData.user) return false;
if (!poi) return false;
try {
const {
data: { code, data },
} = await post(`${qmurl}/api/v1/applet/checkInActivity`, {
userId: globalData.user.user.userId,
token: globalData.user.access_token,
shopType: poi.facility ? 2 : 1,
shopId: poi.shopId ? poi.shopId : poi.facilityId,
boothNo: poi.shopId ? poi.ywZh?.boothNo : undefined,
});
if (code === 200) return data;
return false;
} catch (error) {
console.error(error);
return false;
}
}
}
...@@ -75,15 +75,16 @@ export default class PhotoApi { ...@@ -75,15 +75,16 @@ export default class PhotoApi {
} }
} }
async search(imageUrl, rect) { async search(imageUrl, rect) {
const { marketurl, post, globalData } = this.app; const { marketurl, post, globalData, currentBuilding } = this.app;
if (!globalData.user) return false; if (!globalData.user) throw new Error("用户未登录");
if (!imageUrl) return false; if (!imageUrl) throw new Error("没有图片url");
if (!rect) { if (!rect) {
try { try {
const { width, height } = await wx.getImageInfo({ src: imageUrl }); const { width, height } = await wx.getImageInfo({ src: imageUrl });
rect = { width, height, x: 0, y: 0 }; rect = { width, height, x: 0, y: 0 };
} catch (error) { } catch (error) {
console.error(error); console.error(error);
throw new Error("获取图片宽高失败");
} }
} }
try { try {
...@@ -92,12 +93,13 @@ export default class PhotoApi { ...@@ -92,12 +93,13 @@ export default class PhotoApi {
} = await post(`${marketurl}/detector/baidu/image/search`, { } = await post(`${marketurl}/detector/baidu/image/search`, {
imageRectDto: rect, imageRectDto: rect,
imageUrl, imageUrl,
marketCode: currentBuilding.marketCode,
}); });
if (code === 20000) return data; if (code === 20000) return data;
return null; throw new Error("接口返回code不是20000");
} catch (error) { } catch (error) {
console.error(error); console.error(error);
return null; throw new Error("接口异常");
} }
} }
} }
import { getShopMainGoods, getStarredPhone } from "../util";
export default class PoiApi {
constructor(app) {
this.app = app;
this.MAX_CACHE_SIZE = 1000;
this.poiCache = new Map();
// 内存不足时自动清理
if (wx.onMemoryWarning) {
wx.onMemoryWarning((res) => {
console.warn("Memory warning, clearing POI cache:", res.level);
this.poiCache.clear();
});
}
}
// LRU 缓存设置
_setCache(key, value) {
if (this.poiCache.has(key)) this.poiCache.delete(key);
this.poiCache.set(key, value);
if (this.poiCache.size > this.MAX_CACHE_SIZE) {
this.poiCache.delete(this.poiCache.keys().next().value);
}
}
_getCacheKey({ shopType, shopId, boothNo }) {
return `${shopType}_${shopId}_${boothNo || ""}`;
}
// 数据预处理
_processShopData(item) {
if (!item) return item;
// 简单判断是否为店铺逻辑:type=1 或 有ID且无facilityId
const isShop = item.shopType === "1" || (item.shopId && !item.facilityId);
if (isShop) {
try {
item.maingoods = getShopMainGoods(item, false);
item.maingoodsEn = getShopMainGoods(item, true);
if (item.ywZh?.contactPhone)
item.contactPhone = getStarredPhone(item.ywZh.contactPhone);
if (item.ywEn?.contactPhone)
item.contactPhoneEn = getStarredPhone(item.ywEn.contactPhone);
} catch (e) {
console.error("Format shop data error:", e);
}
}
return item;
}
// --- 核心底层方法:批量获取 (含缓存) ---
async getListByIds(params) {
if (!Array.isArray(params) || params.length === 0) return [];
const uncachedParams = [];
const resultMap = {};
// 1. 缓存分流
params.forEach((param) => {
if (!param) return; // 跳过 populate 产生的无效占位
const key = this._getCacheKey(param);
if (this.poiCache.has(key)) {
const val = this.poiCache.get(key);
this._setCache(key, val); // 刷新 LRU
resultMap[key] = val;
} else {
uncachedParams.push(param);
}
});
// 2. 网络请求 (仅请求未命中的)
if (uncachedParams.length > 0) {
try {
const { qmurl, post } = this.app;
const {
data: { data },
} = await post(
`${qmurl}/api/v1/applet/getShopFacilityPoiListBatch`,
uncachedParams.map(({ shopType, shopId, boothNo }) => ({
shopType,
shopId,
boothNo,
})),
);
if (Array.isArray(data)) {
data.forEach((item, index) => {
const param = uncachedParams[index];
if (param && item) {
this._processShopData(item);
const key = this._getCacheKey(param);
this._setCache(key, item);
resultMap[key] = item;
}
});
}
} catch (e) {
console.error("Batch fetch error:", e);
}
}
// 3. 按原顺序返回
return params.map((param) => {
if (!param) return null;
return resultMap[this._getCacheKey(param)] || null;
});
}
// --- 业务层方法 ---
/**
* 智能填充列表 (Page层主要调用此方法)
*/
async populate(list, options = {}) {
if (!Array.isArray(list) || list.length === 0) return [];
const {
getType = (item) => item.shopType,
getId = (item) => item.shopId,
getBooth = (item) => item.boothNo,
targetField = "poi",
} = options;
// 1. 构造请求参数 (保持索引对应)
const params = list.map((item) => {
const type = getType(item);
const id = getId(item);
// 仅处理合法的店铺(1)或设施(2)
if ((type == 1 || type == 2) && id) {
return {
shopType: String(type),
shopId: id,
boothNo: getBooth(item) || "",
};
}
return null;
});
// 2. 批量获取
const details = await this.getListByIds(params);
// 3. 回填数据
return list
.map((item, index) => {
const detail = details[index];
return detail ? { ...item, [targetField]: detail } : null;
})
.filter(Boolean);
}
/**
* 获取单条详情 (复用 populate)
*/
async getOne({ shopType, shopId, boothNo }) {
const res = await this.populate([{ shopType, shopId, boothNo }], {
targetField: "detail",
});
return res[0]?.detail || null;
}
async getTx() {
try {
const {
data: { data },
} = await this.app.get(
`${this.app.qmurl}/api/v1/applet/getShopFacilityPoiSummary`,
);
return data;
} catch (e) {
console.error(e);
return null;
}
}
}
...@@ -11,7 +11,11 @@ ...@@ -11,7 +11,11 @@
"pages/aisearchresult/index", "pages/aisearchresult/index",
"pages/itinerary/index", "pages/itinerary/index",
"pages/nav-end/index", "pages/nav-end/index",
"pages/poi-map/index" "pages/poi-map/index",
"pages/verify-openId/index",
"pages/card-detail/index",
"pages/feedback/index",
"pages/explore/index"
], ],
"permission": { "permission": {
"scope.userLocation": { "scope.userLocation": {
...@@ -34,7 +38,7 @@ ...@@ -34,7 +38,7 @@
"provider": "wx069ba97219f66d99" "provider": "wx069ba97219f66d99"
}, },
"indoormap": { "indoormap": {
"version": "1.3.27", "version": "1.3.32",
"provider": "wxfe8f0709a4de371b", "provider": "wxfe8f0709a4de371b",
"export": "pluginReport.js" "export": "pluginReport.js"
} }
......
module.exports = Behavior({
behaviors: [],
properties: {},
data: {
currentBuilding: getApp().currentBuilding,
},
lifetimes: {
attached() {
this.setData({ currentBuilding: getApp().currentBuilding });
this.setBuilding = (currentBuilding) => {
this.setData({ currentBuilding });
if (this.onCurrentBuildingChange)
this.onCurrentBuildingChange(currentBuilding);
};
getApp().events.on("building", this.setBuilding);
},
detached() {
getApp().events.off("building", this.setBuilding);
},
},
});
...@@ -28,14 +28,13 @@ module.exports = Behavior({ ...@@ -28,14 +28,13 @@ module.exports = Behavior({
}, },
methods: { methods: {
async toggleCollection(poi) { async toggleCollection(poi) {
const { collectionApi } = getApp(); const { collectionApi, buildingIdNameMap } = getApp();
try { try {
let success; let success;
const collected = this.isCollected(poi); const collected = this.isCollected(poi);
try { try {
getApp().sensors?.track("CollectNavPosition", { getApp().sensors?.track("CollectNavPosition", {
action_type: collected ? "取消收藏" : "收藏", action_type: collected ? "取消收藏" : "收藏",
short_market_name: "二区东",
...(poi.tx ...(poi.tx
? { ? {
x: Number(poi.tx.poi_location.longitude), x: Number(poi.tx.poi_location.longitude),
...@@ -46,8 +45,10 @@ module.exports = Behavior({ ...@@ -46,8 +45,10 @@ module.exports = Behavior({
? { ? {
nav_target_type: poi.facility.name, nav_target_type: poi.facility.name,
booth_floor: poi.tx.poi_fl_seq, booth_floor: poi.tx.poi_fl_seq,
short_market_name: buildingIdNameMap[poi.tx.bld_id],
} }
: { : {
short_market_name: poi.ywZh.marketNameDtl,
store_name: poi.ywZh.name, store_name: poi.ywZh.name,
booth_addr_street: poi.ywZh.boothAddrStreet, booth_addr_street: poi.ywZh.boothAddrStreet,
booth_cover_img: poi.ywZh.cover, booth_cover_img: poi.ywZh.cover,
......
...@@ -6,8 +6,15 @@ Component({ ...@@ -6,8 +6,15 @@ Component({
/** /**
* 组件的初始数据 * 组件的初始数据
*/ */
data: { isIOS: getApp().isIOS }, data: { isIOS: getApp().isIOS, isSystem: true },
lifetimes: {
attached() {
const appAuthorizeSetting = wx.getAppAuthorizeSetting();
this.setData({
isSystem: appAuthorizeSetting.bluetoothAuthorized === "authorized",
});
},
},
/** /**
* 组件的方法列表 * 组件的方法列表
*/ */
...@@ -15,6 +22,13 @@ Component({ ...@@ -15,6 +22,13 @@ Component({
close() { close() {
this.triggerEvent("close"); this.triggerEvent("close");
}, },
openAppAuthorizeSetting() {
wx.openAppAuthorizeSetting({
success(res) {
console.log(res);
},
});
},
doNothing() {}, doNothing() {},
}, },
}); });
...@@ -16,20 +16,47 @@ ...@@ -16,20 +16,47 @@
height: 100vh; height: 100vh;
.image { .image {
position: absolute; position: absolute;
top: 32px; top: 120px;
left: 0; left: 0;
right: 0; right: 0;
margin: auto; margin: auto;
width: 304px; width: 302px;
height: 572px; height: 396px;
z-index: 1;
}
.close {
position: absolute;
top: 130px;
right: calc(50vw - 151px + 10px);
width: 32px;
height: 32px;
z-index: 2;
} }
.btn { .btn {
position: absolute; position: absolute;
top: 542px; top: 452px;
left: 0; left: 0;
right: 0; right: 0;
margin: auto; margin: auto;
width: 260px; width: 260px;
height: 38px; height: 38px;
z-index: 2;
}
.btn1 {
position: absolute;
top: 452px;
left: calc(50vw - 126px - 4px);
width: 126px;
height: 38px;
z-index: 2;
}
.btn2 {
position: absolute;
top: 452px;
right: calc(50vw - 126px - 4px);
margin: auto;
width: 126px;
height: 38px;
z-index: 2;
} }
} }
<textarea disabled class="bluetooth-bg"></textarea> <textarea disabled class="bluetooth-bg"></textarea>
<view class="bluetooth-modal" bind:tap="close"> <view class="bluetooth-modal" bind:tap="close">
<image wx:if="{{isIOS}}" class="image" catch:tap="donothing" src="https://cdnimg.chinagoods.com/png/2025/09/01/dacfdaux2wtvloq0mfvhd48otw8gplir.png" mode="" /> <block wx:if="{{isSystem}}">
<image wx:else catch:tap="donothing" class="image" src="https://cdnimg.chinagoods.com/png/2025/09/01/mbx4nn2dwya3xovr7lp1yfhzrn6qgxsq.png" catch:tap="doNothing" mode="" /> <image wx:if="{{isIOS}}" class="image" catch:tap="doNothing" src="https://cdnimg.chinagoods.com/png/2025/10/30/iowxo8oegleiwnzm1lci81ngipjqxrkm.png" mode="" />
<view class="btn" catch:tap="close"></view> <image wx:else catch:tap="doNothing" class="image" src="https://cdnimg.chinagoods.com/png/2025/10/30/65vtmu6ebrcalmekbb9bimrykmcpnsqi.png" catch:tap="doNothing" mode="" />
<view class="btn" catch:tap="close"></view>
</block>
<block wx:else>
<image wx:if="{{isIOS}}" class="image" catch:tap="doNothing" src="https://cdnimg.chinagoods.com/png/2025/10/30/fu5mur0sheld26mgetp8hjddzh7fh64i.png" mode="" />
<image wx:else catch:tap="doNothing" class="image" src="https://cdnimg.chinagoods.com/png/2025/10/30/br1lik6ag7902e2kjmz3iy0ep5ctvkj6.png" catch:tap="doNothing" mode="" />
<view class="btn1" catch:tap="close"></view>
<view class="btn2" catch:tap="openAppAuthorizeSetting"></view>
</block>
<view class="close" catch:tap="close"></view>
</view> </view>
\ No newline at end of file
...@@ -21,6 +21,13 @@ Component({ ...@@ -21,6 +21,13 @@ Component({
activeIcon: "./selectedSurroundings.png", activeIcon: "./selectedSurroundings.png",
}, },
{ {
url: "/pages/explore/index",
text: "探索",
textEn: "Explore",
icon: "./explore.png",
activeIcon: "./selectedExplore.png",
},
{
url: "/pages/mine/index", url: "/pages/mine/index",
text: "我的", text: "我的",
textEn: "My", textEn: "My",
...@@ -36,7 +43,7 @@ Component({ ...@@ -36,7 +43,7 @@ Component({
methods: { methods: {
handleTap({ currentTarget: { id } }) { handleTap({ currentTarget: { id } }) {
if ( if (
["0", "1", "2"].includes(id) && ["0", "1", "2", "3"].includes(id) &&
this.data.currentIndex !== Number(id) this.data.currentIndex !== Number(id)
) { ) {
const { currentIndex } = this.data; const { currentIndex } = this.data;
......
import langBehavior from "../../behaviors/langBehavior"; import langBehavior from "../../behaviors/langBehavior";
import buildingBehavior from "../../behaviors/buildingBehavior";
Component({ Component({
behaviors: [langBehavior], behaviors: [langBehavior, buildingBehavior],
properties: { properties: {
floors: Array, floors: Array,
floorName: String, floorName: String,
...@@ -16,7 +17,18 @@ Component({ ...@@ -16,7 +17,18 @@ Component({
/** /**
* 组件的初始数据 * 组件的初始数据
*/ */
data: {}, data: {
reversedFloors: [],
scrollTop: 0,
},
observers: {
floors() {
this.setData({ reversedFloors: [...this.data.floors].reverse() });
},
"floorName,reversedFloors"() {
this.scrollToCurrent();
},
},
/** /**
* 组件的方法列表 * 组件的方法列表
...@@ -28,5 +40,28 @@ Component({ ...@@ -28,5 +40,28 @@ Component({
handleFloor({ currentTarget: { id: floorName } }) { handleFloor({ currentTarget: { id: floorName } }) {
this.triggerEvent("floorname", floorName); this.triggerEvent("floorname", floorName);
}, },
scrollToCurrent() {
if (this.scollContext) {
const index = this.data.reversedFloors.findIndex(
(item) => item === this.data.floorName
);
if (index > -1) {
const scrollTop = Math.max(0, (index - 2) * 36);
this.setData({ scrollTop });
}
}
},
},
lifetimes: {
attached() {
this.setData({ reversedFloors: [...this.data.floors].reverse() });
this.createSelectorQuery()
.select("#floors")
.node((res) => {
this.scollContext = res.node;
this.scrollToCurrent();
})
.exec();
},
}, },
}); });
...@@ -51,8 +51,8 @@ ...@@ -51,8 +51,8 @@
display: flex; display: flex;
align-items: center; align-items: center;
.left { .left {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
height: 24px; height: 24px;
border-radius: 4px; border-radius: 4px;
background: linear-gradient(90deg, #fa643c 0%, #e92927 100%); background: linear-gradient(90deg, #fa643c 0%, #e92927 100%);
...@@ -115,11 +115,9 @@ ...@@ -115,11 +115,9 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
top: -152px; top: -152px;
&.has-reset { left: 10px;
top: -202px; padding: 7px 0;
} width: 40px;
right: 10px;
padding: 7px 4px;
z-index: 2; z-index: 2;
gap: 2px; gap: 2px;
align-items: center; align-items: center;
...@@ -131,26 +129,34 @@ ...@@ -131,26 +129,34 @@
width: 8px; width: 8px;
height: 3px; height: 3px;
} }
.list { .scroller {
display: flex; width: 40px;
flex-direction: column; height: 104px;
gap: 4px; .list {
.floor { width: 40px;
display: flex; display: inline-flex;
width: 32px; flex-direction: column;
height: 32px;
align-items: center; align-items: center;
justify-content: center; gap: 4px;
color: #323337; padding: 0 4px;
text-align: center; box-sizing: border-box;
font-family: DINPro; .floor {
font-size: 14px; display: flex;
font-style: normal; width: 32px;
font-weight: 500; height: 32px;
border-radius: 8px; align-items: center;
&.active { justify-content: center;
background: #fff3f3; color: #323337;
color: #e92927; text-align: center;
font-family: DINPro;
font-size: 14px;
font-style: normal;
font-weight: 500;
border-radius: 8px;
&.active {
background: #fff3f3;
color: #e92927;
}
} }
} }
} }
...@@ -158,10 +164,7 @@ ...@@ -158,10 +164,7 @@
.floors-mask { .floors-mask {
position: absolute; position: absolute;
top: -152px; top: -152px;
&.has-reset { left: 10px;
top: -202px;
}
right: 10px;
width: 40px; width: 40px;
height: 128px; height: 128px;
z-index: 1; z-index: 1;
......
<textarea disabled class="reset-mask" wx:if="{{showReset}}"></textarea> <textarea disabled class="reset-mask" wx:if="{{showReset}}"></textarea>
<view class="reset-wrapper"> <view class="reset-wrapper">
<view class="reset" bind:tap="handleReset" wx:if="{{showReset}}"> <view class="reset" bind:tap="handleReset" wx:if="{{showReset}}">
<image wx:if="{{refreshing}}" class="size-24 refresh" src="./refresh.png" mode="" /> <image wx:if="{{refreshing}}" class="size-24 refresh" src="./refresh.png" mode="" />
<image wx:else class="size-24" src="./reset.png" mode="" /> <image wx:else class="size-24" src="./reset.png" mode="" />
</view> </view>
<view class="tip1" wx:if="{{refreshing}}">{{isEn?'Locating...':'定位中…'}}</view> <view class="tip1" wx:if="{{refreshing}}">{{isEn?'Locating...':'定位中…'}}</view>
<view class="tip2" wx:elif="{{showSuccess}}">{{isEn?'Successfully located':'定位成功'}}</view> <view class="tip2" wx:elif="{{showSuccess}}">{{isEn?'Successfully located':'定位成功'}}</view>
<view class="tip3" wx:elif="{{neverAuthed}}"> <view class="tip3" wx:elif="{{neverAuthed}}">
<view class="left">{{isEn?'Tap to locate':'点击获取定位'}}</view> <view class="left">{{isEn?'Tap to locate':'点击获取定位'}}</view>
<image src="./tri.png" class="right" mode="" /> <image src="./tri.png" class="right" mode="" />
</view> </view>
</view> </view>
<textarea disabled class="floors-mask {{showReset?'has-reset':''}}"></textarea> <textarea disabled class="floors-mask {{showReset?'has-reset':''}}"></textarea>
<view class="floors {{showReset?'has-reset':''}}"> <view class="floors {{showReset?'has-reset':''}}">
<image class="arrow" src="./floorUp.png" mode="" /> <image class="arrow" src="./floorUp.png" mode="" />
<scroll-view id="floors" scroll-y scroll-top="{{scrollTop}}" class="scroller" enhanced>
<view class="list"> <view class="list">
<view wx:for="{{floors}}" class="floor {{floorName===item.floorName?'active':''}}" id="{{item.floorName}}" wx:key="floorName" bind:tap="handleFloor">{{item.displayName}}</view> <view wx:for="{{reversedFloors}}" class="floor {{floorName===item?'active':''}}" id="{{item}}" wx:key="*this" bind:tap="handleFloor">{{item}}</view>
</view> </view>
</scroll-view>
<image class="arrow" src="./floorDown.png" mode="" /> <image class="arrow" src="./floorDown.png" mode="" />
</view> </view>
\ No newline at end of file
import langBehavior from "../../behaviors/langBehavior"; import langBehavior from "../../behaviors/langBehavior";
import buildingBehavior from "../../behaviors/buildingBehavior";
const langs = [ const langs = [
"简体中文", "简体中文",
"English", "English",
"العربية", // "العربية",
// "日本語", // "日本語",
"한국어", // "한국어",
"Deutsch", // "Deutsch",
"Français", // "Français",
"Português", // "Português",
"Español", // "Español",
"Italiano", // "Italiano",
"Bahasa Melayu", // "Bahasa Melayu",
"русский", // "русский",
"Bahasa Indonesia", // "Bahasa Indonesia",
"ภาษาไทย", // "ภาษาไทย",
"Türkçe", // "Türkçe",
"繁體中文 香港/澳門", // "繁體中文 香港/澳門",
"繁體中文 中國臺灣", // "繁體中文 中國臺灣",
"Tiếng Việt", // "Tiếng Việt",
]; ];
Component({ Component({
behaviors: [langBehavior], behaviors: [langBehavior, buildingBehavior],
properties: { properties: {
type: String, type: String,
}, },
...@@ -32,6 +33,8 @@ Component({ ...@@ -32,6 +33,8 @@ Component({
showOptions: false, showOptions: false,
langs, langs,
showTip: false, showTip: false,
buildings: getApp().buildings,
showBuildings: false,
}, },
/** /**
...@@ -44,6 +47,12 @@ Component({ ...@@ -44,6 +47,12 @@ Component({
closeOptions() { closeOptions() {
this.setData({ showOptions: false }); this.setData({ showOptions: false });
}, },
openBuildings() {
this.setData({ showBuildings: true });
},
closeBuildings() {
this.setData({ showBuildings: false });
},
chooseLang({ currentTarget: { id: lang } }) { chooseLang({ currentTarget: { id: lang } }) {
if ( if (
(lang === "简体中文" && this.data.isEn) || (lang === "简体中文" && this.data.isEn) ||
...@@ -60,5 +69,17 @@ Component({ ...@@ -60,5 +69,17 @@ Component({
this.setData({ showTip: false }); this.setData({ showTip: false });
}, },
donothing() {}, donothing() {},
changeBuilding({ currentTarget: { id } }) {
const building = this.data.buildings[id];
getApp().setBuilding(building);
getApp().blurPoi();
this.setData({ showBuildings: false });
},
handleFeedback() {
if (!getApp().checkUser()) return;
wx.navigateTo({
url: `/pages/feedback/index`,
});
},
}, },
}); });
.logo {
width: 24px;
height: 24px;
}
.langBtn { .langBtn {
position: absolute; position: absolute;
z-index: 2; z-index: 2;
...@@ -6,13 +10,16 @@ ...@@ -6,13 +10,16 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 40px; width: 40px;
height: 64px; height: 50px;
gap: 2px; gap: 2px;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
border-radius: 8px; border-radius: 8px;
background: #fff; background: #fff;
box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.05); box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.05);
&.index {
height: 150px;
}
&.white { &.white {
background: none; background: none;
box-shadow: none; box-shadow: none;
...@@ -25,13 +32,9 @@ ...@@ -25,13 +32,9 @@
color: #f3f3f3; color: #f3f3f3;
} }
} }
.logo {
width: 24px;
height: 24px;
}
.texts { .texts {
display: flex; display: flex;
height: 24px;
flex-direction: column; flex-direction: column;
color: #333; color: #333;
text-align: center; text-align: center;
...@@ -42,6 +45,49 @@ ...@@ -42,6 +45,49 @@
line-height: 12px; /* 120% */ line-height: 12px; /* 120% */
} }
} }
.marketLang {
position: absolute;
z-index: 2;
top: 10px;
right: 10px;
display: flex;
flex-direction: column;
width: 40px;
height: 102px;
gap: 10px;
justify-content: center;
align-items: center;
border-radius: 8px;
background: #fff;
box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.05);
&.index {
height: 150px;
}
.btn {
display: flex;
flex-direction: column;
align-items: center;
gap: 2px;
color: #333;
text-align: center;
font-family: "PingFang SC";
font-size: 10px;
font-style: normal;
font-weight: 400;
line-height: 12px;
}
}
.lang-bg {
position: absolute;
z-index: 1;
top: 10px;
right: 10px;
width: 40px;
height: 64px;
&.index {
height: 102px;
}
}
.options-bg { .options-bg {
position: absolute; position: absolute;
z-index: 3000; z-index: 3000;
...@@ -52,6 +98,9 @@ ...@@ -52,6 +98,9 @@
border-radius: 0 0 8px 8px; border-radius: 0 0 8px 8px;
border-top: #f3f3f3; border-top: #f3f3f3;
background: #fff; background: #fff;
&.tmp {
height: 108px;
}
} }
.options { .options {
position: absolute; position: absolute;
...@@ -60,6 +109,9 @@ ...@@ -60,6 +109,9 @@
right: 0; right: 0;
width: 100vw; width: 100vw;
height: 196px; height: 196px;
&.tmp {
height: 108px;
}
.close { .close {
position: absolute; position: absolute;
top: 16px; top: 16px;
...@@ -79,12 +131,49 @@ ...@@ -79,12 +131,49 @@
font-weight: 600; font-weight: 600;
line-height: 18px; line-height: 18px;
} }
.row {
position: absolute;
top: 56px;
left: 0;
display: flex;
height: 40px;
width: 100vw;
padding: 0 12px;
gap: 4px;
.item {
position: relative;
display: flex;
align-items: center;
padding-left: 10px;
flex: 1;
height: 40px;
border-radius: 4px;
border-bottom: 0.5px solid rgba(255, 255, 255, 0.1);
background: #f7f7f7;
color: #333;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 18px;
.tick {
position: absolute;
width: 12px;
height: 12px;
top: 0;
bottom: 0;
right: 18px;
margin: auto;
}
}
}
.langs { .langs {
position: absolute; position: absolute;
top: 56px; top: 56px;
left: 0; left: 0;
width: 100vw; width: 100vw;
height: 128px; height: 128px;
.grid { .grid {
width: 1064px; width: 1064px;
height: 128px; height: 128px;
...@@ -165,3 +254,52 @@ ...@@ -165,3 +254,52 @@
height: 38px; height: 38px;
} }
} }
.buildings-bg {
position: absolute;
z-index: 3000;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
}
.buildings {
position: absolute;
z-index: 3001;
top: 10px;
right: 55px;
display: inline-flex;
padding: 2px;
flex-direction: column;
align-items: flex-start;
border-radius: 8px;
background: #4a4a4a;
.tri {
position: absolute;
top: 14px;
right: -3px;
width: 3px;
height: 10px;
}
.building {
display: flex;
padding-left: 10px;
padding-right: 10px;
align-items: center;
min-width: 140px;
height: 40px;
gap: 6px;
color: #fff;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 600;
line-height: 16px;
}
.building + .building {
border-top: 1px solid rgba(255, 255, 255, 0.06);
}
}
.size-12 {
width: 12px;
height: 12px;
}
<view class="langBtn {{type}}" catch:tap="handleLang"> <view wx:if="{{type==='index'}}" class="marketLang {{type}}">
<view class="btn" catch:tap="openBuildings">
<image class="logo" src="./market.png" mode="" />
<view>{{isEn?'Market':'市场'}}</view>
</view>
<view class="btn" catch:tap="handleLang">
<image class="logo" src="./switch.png" mode="" />
<view>{{isEn?'Lang':'语言'}}</view>
</view>
<view class="btn" catch:tap="handleFeedback">
<image class="logo" src="./feedback.png" mode="" />
<view>{{isEn?'Report':'反馈'}}</view>
</view>
</view>
<view wx:else class="langBtn {{type}}" catch:tap="handleLang">
<block wx:if="{{type==='white'}}"> <block wx:if="{{type==='white'}}">
<image class="logo" src="./switchWhite.png" mode="" /> <image class="logo" src="./switchWhite.png" mode="" />
</block> </block>
...@@ -9,16 +23,21 @@ ...@@ -9,16 +23,21 @@
<image class="logo" src="./switch.png" mode="" /> <image class="logo" src="./switch.png" mode="" />
</block> </block>
<view class="texts" wx:if="{{type!== 'white'}}"> <view class="texts" wx:if="{{type!== 'white'}}">
<view>{{isEn?'Change':'更换'}}</view>
<view>{{isEn?'Lang':'语言'}}</view> <view>{{isEn?'Lang':'语言'}}</view>
</view> </view>
</view> </view>
<textarea disabled class="options-bg" wx:if="{{showOptions}}"></textarea> <textarea disabled class="lang-bg {{type}}"></textarea>
<view wx:if="{{showOptions}}" class="options"> <textarea disabled class="options-bg {{langs.length===2?'tmp':''}}" wx:if="{{showOptions}}"></textarea>
<view wx:if="{{showOptions}}" class="options {{langs.length===2?'tmp':''}}">
<view class="t1">{{isEn?'Change language':'更换语言'}}</view> <view class="t1">{{isEn?'Change language':'更换语言'}}</view>
<image src="./close.png" class="close" mode="" bind:tap="closeOptions" /> <image src="./close.png" class="close" mode="" bind:tap="closeOptions" />
<scroll-view scroll-x enhanced show-scrollbar="{{false}}" class="langs"> <view wx:if="{{langs.length===2}}" class="row">
<view class="item" wx:for="{{langs}}" wx:key="*this" bind:tap="chooseLang" id="{{item}}">{{item}}
<image wx:if="{{item==='简体中文'&&!isEn||item==='English'&&isEn}}" src="./tick.png" class="tick" mode="" />
</view>
</view>
<scroll-view wx:else scroll-x enhanced show-scrollbar="{{false}}" class="langs">
<view class="grid"> <view class="grid">
<view class="item" wx:for="{{langs}}" wx:key="*this" bind:tap="chooseLang" id="{{item}}">{{item}} <view class="item" wx:for="{{langs}}" wx:key="*this" bind:tap="chooseLang" id="{{item}}">{{item}}
<image wx:if="{{item==='简体中文'&&!isEn||item==='English'&&isEn}}" src="./tick.png" class="tick" mode="" /> <image wx:if="{{item==='简体中文'&&!isEn||item==='English'&&isEn}}" src="./tick.png" class="tick" mode="" />
...@@ -31,4 +50,13 @@ ...@@ -31,4 +50,13 @@
<image src="./arrow.png" class="arrow" mode="" /> <image src="./arrow.png" class="arrow" mode="" />
<image catch:tap="donothing" class="image" src="https://cdnimg.chinagoods.com/png/2025/09/03/e3evgoktoetqebfymujhse0kmoxzjkt8.png" mode="" /> <image catch:tap="donothing" class="image" src="https://cdnimg.chinagoods.com/png/2025/09/03/e3evgoktoetqebfymujhse0kmoxzjkt8.png" mode="" />
<view class="btn" catch:tap="closeTip"></view> <view class="btn" catch:tap="closeTip"></view>
</view>
<textarea disabled class="buildings-bg" wx:if="{{showBuildings}}" bind:tap="closeBuildings"></textarea>
<view class="buildings" wx:if="{{showBuildings}}">
<image src="./tri.png" class="tri" mode="" />
<view wx:for="{{buildings}}" class="building" id="{{index}}" wx:key="name" catch:tap="changeBuilding">
<image wx:if="{{currentBuilding.name===item.name}}" class="size-12" src="./checked.png" mode="" />
<image wx:else class="size-12" src="./unchecked.png" mode="" />
{{isEn ? item.displayNameEn: item.displayName}}
</view>
</view> </view>
\ No newline at end of file
...@@ -6,8 +6,15 @@ Component({ ...@@ -6,8 +6,15 @@ Component({
/** /**
* 组件的初始数据 * 组件的初始数据
*/ */
data: { isIOS: getApp().isIOS }, data: { isIOS: getApp().isIOS, isSystem: true },
lifetimes: {
attached() {
const appAuthorizeSetting = wx.getAppAuthorizeSetting();
this.setData({
isSystem: appAuthorizeSetting.locationAuthorized === "authorized",
});
},
},
/** /**
* 组件的方法列表 * 组件的方法列表
*/ */
...@@ -15,6 +22,13 @@ Component({ ...@@ -15,6 +22,13 @@ Component({
close() { close() {
this.triggerEvent("close"); this.triggerEvent("close");
}, },
openAppAuthorizeSetting() {
wx.openAppAuthorizeSetting({
success(res) {
console.log(res);
},
});
},
doNothing() {}, doNothing() {},
}, },
}); });
...@@ -16,20 +16,47 @@ ...@@ -16,20 +16,47 @@
height: 100vh; height: 100vh;
.image { .image {
position: absolute; position: absolute;
top: 32px; top: 120px;
left: 0; left: 0;
right: 0; right: 0;
margin: auto; margin: auto;
width: 304px; width: 302px;
height: 572px; height: 396px;
z-index: 1;
}
.close {
position: absolute;
top: 130px;
right: calc(50vw - 151px + 10px);
width: 32px;
height: 32px;
z-index: 2;
} }
.btn { .btn {
position: absolute; position: absolute;
top: 542px; top: 452px;
left: 0; left: 0;
right: 0; right: 0;
margin: auto; margin: auto;
width: 260px; width: 260px;
height: 38px; height: 38px;
z-index: 2;
}
.btn1 {
position: absolute;
top: 452px;
left: calc(50vw - 126px - 4px);
width: 126px;
height: 38px;
z-index: 2;
}
.btn2 {
position: absolute;
top: 452px;
right: calc(50vw - 126px - 4px);
margin: auto;
width: 126px;
height: 38px;
z-index: 2;
} }
} }
<textarea disabled class="bluetooth-bg"></textarea> <textarea disabled class="bluetooth-bg"></textarea>
<view class="bluetooth-modal" bind:tap="close"> <view class="bluetooth-modal" bind:tap="close">
<image wx:if="{{isIOS}}" class="image" catch:tap="donothing" src="https://cdnimg.chinagoods.com/png/2025/09/01/l5z7pr16cdmgrjxqzwtkps1fl5m4yaiy.png" mode="" /> <block wx:if="{{isSystem}}">
<image wx:else catch:tap="donothing" class="image" src="https://cdnimg.chinagoods.com/png/2025/09/01/6rkar7dc5ot10homibl4ohrnrun8vwtq.png" catch:tap="doNothing" mode="" /> <image wx:if="{{isIOS}}" class="image" catch:tap="doNothing" src="https://cdnimg.chinagoods.com/png/2025/10/30/d9bcjoms6szz980q0ngpmaddd59v0jwh.png" mode="" />
<view class="btn" catch:tap="close"></view> <image wx:else catch:tap="doNothing" class="image" src="https://cdnimg.chinagoods.com/png/2025/10/30/srefp3tal0ys1ztdqnkdao8lhrg0pvul.png" catch:tap="doNothing" mode="" />
<view class="btn" catch:tap="close"></view>
</block>
<block wx:else>
<image wx:if="{{isIOS}}" class="image" catch:tap="doNothing" src="https://cdnimg.chinagoods.com/png/2025/10/30/o8oxwdtxr651n3ocmvanea8arvzsz95y.png" mode="" />
<image wx:else catch:tap="doNothing" class="image" src="https://cdnimg.chinagoods.com/png/2025/10/30/gk0taraemutjyhsrbfpzrupz3aqvttj2.png" catch:tap="doNothing" mode="" />
<view class="btn1" catch:tap="close"></view>
<view class="btn2" catch:tap="openAppAuthorizeSetting"></view>
</block>
<view class="close" catch:tap="close"></view>
</view> </view>
\ No newline at end of file
<map class="map" id="indexMap" show-compass show-location="{{userLocation&&!(userLocation&&userLocation.floorName&&userLocation.floorName!==floorName)}}" enable-rotate enable-3D enable-overlooking enable-auto-max-overlooking enable-indoor subkey="QUIBZ-OTL6U-T2MVM-GMPIT-EON66-LGBCU" latitude="{{latitude}}" longitude="{{longitude}}" markers="{{markers}}" max-scale="22" setting="{{setting}}" bind:tap="{{type === 'index' ? 'handleTap' : ''}}" bind:poitap="{{type === 'index' ? 'handleTap' : ''}}" bind:markertap="{{type === 'surroundings' ? 'handleMarkerTap' : ''}}" bind:callouttap="{{type === 'index' ? 'handleCalloutTap' : ''}}" bind:indoorchange="handleIndoorChange"></map> <map wx:if="{{latitude&&longitude}}" class="map" id="indexMap" show-compass show-location="{{userLocation&&!(userLocation&&userLocation.floorName&&userLocation.floorName!==floorName)}}" enable-rotate enable-3D enable-overlooking enable-auto-max-overlooking enable-indoor subkey="QUIBZ-OTL6U-T2MVM-GMPIT-EON66-LGBCU" latitude="{{latitude}}" longitude="{{longitude}}" max-scale="22" setting="{{setting}}" bind:tap="{{type === 'index' ? 'handleTap' : ''}}" bind:poitap="{{type === 'index' ? 'handleTap' : ''}}" bind:markertap="{{type === 'surroundings' ? 'handleMarkerTap' : ''}}" bind:callouttap="{{type === 'index' ? 'handleCalloutTap' : ''}}" bind:indoorchange="handleIndoorChange"></map>
\ No newline at end of file \ No newline at end of file
...@@ -36,13 +36,14 @@ Component({ ...@@ -36,13 +36,14 @@ Component({
async handleGo() { async handleGo() {
const { isEn, focusedPoi: poi, isIndex } = this.data; const { isEn, focusedPoi: poi, isIndex } = this.data;
try { try {
const { buildingIdNameMap } = getApp();
getApp().sensors?.track("NavEntryBtnClick", { getApp().sensors?.track("NavEntryBtnClick", {
page_name: isIndex ? "导航弹出框" : "周边弹出框", page_name: isIndex ? "导航弹出框" : "周边弹出框",
short_market_name: "二区东",
...(poi.tx ...(poi.tx
? { ? {
x: Number(poi.tx.poi_location.longitude), x: Number(poi.tx.poi_location.longitude),
y: Number(poi.tx.poi_location.latitude), y: Number(poi.tx.poi_location.latitude),
short_market_name: buildingIdNameMap[poi.tx.bld_id],
} }
: {}), : {}),
...(poi.facilityId ...(poi.facilityId
......
<view class="popup" wx:if="{{focusedPoi}}"> <view class="popup" wx:if="{{focusedPoi}}">
<slot></slot> <slot></slot>
<view class="shop" wx:if="{{focusedPoi.facility&&focusedPoi.facility.name==='yandoocafe'}}"> <view class="shop" wx:if="{{focusedPoi.facility&&focusedPoi.facility.type===2}}">
<image wx:if="{{focusedPoi.facility.logo}}" src="{{focusedPoi.facility.logo}}" class="avatar" mode="" /> <image wx:if="{{focusedPoi.facility.logo}}" src="{{focusedPoi.facility.logo}}" class="avatar" mode="" />
<view class="right"> <view class="right">
<view class="c-gap-6"> <view class="c-gap-6">
......
import md5 from "./md5";
const app = "indoor";
const secret = "ysGsjd08sUxPsxz2";
/**
* 使用md5加密方式发起请求
* @param {*} url
* @param {*} queryData path为加密参数,必传
* @param {*} options
*/
function MD5Request(url, queryData = {}, options = {}) {
// 是否loading
if (options && options.loading) {
wx.showLoading({
title: "加载中",
mask: true,
});
}
const secretParams = getCommonReqParams(queryData);
url = url + queryData.path || "";
delete queryData.path;
const method = (options && options.method) || "GET";
return new Promise((resolve, reject) => {
wx.request({
url,
data: queryData,
method,
header: {
"Content-Type": "application/json; charset=UTF-8",
...secretParams,
},
success(res) {
resolve(res.data);
},
fail(e) {
console.log(e);
reject(e);
},
complete() {
if (options && options.delay) {
setTimeout(() => {
wx.hideLoading();
}, options.delay);
} else {
wx.hideLoading();
}
},
...options,
});
});
}
// 加密参数
function getCommonReqParams(params) {
const ts = Date.parse(new Date()) / 1000;
const path = params.path;
const sign = md5(path + secret + ts);
return {
app,
ts,
sign,
};
}
export default MD5Request;
...@@ -67,9 +67,9 @@ Page({ ...@@ -67,9 +67,9 @@ Page({
} }
}, },
async takePhoto() { async takePhoto() {
const { state, states } = this.data;
try { try {
wx.showLoading(); wx.showLoading();
const { state, states } = this.data;
if (state !== states.init) return; if (state !== states.init) return;
this.setData({ state: states.takingPhoto, isAlbum: false }); this.setData({ state: states.takingPhoto, isAlbum: false });
const ctx = wx.createCameraContext(); const ctx = wx.createCameraContext();
...@@ -235,10 +235,6 @@ Page({ ...@@ -235,10 +235,6 @@ Page({
}); });
const shopId = params.shopId; const shopId = params.shopId;
if (shopId) { if (shopId) {
const { shopIdMap } = getApp();
if (!shopIdMap) return;
const shop = shopIdMap[shopId];
if (!shop) return;
wx.navigateTo({ wx.navigateTo({
url: `/pages/poi-map/index?shopId=${shopId}`, url: `/pages/poi-map/index?shopId=${shopId}`,
}); });
......

1.0 KB | W: | H:

637 Bytes | W: | H:

pages/aisearchresult/add.png
pages/aisearchresult/add.png
pages/aisearchresult/add.png
pages/aisearchresult/add.png
  • 2-up
  • Swipe
  • Onion skin

951 Bytes | W: | H:

774 Bytes | W: | H:

pages/aisearchresult/added.png
pages/aisearchresult/added.png
pages/aisearchresult/added.png
pages/aisearchresult/added.png
  • 2-up
  • Swipe
  • Onion skin
import langBehavior from "../../behaviors/langBehavior"; import langBehavior from "../../behaviors/langBehavior";
import modalBehavior from "../../behaviors/modalBehavior"; import modalBehavior from "../../behaviors/modalBehavior";
import { toRoutePlan, getDistance } from "../../util"; import { toRoutePlan, getDistance, nearDistrict2East } from "../../util";
import mockData from "./mock.js";
const sortByStates = {
nosort: "nosort",
distanceDesc: "distanceDesc",
distanceAsc: "distanceAsc",
priceDesc: "priceDesc",
priceAsc: "priceAsc",
};
Page({ Page({
behaviors: [langBehavior, modalBehavior], behaviors: [langBehavior, modalBehavior],
data: { data: {
photoUrl: "", photoUrl: "",
rectVoList: [], rectVoList: [],
originalList: [],
voList: [], voList: [],
currentIndex: 0, currentIndex: 0,
itineraryMap: {}, itineraryMap: {},
userLocation: null, userLocation: null,
sortByStates,
sortBy: sortByStates.nosort,
}, },
/** /**
...@@ -17,12 +29,16 @@ Page({ ...@@ -17,12 +29,16 @@ Page({
*/ */
async onLoad({ photoUrl }) { async onLoad({ photoUrl }) {
this.setUserLocation = () => { this.setUserLocation = () => {
this.setData({ userLocation: getApp().userLocation }); const { userLocation } = getApp();
if (
userLocation &&
(userLocation.buildingId || nearDistrict2East(userLocation))
)
this.setData({ userLocation });
}; };
getApp().events.on("userLocation", this.setUserLocation); getApp().events.on("userLocation", this.setUserLocation);
this.setUserLocation(); this.setUserLocation();
photoUrl = decodeURIComponent(photoUrl); photoUrl = decodeURIComponent(photoUrl);
await this.init(photoUrl); await this.init(photoUrl);
if (!this.data.rectVoList.length) { if (!this.data.rectVoList.length) {
...@@ -50,67 +66,137 @@ Page({ ...@@ -50,67 +66,137 @@ Page({
app.events.off("itineraryRefresh", this.setItineraryMap); app.events.off("itineraryRefresh", this.setItineraryMap);
} }
}, },
handleDistanceSort() {
if (
this.data.sortBy !== sortByStates.distanceDesc &&
this.data.sortBy !== sortByStates.distanceAsc
) {
this.setData({ sortBy: sortByStates.distanceAsc });
} else if (this.data.sortBy === sortByStates.distanceAsc) {
this.setData({ sortBy: sortByStates.distanceDesc });
} else {
this.setData({ sortBy: sortByStates.nosort });
}
this.setSortedList();
},
handlePriceSort() {
if (
this.data.sortBy !== sortByStates.priceDesc &&
this.data.sortBy !== sortByStates.priceAsc
) {
this.setData({ sortBy: sortByStates.priceAsc });
} else if (this.data.sortBy === sortByStates.priceAsc) {
this.setData({ sortBy: sortByStates.priceDesc });
} else {
this.setData({ sortBy: sortByStates.nosort });
}
this.setSortedList();
},
handleNoSort() {
this.setData({ sortBy: sortByStates.nosort });
this.setSortedList();
},
setSortedList() {
if (!this.data.originalList || !Array.isArray(this.data.originalList))
return;
let list = [...this.data.originalList];
if (this.data.sortBy === sortByStates.nosort)
return this.setData({ voList: list });
list.sort((a, b) => {
switch (this.data.sortBy) {
case sortByStates.distanceAsc:
case sortByStates.distanceDesc:
// 无论升序还是降序,distance为null的元素都排在最后
if (a.distance === null && b.distance === null) return 0;
if (a.distance === null) return 1;
if (b.distance === null) return -1;
// 正常的距离比较
return this.data.sortBy === sortByStates.distanceAsc
? a.distance - b.distance
: b.distance - a.distance;
case sortByStates.priceAsc:
return a.price - b.price;
case sortByStates.priceDesc:
return b.price - a.price;
default:
return 0;
}
});
this.setData({ voList: list });
},
async init(photoUrl) { async init(photoUrl) {
try { try {
wx.showLoading(); wx.showLoading();
console.log(photoUrl); console.log(photoUrl);
const { photoApi } = getApp(); const { photoApi } = getApp();
const { rectVoList = [], voList } = await photoApi.search(photoUrl); const { rectVoList = [], voList } = await photoApi.search(photoUrl);
const originalList = await this.processVoList(voList);
this.setData({ this.setData({
photoUrl, photoUrl,
rectVoList: [{ cutImageURL: photoUrl }, ...rectVoList], rectVoList: [{ cutImageURL: photoUrl }, ...rectVoList],
voList: this.processVoList(voList), originalList,
}); });
this.setSortedList();
} catch (error) { } catch (error) {
console.error(error); console.error(error);
const originalList = await this.processVoList(mockData.voList);
this.setData({
photoUrl,
rectVoList: [{ cutImageURL: photoUrl }],
originalList,
});
this.setSortedList();
} finally { } finally {
wx.hideLoading(); wx.hideLoading();
} }
}, },
processVoList(voList) { async processVoList(voList) {
const { shopIdMap } = getApp(); if (!Array.isArray(voList)) return [];
const result = voList
.map((good) => ({ // 1. 批量填充
...good, const list = await getApp().poiApi.populate(voList, {
shop: shopIdMap && shopIdMap[good.shopId], getType: () => "1",
})) getId: (item) => item.shopId,
.filter(({ shop }) => shop); targetField: "shop",
result.forEach((good) => {
try {
good.yuan = Math.floor(good.price);
good.fen =
"." + String(Math.round(good.price * 100) % 100).padStart(2, "0");
} catch (error) {
good.yuan = good.price;
console.error(error);
}
const poi = good.shop;
if (!poi.tx) good.distance = null;
if (!this.data.userLocation) good.distance = null;
try {
const lat = Number(poi.tx.poi_location.latitude);
const lng = Number(poi.tx.poi_location.longitude);
good.distance = Math.ceil(
getDistance(
lat,
lng,
this.data.userLocation.latitude,
this.data.userLocation.longitude
)
);
} catch (error) {
good.distance = null;
}
try {
const floorDiff = Math.abs(
Number(poi.tx.poi_fl_name[0]) -
Number(this.data.userLocation.floorName[0])
);
if (floorDiff && good.distance) good.distance += floorDiff;
} catch (error) {}
if (good.distance > 3000) good.distance = null;
}); });
return result;
const { userLocation } = this.data;
// 2. 过滤 + 格式化 (价格 & 距离)
return list
.filter((item) => item?.shop)
.map((item) => {
// 价格格式化
const price = Number(item.price) || 0;
item.yuan = Math.floor(price);
item.fen = `.${String(Math.round(price * 100) % 100).padStart(2, "0")}`;
// 距离计算
const tx = item.shop.tx;
if (tx && userLocation) {
try {
const dist = getDistance(
Number(tx.poi_location.latitude),
Number(tx.poi_location.longitude),
userLocation.latitude,
userLocation.longitude,
);
// 楼层不同增加 60m 距离
const floorDiff = Math.abs(
parseInt(tx.poi_fl_name) - parseInt(userLocation.floorName),
);
item.distance = Math.ceil(dist) + (floorDiff > 0 ? 60 : 0);
} catch (e) {
console.error(e);
}
}
return item;
});
}, },
async handleRectImg(e) { async handleRectImg(e) {
const { const {
...@@ -127,10 +213,12 @@ Page({ ...@@ -127,10 +213,12 @@ Page({
const res = await photoApi.search(this.data.photoUrl, rectVo.rect); const res = await photoApi.search(this.data.photoUrl, rectVo.rect);
if (res.voList) { if (res.voList) {
const originalList = await this.processVoList(res.voList);
this.setData({ this.setData({
voList: this.processVoList(res.voList), originalList,
currentIndex: Number(index), currentIndex: Number(index),
}); });
this.setSortedList();
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
...@@ -159,7 +247,13 @@ Page({ ...@@ -159,7 +247,13 @@ Page({
app.refreshItinerary(); app.refreshItinerary();
} }
wx.showToast({ wx.showToast({
title: success ? (isEn ? "success" : "成功") : isEn ? "fail" : "失败", title: success
? isEn
? "success"
: "取消收藏"
: isEn
? "fail"
: "失败",
icon: "none", icon: "none",
}); });
} else { } else {
...@@ -173,7 +267,7 @@ Page({ ...@@ -173,7 +267,7 @@ Page({
app.refreshItinerary(); app.refreshItinerary();
} }
wx.showToast({ wx.showToast({
title: id ? (isEn ? "success" : "成功") : isEn ? "fail" : "失败", title: id ? (isEn ? "success" : "收藏成功") : isEn ? "fail" : "失败",
icon: "none", icon: "none",
}); });
} }
...@@ -185,13 +279,14 @@ Page({ ...@@ -185,13 +279,14 @@ Page({
const { isEn, voList } = this.data; const { isEn, voList } = this.data;
const { shop: poi } = voList[index]; const { shop: poi } = voList[index];
try { try {
const { buildingIdNameMap } = getApp();
getApp().sensors?.track("NavEntryBtnClick", { getApp().sensors?.track("NavEntryBtnClick", {
page_name: "AI识物结果", page_name: "AI识物结果",
short_market_name: "二区东",
...(poi.tx ...(poi.tx
? { ? {
x: Number(poi.tx.poi_location.longitude), x: Number(poi.tx.poi_location.longitude),
y: Number(poi.tx.poi_location.latitude), y: Number(poi.tx.poi_location.latitude),
short_market_name: buildingIdNameMap[poi.tx.bld_id],
} }
: {}), : {}),
...(poi.facilityId ...(poi.facilityId
......
...@@ -83,10 +83,35 @@ ...@@ -83,10 +83,35 @@
bottom: 0; bottom: 0;
border-radius: 16px 16px 0; border-radius: 16px 16px 0;
background: #f7f7f7; background: #f7f7f7;
padding: 8px 10px 0 10px; padding: 4px 10px 0 10px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 10px; gap: 4px;
.tabs {
display: flex;
padding: 0 21px;
align-items: center;
justify-content: space-between;
&.dual {
padding: 0 77px;
}
.tab {
display: inline-flex;
align-items: center;
height: 38px;
color: #333;
text-align: center;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 400;
gap: 4px;
.icon {
width: 10px;
height: 16px;
}
}
}
.title { .title {
display: flex; display: flex;
align-items: baseline; align-items: baseline;
...@@ -109,7 +134,7 @@ ...@@ -109,7 +134,7 @@
.scroll-y { .scroll-y {
width: 100%; width: 100%;
flex: 1; flex: 1;
height: calc(100vh - 117px); height: calc(100vh - 145px);
.goods { .goods {
display: inline-flex; display: inline-flex;
flex-direction: column; flex-direction: column;
...@@ -149,6 +174,7 @@ ...@@ -149,6 +174,7 @@
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
line-height: 22px; line-height: 22px;
padding-right: 20px;
} }
.t2 { .t2 {
display: flex; display: flex;
...@@ -203,20 +229,25 @@ ...@@ -203,20 +229,25 @@
position: absolute; position: absolute;
bottom: 0; bottom: 0;
right: 0; right: 0;
top: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 24px; align-items: flex-end;
.row { justify-content: space-between;
.collect {
display: flex; display: flex;
gap: 6px; flex-direction: column;
gap: 2px;
align-items: center; align-items: center;
.t5 { .t5 {
color: #333; color: #333;
text-align: center;
font-family: "PingFang SC"; font-family: "PingFang SC";
font-size: 10px; font-size: 8px;
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 400;
line-height: 12px; line-height: 12px; /* 150% */
} }
.t51 { .t51 {
display: flex; display: flex;
...@@ -239,6 +270,25 @@ ...@@ -239,6 +270,25 @@
} }
} }
} }
.red-btn {
display: flex;
width: 64px;
height: 48px;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 8px;
background: linear-gradient(90deg, #fa643c 0%, #e92927 100%);
font-family: "PingFang SC";
font-size: 10px;
font-style: normal;
font-weight: 600;
line-height: 12px;
color: white;
.meta {
color: var(--W-80, rgba(255, 255, 255, 0.8));
}
}
} }
} }
} }
...@@ -308,4 +358,8 @@ ...@@ -308,4 +358,8 @@
width: 20px; width: 20px;
height: 20px; height: 20px;
} }
.size-16 {
width: 16px;
height: 16px;
}
} }
...@@ -13,6 +13,19 @@ ...@@ -13,6 +13,19 @@
<image class="tri" src="./tri.png" mode="" /> <image class="tri" src="./tri.png" mode="" />
</view> </view>
<view class="bottom"> <view class="bottom">
<view class="tabs {{!userLocation?'dual':''}}">
<view class="tab" bind:tap="handleNoSort">{{isEn?'Comprehensive':'综合'}}</view>
<view class="tab" wx:if="{{!!userLocation}}" bind:tap="handleDistanceSort">{{isEn?'Distance':'距离'}}
<image wx:if="{{sortBy===sortByStates.distanceDesc}}" class="icon" src="./desc.png" mode="" />
<image wx:elif="{{sortBy===sortByStates.distanceAsc}}" class="icon" src="./asc.png" mode="" />
<image wx:else class="icon" src="./sort.png" mode="" />
</view>
<view class="tab" bind:tap="handlePriceSort">{{isEn?'Price':'价格'}}
<image wx:if="{{sortBy===sortByStates.priceDesc}}" class="icon" src="./desc.png" mode="" />
<image wx:elif="{{sortBy===sortByStates.priceAsc}}" class="icon" src="./asc.png" mode="" />
<image wx:else class="icon" src="./sort.png" mode="" />
</view>
</view>
<view class="title" wx:if="{{isEn}}"> <view class="title" wx:if="{{isEn}}">
Find similar stores for you Find similar stores for you
<text class="red">{{voList.length}}</text> <text class="red">{{voList.length}}</text>
...@@ -44,21 +57,20 @@ ...@@ -44,21 +57,20 @@
</view> </view>
</view> </view>
<view class="right-corner"> <view class="right-corner">
<view class="row" catch:tap="handleItinerary" id="{{index}}"> <view class="collect" catch:tap="handleItinerary" id="{{index}}">
<image wx:if="{{itineraryMap[item.shopId]}}" class="size-20" src="./added.png" mode="" /> <image wx:if="{{itineraryMap[item.shopId]}}" class="size-20" src="./added.png" mode="" />
<image wx:else class="size-20" src="./add.png" mode="" /> <image wx:else class="size-20" src="./add.png" mode="" />
<view wx:if="{{itineraryMap[item.shopId]}}" class="t5 red"> <view class="t5" wx:if="{{itineraryMap[item.shopId]}}">
{{isEn?'Added itinerary':'已加行程'}} {{isEn?'Collected':'已收藏'}}
</view> </view>
<view wx:else class="t5">{{isEn?'Add itinerary':'加入行程'}}</view> <view class="t5" wx:else>
{{isEn?'Collect':'收藏'}}
</view>
</view> </view>
<view class="row" wx:if="{{item.shop&&item.shop.tx}}" id="{{index}}" bind:tap="handleGo"> <view class="red-btn" wx:if="{{item.shop&&item.shop.tx}}" id="{{index}}" bind:tap="handleGo">
<image class="size-20" src="./nav.png" mode="" /> <image class="size-16" src="./wnav.png" mode="" />
<view class="t5" wx:if="{{!item.distance}}">{{isEn?'Go Here':'到这去'}}</view> <view>{{isEn?'Go Here':'立即导航'}}</view>
<view wx:else class="t51"> <view class="meta" wx:if="{{item.distance}}">{{item.distance}}m</view>
<view class="t511">{{item.distance}}m</view>
<view class="t512">{{isEn?'Go Here':'到这去'}}</view>
</view>
</view> </view>
</view> </view>
</view> </view>
......
import langBehavior from "../../behaviors/langBehavior";
import { getPoiName } from "../../util";
Page({
behaviors: [langBehavior],
/**
* 页面的初始数据
*/
data: {
card: null,
collapsed: true,
isOverflow: false,
pois: [],
scrollTop: 0,
showToast: false,
},
/**
* 生命周期函数--监听页面加载
*/
onLoad({ cardId }) {
this.getCard(cardId);
},
back() {
wx.navigateBack();
},
async getCard(cardId) {
const app = getApp();
try {
const card = await app.cardApi.get(cardId);
if (!card) return wx.navigateBack();
this.setData({ card });
// 1. 自动填充 (默认配置即可匹配 shopType/shopId 字段,且会自动过滤无效项)
const list = await app.poiApi.populate(card.activityShopList || []);
// 2. 格式化并更新视图
this.setData({
pois: list.map((item) => ({
...item,
poiName: getPoiName(item.poi, this.data.isEn),
})),
});
wx.nextTick(() => this.checkTextOverflow());
} catch (error) {
console.error(error);
wx.navigateBack();
}
},
async toPoi({ currentTarget: { id } }) {
const poi = this.data.pois.find((el) => el.shopId === id);
if (poi.checkInStatus === 1) return;
if (this.data.card.isFinish) {
this.setData({ showToast: true });
await new Promise((resolve) => {
setTimeout(() => {
this.setData({ showToast: false });
resolve();
}, 1000);
});
}
if (poi.shopType === 1)
wx.navigateTo({
url: `/pages/poi-map/index?shopId=${poi.shopId}&isCardNav=true`,
});
else {
wx.navigateTo({
url: `/pages/poi-map/index?facilityId=${poi.shopId}&isCardNav=true`,
});
}
},
showDetail() {
wx.previewImage({
urls: [this.data.card?.pointMapImage],
});
},
handleScroll({ detail: { scrollTop } }) {
this.setData({ scrollTop });
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
const menuButtonInfo = wx.getMenuButtonBoundingClientRect();
const windowInfo = wx.getWindowInfo();
const rightPadding = windowInfo.screenWidth - menuButtonInfo.right;
const contentTop = menuButtonInfo.top;
this.setData({
menuButtonInfo,
rightPadding,
contentTop,
});
},
// 添加toggle点击事件
toggleCollapse() {
this.setData({
collapsed: !this.data.collapsed,
});
},
// 添加判断文本是否超过3行的逻辑
checkTextOverflow() {
// 先临时设置为展开状态,获取完整高度
this.setData({ collapsed: false }, () => {
const query = wx.createSelectorQuery();
query
.select(".text")
.boundingClientRect((rect) => {
const lineHeight = 23; // 与样式中定义的line-height一致
const maxLines = 3;
const maxHeight = lineHeight * maxLines;
const isOverflow = rect.height > maxHeight;
// 根据是否溢出设置初始状态
this.setData({
isOverflow,
collapsed: isOverflow, // 如果溢出,默认折叠;否则,默认展开
});
})
.exec();
});
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
getApp().blurPoi();
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {},
});
{
"usingComponents": {},
"navigationStyle": "custom"
}
.card {
position: relative;
width: 100vw;
height: 100vh;
.bg {
position: absolute;
width: 100vw;
height: 100vh;
z-index: 1;
}
.bgTop {
position: absolute;
width: 100vw;
z-index: 2;
}
.header {
position: absolute;
top: 0;
left: 0;
z-index: 5;
display: flex;
width: 100vw;
padding-bottom: 6px;
box-sizing: border-box;
align-items: center;
padding-left: 10px;
.back {
width: 22px;
height: 22px;
}
.placeholder {
width: 22px;
}
.title {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
color: #333;
font-family: "PingFang SC";
font-size: 17px;
font-style: normal;
font-weight: 500;
line-height: normal;
}
}
.toast {
position: absolute;
z-index: 6;
top: 99px;
left: 0;
right: 0;
margin: auto;
width: 312px;
padding: 16px 24px;
display: flex;
flex-direction: column;
gap: 8px;
border-radius: 8px;
background: rgba(0, 0, 0, 0.7);
align-items: center;
.t1 {
color: #fff;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 22px;
}
.t2 {
color: #fff;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 16px;
}
}
.scroller {
position: absolute;
box-sizing: border-box;
top: 0;
left: 0;
z-index: 4;
width: 100vw;
height: 100vh;
.scroll-content {
position: relative;
width: 100vw;
display: inline-flex;
flex-direction: column;
align-items: center;
gap: 16px;
padding: 0 12px;
.top {
width: 100%;
height: 216px;
}
.desc {
width: calc(100vw - 24px);
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
padding: 16px 14px;
border-radius: 16px;
border: 1px solid var(--W-100, #fff);
background: linear-gradient(
180deg,
#fff 0%,
rgba(255, 255, 255, 0.2) 100%
);
backdrop-filter: blur(4px);
.text {
width: 100%;
color: #333;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 23px;
/* 默认展示全部 */
overflow: visible;
text-overflow: unset;
display: block;
}
/* 折叠状态 */
.text:not(.expanded) {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
.toggle {
display: flex;
align-items: center;
gap: 4px;
color: #666;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
.arrow {
width: 14px;
height: 14px;
}
}
}
.pois {
position: relative;
width: calc(100vw - 24px);
border-radius: 16px;
padding: 12px;
overflow: hidden;
display: inline-flex;
flex-direction: column;
gap: 14px;
.title {
position: relative;
z-index: 2;
width: 100%;
color: #fff;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: normal;
vertical-align: baseline;
.meta {
display: inline;
margin-left: 8px;
color: rgba(255, 255, 255, 0.75);
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: normal;
}
}
.poisBg {
position: absolute;
z-index: 1;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
}
.grid {
width: 100%;
padding: 12px;
background: #ffecec;
border-radius: 16px;
position: relative;
z-index: 2;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px 9px;
.item {
position: relative;
width: calc((100vw - 36px - 9px - 36px) / 2);
display: flex;
flex: 1;
height: 40px;
align-items: center;
justify-content: center;
.item-bg {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 1;
width: 100%;
height: 100%;
}
.text {
position: relative;
z-index: 2;
padding: 0 5px;
color: #fff;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ticked {
position: absolute;
z-index: 4;
top: -4px;
right: 0;
width: 56px;
height: 24px;
.img {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.meta {
position: absolute;
z-index: 2;
top: 3px;
left: 12px;
right: 0px;
color: #fff;
font-family: "PingFang SC";
font-size: 10px;
font-style: normal;
font-weight: 400;
line-height: 14px;
text-align: center;
}
}
}
}
}
.poiMap {
padding: 0 12px 12px 12px;
display: flex;
flex-direction: column;
align-items: center;
width: calc(100vw - 24px);
border-radius: 16px;
margin-bottom: 10px;
background: linear-gradient(155deg, #fff 3.79%, #fff6f6 84.49%);
border: 1px solid #fff;
.title {
max-width: calc(100vw - 24px);
margin-top: -1px;
position: relative;
padding: 0 23px;
display: flex;
align-items: center;
justify-content: center;
height: 36px;
gap: 3px;
.titlebg {
position: absolute;
z-index: 1;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
}
.star {
position: relative;
width: 10px;
height: 10px;
z-index: 2;
flex-shrink: 0;
}
.text {
position: relative;
z-index: 2;
color: #222;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: normal;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.map {
margin-top: 12px;
width: calc(100vw - 48px);
border-radius: 16px;
}
}
}
}
}
<view class="card">
<image wx:if="{{card}}" class="bg" src="{{card.backgroundImage}}" mode="" />
<image wx:if="{{card}}" class="bgTop" src="{{card.topBackgroundImage}}" mode="widthFix" />
<view class="header" style="background: rgba(255,255,255,{{scrollTop>144?1:scrollTop/144}}); padding-top: {{contentTop}}px; height: {{menuButtonInfo.height+contentTop+6}}px; padding-right: {{rightPadding}}px;">
<image class="back" src="./back.png" mode="" bind:tap="back" />
<view class="title">{{isEn?'Check-in Rewards':'活动有奖'}}</view>
<view class="placeholder"></view>
</view>
<view class="toast" wx:if="{{showToast}}">
<view class="t1">{{isEn?'Check-in Complete!':'打卡圆满完成'}}</view>
<view class="t2">{{isEn?'Rewards sent to Coupon Center. View now on homepage.':'活动奖励已发放至您的卡券中心,请至首页查看!'}}</view>
</view>
<scroll-view class="scroller" bindscroll="handleScroll" scroll-y wx:if="{{card}}">
<view class="scroll-content">
<view class="top"></view>
<view class="desc">
<view class="text {{collapsed ? '' : 'expanded'}}">{{isEn?card.introEn:card.intro}}</view>
<view class="toggle" wx:if="{{isOverflow}}" bind:tap="toggleCollapse">
{{isEn?(collapsed?'Read More':'Read Less'):(collapsed?'展开全部':'收起')}}
<image class="arrow" src="./{{collapsed?'arrowDown':'arrowUp'}}.png" mode="" />
</view>
</view>
<view class="pois">
<image class="poisBg" src="https://cdnimg.chinagoods.com/png/2025/12/18/zsk9v9knwhz4cf9wvfz6dfjnv1ju7s4n.png" mode="" />
<view class="title">
{{isEn?card.pointTitleEn:card.pointTitle }}
<view class="meta" wx:if="{{isEn?card.tipEn:card.tip}}">{{isEn?card.tipEn:card.tip}}</view>
</view>
<view class="grid">
<view class="item" wx:for="{{pois}}" wx:key="poiName" id="{{item.shopId}}" bind:tap="toPoi">
<view class="ticked" wx:if="{{item.checkInStatus===1}}">
<image class="img" src="./ticked.png" mode="" />
<view class="meta">{{isEn?'Checked':'已打卡'}}</view>
</view>
<image wx:if="{{item.checkInStatus===0}}" class="item-bg" src="https://cdnimg.chinagoods.com/png/2025/12/18/zlvfpfl0rxrrebfjyvyairvz3poq2dbp.png" mode="" />
<image wx:else src="https://cdnimg.chinagoods.com/png/2025/12/18/tqgtxm4vnpwe1neblbtyg8gob2j4my2q.png" class="item-bg" mode="" />
<view class="text">{{item.poiName}}</view>
</view>
</view>
</view>
<view class="poiMap" wx:if="{{card.pointMapImage}}">
<view class="title" wx:if="{{card.pointExplain}}">
<image class="titlebg" src="./titlebg.png" mode="" />
<image class="star" src="./star.png" mode="" />
<view class="text">{{card.pointExplain}}</view>
<image class="star" src="./star.png" mode="" />
</view>
<image class="map" bind:tap="showDetail" src="{{card.pointMapImage}}" mode="widthFix" />
</view>
</view>
</scroll-view>
</view>
\ No newline at end of file
import { getDistance } from "../../util";
// Constants
const API_URL = "https://apis.map.qq.com/ws/place/v1/search";
const API_PARAMS = "get_rich=0";
const PAGE_SIZE = 10;
const SEARCH_RADIUS = 1000;
/**
* 构建API请求URL
*/
export function buildApiUrl(keyword, pageIndex, currentBuilding, mapKey) {
const params = [
API_PARAMS,
`key=${mapKey}`,
`keyword=${encodeURI(keyword)}`,
`boundary=nearby(${currentBuilding.latlng.lat},${currentBuilding.latlng.lng},${SEARCH_RADIUS})`,
`page_size=${PAGE_SIZE}`,
`page_index=${pageIndex}`,
].join("&");
return `${API_URL}?${params}`;
}
/**
* 处理店铺数据,计算距离和分类
*/
export function processShopData(shops, currentBuilding) {
return shops.map((shop) => {
const result = { ...shop };
try {
result.distance = Math.ceil(
getDistance(
currentBuilding.latlng.lat,
currentBuilding.latlng.lng,
shop.location.lat,
shop.location.lng
)
);
result.minite = Math.ceil(result.distance / 1.4 / 60);
} catch (error) {
console.warn("Failed to calculate distance:", error);
result.distance = null;
result.minite = null;
}
try {
result.category = result.category?.split(":").pop() || "";
} catch (error) {
console.warn("Failed to process category:", error);
result.category = "";
}
return result;
});
}
/**
* 获取店铺列表数据
*/
export async function getShopList(
keyword,
pageIndex,
currentBuilding,
mapKey,
appInstance
) {
const apiUrl = buildApiUrl(keyword, pageIndex, currentBuilding, mapKey);
const { data } = await appInstance.get(apiUrl);
const rawData = data.data || [];
const totalCount = data.count || 0;
const processedData = processShopData(rawData, currentBuilding);
return {
rawData,
totalCount,
processedData,
};
}
{
"disableScroll": true,
"usingComponents": {
"custom-tab-bar": "../../components/custom-tab-bar/index"
}
}
/* components/explore/index.wxss */
.explore {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
.map {
width: 100vw;
height: calc(100vh - 140px);
}
.bottom-bg {
position: absolute;
bottom: 0;
z-index: 200;
display: flex;
flex-direction: column;
height: 414px;
width: 100vw;
border-radius: 8px;
border: 1px solid #fff;
background: linear-gradient(180deg, #fbfbfb 0%, #f4f4f4 41.8%);
}
.bottom-hud {
position: absolute;
bottom: 0;
z-index: 200;
height: 420px;
width: 100vw;
.handle {
position: absolute;
top: -4px;
left: 0;
right: 0;
margin: auto;
width: 40px;
height: 4px;
border-radius: 27px;
background: rgba(0, 0, 0, 0.2);
&::before {
content: "";
display: block;
position: absolute;
left: -5px;
right: -5px;
top: -10px;
bottom: -10px;
}
}
.title {
padding-top: 16px;
padding-left: 22px;
display: flex;
gap: 24px;
align-items: center;
.item {
display: inline-flex;
flex-direction: column;
align-items: center;
gap: 2px;
.txt {
color: rgba(0, 0, 0, 0.7);
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 22px;
}
.mark {
width: 16px;
height: 4px;
border-radius: 17px;
}
&.active {
.txt {
color: rgba(0, 0, 0, 0.9);
font-weight: 600;
}
.mark {
background: #e92927;
}
}
}
}
.collapsed {
display: flex;
width: 100vw;
height: 62px;
align-items: center;
justify-content: center;
padding-top: 6px;
color: #333;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 600;
line-height: 18px;
}
.scroll-view {
position: absolute;
z-index: 1;
left: 10px;
right: 10px;
top: 58px;
height: calc(100vh - 158px);
width: calc(100vw - 20px);
.list {
display: inline-flex;
flex-direction: column;
width: calc(100vw - 20px);
gap: 8px;
.item {
position: relative;
width: calc(100vw - 20px);
border-radius: 8px;
background: #fff;
padding: 12px 16px;
.content {
display: inline-flex;
flex-direction: column;
flex: 1;
overflow: hidden;
.t1 {
color: #333;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 22px; /* 137.5% */
}
.t2 {
margin-top: 4px;
color: rgba(0, 0, 0, 0.4);
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 16px;
}
.t3 {
display: flex;
width: calc(100vw - 52px);
align-items: center;
gap: 4px;
margin-top: 8px;
color: #666;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 16px;
.loc {
width: 16px;
height: 16px;
}
.right {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
.tel {
position: absolute;
top: 12px;
right: 16px;
display: flex;
flex-direction: column;
align-items: center;
color: #666;
font-family: "PingFang SC";
font-size: 11px;
font-style: normal;
font-weight: 400;
line-height: normal;
.phone {
width: 24px;
height: 24px;
}
}
}
.loading,
.no-more {
text-align: center;
padding: 10px;
color: #666;
font-size: 14px;
}
}
}
}
.detail {
position: absolute;
bottom: 0;
left: 0;
right: 0;
width: 100vw;
z-index: 2000;
.detail-bg {
position: absolute;
top: 0;
left: 0;
width: 100vw;
bottom: 0;
right: 0;
z-index: 1;
background: #fff;
}
.content {
position: relative;
z-index: 2;
background: #fff;
.close {
position: absolute;
top: 10px;
right: 8px;
width: 32px;
height: 32px;
z-index: 10;
}
.top {
position: relative;
display: flex;
flex-direction: column;
gap: 4px;
padding: 16px;
.t1 {
color: #333;
font-feature-settings: "case" on;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 22px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding-right: 24px;
}
.t2 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: rgba(0, 0, 0, 0.4);
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 16px;
padding-right: 24px;
}
.t3 {
display: flex;
width: calc(100vw - 52px);
align-items: center;
gap: 4px;
margin-top: 24px;
color: #666;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 16px;
.loc {
width: 16px;
height: 16px;
}
.right {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.tel {
position: absolute;
bottom: 16px;
right: 16px;
display: flex;
flex-direction: column;
align-items: center;
color: #666;
font-family: "PingFang SC";
font-size: 11px;
font-style: normal;
font-weight: 400;
line-height: normal;
.phone {
width: 24px;
height: 24px;
}
}
}
.bottom {
height: 98px;
border-top: 1px solid rgba(0, 0, 0, 0.06);
padding-top: 12px;
padding-left: 16px;
padding-right: 16px;
.btn {
border-radius: 99px;
background: linear-gradient(90deg, #fa643c 0%, #e92927 100%);
height: 40px;
display: flex;
gap: 8px;
align-items: center;
justify-content: center;
color: #fff;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 600;
line-height: 18px;
.img {
width: 24px;
height: 24px;
}
}
}
}
}
}
<view class="explore">
<map wx:if="{{latitude&&longitude}}" id="explore-map" class="map" show-compass latitude="{{latitude}}" longitude="{{longitude}}" max-scale="22" bind:markertap="handleMarkerTap"></map>
<textarea wx:if="{{!detail}}" disabled class="bottom-bg" style="z-index: 100;height: {{height - 6}}px;transition: {{!doTransition ? 'none' : 'height 0.5s ease'}}"></textarea>
<view class="bottom-hud" hidden="{{detail}}" style="height: {{height}}px;transition: {{!doTransition ? 'none' : 'height 0.5s ease'}}" bind:touchstart="handleTouchStart" bind:touchmove="handleTouchMove" bind:touchend="handleTouchEnd" bind:touchcancel="handleTouchEnd">
<view class="handle"></view>
<view class="title" wx:if="{{viewState!=='collapsed'}}">
<view class="item {{currentIndex===index?'active':''}}" wx:for="{{categories}}" wx:key="name" id="{{index}}" bind:tap="switchCat">
<view class="txt">{{isEn?item.nameEn:item.name}}</view>
<view class="mark"></view>
</view>
</view>
<view wx:if="{{viewState==='collapsed'}}" class="collapsed">{{isEn?'Show more':'上滑查看全部结果'}}</view>
<scroll-view hidden="{{viewState==='collapsed'}}" id="scroller" enhanced bounces="{{false}}" scroll-y="{{viewState==='fullscreen'&&!snapped}}" class="scroll-view" scroll-top="{{ nextTop }}" bindscrolltolower="onScrollToLower">
<view class="list">
<view class="item" wx:for="{{list}}" wx:for-item="shop" wx:key="id" id="{{shop.id}}" bind:tap="toDetail">
<view class="content">
<view class="t1">{{shop.title}}</view>
<view class="t2">{{isEn?'Distance':'距此'}}{{shop.distance}}m</view>
<view class="t3">
<image src="./loc.png" class="loc" mode="" />
<view class="right">{{shop.address}}</view>
</view>
</view>
<view wx:if="{{shop.tel}}" id="{{shop.tel}}" class="tel" catch:tap="makePhoneCall">
<image class="phone" src="./tel.png" mode="" />
{{isEn?'Tel':'电话'}}
</view>
</view>
<view wx:if="{{loading}}" class="loading">{{isEn?'Loading...':'加载中...'}}</view>
<view wx:elif="{{!hasMore}}" class="no-more">{{isEn?'No more data':'没有更多数据了'}}</view>
</view>
</scroll-view>
</view>
<view class="detail" wx:if="{{detail}}">
<textarea disabled class="detail-bg"></textarea>
<view class="content">
<image class="close" src="./close.png" mode="" bind:tap="back" />
<view class="top">
<view class="t1">{{detail.title}}</view>
<view class="t2">{{isEn?'Distance':'距此'}}{{detail.distance}}m</view>
<view class="t3">
<image src="./loc.png" class="loc" mode="" />
<view class="right">{{detail.address}}</view>
</view>
<view wx:if="{{detail.tel}}" id="{{detail.tel}}" class="tel" bind:tap="makePhoneCall">
<image class="phone" src="./tel.png" mode="" />
{{isEn?'Tel':'电话'}}
</view>
</view>
<view class="bottom">
<view class="btn" bind:tap="toApp">
<image class="img" src="./dir.png" mode="" />
<view>{{isEn?'Go here':'到这去'}}</view>
</view>
</view>
</view>
</view>
<custom-tab-bar current-index="{{2}}" bind:tab="handleTab"></custom-tab-bar>
</view>
\ No newline at end of file
// pages/feedback/index.js
Page({
/**
* 页面的初始数据
*/
data: { src: "" },
/**
* 生命周期函数--监听页面加载
*/
onLoad() {
const token = getApp().globalData.user.access_token;
this.setData({
src: `https://h5.chinagoods.com/aigc/feedback-list?token=${token}`,
});
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {},
/**
* 生命周期函数--监听页面显示
*/
onShow() {},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {},
});
{
"usingComponents": {},
"navigationBarTitleText": "贡献反馈"
}
/* pages/feedback/index.wxss */
\ No newline at end of file
<web-view src="{{src}}" />
\ No newline at end of file
...@@ -29,7 +29,7 @@ Component({ ...@@ -29,7 +29,7 @@ Component({
moveTouches(touches) { moveTouches(touches) {
if (!this.data.touchStart) return; if (!this.data.touchStart) return;
let touch = Array.from(touches).find( let touch = Array.from(touches).find(
({ identifier }) => identifier === this.data.touchStart.identifier ({ identifier }) => identifier === this.data.touchStart.identifier,
); );
if (!touch) { if (!touch) {
if (touches.length > 0) { if (touches.length > 0) {
...@@ -50,14 +50,14 @@ Component({ ...@@ -50,14 +50,14 @@ Component({
this.setData({ this.setData({
height: Math.max( height: Math.max(
Math.min(this.baseHeight() - delta, this.data.windowHeight - 24), Math.min(this.baseHeight() - delta, this.data.windowHeight - 24),
146 146,
), ),
}); });
}, },
endTouches(touches) { endTouches(touches) {
if (!this.data.touchStart) return; if (!this.data.touchStart) return;
let touch = Array.from(touches).find( let touch = Array.from(touches).find(
({ identifier }) => identifier === this.data.touchStart.identifier ({ identifier }) => identifier === this.data.touchStart.identifier,
); );
if (!touch) { if (!touch) {
...@@ -188,31 +188,38 @@ Component({ ...@@ -188,31 +188,38 @@ Component({
console.log(error); console.log(error);
} }
}, },
handlePoi({ detail: poi }) {
this.triggerEvent("poi", poi);
},
async getNavHistory() { async getNavHistory() {
const { post, qmurl, shopIdMap, facilityIdMap, globalData } = getApp(); const app = getApp();
if (!globalData.user) return; const userId = app.globalData.user?.user?.userId;
if (!shopIdMap) return; if (!userId) return;
try { try {
const { const {
data: { data }, data: { data },
} = await post( } = await app.post(
`${qmurl}/api/v1/applet/getUserFootPrintList?userId=${globalData.user.user.userId}`, `${app.qmurl}/api/v1/applet/getUserFootPrintList?userId=${userId}`,
{ { userId },
userId: globalData.user.user.userId,
}
); );
if (data && data.length !== undefined) {
this.setData({ if (!Array.isArray(data)) return;
navHistory: data
.map(({ shopType, shopId }) => // 1. 性能优化:先过滤并截取前 10 条 (避免填充无需显示的后续数据)
shopType === 1 ? shopIdMap[shopId] : null const rawList = data.filter((item) => item.shopType === 1).slice(0, 10);
)
.filter((el) => el) // 2. 自动填充 (利用 populate 默认读取 shopType/shopId 的特性,无需配置参数)
.slice(0, 10), const populatedList = await app.poiApi.populate(rawList, {
}); targetField: "detail",
} });
// 3. 提取结果并更新
this.setData({
navHistory: populatedList.map((item) => item.detail).filter(Boolean),
});
} catch (error) { } catch (error) {
console.log(error); console.error(error);
} }
}, },
}, },
...@@ -222,14 +229,7 @@ Component({ ...@@ -222,14 +229,7 @@ Component({
.select("#scroller") .select("#scroller")
.scrollOffset(); .scrollOffset();
this.getPrimeSpots(); this.getPrimeSpots();
const app = getApp(); this.getNavHistory();
if (!app.shopIdMap) {
app.events.once("globalData", () => {
this.getNavHistory();
});
} else {
this.getNavHistory();
}
}, },
}, },
}); });
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<scroll-view id="scroller" enhanced bounces="{{false}}" scroll-y="{{viewState==='fullscreen'}}" class="scroll-view" scroll-top="{{ nextTop }}" bindscrolltolower="onScrollToLower" lower-threshold="251"> <scroll-view id="scroller" enhanced bounces="{{false}}" scroll-y="{{viewState==='fullscreen'}}" class="scroll-view" scroll-top="{{ nextTop }}" bindscrolltolower="onScrollToLower" lower-threshold="251">
<view style="width: 100%; height: 46px;"></view> <view style="width: 100%; height: 46px;"></view>
<prime-spot wx:if="{{primeSpots.length>0&&!isEn}}" list="{{primeSpots}}"></prime-spot> <prime-spot wx:if="{{primeSpots.length>0&&!isEn}}" list="{{primeSpots}}"></prime-spot>
<nav-history wx:if="{{navHistory.length>0}}" list="{{navHistory}}" bind:navhistorycleared="getNavHistory"></nav-history> <nav-history wx:if="{{navHistory.length>0}}" list="{{navHistory}}" bind:navhistorycleared="getNavHistory" bind:poi="handlePoi"></nav-history>
<shops scroll-end-count="{{scrollEndCount}}"></shops> <shops scroll-end-count="{{scrollEndCount}}"></shops>
</scroll-view> </scroll-view>
</view> </view>
......
...@@ -40,7 +40,7 @@ Component({ ...@@ -40,7 +40,7 @@ Component({
}, },
handleShop({ currentTarget: { id: index } }) { handleShop({ currentTarget: { id: index } }) {
const poi = this.data.list[index]; const poi = this.data.list[index];
getApp().focusPoi(poi); this.triggerEvent("poi", poi);
}, },
async clearNavHistory() { async clearNavHistory() {
const { isEn } = this.data; const { isEn } = this.data;
......
import langBehavior from "../../../../behaviors/langBehavior"; import langBehavior from "../../../../behaviors/langBehavior";
import buildingBehavior from "../../../../behaviors/buildingBehavior";
Component({ Component({
behaviors: [langBehavior], behaviors: [langBehavior, buildingBehavior],
properties: {}, properties: {},
/** /**
...@@ -8,22 +9,13 @@ Component({ ...@@ -8,22 +9,13 @@ Component({
*/ */
data: { data: {
placeholderIndex: 0, placeholderIndex: 0,
placeholders: [ placeholders: [],
{ },
en: "District 2-East New Energy Product Market Welcome!", observers: {
cn: "欢迎光临二区东新能源产品市场", currentBuilding() {
}, this.setPlaceholder();
{ },
en: "Search store number/facilities/block/exit number",
cn: "搜铺号/公共设施/街区号/出入口号",
},
{
en: "Click or search shoplD for click navigation",
cn: "点击或搜索任意商铺可一键导航前往",
},
],
}, },
/** /**
* 组件的方法列表 * 组件的方法列表
*/ */
...@@ -34,6 +26,25 @@ Component({ ...@@ -34,6 +26,25 @@ Component({
aiTap() { aiTap() {
this.triggerEvent("ai"); this.triggerEvent("ai");
}, },
setPlaceholder() {
const building = this.data.currentBuilding;
this.setData({
placeholders: [
{
en: `${building.displayNameEn} Welcome!`,
cn: `欢迎光临${building.displayName}`,
},
{
en: "Search store number/facilities/block/exit number",
cn: "搜铺号/公共设施/街区号/出入口号",
},
{
en: "Click or search shoplD for click navigation",
cn: "点击或搜索任意商铺可一键导航前往",
},
],
});
},
}, },
lifetimes: { lifetimes: {
attached() { attached() {
...@@ -42,6 +53,7 @@ Component({ ...@@ -42,6 +53,7 @@ Component({
placeholderIndex: (this.data.placeholderIndex + 1) % 3, placeholderIndex: (this.data.placeholderIndex + 1) % 3,
}); });
}, 3000); }, 3000);
this.setPlaceholder();
}, },
detached() { detached() {
if (this.interval) { if (this.interval) {
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
color: #000; color: #000;
border-radius: 99px; border-radius: 99px;
border: 0.2px solid var(--W-100, #fff); border: 0.2px solid var(--W-100, #fff);
background: rgba(255, 255, 255, 0.08); background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(33.05883026123047px); backdrop-filter: blur(33.05883026123047px);
} }
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<image src="./search.png" class="search" mode="" /> <image src="./search.png" class="search" mode="" />
<view class="text">{{placeholders[placeholderIndex][isEn?'en':'cn']}}</view> <view class="text">{{placeholders[placeholderIndex][isEn?'en':'cn']}}</view>
<view class="ai" catch:tap="aiTap"> <view class="ai" catch:tap="aiTap">
<image src="./ai.png" class="icon" mode="" /> <image src="https://cdnimg.chinagoods.com/png/2025/10/10/tabzvwxow9xlggugfr0e0oe3s5pahny2.png" class="icon" mode="" />
<view class="text" style="{{'width: '+(isEn?50:35)+'px'}}">{{isEn?"AI Search":"AI识物"}}</view> <view class="text" style="{{'width: '+(isEn?50:35)+'px'}}">{{isEn?"AI Search":"AI识物"}}</view>
</view> </view>
</view> </view>
\ No newline at end of file
import langBehavior from "../../../../behaviors/langBehavior"; import langBehavior from "../../../../behaviors/langBehavior";
import buildingBehavior from "../../../../behaviors/buildingBehavior";
Component({ Component({
behaviors: [langBehavior], behaviors: [langBehavior, buildingBehavior],
/** /**
* 组件的属性列表 * 组件的属性列表
*/ */
...@@ -12,7 +13,10 @@ Component({ ...@@ -12,7 +13,10 @@ Component({
* 组件的初始数据 * 组件的初始数据
*/ */
data: { data: {
formats: [{ key: "all", name: "全部", nameEn: "All" }, ...getApp().formats], formats: [
{ key: "all", name: "全部", nameEn: "All" },
...getApp().currentBuilding.formats,
],
key: "all", key: "all",
page: 1, page: 1,
page_size: 10, page_size: 10,
...@@ -20,6 +24,15 @@ Component({ ...@@ -20,6 +24,15 @@ Component({
isLoading: false, isLoading: false,
}, },
observers: { observers: {
currentBuilding() {
this.setData({
formats: [
{ key: "all", name: "全部", nameEn: "All" },
...getApp().currentBuilding.formats,
],
key: "all",
});
},
key() { key() {
this.setData({ this.setData({
page: 1, page: 1,
...@@ -45,61 +58,68 @@ Component({ ...@@ -45,61 +58,68 @@ Component({
*/ */
methods: { methods: {
async getList(nxtPage = 1) { async getList(nxtPage = 1) {
const { post, marketurl, formats, md5, salt, shopIdMap } = getApp(); const app = getApp();
const { key, isEn, page_size } = this.data; const { key, isEn, page_size, currentBuilding, list, isLoading } =
if (this.data.isLoading) return; this.data;
if (!shopIdMap) return; if (isLoading) return;
try {
this.setData({
isLoading: true,
});
this.setData({ isLoading: true });
try {
const { const {
data: { data: { data: res },
data: { total_page, page, first_result, last_result, data }, } = await app.post(
`${app.marketurl}/osc/v1/shops/open/toBaiDu/search`,
{
page: nxtPage,
page_size,
industryKeyList:
key === "all" ? currentBuilding.formats.map((f) => f.key) : [key],
lang: isEn ? "en" : "zh",
keySecret: app.md5(app.md5(app.salt + nxtPage)),
zone: currentBuilding.zone,
}, },
} = await post(`${marketurl}/osc/v1/shops/open/toBaiDu/search`, { );
page: nxtPage,
page_size, // 1. 自动填充
industryKeyList: const filledItems = await app.poiApi.populate(res.data, {
key === "all" ? formats.map((format) => format.key) : [key], getType: () => "1",
lang: isEn ? "en" : "zh", getId: (i) => i.shopId,
keySecret: md5(md5(salt + nxtPage)), getBooth: (i) => i.boothNo,
targetField: "detail",
}); });
const nxtList = data
.map((shop) => { // 2. 提取详情
if (!shopIdMap[shop.shopId]) const nxtList = filledItems.map((i) => i.detail).filter(Boolean);
console.warn("列表接口里有,但是全量没有的店铺", shop);
return shopIdMap[shop.shopId]; // 3. 批量埋点
})
.filter((el) => el);
nxtList.forEach((poi) => { nxtList.forEach((poi) => {
const yw = poi.ywZh || {};
try { try {
getApp().sensors?.track("ExposureBoothActivity", { app.sensors?.track("ExposureBoothActivity", {
shop_id: poi.shopId, shop_id: poi.shopId,
shop_name: poi.ywZh.name, shop_name: yw.name,
booth_no: poi.ywZh.boothNo, booth_no: yw.boothNo,
store_name: poi.ywZh.name, store_name: yw.name,
short_market_name: "二区东", short_market_name: yw.marketNameDtl,
booth_addr_street: poi.ywZh.boothAddrStreet, booth_addr_street: yw.boothAddrStreet,
industry: poi.ywZh.frontIndustryCategory, industry: yw.frontIndustryCategory,
booth_floor: poi.ywZh.addrFloor, booth_floor: yw.addrFloor,
}); });
} catch (error) { } catch (e) {
console.error("埋点失败", error); console.error(e);
} }
}); });
this.setData({ this.setData({
list: [...this.data.list, ...nxtList], list: [...list, ...nxtList],
total_page, total_page: res.total_page,
page, page: res.page,
}); });
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} finally { } finally {
this.setData({ this.setData({ isLoading: false });
isLoading: false,
});
} }
}, },
handleFormat({ currentTarget: { id: key } }) { handleFormat({ currentTarget: { id: key } }) {
...@@ -110,36 +130,34 @@ Component({ ...@@ -110,36 +130,34 @@ Component({
} }
}, },
handleShop({ currentTarget: { id: shopId } }) { handleShop({ currentTarget: { id: shopId } }) {
try { // 1. 立即跳转 (UI 响应优先,不阻塞)
const poi = getApp().shopIdMap[shopId]; wx.navigateTo({ url: `/pages/shop/index?shopId=${shopId}` });
getApp().sensors?.track("BoothActivityClick", {
shop_id: poi.shopId, // 2. 异步埋点 (Fire-and-forget)
shop_name: poi.ywZh.name, const app = getApp();
booth_no: poi.ywZh.boothNo, app.poiApi
store_name: poi.ywZh.name, .getOne({ shopType: "1", shopId })
short_market_name: "二区东", .then((poi) => {
booth_addr_street: poi.ywZh.boothAddrStreet, if (!poi) return;
industry: poi.ywZh.frontIndustryCategory, const yw = poi.ywZh || {}; // 缓存对象,简化下方取值
booth_floor: poi.ywZh.addrFloor,
}); app.sensors?.track("BoothActivityClick", {
} catch (error) { shop_id: poi.shopId,
console.error("埋点失败", error); shop_name: yw.name,
} booth_no: yw.boothNo,
wx.navigateTo({ store_name: yw.name,
url: `/pages/shop/index?shopId=${shopId}`, short_market_name: yw.marketNameDtl,
}); booth_addr_street: yw.boothAddrStreet,
industry: yw.frontIndustryCategory,
booth_floor: yw.addrFloor,
});
})
.catch((e) => console.error("埋点失败", e));
}, },
}, },
lifetimes: { lifetimes: {
attached() { attached() {
const app = getApp(); this.getList();
if (app.shopIdMap) {
this.getList();
} else {
app.events.once("globalData", () => {
this.getList();
});
}
}, },
}, },
}); });
...@@ -213,4 +213,12 @@ ...@@ -213,4 +213,12 @@
width: 16px; width: 16px;
height: 16px; height: 16px;
} }
.card {
position: absolute;
top: 168px;
right: 2px;
width: 56px;
height: 56px;
z-index: 2;
}
} }
<view class="index"> <view class="index">
<map-wrapper type="{{isIndex?'index':'surroundings'}}" viewstate="{{viewstate}}" user-location="{{userLocation}}" acts="{{acts}}" reset-count="{{resetCount}}" building-id="{{buildingId}}" floor-name="{{floorName}}" facilities="{{currentFloorFacilities}}" bind:poi="handlePoi" bind:act="handleAct"></map-wrapper> <map-wrapper type="{{isIndex?'index':'surroundings'}}" viewstate="{{viewstate}}" user-location="{{userLocation}}" acts="{{acts}}" reset-count="{{resetCount}}" floor-name="{{floorName}}" facilities="{{currentFloorFacilities}}" bind:poi="handlePoi" bind:act="handleAct" bind:buildchange="handleMapBuildChange"></map-wrapper>
<lang-btn wx:if="{{!(isIndex&&viewstate==='fullscreen')}}"></lang-btn> <lang-btn wx:if="{{!(isIndex&&viewstate==='fullscreen')}}" type="index"></lang-btn>
<bottom-hud-index wx:if="{{isIndex}}" bind:viewstate="handleBottomHudViewstate" bind:search="handleSearch" bind:ai="handleAi"> <bottom-hud-index wx:if="{{isIndex}}" bind:viewstate="handleBottomHudViewstate" bind:search="handleSearch" bind:ai="handleAi" bind:poi="handlePoi">
<floors never-authed="{{neverAuthed}}" show-success="{{getLocationSuccess}}" refreshing="{{gettingLocation}}" wx:if="{{viewstate!=='fullscreen'&&!focusedPoi}}" floors="{{floors}}" floor-name="{{floorName}}" bind:floorname="handleFloor" bind:resetmap="handleReset"></floors> <floors never-authed="{{neverAuthed}}" show-success="{{getLocationSuccess}}" refreshing="{{gettingLocation}}" wx:if="{{viewstate!=='fullscreen'&&!focusedPoi}}" floors="{{currentBuilding.floors}}" floor-name="{{floorName}}" bind:floorname="handleFloor" bind:resetmap="handleReset"></floors>
</bottom-hud-index> </bottom-hud-index>
<bottom-hud-surroundings wx:else badge-num="{{currentFloorFacilities.length}}" active-id="{{activeId}}" fac-types="{{facTypes}}" bind:factypetap="handleFacTypeTap"> <bottom-hud-surroundings wx:else badge-num="{{currentFloorFacilities.length}}" active-id="{{activeId}}" fac-types="{{facTypes}}" bind:factypetap="handleFacTypeTap">
<floors never-authed="{{neverAuthed}}" show-success="{{getLocationSuccess}}" refreshing="{{gettingLocation}}" wx:if="{{!focusedPoi}}" floors="{{floors}}" floor-name="{{floorName}}" bind:floorname="handleFloor" bind:resetmap="handleReset"></floors> <floors never-authed="{{neverAuthed}}" show-success="{{getLocationSuccess}}" refreshing="{{gettingLocation}}" wx:if="{{!focusedPoi}}" floors="{{currentBuilding.floors}}" floor-name="{{floorName}}" bind:floorname="handleFloor" bind:resetmap="handleReset"></floors>
</bottom-hud-surroundings> </bottom-hud-surroundings>
<popup wx:if="{{focusedPoi}}" is-index="{{true}}" bind:showbluetoothmodal="openBluetoothModal" bind:showlocationmodal="openLocationModal" bind:showauthmodal="openAuthModal"> <popup wx:if="{{focusedPoi}}" is-index="{{true}}" bind:showbluetoothmodal="openBluetoothModal" bind:showlocationmodal="openLocationModal" bind:showauthmodal="openAuthModal">
<floors never-authed="{{neverAuthed}}" show-success="{{getLocationSuccess}}" refreshing="{{gettingLocation}}" floors="{{floors}}" floor-name="{{floorName}}" bind:floorname="handleFloor" bind:resetmap="handleReset"></floors> <floors never-authed="{{neverAuthed}}" show-success="{{getLocationSuccess}}" refreshing="{{gettingLocation}}" floors="{{currentBuilding.floors}}" floor-name="{{floorName}}" bind:floorname="handleFloor" bind:resetmap="handleReset"></floors>
</popup> </popup>
<custom-tab-bar current-index="{{isIndex?0:1}}" bind:tab="handleTab"></custom-tab-bar> <custom-tab-bar current-index="{{isIndex?0:1}}" bind:tab="handleTab"></custom-tab-bar>
<view class="banner" wx:if="{{isIndex&&showBanner}}" bind:tap="closeBanner"> <view class="banner" wx:if="{{isIndex&&showBanner}}" bind:tap="closeBanner">
...@@ -46,4 +46,8 @@ ...@@ -46,4 +46,8 @@
</view> </view>
<image src="./close.png" class="close" catch:tap="closeAct" mode="" /> <image src="./close.png" class="close" catch:tap="closeAct" mode="" />
</view> </view>
<block wx:if="{{cardId}}">
<textarea class="card" disabled style="z-index: 1"></textarea>
<image class="card" src="./card.png" mode="" bind:tap="toCard" />
</block>
</view> </view>
\ No newline at end of file
...@@ -20,10 +20,13 @@ Component({ ...@@ -20,10 +20,13 @@ Component({
touchStartY: 0, touchStartY: 0,
}, },
observers: { observers: {
itineraryList(list) { async itineraryList(list) {
this.setData({ this.setData({
notVisitedCount: list.filter(({ status }) => status !== 1).length, notVisitedCount: list.filter(({ status }) => status !== 1).length,
listGroupByYmd: this.groupByCreateTime(list), });
const listGroupByYmd = await this.groupByCreateTime(list);
this.setData({
listGroupByYmd,
}); });
}, },
bulkDeleting() { bulkDeleting() {
...@@ -35,30 +38,28 @@ Component({ ...@@ -35,30 +38,28 @@ Component({
async handleGo({ currentTarget: { id } }) { async handleGo({ currentTarget: { id } }) {
const { isEn, itineraryList } = this.data; const { isEn, itineraryList } = this.data;
const iti = itineraryList.find((iti) => Number(id) === iti.id); const iti = itineraryList.find((iti) => Number(id) === iti.id);
const poi = getApp().shopIdMap[iti.shopId]; const app = getApp();
const poi = await app.poiApi.getOne({
shopType: "1",
shopId: iti.shopId,
});
if (!poi) return;
try { try {
getApp().sensors?.track("NavEntryBtnClick", { app.sensors?.track("NavEntryBtnClick", {
page_name: "我的行程", page_name: "我的行程",
short_market_name: "二区东",
...(poi.tx ...(poi.tx
? { ? {
x: Number(poi.tx.poi_location.longitude), x: Number(poi.tx.poi_location.longitude),
y: Number(poi.tx.poi_location.latitude), y: Number(poi.tx.poi_location.latitude),
} }
: {}), : {}),
...(poi.facilityId short_market_name: poi.ywZh?.marketNameDtl,
? { store_name: poi.ywZh?.name,
nav_target_type: poi.facility.name, booth_addr_street: poi.ywZh?.boothAddrStreet,
booth_floor: poi.tx.poi_fl_seq, booth_cover_img: poi.ywZh?.cover,
} booth_no: poi.ywZh?.boothNo,
: { industry: poi.ywZh?.frontIndustryCategory,
store_name: poi.ywZh.name, booth_floor: poi.ywZh?.addrFloor,
booth_addr_street: poi.ywZh.boothAddrStreet,
booth_cover_img: poi.ywZh.cover,
booth_no: poi.ywZh.boothNo,
industry: poi.ywZh.frontIndustryCategory,
booth_floor: poi.ywZh.addrFloor,
}),
}); });
} catch (error) { } catch (error) {
console.error("埋点失败", error); console.error("埋点失败", error);
...@@ -113,7 +114,7 @@ Component({ ...@@ -113,7 +114,7 @@ Component({
this.setData({ this.setData({
deleteIdMap: this.data.itineraryList.reduce( deleteIdMap: this.data.itineraryList.reduce(
(acc, nxt) => ({ ...acc, [nxt.id]: true }), (acc, nxt) => ({ ...acc, [nxt.id]: true }),
{} {},
), ),
allSelected: true, allSelected: true,
}); });
...@@ -163,44 +164,45 @@ Component({ ...@@ -163,44 +164,45 @@ Component({
wx.hideLoading(); wx.hideLoading();
} }
}, },
groupByCreateTime(dataList) { async groupByCreateTime(dataList) {
const { shopIdMap } = getApp(); if (!Array.isArray(dataList) || dataList.length === 0) return [];
if (!shopIdMap) return [];
if (!dataList || !Array.isArray(dataList)) return []; // 1. 自动填充店铺数据
dataList = dataList.filter(({ shopId }) => shopIdMap[shopId]); const populatedList = await getApp().poiApi.populate(dataList, {
if (dataList.length === 0) { getType: () => "1",
return []; getId: (item) => item.shopId,
} targetField: "shop",
const today = new Date(); });
const todayStr = `${today.getFullYear()}-${(today.getMonth() + 1)
.toString() // 2. 获取今天的日期字符串 (YYYY-MM-DD)
.padStart(2, "0")}-${today.getDate().toString().padStart(2, "0")}`; const now = new Date();
const todayStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
const result = []; const result = [];
let currentGroup = null; let currentGroup = null;
dataList.forEach((item) => { // 3. 遍历、过滤、格式化、分组 (一次循环完成)
const datePart = item.createTime.split(" ")[0]; populatedList.forEach((item) => {
// 过滤无效数据
if (!item?.shop) return;
// --- 价格格式化 (无需 try-catch) ---
// Number() 失败会返回 NaN,逻辑依然安全
const price = Number(item.goodsPrice) || 0;
item.yuan = Math.floor(price);
item.fen = `.${String(Math.round(price * 100) % 100).padStart(2, "0")}`;
// --- 分组逻辑 ---
const datePart = (item.createTime || "").split(" ")[0];
const dateKey = datePart === todayStr ? "今天" : datePart; const dateKey = datePart === todayStr ? "今天" : datePart;
// 如果是新的一天,创建新组
if (!currentGroup || currentGroup.date !== dateKey) { if (!currentGroup || currentGroup.date !== dateKey) {
currentGroup = { currentGroup = { date: dateKey, list: [] };
date: dateKey,
list: [],
};
result.push(currentGroup); result.push(currentGroup);
} }
try {
item.goodsPrice = Number(item.goodsPrice); currentGroup.list.push(item);
item.yuan = Math.floor(item.goodsPrice);
item.fen =
"." +
String(Math.round(item.goodsPrice * 100) % 100).padStart(2, "0");
} catch (error) {
item.yuan = item.goodsPrice;
console.error(error);
}
currentGroup.list.push({ ...item, shop: shopIdMap[item.shopId] });
}); });
return result; return result;
......
<view class="itinerary"> <view class="itinerary">
<scroll-view class="scroller {{bulkDeleting?'bulk':''}}" scroll-y> <scroll-view class="scroller {{bulkDeleting?'bulk':''}}" scroll-y>
<view class="title"> <view class="title">
<view class="left">{{isEn?'My Itinerary':'我的行程'}} <view class="left">{{isEn?'Saved Items':'商品收藏'}}
<text class="nums"><text class="red">{{notVisitedCount}}</text>/{{itineraryList.length}}</text> <text class="nums"><text class="red">{{notVisitedCount}}</text>/{{itineraryList.length}}</text>
</view> </view>
<view class="btns"> <view class="btns">
......
...@@ -5,6 +5,7 @@ Page({ ...@@ -5,6 +5,7 @@ Page({
checked: false, checked: false,
phoneLock: false, phoneLock: false,
showModal: false, showModal: false,
bindingModalData: null,
}, },
/** /**
...@@ -29,6 +30,57 @@ Page({ ...@@ -29,6 +30,57 @@ Page({
}); });
} }
}, },
async checkRedPocketOpenid() {
try {
const { marketurl, post, globalData } = getApp();
const {
data: { code, data, message },
} = await post(
`${marketurl}/rpt/user/openId/query`,
{},
{
Authorization: `Bearer ${globalData.user.access_token}`,
}
);
if (code === 20000) {
console.log("检查红包openid", data.hasOpen);
return data.hasOpen;
} else {
console.log("检查红包openid报错", message);
return true;
}
} catch (error) {
console.log("检查红包openid报错", error);
return true;
}
},
async getRedPocketOpenid() {
try {
const { marketurl, post, globalData } = getApp();
const {
data: { code, message },
} = await post(
`${marketurl}/rpt/user/openId`,
{
returnUrl: `https://h5.chinagoods.com/verify-openid/?targetPath=${encodeURIComponent(
"/pages/verify-openId/index"
)}`,
},
{
Authorization: `Bearer ${globalData.user.access_token}`,
}
);
if (code === 20000) {
wx.redirectTo({
url: `/pages/wap/index?url=${encodeURIComponent(message)}`,
});
return false;
} else return true;
} catch (error) {
console.log(error);
}
},
handleUnchecked() { handleUnchecked() {
this.setData({ showModal: true }); this.setData({ showModal: true });
}, },
...@@ -39,8 +91,26 @@ Page({ ...@@ -39,8 +91,26 @@ Page({
this.setData({ phoneLock: true }); this.setData({ phoneLock: true });
try { try {
if (code) { if (code) {
const success = await getApp().login(code); const response = await getApp().login(code);
if (success) this.back(); if (!response)
return wx.showToast({
title: "登录失败",
icon: "none",
});
if (response.code === 20000) {
const hasOpenid = await this.checkRedPocketOpenid();
if (hasOpenid) this.back();
else {
await this.getRedPocketOpenid();
}
} else if (response.code === 88051) {
return this.setData({ bindingModalData: response.data });
} else {
return wx.showToast({
title: response.message,
icon: "none",
});
}
} }
} catch (error) { } catch (error) {
console.log("error", error); console.log("error", error);
...@@ -48,6 +118,9 @@ Page({ ...@@ -48,6 +118,9 @@ Page({
this.setData({ phoneLock: false }); this.setData({ phoneLock: false });
} }
}, },
closeBindingModal() {
this.setData({ bindingModalData: null });
},
/** /**
* 生命周期函数--监听页面初次渲染完成 * 生命周期函数--监听页面初次渲染完成
*/ */
......
...@@ -175,4 +175,84 @@ ...@@ -175,4 +175,84 @@
} }
} }
} }
.binding-modal {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
gap: 40px;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 3;
background: rgba(0, 0, 0, 0.6);
.modal-content {
width: 304px;
padding: 32px 36px;
border-radius: 8px;
background: #fff;
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
.r1 {
color: #333;
text-align: center;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 18px;
}
.r2 {
color: #333;
text-align: center;
font-family: "PingFang SC";
font-size: 24px;
font-style: normal;
font-weight: 600;
line-height: normal;
}
.r3 {
display: flex;
width: 100%;
gap: 4px;
color: #666;
text-align: center;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: normal;
.icon {
width: 12px;
height: 12px;
margin-top: 1px;
flex-shrink: 0;
}
}
.r4 {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 40px;
border-radius: 99px;
border: 1px solid #e92927;
color: #e92927;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 22px;
margin-top: 16px;
}
}
.close {
width: 32px;
height: 32px;
}
}
} }
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
</view> </view>
</view> </view>
<lang-btn type="black"></lang-btn> <lang-btn type="black"></lang-btn>
<view class="modal" wx:if="{{showModal}}" bind:tap="closeModal"> <view class="modal" wx:if="{{showModal&&!bindingModalData}}" bind:tap="closeModal">
<view class="modal-content" catch:tap> <view class="modal-content" catch:tap>
<view class="r1" wx:if="{{isEn}}"> <view class="r1" wx:if="{{isEn}}">
Please read carefully and fully understand the relevant terms, click agree means that you have Please read carefully and fully understand the relevant terms, click agree means that you have
...@@ -41,5 +41,21 @@ ...@@ -41,5 +41,21 @@
</view> </view>
</view> </view>
</view> </view>
<view class="binding-modal" wx:if="{{bindingModalData}}" bind:tap="closeBindingModal">
<view class="modal-content" catch:tap>
<view class="r1">
当前微信注册的Chinagoods账号
已绑定其他手机号,占用绑定手机号为
</view>
<view class="r2">
{{bindingModalData}}
</view>
<view class="r3">
<image class="icon" src="./icon.png" mode="" />
<text style="text-align: left;">使用已绑定过微信账号的手机号进行登录,启用导航一键到店</text>
</view>
<view class="r4" catch:tap="closeBindingModal">切换账号登录</view>
</view>
<image src="./close.png" class="close" bind:tap="closeBindingModal" mode="" />
</view>
</view> </view>
\ No newline at end of file
...@@ -34,7 +34,10 @@ Component({ ...@@ -34,7 +34,10 @@ Component({
this.setData({ this.setData({
formats: [ formats: [
{ key: "all", name: "全部收藏", nameEn: "All" }, { key: "all", name: "全部收藏", nameEn: "All" },
...getApp().formats.filter(({ key }) => formatKeyMap[key]), ...getApp()
.buildings.map(({ formats }) => formats)
.reduce((acc, nxt) => acc.concat(nxt), [])
.filter(({ key }) => formatKeyMap[key]),
], ],
}); });
this.setDisplayList(); this.setDisplayList();
...@@ -77,7 +80,7 @@ Component({ ...@@ -77,7 +80,7 @@ Component({
this.setData({ this.setData({
deleteIdMap: this.data.displayList.reduce( deleteIdMap: this.data.displayList.reduce(
(acc, nxt) => ({ ...acc, [nxt.id]: true }), (acc, nxt) => ({ ...acc, [nxt.id]: true }),
{} {},
), ),
allSelected: true, allSelected: true,
}); });
...@@ -121,16 +124,24 @@ Component({ ...@@ -121,16 +124,24 @@ Component({
toggleBulkDeleting() { toggleBulkDeleting() {
this.setData({ bulkDeleting: !this.data.bulkDeleting }); this.setData({ bulkDeleting: !this.data.bulkDeleting });
}, },
setPoiList() { async setPoiList() {
const { shopIdMap, facilityIdMap } = getApp(); const { collectList } = this.data;
if (!shopIdMap) return this.setData({ poiList: [] }); // 1. 快速判空
const poiList = this.data.collectList if (!collectList?.length) return this.setData({ poiList: [] });
.map(({ id, shopId, shopType }) => ({
id, // 2. 自动填充 (省略默认配置,populate 默认读取 item.shopType 和 item.shopId)
poi: shopType === 1 ? shopIdMap[shopId] : facilityIdMap[shopId], const list = await getApp().poiApi.populate(collectList, {
})) targetField: "poi",
.filter(({ poi }) => poi); });
this.setData({ poiList });
// 3. 过滤并重组 (最小化 setData 传输的数据量)
this.setData({
poiList: list
.filter((item) => item.poi)
.map(({ id, poi }) => ({ id, poi })),
});
this.setDisplayList();
}, },
cleanSwipeDeleteId() { cleanSwipeDeleteId() {
this.setData({ swipeDeleteId: null }); this.setData({ swipeDeleteId: null });
...@@ -151,14 +162,16 @@ Component({ ...@@ -151,14 +162,16 @@ Component({
const { isEn, displayList } = this.data; const { isEn, displayList } = this.data;
const { poi } = displayList[index]; const { poi } = displayList[index];
try { try {
const { buildingIdNameMap } = getApp();
getApp().sensors?.track("NavEntryBtnClick", { getApp().sensors?.track("NavEntryBtnClick", {
page_name: "我的收藏列表", page_name: "我的收藏列表",
short_market_name: "二区东",
rank: Number(index) + 1, rank: Number(index) + 1,
label_name: this.data.formats.find(({ key }) => this.data.key === key) label_name: this.data.formats.find(({ key }) => this.data.key === key)
.name, .name,
...(poi.tx ...(poi.tx
? { ? {
short_market_name: buildingIdNameMap[poi.tx.bld_id],
x: Number(poi.tx.poi_location.longitude), x: Number(poi.tx.poi_location.longitude),
y: Number(poi.tx.poi_location.latitude), y: Number(poi.tx.poi_location.latitude),
} }
...@@ -241,7 +254,7 @@ Component({ ...@@ -241,7 +254,7 @@ Component({
}, },
handleShopTap({ currentTarget: { id } }) { handleShopTap({ currentTarget: { id } }) {
const collect = this.data.displayList.find( const collect = this.data.displayList.find(
(collect) => Number(id) === collect.id (collect) => Number(id) === collect.id,
); );
if (!collect) return; if (!collect) return;
if (!this.data.bulkDeleting) { if (!this.data.bulkDeleting) {
......
<view class="collection"> <view class="collection">
<view class="title"> <view class="title">
<view class="left"> <view class="left">
{{isEn?'My Collection':'我收藏的地点'}} {{isEn?'Saved Stores':'店铺收藏'}}
<view>{{poiList.length}}</view>
</view> </view>
<block wx:if="{{poiList.length}}"> <block wx:if="{{poiList.length}}">
<view wx:if="{{bulkDeleting}}" class="edit red" bind:tap="toggleBulkDeleting">{{isEn?'Finish':'完成'}}</view> <view wx:if="{{bulkDeleting}}" class="edit red" bind:tap="toggleBulkDeleting">{{isEn?'Finish':'完成'}}</view>
......

2.9 KB | W: | H:

2.9 KB | W: | H:

pages/mine/history.png
pages/mine/history.png
pages/mine/history.png
pages/mine/history.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -30,7 +30,9 @@ Page({ ...@@ -30,7 +30,9 @@ Page({
getApp().login(); getApp().login();
}, },
toggleBulkDeleting({ detail: bulkDeleting }) { toggleBulkDeleting({ detail: bulkDeleting }) {
this.setData({ bulkDeleting }); this.setData({
bulkDeleting,
});
}, },
toCouponCenter() { toCouponCenter() {
getApp().sensors?.track("MyCouponClick", { getApp().sensors?.track("MyCouponClick", {
...@@ -49,7 +51,11 @@ Page({ ...@@ -49,7 +51,11 @@ Page({
url: "/pages/itinerary/index", url: "/pages/itinerary/index",
}); });
}, },
onLoad(options) { onLoad(params) {
console.log(params);
const { utm_campaign, utm_term } = params;
if (utm_campaign) getApp().utm_campaign = utm_campaign;
if (utm_term) getApp().utm_term = utm_term;
this.setItineraryCount = () => this.setItineraryCount = () =>
this.setData({ this.setData({
itineraryCount: getApp().itineraryList.filter( itineraryCount: getApp().itineraryList.filter(
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
</view> </view>
<view class="btn" bind:tap="toItinerary"> <view class="btn" bind:tap="toItinerary">
<image class="icon" src="./history.png" mode="" /> <image class="icon" src="./history.png" mode="" />
<view class="text">{{isEn?"My Itinerary":"我的行程"}}<text style="margin-left: 6px;" wx:if="{{itineraryCount>0}}">{{itineraryCount}}</text></view> <view class="text">{{isEn?"Saved Items":"商品收藏"}}</view>
<image class="arrow" src="./arrow.png" mode="" /> <image class="arrow" src="./arrow.png" mode="" />
</view> </view>
</view> </view>
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
</view> </view>
<view style="height: 90px;"></view> <view style="height: 90px;"></view>
</scroll-view> </scroll-view>
<custom-tab-bar wx:if="{{!bulkDeleting}}" current-index="{{2}}" bind:tab="handleTab"></custom-tab-bar> <custom-tab-bar wx:if="{{!bulkDeleting}}" current-index="{{3}}" bind:tab="handleTab"></custom-tab-bar>
<bluetooth-modal wx:if="{{showBluetoothModal}}" bind:close="closeBluetoothModal"></bluetooth-modal> <bluetooth-modal wx:if="{{showBluetoothModal}}" bind:close="closeBluetoothModal"></bluetooth-modal>
<location-modal wx:if="{{showLocationModal}}" bind:close="closeLocationModal"></location-modal> <location-modal wx:if="{{showLocationModal}}" bind:close="closeLocationModal"></location-modal>
<auth-modal wx:if="{{showAuthModal}}" bind:close="closeAuthModal"></auth-modal> <auth-modal wx:if="{{showAuthModal}}" bind:close="closeAuthModal"></auth-modal>
......
import langBehavior from "../../behaviors/langBehavior"; import langBehavior from "../../behaviors/langBehavior";
import { findNearbyLocations } from "../../util"; import { findNearbyLocations, getPoiName, getDistance } from "../../util";
Page({ Page({
behaviors: [langBehavior], behaviors: [langBehavior],
/** /**
...@@ -9,6 +9,8 @@ Page({ ...@@ -9,6 +9,8 @@ Page({
showTip1: false, showTip1: false,
showTip2: false, showTip2: false,
showTip3: false, showTip3: false,
showTip4: false,
pois: null,
couponId: null, couponId: null,
receivingCoupon: false, receivingCoupon: false,
poi: null, poi: null,
...@@ -21,6 +23,7 @@ Page({ ...@@ -21,6 +23,7 @@ Page({
*/ */
async onLoad(options) { async onLoad(options) {
const { lastNav } = getApp().globalData; const { lastNav } = getApp().globalData;
if (!lastNav) return this.toIndex();
this.setData({ lastNav }); this.setData({ lastNav });
try { try {
this.setData({ this.setData({
...@@ -29,12 +32,20 @@ Page({ ...@@ -29,12 +32,20 @@ Page({
} catch (error) { } catch (error) {
console.error("设置卡路里失败", error); console.error("设置卡路里失败", error);
} }
if (!lastNav) return this.toIndex();
const poi = this.getEndPoi(); const poi = this.getEndPoi();
console.log("导航结束页面poi", poi); console.log("导航结束页面poi", poi);
// 自动收藏 // 自动收藏
// if (poi) this.collectPoi(poi); // if (poi) this.collectPoi(poi);
this.setData({ poi }); this.setData({ poi });
if (getApp().isCardNav) {
getApp().isCardNav = false;
const checkInResult = await this.checkIn(poi);
if (checkInResult === "showTip4") return this.setData({ showTip4: true });
if (checkInResult) return this.setData({ pois: checkInResult });
return;
}
const rewardConfig = await this.getRewardConfig(); const rewardConfig = await this.getRewardConfig();
console.log(rewardConfig); console.log(rewardConfig);
if (!rewardConfig) return; if (!rewardConfig) return;
...@@ -44,12 +55,12 @@ Page({ ...@@ -44,12 +55,12 @@ Page({
if (isvalid) { if (isvalid) {
try { try {
getApp().sensors?.track("ExposureActivityCoupon", { getApp().sensors?.track("ExposureActivityCoupon", {
short_market_name: "二区东",
...(poi.facilityId ...(poi.facilityId
? { ? {
booth_floor: poi.tx.poi_fl_seq, booth_floor: poi.tx.poi_fl_seq,
} }
: { : {
short_market_name: poi.ywZh.marketNameDtl,
booth_addr_street: poi.ywZh.boothAddrStreet, booth_addr_street: poi.ywZh.boothAddrStreet,
booth_no: poi.ywZh.boothNo, booth_no: poi.ywZh.boothNo,
industry: poi.ywZh.frontIndustryCategory, industry: poi.ywZh.frontIndustryCategory,
...@@ -66,20 +77,117 @@ Page({ ...@@ -66,20 +77,117 @@ Page({
}, },
toIndex() { toIndex() {
getApp().globalData.lastNav = null; getApp().globalData.lastNav = null;
console.log("toIndex");
wx.reLaunch({ wx.reLaunch({
url: "/pages/index/index", url: "/pages/index/index",
}); });
}, },
async checkIn(poi) {
try {
const app = getApp();
const res = await app.cardApi.check(poi);
if (!res) return null;
if (res.isFinish && res.receiveIsSuccess === 1) return "showTip4";
if (res.isFinish || !res.activityId) return null;
// 1. 获取活动详情
const card = await app.cardApi.get(res.activityId);
const rawList = card?.activityShopList?.filter(
(el) => el.checkInStatus === 0,
);
if (!rawList?.length) return null;
// 2. 自动填充 POI
const list = await app.poiApi.populate(rawList, {
getType: (item) => item.shopType,
getId: (item) => item.shopId,
getBooth: (item) => item.boothNo,
});
const { userLocation } = app;
// 3. 处理数据 (距离计算 & 格式化)
const pois = list
.filter((item) => item.poi?.tx) // 确保有坐标
.map((item) => {
const { poi } = item;
let distance = null;
if (userLocation) {
const { latitude, longitude } = poi.tx.poi_location;
distance = Math.ceil(
getDistance(
userLocation.latitude,
userLocation.longitude,
Number(latitude),
Number(longitude),
),
);
}
return {
...item,
distance,
poiName: getPoiName(poi, this.data.isEn),
poiAvatar: poi.ywZh?.cover || poi.facility?.logo,
};
});
// 4. 排序与返回
if (userLocation) pois.sort((a, b) => a.distance - b.distance);
return pois.length ? pois : null;
} catch (error) {
console.error(error);
return null;
}
},
handleGo({ currentTarget: { id } }) {
const poi = this.data.pois.find((el) => el.shopId === id);
if (poi.shopType === 1)
wx.navigateTo({
url: `/pages/poi-map/index?shopId=${poi.shopId}&isCardNav=true`,
});
else {
wx.navigateTo({
url: `/pages/poi-map/index?facilityId=${poi.shopId}&isCardNav=true`,
});
}
},
async isCouponOnValid(couponId) { async isCouponOnValid(couponId) {
try { try {
const { marketurl, get } = getApp(); const { marketurl, get, globalData } = getApp();
const { const {
data: { code, data }, data: { code, data },
} = await get(`${marketurl}/coupon/coupon/info?couponId=${couponId}`); } = await get(`${marketurl}/coupon/coupon/info?couponId=${couponId}`, {
Authorization: `Bearer ${globalData.user.access_token}`,
});
if (code === 200) { if (code === 200) {
console.log("券详情", data); console.log("券详情", data);
if (data.leftQuantity > 0) return true; // 检查库存
return false; if (data.leftQuantity <= 0) {
console.log("券库存不足", data.leftQuantity);
return false;
}
// 检查有效期
const now = new Date();
const openStart = new Date(data.openStart);
const openEnd = new Date(data.openEnd);
if (now < openStart || now > openEnd) {
console.log("券未到领取时间", openStart, openEnd);
return false;
}
// 检查领取限制
if (data.recordSize >= data.receiveLimit) {
console.log("券到达领取限制", data.recordSize, data.receiveLimit);
return false;
}
return true;
} else { } else {
return false; return false;
} }
...@@ -108,24 +216,40 @@ Page({ ...@@ -108,24 +216,40 @@ Page({
if (success) getApp().refreshCollection(); if (success) getApp().refreshCollection();
console.log(`自动收藏poi${success ? "成功" : "失败"}`); console.log(`自动收藏poi${success ? "成功" : "失败"}`);
}, },
getEndPoi() { async getEndPoi() {
const { txQmMap, globalData, indexData } = getApp(); const app = getApp();
const { lastNav } = globalData; const { txQmMap, indexData, globalData } = app;
const { latitude, longitude, floorName } = lastNav.endPoint; // 防御性编程:防止 lastNav 为空报错
const endPoint = globalData.lastNav?.endPoint;
if (!endPoint) return null;
const { latitude, longitude, floorName } = endPoint;
try { try {
const list = findNearbyLocations( // 1. 查找最近点 (利用 indexData 空间索引)
const [shineiId] = findNearbyLocations(
latitude, latitude,
longitude, longitude,
floorName, floorName,
indexData indexData,
); );
if (list.length) { const baseInfo = txQmMap?.[shineiId];
console.log("txQmMap[list[0]]", txQmMap[list[0]]);
return txQmMap[list[0]]; // 2. 没找到基础信息,直接返回
} else { if (!baseInfo) return null;
return null;
} // 3. 动态查询详情
// facilityId 存在与否推断 "2"(设施) 或 "1"(店铺)
const poi = await app.poiApi.getOne({
shopType: baseInfo.facilityId ? "2" : "1",
shopId: baseInfo.shopId || baseInfo.facilityId,
boothNo: baseInfo.boothNo,
});
console.log("getEndPoi result:", poi);
return poi;
} catch (error) { } catch (error) {
console.error("getEndPoi error:", error);
return null; return null;
} }
}, },
...@@ -140,7 +264,7 @@ Page({ ...@@ -140,7 +264,7 @@ Page({
{ {
Authorization: `Bearer ${globalData.user.access_token}`, Authorization: `Bearer ${globalData.user.access_token}`,
userId: globalData.user.user.userId, userId: globalData.user.user.userId,
} },
); );
if (code === 20000) { if (code === 20000) {
console.log("积分领取成功" + message); console.log("积分领取成功" + message);
...@@ -162,13 +286,13 @@ Page({ ...@@ -162,13 +286,13 @@ Page({
const { poi, couponId } = this.data; const { poi, couponId } = this.data;
getApp().sensors?.track("ActivityCouponClick", { getApp().sensors?.track("ActivityCouponClick", {
is_receive: true, is_receive: true,
short_market_name: "二区东",
coupon_record_id: couponId, coupon_record_id: couponId,
...(poi.facilityId ...(poi.facilityId
? { ? {
booth_floor: poi.tx.poi_fl_seq, booth_floor: poi.tx.poi_fl_seq,
} }
: { : {
short_market_name: poi.ywZh.marketNameDtl,
booth_addr_street: poi.ywZh.boothAddrStreet, booth_addr_street: poi.ywZh.boothAddrStreet,
industry: poi.ywZh.frontIndustryCategory, industry: poi.ywZh.frontIndustryCategory,
booth_floor: poi.ywZh.addrFloor, booth_floor: poi.ywZh.addrFloor,
...@@ -186,7 +310,7 @@ Page({ ...@@ -186,7 +310,7 @@ Page({
{}, {},
{ {
Authorization: `Bearer ${globalData.user.access_token}`, Authorization: `Bearer ${globalData.user.access_token}`,
} },
); );
if (code === 200) { if (code === 200) {
this.setData({ showTip2: false, showTip3: true }); this.setData({ showTip2: false, showTip3: true });
...@@ -210,13 +334,13 @@ Page({ ...@@ -210,13 +334,13 @@ Page({
const { poi, couponId } = this.data; const { poi, couponId } = this.data;
getApp().sensors?.track("ActivityCouponClick", { getApp().sensors?.track("ActivityCouponClick", {
is_receive: false, is_receive: false,
short_market_name: "二区东",
coupon_record_id: couponId, coupon_record_id: couponId,
...(poi.facilityId ...(poi.facilityId
? { ? {
booth_floor: poi.tx.poi_fl_seq, booth_floor: poi.tx.poi_fl_seq,
} }
: { : {
short_market_name: poi.ywZh.marketNameDtl,
booth_addr_street: poi.ywZh.boothAddrStreet, booth_addr_street: poi.ywZh.boothAddrStreet,
industry: poi.ywZh.frontIndustryCategory, industry: poi.ywZh.frontIndustryCategory,
booth_floor: poi.ywZh.addrFloor, booth_floor: poi.ywZh.addrFloor,
...@@ -227,6 +351,12 @@ Page({ ...@@ -227,6 +351,12 @@ Page({
} }
this.setData({ showTip2: false }); this.setData({ showTip2: false });
}, },
closeTip4() {
this.setData({ showTip4: false });
},
closePois() {
this.setData({ pois: null });
},
doNothing() {}, doNothing() {},
onReady() {}, onReady() {},
...@@ -244,9 +374,7 @@ Page({ ...@@ -244,9 +374,7 @@ Page({
* 生命周期函数--监听页面卸载 * 生命周期函数--监听页面卸载
*/ */
onUnload() { onUnload() {
wx.reLaunch({ getApp().blurPoi();
url: "/pages/index/index",
});
}, },
/** /**
...@@ -265,8 +393,8 @@ Page({ ...@@ -265,8 +393,8 @@ Page({
onShareAppMessage() { onShareAppMessage() {
return { return {
title: this.data.isEn title: this.data.isEn
? "Share Chinagoods Nav District 2 East indoor navigation miniprogram" ? "Share Chinagoods Nav indoor navigation miniprogram"
: "分享义乌商贸城二区东室内导航小程序,助你场内高效找店", : "义乌小商品城市场室内导航,助您精准导航到店",
path: `/pages/index/index?fromshare=true`, path: `/pages/index/index?fromshare=true`,
imageUrl: this.data.isEn imageUrl: this.data.isEn
? `https://cdnimg.chinagoods.com/png/2025/08/13/qmzbxkjo3fse9xs5c2uujdc60tsc3wum.png` ? `https://cdnimg.chinagoods.com/png/2025/08/13/qmzbxkjo3fse9xs5c2uujdc60tsc3wum.png`
......
{ {
"usingComponents": {} "usingComponents": {
"shop-maingoods": "/components/shop-maingoods/index",
"shop-addr": "/components/shop-addr/index",
"shop-name": "/components/shop-name/index"
}
} }
...@@ -251,6 +251,218 @@ ...@@ -251,6 +251,218 @@
z-index: 3; z-index: 3;
} }
} }
.tip4 {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
z-index: 4;
.coupon {
position: absolute;
top: 77px;
left: 0;
right: 0;
margin: auto;
width: 304px;
height: 390px;
z-index: 1;
}
.close {
position: absolute;
display: flex;
top: 515px;
left: 0;
right: 0;
margin: auto;
width: 32px;
height: 32px;
justify-content: center;
align-items: center;
border-radius: 24px;
border: 1px solid rgba(0, 0, 0, 0.06);
background: rgba(0, 0, 0, 0.06);
backdrop-filter: blur(4px);
z-index: 3;
}
}
.pois {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
z-index: 4;
.pois-inner {
position: absolute;
width: 302px;
left: 0;
right: 0;
top: 63px;
margin: auto;
background: #fff;
border-radius: 8px;
overflow: hidden;
.top-bg {
position: absolute;
top: 0;
right: 0;
width: 203px;
height: 212px;
z-index: 1;
}
.close {
position: absolute;
display: flex;
top: 10px;
right: 10px;
width: 32px;
height: 32px;
justify-content: center;
align-items: center;
border-radius: 24px;
background: rgba(0, 0, 0, 0.06);
z-index: 3;
}
.top {
position: relative;
z-index: 2;
padding: 20px 16px;
.avatar {
width: 96px;
height: 96px;
}
.t1 {
color: #333;
font-family: "PingFang SC";
font-size: 18px;
font-style: normal;
font-weight: 600;
line-height: 24px;
margin-top: 10px;
}
.t2 {
color: #666;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 16px;
margin-top: 6px;
}
.t3 {
color: #666;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 18px;
margin-top: 6px;
}
.row {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 18px;
.dis {
display: flex;
align-items: baseline;
color: #333;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 16px;
.v {
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 22px;
color: #e92927;
}
}
.go {
display: flex;
width: 174px;
height: 38px;
border-radius: 99px;
background: linear-gradient(90deg, #fa643c 0%, #e92927 100%);
gap: 4px;
align-items: center;
justify-content: center;
color: #fff;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 600;
line-height: 18px;
}
}
}
.list {
background: #f3f3f3;
height: 220px;
.inner {
padding: 16px;
.t1 {
color: #333;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 600;
line-height: 18px;
margin-bottom: 12px;
}
.item {
display: flex;
align-items: center;
padding: 8px 12px 8px 8px;
height: 56px;
margin-bottom: 8px;
border-radius: 10px;
background: linear-gradient(180deg, #fff 0%, #fff 100%);
.avatar {
width: 40px;
height: 40px;
border-radius: 8px;
}
.name {
flex: 1;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #333;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 600;
line-height: normal;
padding: 0 8px;
}
.go {
display: flex;
align-items: center;
justify-content: center;
width: 64px;
height: 31px;
border-radius: 99px;
background: linear-gradient(90deg, #fa643c 0%, #e92927 100%);
color: #fff3f3;
text-align: center;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 600;
line-height: normal;
}
}
}
}
}
}
.size-20 { .size-20 {
width: 20px; width: 20px;
height: 20px; height: 20px;
......
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
<view class="t1">积分领取成功!</view> <view class="t1">积分领取成功!</view>
<view class="t2">导航到店积分福利已发放至您的会员账户</view> <view class="t2">导航到店积分福利已发放至您的会员账户</view>
</view> </view>
<view class="tip2" bing:tap="closeTip2" wx:if="{{showTip2}}"> <view class="tip2" bind:tap="closeTip2" wx:if="{{showTip2}}">
<image class="coupon" src="https://cdnimg.chinagoods.com/png/2025/08/05/tokz4ivypgnaljlau3juad1zq2zgf2o4.png" mode="" catch:tap="doNothing" /> <image class="coupon" src="https://cdnimg.chinagoods.com/png/2025/08/05/tokz4ivypgnaljlau3juad1zq2zgf2o4.png" mode="" catch:tap="doNothing" />
<image catch:tap="receiveCoupon" class="btn" src="./btn.png" mode="" /> <image catch:tap="receiveCoupon" class="btn" src="./btn.png" mode="" />
<view class="close" catch:tap="closeTip2"> <view class="close" catch:tap="closeTip2">
...@@ -64,4 +64,63 @@ ...@@ -64,4 +64,63 @@
<view class="t1">领取成功!</view> <view class="t1">领取成功!</view>
<view class="t2">活动券将发放您的会员账户</view> <view class="t2">活动券将发放您的会员账户</view>
</view> </view>
<view class="tip4" bind:tap="closeTip4" wx:if="{{showTip4}}">
<image class="coupon" src="https://cdnimg.chinagoods.com/png/2025/12/19/gnu2fvvbgoe6jvpt984ls43qocmldhad.png" mode="" catch:tap="doNothing" />
<view class="close" catch:tap="closeTip4">
<image class="size-20" src="./close.png" mode="" />
</view>
</view>
<view class="pois" wx:if="{{pois}}" catch:tap="closePois">
<view class="pois-inner" catch:tap="doNothing">
<image class="top-bg" src="https://cdnimg.chinagoods.com/png/2025/12/19/gq8chjlyczzz7rvadgnwgys0daeq2smq.png" mode="" />
<view class="close" catch:tap="closePois">
<image class="size-20" src="./close-black.png" mode="" />
</view>
<view class="top">
<image class="avatar" src="{{pois[0].poiAvatar}}" mode="aspectFill" />
<block wx:if="{{pois[0].poi.facility}}">
<view class="t1">
{{isEn?pois[0].poi.facility.nameEn:pois[0].poi.facility.name}}
</view>
<view class="t2">{{isEn?pois[0].poi.facility.addressEn:pois[0].poi.facility.address}}</view>
</block>
<block wx:else>
<view class="t1">
<shop-name shop="{{pois[0].poi}}"></shop-name>
</view>
<view class="t2">
<shop-addr shop="{{pois[0].poi}}"></shop-addr>
</view>
<view class="t3">
<shop-maingoods shop="{{pois[0].poi}}"></shop-maingoods>
</view>
</block>
<view class="row">
<view class="dis">{{!pois[0].distance?'':isEn?'':'距您:'}}
<view wx:if="{{pois[0].distance}}" class="v">{{pois[0].distance}}m</view>
{{!pois[0].distance?'':isEn?' away':''}}
</view>
<view class="go" bind:tap="handleGo" id="{{pois[0].shopId}}">
<image class="size-20" src="./go.png" mode="" />
<view>{{isEn?'Check in':'去打卡'}}</view>
</view>
</view>
</view>
<scroll-view class="list" wx:if="{{pois.length>1}}" scroll-y>
<view class="inner">
<view class="t1">{{isEn?'Other Check-in Spots':'其它打卡点'}}</view>
<view class="item" wx:for="{{pois}}" wx:key="shopId" wx:if="{{index!==0}}">
<image class="avatar" src="{{item.poiAvatar}}" mode="" />
<view class="name" wx:if="{{item.poi.facility}}">
{{isEn?item.poi.facility.nameEn:item.poi.facility.name}}
</view>
<view class="name" wx:else>
<shop-name shop="{{item.poi}}"></shop-name>
</view>
<view class="go" id="{{item.shopId}}" bind:tap="handleGo">{{isEn?'Check in':'去打卡'}}</view>
</view>
</view>
</scroll-view>
</view>
</view>
</view> </view>
\ No newline at end of file
...@@ -2,56 +2,36 @@ import langBehavior from "../../behaviors/langBehavior"; ...@@ -2,56 +2,36 @@ import langBehavior from "../../behaviors/langBehavior";
import poiFocusBehavior from "../../behaviors/poiFocusBehavior"; import poiFocusBehavior from "../../behaviors/poiFocusBehavior";
import modalBehavior from "../../behaviors/modalBehavior"; import modalBehavior from "../../behaviors/modalBehavior";
import { getShopShareTitle, getFacilityShareTitle } from "../../util"; import { getShopShareTitle, getFacilityShareTitle } from "../../util";
const app = getApp();
Page({ Page({
behaviors: [langBehavior, poiFocusBehavior, modalBehavior], behaviors: [langBehavior, poiFocusBehavior, modalBehavior],
data: { data: {
buildingId: "3307001549220",
floorName: "1F", floorName: "1F",
floors: [ floors: [],
{ floorName: "3F", displayName: "3F" },
{ floorName: "2F", displayName: "2F" },
{ floorName: "1F", displayName: "1F" },
],
resetCount: 0, resetCount: 0,
userLocation: null, userLocation: null,
reseting: false, reseting: false,
acts: [],
}, },
async onLoad({ shopId, facilityId }) { async onLoad({ shopId, boothNo, facilityId, isCardNav }) {
const app = getApp(); app.isCardNav = !!isCardNav;
if (shopId) {
if (!app.shopIdMap) { if (boothNo) {
app.events.once("globalData", () => { const shop = await app.poiApi.getOne({ shopType: "1", shopId, boothNo });
const shop = app.shopIdMap[shopId]; if (shop) {
if (shop) { this.setStateByPoi(shop);
if (shop.tx) this.setData({ floorName: shop.tx.poi_fl_name });
app.focusPoi(shop);
}
});
} else {
const shop = app.shopIdMap[shopId];
if (shop) {
if (shop.tx) this.setData({ floorName: shop.tx.poi_fl_name });
app.focusPoi(shop);
}
} }
} } else if (shopId) {
if (facilityId) { const shop = await app.poiApi.getOne({ shopType: "1", shopId });
if (!app.facilityIdMap) { if (shop) {
app.events.once("globalData", () => { this.setStateByPoi(shop);
const facility = app.facilityIdMap[facilityId]; }
if (facility) { } else if (facilityId) {
if (facility.tx) const facility = await app.poiApi.getOne({
this.setData({ floorName: facility.tx.poi_fl_name }); shopType: "2",
app.focusPoi(facility); shopId: facilityId,
} });
}); if (facility) {
} else { this.setStateByPoi(facility);
const facility = app.facilityIdMap[facilityId];
if (facility) {
if (facility.tx) this.setData({ floorName: facility.tx.poi_fl_name });
app.focusPoi(facility);
}
} }
} }
this.setUserLocation = () => { this.setUserLocation = () => {
...@@ -60,6 +40,27 @@ Page({ ...@@ -60,6 +40,27 @@ Page({
getApp().events.on("userLocation", this.setUserLocation); getApp().events.on("userLocation", this.setUserLocation);
this.setUserLocation(); this.setUserLocation();
}, },
setStateByPoi(poi) {
const app = getApp();
if (poi?.tx) {
const building = app.buildings.find(
({ buildingId }) => buildingId === poi?.tx?.bld_id,
);
this.setData({
floors: building?.floors,
buildingId: poi.tx.bld_id,
floorName: poi.tx.poi_fl_name,
});
} else {
const building = app.currentBuilding;
this.setData({
floors: building.floors,
buildingId: building.buildingId,
floorName: building.floors[0],
});
}
app.focusPoi(poi);
},
onUnload() { onUnload() {
if (this.setUserLocation) if (this.setUserLocation)
getApp().events.off("userLocation", this.setUserLocation); getApp().events.off("userLocation", this.setUserLocation);
......
import poiFocusBehavior from "../../../behaviors/poiFocusBehavior"; import poiFocusBehavior from "../../../behaviors/poiFocusBehavior";
const defaultScale = 20; const defaultScale = 20;
const defaultRotate = 329; const defaultRotate = 329;
const defaultLatitude = 29.331723;
const defaultLongitude = 120.106838;
const defaultSkew = 30; const defaultSkew = 30;
Component({ Component({
...@@ -16,12 +14,12 @@ Component({ ...@@ -16,12 +14,12 @@ Component({
}, },
data: { data: {
latitude: defaultLatitude, latitude: getApp().currentBuilding.latlng.lat,
longitude: defaultLongitude, longitude: getApp().currentBuilding.latlng.lng,
setting: { setting: {
skew: defaultSkew, skew: defaultSkew,
rotate: defaultRotate, rotate: defaultRotate,
scale: defaultScale, scale: getApp().currentBuilding.scale,
}, },
}, },
observers: { observers: {
...@@ -32,33 +30,6 @@ Component({ ...@@ -32,33 +30,6 @@ Component({
this.setIndoorFloor(); this.setIndoorFloor();
this.handleModel(); this.handleModel();
}, },
"floorName,acts"() {
this.setData({
markers: this.data.acts
.filter(({ floor_name }) => floor_name === this.data.floorName)
.map(({ latitude, longitude, short_name, id }) => ({
id,
latitude,
longitude,
iconPath: "./actMarker.png",
width: 1,
height: 1,
zIndex: 1,
callout: {
content: short_name,
color: "#E92927",
fontSize: 12,
bgColor: "#ffffff",
padding: 6,
borderRadius: 100,
borderWidth: 1,
borderColor: "#eeeeee",
textAlign: "center",
display: "ALWAYS",
},
})),
});
},
focusedPoi(poi) { focusedPoi(poi) {
try { try {
if (!poi) { if (!poi) {
...@@ -118,6 +89,16 @@ Component({ ...@@ -118,6 +89,16 @@ Component({
}) })
); );
}, 500); }, 500);
} else {
this.setData({
latitude: getApp().currentBuilding.latlng.lat,
longitude: getApp().currentBuilding.latlng.lng,
setting: {
skew: defaultSkew,
rotate: defaultRotate,
scale: getApp().currentBuilding.scale,
},
});
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论