305 lines
9.1 KiB
JavaScript
305 lines
9.1 KiB
JavaScript
|
|
const fortuneStore = require("../../store/fortuneStore");
|
||
|
|
const messages = require("../../constants/messages");
|
||
|
|
const { analyzeFortune } = require("../../services/fortuneService");
|
||
|
|
const { showRewardedVideoAd } = require("../../utils/adService");
|
||
|
|
const { getPageSafeTop } = require("../../utils/safeArea");
|
||
|
|
const { formatRegionDisplay, deriveRegionFromParts, getRegionParts, normalizeRegionArray } = require("../../utils/region");
|
||
|
|
|
||
|
|
const LOADING_HINTS = [
|
||
|
|
"正在推演今日天干地支,请稍候...",
|
||
|
|
"为你梳理六维度能量波动...",
|
||
|
|
"结合命盘与今日日运,编排最佳行动节奏..."
|
||
|
|
];
|
||
|
|
|
||
|
|
function showToast(title) {
|
||
|
|
if (typeof tt === "undefined" || !tt.showToast) {
|
||
|
|
console.warn("Toast:", title);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
tt.showToast({
|
||
|
|
title,
|
||
|
|
icon: "none",
|
||
|
|
duration: 2000
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
Page({
|
||
|
|
data: {
|
||
|
|
birthDate: "",
|
||
|
|
birthTime: "",
|
||
|
|
selectedCity: "",
|
||
|
|
selectedProvince: "",
|
||
|
|
selectedDistrict: "",
|
||
|
|
regionValue: [],
|
||
|
|
regionDisplay: "",
|
||
|
|
isSubmitting: false,
|
||
|
|
isLoading: false,
|
||
|
|
loadingMessage: "",
|
||
|
|
safeAreaTop: 64,
|
||
|
|
tips: [
|
||
|
|
"建议每天专注测算一次,深度分析更精准",
|
||
|
|
"填写精确城市,可获得更贴近地域气场的指引",
|
||
|
|
"保持心态稳定,才能更好接住好运"
|
||
|
|
],
|
||
|
|
tipIndex: 0
|
||
|
|
},
|
||
|
|
onLoad() {
|
||
|
|
const { form } = fortuneStore.getState();
|
||
|
|
const persistedRegion = normalizeRegionArray(form.birthRegion);
|
||
|
|
const regionValue = persistedRegion.length ? persistedRegion : this.getInitialRegionValue(form);
|
||
|
|
const parts = getRegionParts(regionValue, {
|
||
|
|
province: form.birthProvince,
|
||
|
|
city: form.birthCity,
|
||
|
|
district: form.birthDistrict
|
||
|
|
});
|
||
|
|
this.setData({
|
||
|
|
birthDate: form.birthDate,
|
||
|
|
birthTime: form.birthTime,
|
||
|
|
selectedProvince: parts.province,
|
||
|
|
selectedCity: parts.city,
|
||
|
|
selectedDistrict: parts.district,
|
||
|
|
regionValue,
|
||
|
|
regionDisplay: formatRegionDisplay(regionValue, [parts.province, parts.city, parts.district]),
|
||
|
|
tipIndex: Math.floor(Math.random() * this.data.tips.length)
|
||
|
|
});
|
||
|
|
if (!persistedRegion.length && regionValue.length && parts.city) {
|
||
|
|
fortuneStore.setForm({
|
||
|
|
birthProvince: parts.province,
|
||
|
|
birthCity: parts.city,
|
||
|
|
birthDistrict: parts.district,
|
||
|
|
birthRegion: regionValue
|
||
|
|
});
|
||
|
|
}
|
||
|
|
this.updateSafeAreaPadding();
|
||
|
|
},
|
||
|
|
getInitialRegionValue(form) {
|
||
|
|
return deriveRegionFromParts({
|
||
|
|
province: form.birthProvince,
|
||
|
|
city: form.birthCity,
|
||
|
|
district: form.birthDistrict
|
||
|
|
});
|
||
|
|
},
|
||
|
|
updateSafeAreaPadding() {
|
||
|
|
const padding = getPageSafeTop();
|
||
|
|
this.setData({ safeAreaTop: padding });
|
||
|
|
},
|
||
|
|
resetRegionState() {
|
||
|
|
this.setData({
|
||
|
|
regionValue: [],
|
||
|
|
selectedProvince: "",
|
||
|
|
selectedCity: "",
|
||
|
|
selectedDistrict: "",
|
||
|
|
regionDisplay: ""
|
||
|
|
});
|
||
|
|
},
|
||
|
|
syncRegion(regionValue, fallbackParts = {}, options = {}) {
|
||
|
|
let normalized = normalizeRegionArray(regionValue);
|
||
|
|
if (!normalized.length) {
|
||
|
|
normalized = deriveRegionFromParts(fallbackParts);
|
||
|
|
}
|
||
|
|
const parts = getRegionParts(normalized, fallbackParts);
|
||
|
|
if (!parts.city) {
|
||
|
|
if (options.resetOnEmpty) {
|
||
|
|
this.resetRegionState();
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
this.setData({
|
||
|
|
regionValue: normalized,
|
||
|
|
selectedProvince: parts.province,
|
||
|
|
selectedCity: parts.city,
|
||
|
|
selectedDistrict: parts.district,
|
||
|
|
regionDisplay: formatRegionDisplay(normalized, [parts.province, parts.city, parts.district])
|
||
|
|
});
|
||
|
|
if (options.persist !== false) {
|
||
|
|
fortuneStore.setForm({
|
||
|
|
birthProvince: parts.province,
|
||
|
|
birthCity: parts.city,
|
||
|
|
birthDistrict: parts.district,
|
||
|
|
birthRegion: normalized
|
||
|
|
});
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
},
|
||
|
|
handleDateChange(event) {
|
||
|
|
const value = event.detail.value;
|
||
|
|
this.setData({ birthDate: value });
|
||
|
|
fortuneStore.setForm({ birthDate: value });
|
||
|
|
},
|
||
|
|
handleTimeChange(event) {
|
||
|
|
const value = event.detail.value;
|
||
|
|
this.setData({ birthTime: value });
|
||
|
|
fortuneStore.setForm({ birthTime: value });
|
||
|
|
},
|
||
|
|
handleRegionChange(event) {
|
||
|
|
const value = event.detail.value || [];
|
||
|
|
this.syncRegion(value, {}, { resetOnEmpty: true });
|
||
|
|
},
|
||
|
|
handleLocate() {
|
||
|
|
if (typeof tt === "undefined" || !tt.chooseLocation) {
|
||
|
|
showToast("当前端暂不支持定位");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
tt.chooseLocation({
|
||
|
|
success: (res) => {
|
||
|
|
const city = this.extractCity(res.address || res.name || "");
|
||
|
|
if (!city) {
|
||
|
|
showToast("未能识别所在城市,请通过选择器选择");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const segments = this.parseAddressSegments(res);
|
||
|
|
const fallback = {
|
||
|
|
province: segments[0] || res.province || "",
|
||
|
|
city,
|
||
|
|
district: segments[2] || res.district || ""
|
||
|
|
};
|
||
|
|
this.syncRegion(segments, fallback, { resetOnEmpty: true });
|
||
|
|
},
|
||
|
|
fail: () => {
|
||
|
|
showToast("定位失败,请检查权限后重试");
|
||
|
|
}
|
||
|
|
});
|
||
|
|
},
|
||
|
|
extractCity(text) {
|
||
|
|
if (!text) {
|
||
|
|
return "";
|
||
|
|
}
|
||
|
|
const cityMatch = text.match(/([\u4e00-\u9fa5]+?(市|自治州|地区|盟))/);
|
||
|
|
if (cityMatch) {
|
||
|
|
return cityMatch[1];
|
||
|
|
}
|
||
|
|
const districtMatch = text.match(/([\u4e00-\u9fa5]+?(区|县))/);
|
||
|
|
if (districtMatch) {
|
||
|
|
return districtMatch[1].replace(/(区|县)$/, "市");
|
||
|
|
}
|
||
|
|
return "";
|
||
|
|
},
|
||
|
|
parseAddressSegments(locationResult) {
|
||
|
|
const segments = [];
|
||
|
|
const province = locationResult.province || "";
|
||
|
|
const city = locationResult.city || "";
|
||
|
|
const address = locationResult.address || "";
|
||
|
|
const text = `${province}${city}${address}`;
|
||
|
|
const provinceMatch = text.match(/([\u4e00-\u9fa5]+?(省|自治区|特别行政区))/);
|
||
|
|
const cityMatch = text.match(/([\u4e00-\u9fa5]+?(市|自治州|地区|盟))/);
|
||
|
|
const districtMatch = text.match(/([\u4e00-\u9fa5]+?(区|县|市))/);
|
||
|
|
if (provinceMatch) {
|
||
|
|
segments.push(provinceMatch[1]);
|
||
|
|
}
|
||
|
|
if (cityMatch) {
|
||
|
|
segments.push(cityMatch[1]);
|
||
|
|
}
|
||
|
|
if (districtMatch && (!segments.length || segments[segments.length - 1] !== districtMatch[1])) {
|
||
|
|
segments.push(districtMatch[1]);
|
||
|
|
}
|
||
|
|
return segments;
|
||
|
|
},
|
||
|
|
handleGoHistory() {
|
||
|
|
if (typeof tt !== "undefined" && tt.navigateTo) {
|
||
|
|
tt.navigateTo({ url: "/pages/history/index" });
|
||
|
|
}
|
||
|
|
},
|
||
|
|
validateForm() {
|
||
|
|
const { birthDate, selectedCity } = this.data;
|
||
|
|
if (!birthDate || !selectedCity) {
|
||
|
|
showToast(messages.FORM_INCOMPLETE);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (selectedCity.length < 2) {
|
||
|
|
showToast(messages.CITY_INVALID);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (!fortuneStore.canGenerateToday()) {
|
||
|
|
showToast(messages.QUOTA_EXCEEDED);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
},
|
||
|
|
handleGenerate() {
|
||
|
|
if (this.data.isSubmitting) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (!this.validateForm()) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
this.setData({ isSubmitting: true });
|
||
|
|
showRewardedVideoAd()
|
||
|
|
.then(() => this.requestFortune())
|
||
|
|
.catch((error) => {
|
||
|
|
if (error && error.code === "ad_not_completed") {
|
||
|
|
showToast(messages.WATCH_AD_TO_CONTINUE);
|
||
|
|
} else {
|
||
|
|
showToast(messages.GENERATION_FAILED);
|
||
|
|
}
|
||
|
|
this.hideLoadingOverlay();
|
||
|
|
this.setData({ isSubmitting: false });
|
||
|
|
});
|
||
|
|
},
|
||
|
|
requestFortune() {
|
||
|
|
const payload = {
|
||
|
|
birthDate: this.data.birthDate,
|
||
|
|
birthTime: this.data.birthTime || "",
|
||
|
|
birthProvince: this.data.selectedProvince,
|
||
|
|
birthCity: this.data.selectedCity,
|
||
|
|
birthDistrict: this.data.selectedDistrict,
|
||
|
|
birthRegion: Array.isArray(this.data.regionValue) ? this.data.regionValue.slice() : []
|
||
|
|
};
|
||
|
|
this.showLoadingOverlay();
|
||
|
|
return analyzeFortune(payload)
|
||
|
|
.then((response) => {
|
||
|
|
|
||
|
|
if (!response) {
|
||
|
|
showToast(messages.GENERATION_FAILED);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
fortuneStore.setCurrentFortune(response);
|
||
|
|
fortuneStore.incrementQuota();
|
||
|
|
fortuneStore.appendHistory(
|
||
|
|
{
|
||
|
|
birthDate: payload.birthDate,
|
||
|
|
birthTime: payload.birthTime,
|
||
|
|
birthProvince: payload.birthProvince,
|
||
|
|
birthCity: payload.birthCity,
|
||
|
|
birthDistrict: payload.birthDistrict,
|
||
|
|
birthRegion: payload.birthRegion
|
||
|
|
},
|
||
|
|
response
|
||
|
|
);
|
||
|
|
if (typeof tt !== "undefined" && tt.navigateTo) {
|
||
|
|
tt.navigateTo({ url: "/pages/result/index" });
|
||
|
|
}
|
||
|
|
})
|
||
|
|
.catch((error) => {
|
||
|
|
console.log(error)
|
||
|
|
const message = error && error.data && error.data.message;
|
||
|
|
if (message === "CONTENT_RISK") {
|
||
|
|
showToast(messages.CONTENT_RISK);
|
||
|
|
} else if (message === "BIRTHDATE_INVALID") {
|
||
|
|
showToast("出生日期格式异常,请重新选择");
|
||
|
|
} else {
|
||
|
|
showToast(messages.GENERATION_FAILED);
|
||
|
|
}
|
||
|
|
})
|
||
|
|
.finally(() => {
|
||
|
|
this.hideLoadingOverlay();
|
||
|
|
this.setData({ isSubmitting: false });
|
||
|
|
});
|
||
|
|
},
|
||
|
|
showLoadingOverlay() {
|
||
|
|
const hint = LOADING_HINTS[Math.floor(Math.random() * LOADING_HINTS.length)];
|
||
|
|
this.setData({
|
||
|
|
isLoading: true,
|
||
|
|
loadingMessage: hint
|
||
|
|
});
|
||
|
|
},
|
||
|
|
hideLoadingOverlay() {
|
||
|
|
if (!this.data.isLoading) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
this.setData({
|
||
|
|
isLoading: false,
|
||
|
|
loadingMessage: ""
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|