每日运势小程序
This commit is contained in:
77
DailyFortuneGuide/pages/history-detail/index.js
Normal file
77
DailyFortuneGuide/pages/history-detail/index.js
Normal file
@@ -0,0 +1,77 @@
|
||||
const fortuneStore = require("../../store/fortuneStore");
|
||||
const { normalizeFortunePayload } = require("../../utils/fortuneFormatter");
|
||||
const { formatDisplayDateTime } = require("../../utils/date");
|
||||
const messages = require("../../constants/messages");
|
||||
const { getPageSafeTop } = require("../../utils/safeArea");
|
||||
const { formatRegionDisplay, normalizeRegionArray } = require("../../utils/region");
|
||||
|
||||
function showToast(title) {
|
||||
if (typeof tt === "undefined" || !tt.showToast) {
|
||||
console.warn("Toast:", title);
|
||||
return;
|
||||
}
|
||||
tt.showToast({
|
||||
title,
|
||||
icon: "none",
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
|
||||
Page({
|
||||
data: {
|
||||
safeAreaTop: 64,
|
||||
recordTime: "",
|
||||
fortuneDate: "",
|
||||
summary: "",
|
||||
narrative: "",
|
||||
dimensions: [],
|
||||
luckyGuide: null,
|
||||
profile: null,
|
||||
overallScore: 0,
|
||||
city: ""
|
||||
},
|
||||
onLoad(options) {
|
||||
this.updateSafeAreaPadding();
|
||||
fortuneStore.loadHistory();
|
||||
const id = options && options.id ? options.id : "";
|
||||
if (!id) {
|
||||
showToast(messages.HISTORY_NOT_FOUND);
|
||||
this.safeBack();
|
||||
return;
|
||||
}
|
||||
const record = fortuneStore.getHistoryById(id);
|
||||
if (!record) {
|
||||
showToast(messages.HISTORY_NOT_FOUND);
|
||||
this.safeBack();
|
||||
return;
|
||||
}
|
||||
const normalized = normalizeFortunePayload(record.fortune);
|
||||
if (!normalized) {
|
||||
showToast(messages.HISTORY_NOT_FOUND);
|
||||
this.safeBack();
|
||||
return;
|
||||
}
|
||||
const snapshot = record.formSnapshot || {};
|
||||
const regionValue = normalizeRegionArray(snapshot.birthRegion);
|
||||
const fallbackSegments = [snapshot.birthProvince, snapshot.birthCity, snapshot.birthDistrict].filter(Boolean);
|
||||
const cityLabel = formatRegionDisplay(regionValue, fallbackSegments);
|
||||
this.setData(
|
||||
Object.assign({}, normalized, {
|
||||
recordTime: formatDisplayDateTime(record.createdAt),
|
||||
city: cityLabel || snapshot.birthCity || ""
|
||||
})
|
||||
);
|
||||
},
|
||||
handleBack() {
|
||||
this.safeBack();
|
||||
},
|
||||
updateSafeAreaPadding() {
|
||||
const padding = getPageSafeTop();
|
||||
this.setData({ safeAreaTop: padding });
|
||||
},
|
||||
safeBack() {
|
||||
if (typeof tt !== "undefined" && tt.navigateBack) {
|
||||
tt.navigateBack();
|
||||
}
|
||||
}
|
||||
});
|
||||
3
DailyFortuneGuide/pages/history-detail/index.json
Normal file
3
DailyFortuneGuide/pages/history-detail/index.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
112
DailyFortuneGuide/pages/history-detail/index.ttml
Normal file
112
DailyFortuneGuide/pages/history-detail/index.ttml
Normal file
@@ -0,0 +1,112 @@
|
||||
<view class="page">
|
||||
<scroll-view class="content" scroll-y="true" style="padding-top: {{safeAreaTop}}px;">
|
||||
<view class="record-card">
|
||||
<text class="record-label">保存时间</text>
|
||||
<text class="record-value">{{recordTime}}</text>
|
||||
<text class="record-label">测算城市</text>
|
||||
<text class="record-value">{{city}}</text>
|
||||
</view>
|
||||
|
||||
<view class="summary-card">
|
||||
<view class="summary-header">
|
||||
<view>
|
||||
<text class="summary-title">整体指数</text>
|
||||
<text class="summary-date">{{fortuneDate || '历史记录'}}</text>
|
||||
</view>
|
||||
<text class="summary-score">{{overallScore}}</text>
|
||||
</view>
|
||||
<text class="summary-text" tt:if="{{summary}}">{{summary}}</text>
|
||||
</view>
|
||||
|
||||
<view class="lucky-card" tt:if="{{luckyGuide}}">
|
||||
<view class="card-title">
|
||||
<text>吉祥元素</text>
|
||||
<text class="element-tag">{{luckyGuide.element}}</text>
|
||||
</view>
|
||||
<view class="guide-row" tt:if="{{luckyGuide.colorText}}">
|
||||
<text class="guide-label">幸运色</text>
|
||||
<text class="guide-value">{{luckyGuide.colorText}}</text>
|
||||
</view>
|
||||
<view class="guide-row" tt:if="{{luckyGuide.directionText}}">
|
||||
<text class="guide-label">方位</text>
|
||||
<text class="guide-value">{{luckyGuide.directionText}}</text>
|
||||
</view>
|
||||
<view class="guide-row" tt:if="{{luckyGuide.activitiesText}}">
|
||||
<text class="guide-label">建议</text>
|
||||
<text class="guide-value">{{luckyGuide.activitiesText}}</text>
|
||||
</view>
|
||||
<view class="time-slots" tt:if="{{luckyGuide.bestTimeSlots.length}}">
|
||||
<block tt:for="{{luckyGuide.bestTimeSlots}}" tt:key="label">
|
||||
<view class="time-slot">
|
||||
<text class="time-label">{{item.label}}</text>
|
||||
<text class="time-period">{{item.period}}</text>
|
||||
<text class="time-reason">{{item.reason}}</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="dimension-card" tt:if="{{dimensions.length}}">
|
||||
<view class="card-title">
|
||||
<text>六维运势</text>
|
||||
</view>
|
||||
<view class="dimension-grid">
|
||||
<block tt:for="{{dimensions}}" tt:key="key">
|
||||
<view class="dimension-item">
|
||||
<view class="dimension-header">
|
||||
<text class="dimension-icon">{{item.icon}}</text>
|
||||
<view>
|
||||
<text class="dimension-title">{{item.title}}</text>
|
||||
<text class="dimension-trend">{{item.trendText}}</text>
|
||||
</view>
|
||||
<text class="dimension-score">{{item.score}}</text>
|
||||
</view>
|
||||
<text class="dimension-insight">{{item.insight}}</text>
|
||||
<text class="dimension-suggestion">{{item.suggestion}}</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="profile-card" tt:if="{{profile}}">
|
||||
<view class="card-title">
|
||||
<text>命盘摘要</text>
|
||||
<text class="card-subtitle">{{profile.birthCity}}</text>
|
||||
</view>
|
||||
<view class="profile-row">
|
||||
<text class="profile-label">出生信息</text>
|
||||
<text class="profile-value">{{profile.birthDateTime}}</text>
|
||||
</view>
|
||||
<view class="pillars">
|
||||
<block tt:for="{{profile.birthPillars}}" tt:key="label">
|
||||
<view class="pillar">
|
||||
<text class="pillar-label">{{item.label}}</text>
|
||||
<text class="pillar-value">{{item.value}}</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
<view class="elements" tt:if="{{profile.distribution.length}}">
|
||||
<block tt:for="{{profile.distribution}}" tt:key="element">
|
||||
<view class="element-bar">
|
||||
<text class="element-label">{{item.element}}</text>
|
||||
<view class="bar-track">
|
||||
<view class="bar-fill" style="width: {{item.width}};"></view>
|
||||
</view>
|
||||
<text class="element-percent">{{item.percent}}%</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="narrative-card" tt:if="{{narrative}}">
|
||||
<view class="card-title">
|
||||
<text>解读</text>
|
||||
</view>
|
||||
<text class="narrative-text">{{narrative}}</text>
|
||||
</view>
|
||||
|
||||
<view class="actions">
|
||||
<button class="secondary" bindtap="handleBack">返回</button>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
21
DailyFortuneGuide/pages/history-detail/index.ttss
Normal file
21
DailyFortuneGuide/pages/history-detail/index.ttss
Normal file
@@ -0,0 +1,21 @@
|
||||
@import "../result/index.ttss";
|
||||
|
||||
.record-card {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-radius: 24rpx;
|
||||
padding: 28rpx;
|
||||
margin-bottom: 28rpx;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.record-label {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
.record-value {
|
||||
display: block;
|
||||
font-size: 30rpx;
|
||||
color: #fff7e3;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
51
DailyFortuneGuide/pages/history/index.js
Normal file
51
DailyFortuneGuide/pages/history/index.js
Normal file
@@ -0,0 +1,51 @@
|
||||
const fortuneStore = require("../../store/fortuneStore");
|
||||
const messages = require("../../constants/messages");
|
||||
const { formatDisplayDateTime } = require("../../utils/date");
|
||||
const { formatRegionDisplay, normalizeRegionArray } = require("../../utils/region");
|
||||
const { getPageSafeTop } = require("../../utils/safeArea");
|
||||
|
||||
Page({
|
||||
data: {
|
||||
safeAreaTop: 64,
|
||||
history: [],
|
||||
emptyText: messages.HISTORY_EMPTY
|
||||
},
|
||||
onLoad() {
|
||||
this.updateSafeAreaPadding();
|
||||
},
|
||||
onShow() {
|
||||
fortuneStore.loadHistory();
|
||||
const { history } = fortuneStore.getState();
|
||||
const normalized = history.map((item) => {
|
||||
const snapshot = item.formSnapshot || {};
|
||||
const fortune = item.fortune || {};
|
||||
const regionValue = normalizeRegionArray(snapshot.birthRegion);
|
||||
const fallbackSegments = [snapshot.birthProvince, snapshot.birthCity, snapshot.birthDistrict].filter(Boolean);
|
||||
const regionLabel = formatRegionDisplay(regionValue, fallbackSegments);
|
||||
const fortuneDate = fortune.fortuneDate || fortune.FortuneDate || "";
|
||||
const summary = fortune.summary || fortune.Summary || "";
|
||||
return {
|
||||
id: item.id,
|
||||
createdAt: item.createdAt,
|
||||
displayTime: formatDisplayDateTime(item.createdAt),
|
||||
city: regionLabel || snapshot.birthCity || snapshot.birthProvince || "",
|
||||
fortuneDate,
|
||||
summary
|
||||
};
|
||||
});
|
||||
this.setData({ history: normalized });
|
||||
},
|
||||
handleViewDetail(event) {
|
||||
const { id } = event.currentTarget.dataset;
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
if (typeof tt !== "undefined" && tt.navigateTo) {
|
||||
tt.navigateTo({ url: `/pages/history-detail/index?id=${id}` });
|
||||
}
|
||||
},
|
||||
updateSafeAreaPadding() {
|
||||
const padding = getPageSafeTop();
|
||||
this.setData({ safeAreaTop: padding });
|
||||
}
|
||||
});
|
||||
3
DailyFortuneGuide/pages/history/index.json
Normal file
3
DailyFortuneGuide/pages/history/index.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
19
DailyFortuneGuide/pages/history/index.ttml
Normal file
19
DailyFortuneGuide/pages/history/index.ttml
Normal file
@@ -0,0 +1,19 @@
|
||||
<view class="page">
|
||||
<scroll-view class="content" scroll-y="true" style="padding-top: {{safeAreaTop}}px;">
|
||||
<view class="empty" tt:if="{{!history.length}}">
|
||||
<text class="empty-text">{{emptyText}}</text>
|
||||
</view>
|
||||
|
||||
<block tt:for="{{history}}" tt:key="id">
|
||||
<view class="history-card" bindtap="handleViewDetail" data-id="{{item.id}}">
|
||||
<view class="card-header">
|
||||
<text class="card-date">{{item.displayTime}}</text>
|
||||
<text class="card-city">{{item.city}}</text>
|
||||
</view>
|
||||
<text class="card-summary" tt:if="{{item.summary}}">{{item.summary}}</text>
|
||||
<text class="card-summary" tt:else>鏈娴嬬畻宸蹭繚瀛橈紝鍙偣鍑绘煡鐪嬭鎯?/text>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
48
DailyFortuneGuide/pages/history/index.ttss
Normal file
48
DailyFortuneGuide/pages/history/index.ttss
Normal file
@@ -0,0 +1,48 @@
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
padding: 24rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.content {
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.empty {
|
||||
margin-top: 200rpx;
|
||||
text-align: center;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.history-card {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-radius: 22rpx;
|
||||
padding: 28rpx;
|
||||
margin-bottom: 24rpx;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.card-date {
|
||||
font-size: 26rpx;
|
||||
color: #ffead1;
|
||||
}
|
||||
|
||||
.card-city {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.card-summary {
|
||||
font-size: 26rpx;
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
line-height: 40rpx;
|
||||
}
|
||||
304
DailyFortuneGuide/pages/home/index.js
Normal file
304
DailyFortuneGuide/pages/home/index.js
Normal file
@@ -0,0 +1,304 @@
|
||||
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: ""
|
||||
});
|
||||
}
|
||||
});
|
||||
3
DailyFortuneGuide/pages/home/index.json
Normal file
3
DailyFortuneGuide/pages/home/index.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
84
DailyFortuneGuide/pages/home/index.ttml
Normal file
84
DailyFortuneGuide/pages/home/index.ttml
Normal file
@@ -0,0 +1,84 @@
|
||||
<view class="page">
|
||||
<view class="glow-layer">
|
||||
<view class="glow glow-one"></view>
|
||||
<view class="glow glow-two"></view>
|
||||
<view class="glow glow-three"></view>
|
||||
</view>
|
||||
|
||||
<view class="loading-overlay" tt:if="{{isLoading}}">
|
||||
<view class="loading-dialog">
|
||||
<view class="loading-spinner"></view>
|
||||
<text class="loading-text">{{loadingMessage}}</text>
|
||||
<text class="loading-subtext">深度推算无需久等,请保持耐心</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view class="content" scroll-y="true" style="padding-top: {{safeAreaTop}}px;">
|
||||
<view class="hero">
|
||||
<view class="hero-text">
|
||||
<text class="hero-label">行知节奏</text>
|
||||
<text class="hero-title">每日运势指南</text>
|
||||
<text class="hero-desc">结合八字命盘与当日天象,规划六维行动节奏</text>
|
||||
</view>
|
||||
<view class="hero-tags">
|
||||
<text class="tag">八字推演</text>
|
||||
<text class="tag">吉时提醒</text>
|
||||
<text class="tag">专属建议</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<view class="card-header">
|
||||
<text class="card-title">基础信息</text>
|
||||
<text class="card-subtitle">填写准确数据可提升推演可靠度</text>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="label">出生日期</text>
|
||||
<picker mode="date" value="{{birthDate}}" bindchange="handleDateChange">
|
||||
<view class="picker-value">{{birthDate}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="label">出生时间(可选)</text>
|
||||
<picker mode="time" value="{{birthTime}}" bindchange="handleTimeChange">
|
||||
<view class="picker-value {{birthTime ? '' : 'placeholder'}}">
|
||||
{{birthTime || '不清楚时间'}}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="label">出生城市</text>
|
||||
<view class="city-row">
|
||||
<picker mode="region" value="{{regionValue}}" bindchange="handleRegionChange">
|
||||
<view class="picker-value {{regionDisplay ? '' : 'placeholder'}}">
|
||||
{{regionDisplay || '请选择出生城市'}}
|
||||
</view>
|
||||
</picker>
|
||||
<!-- <button class="locate-btn" size="mini" plain="true" bindtap="handleLocate">定位</button> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card cta-card">
|
||||
<view class="cta-text">
|
||||
<text class="cta-title">结果生成</text>
|
||||
<text class="cta-subtitle">完成激励广告后立即开启</text>
|
||||
</view>
|
||||
<button
|
||||
class="primary"
|
||||
type="primary"
|
||||
bindtap="handleGenerate"
|
||||
loading="{{isSubmitting}}"
|
||||
disabled="{{isSubmitting}}"
|
||||
>
|
||||
观看广告后生成
|
||||
</button>
|
||||
<button class="secondary" bindtap="handleGoHistory">查看历史记录</button>
|
||||
</view>
|
||||
|
||||
<view class="card tips-card">
|
||||
<text class="tips-label">灵感提示</text>
|
||||
<text class="tips-text">{{tips[tipIndex]}}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
259
DailyFortuneGuide/pages/home/index.ttss
Normal file
259
DailyFortuneGuide/pages/home/index.ttss
Normal file
@@ -0,0 +1,259 @@
|
||||
.page {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
padding: 0 24rpx 80rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.glow-layer {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.glow {
|
||||
position: absolute;
|
||||
border-radius: 999px;
|
||||
filter: blur(120rpx);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.glow-one {
|
||||
width: 320rpx;
|
||||
height: 320rpx;
|
||||
top: 60rpx;
|
||||
right: -80rpx;
|
||||
background: #ff6ac1;
|
||||
}
|
||||
|
||||
.glow-two {
|
||||
width: 260rpx;
|
||||
height: 260rpx;
|
||||
bottom: 300rpx;
|
||||
left: -100rpx;
|
||||
background: #6c7bff;
|
||||
}
|
||||
|
||||
.glow-three {
|
||||
width: 220rpx;
|
||||
height: 220rpx;
|
||||
bottom: 80rpx;
|
||||
right: 20rpx;
|
||||
background: #48d2c0;
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hero {
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.hero-text {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.hero-label {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
letter-spacing: 4rpx;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
display: block;
|
||||
margin-top: 12rpx;
|
||||
font-size: 48rpx;
|
||||
font-weight: 700;
|
||||
color: #fff3d6;
|
||||
}
|
||||
|
||||
.hero-desc {
|
||||
display: block;
|
||||
font-size: 26rpx;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.hero-tags {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.tag {
|
||||
padding: 10rpx 26rpx;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
color: #fff;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-radius: 26rpx;
|
||||
padding: 32rpx;
|
||||
margin-bottom: 28rpx;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 30rpx;
|
||||
color: #fff9ea;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.card-subtitle {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
.form-item + .form-item {
|
||||
margin-top: 28rpx;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.65);
|
||||
margin-bottom: 12rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.picker-value {
|
||||
width: 100%;
|
||||
padding: 24rpx;
|
||||
min-height: 72rpx;
|
||||
border-radius: 20rpx;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
font-size: 30rpx;
|
||||
color: #fff7e3;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.city-row {
|
||||
/* display: flex; */
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.locate-btn {
|
||||
padding: 0 28rpx;
|
||||
height: 68rpx;
|
||||
line-height: 64rpx;
|
||||
border-radius: 22rpx;
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
color: #fff;
|
||||
font-size: 24rpx;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.cta-card .primary {
|
||||
margin-top: 24rpx;
|
||||
}
|
||||
|
||||
.cta-card .secondary {
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
.cta-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6rpx;
|
||||
}
|
||||
|
||||
.cta-title {
|
||||
font-size: 30rpx;
|
||||
color: #fff9ea;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.cta-subtitle {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.tips-card {
|
||||
margin-bottom: 80rpx;
|
||||
}
|
||||
|
||||
.tips-label {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.tips-text {
|
||||
display: block;
|
||||
margin-top: 12rpx;
|
||||
font-size: 28rpx;
|
||||
line-height: 42rpx;
|
||||
color: #fff7e3;
|
||||
}
|
||||
|
||||
.loading-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(5, 6, 15, 0.82);
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
.loading-dialog {
|
||||
width: 520rpx;
|
||||
padding: 48rpx 32rpx;
|
||||
border-radius: 32rpx;
|
||||
background: rgba(23, 27, 48, 0.92);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
margin: 0 auto 24rpx;
|
||||
border-radius: 50%;
|
||||
border: 6rpx solid rgba(255, 255, 255, 0.12);
|
||||
border-top-color: #ffb85c;
|
||||
animation: spin 1.2s linear infinite;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 30rpx;
|
||||
color: #fff9eb;
|
||||
}
|
||||
|
||||
.loading-subtext {
|
||||
margin-top: 12rpx;
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
63
DailyFortuneGuide/pages/result/index.js
Normal file
63
DailyFortuneGuide/pages/result/index.js
Normal file
@@ -0,0 +1,63 @@
|
||||
const fortuneStore = require("../../store/fortuneStore");
|
||||
const { normalizeFortunePayload } = require("../../utils/fortuneFormatter");
|
||||
const { getPageSafeTop } = require("../../utils/safeArea");
|
||||
|
||||
function showToast(title) {
|
||||
if (typeof tt === "undefined" || !tt.showToast) {
|
||||
console.warn("Toast:", title);
|
||||
return;
|
||||
}
|
||||
tt.showToast({
|
||||
title,
|
||||
icon: "none",
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
|
||||
Page({
|
||||
data: {
|
||||
safeAreaTop: 64,
|
||||
fortuneDate: "",
|
||||
summary: "",
|
||||
narrative: "",
|
||||
dimensions: [],
|
||||
luckyGuide: null,
|
||||
profile: null,
|
||||
overallScore: 0
|
||||
},
|
||||
onLoad() {
|
||||
this.updateSafeAreaPadding();
|
||||
const { currentFortune } = fortuneStore.getState();
|
||||
if (!currentFortune) {
|
||||
showToast("暂无结果,请返回重新生成");
|
||||
setTimeout(() => {
|
||||
if (typeof tt !== "undefined" && tt.navigateBack) {
|
||||
tt.navigateBack();
|
||||
}
|
||||
}, 1000);
|
||||
return;
|
||||
}
|
||||
const normalized = normalizeFortunePayload(currentFortune);
|
||||
if (normalized) {
|
||||
this.setData(normalized);
|
||||
}
|
||||
},
|
||||
updateSafeAreaPadding() {
|
||||
const padding = getPageSafeTop();
|
||||
this.setData({ safeAreaTop: padding });
|
||||
},
|
||||
handleBack() {
|
||||
if (typeof tt !== "undefined" && tt.navigateBack) {
|
||||
tt.navigateBack();
|
||||
return;
|
||||
}
|
||||
if (typeof tt !== "undefined" && tt.redirectTo) {
|
||||
tt.redirectTo({ url: "/pages/home/index" });
|
||||
}
|
||||
},
|
||||
handleGoHistory() {
|
||||
if (typeof tt !== "undefined" && tt.navigateTo) {
|
||||
tt.navigateTo({ url: "/pages/history/index" });
|
||||
}
|
||||
}
|
||||
});
|
||||
3
DailyFortuneGuide/pages/result/index.json
Normal file
3
DailyFortuneGuide/pages/result/index.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
122
DailyFortuneGuide/pages/result/index.ttml
Normal file
122
DailyFortuneGuide/pages/result/index.ttml
Normal file
@@ -0,0 +1,122 @@
|
||||
<view class="page">
|
||||
<view class="glow-bg"></view>
|
||||
<scroll-view class="content" scroll-y="true" style="padding-top: {{safeAreaTop}}px;">
|
||||
<view class="summary-card">
|
||||
<view class="summary-header">
|
||||
<view>
|
||||
<text class="summary-title">今日整体指数</text>
|
||||
<text class="summary-date">{{fortuneDate || '今日'}}</text>
|
||||
</view>
|
||||
<text class="summary-score">{{overallScore}}</text>
|
||||
</view>
|
||||
<text class="summary-text" tt:if="{{summary}}">{{summary}}</text>
|
||||
</view>
|
||||
|
||||
<view class="lucky-card" tt:if="{{luckyGuide}}">
|
||||
<view class="card-title">
|
||||
<text>吉祥元素</text>
|
||||
<text class="element-tag">{{luckyGuide.element}}</text>
|
||||
</view>
|
||||
<view class="guide-row" tt:if="{{luckyGuide.colorText}}">
|
||||
<text class="guide-label">幸运色</text>
|
||||
<text class="guide-value">{{luckyGuide.colorText}}</text>
|
||||
</view>
|
||||
<view class="guide-row" tt:if="{{luckyGuide.directionText}}">
|
||||
<text class="guide-label">顺势方位</text>
|
||||
<text class="guide-value">{{luckyGuide.directionText}}</text>
|
||||
</view>
|
||||
<view class="guide-row" tt:if="{{luckyGuide.propsText}}">
|
||||
<text class="guide-label">随身物件</text>
|
||||
<text class="guide-value">{{luckyGuide.propsText}}</text>
|
||||
</view>
|
||||
<view class="guide-row" tt:if="{{luckyGuide.activitiesText}}">
|
||||
<text class="guide-label">行动建议</text>
|
||||
<text class="guide-value">{{luckyGuide.activitiesText}}</text>
|
||||
</view>
|
||||
<view class="time-slots" tt:if="{{luckyGuide.bestTimeSlots.length}}">
|
||||
<block tt:for="{{luckyGuide.bestTimeSlots}}" tt:key="label">
|
||||
<view class="time-slot">
|
||||
<text class="time-label">{{item.label}}</text>
|
||||
<text class="time-period">{{item.period}}</text>
|
||||
<text class="time-reason">{{item.reason}}</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="dimension-card" tt:if="{{dimensions.length}}">
|
||||
<view class="card-title">
|
||||
<text>六维运势</text>
|
||||
<text class="card-subtitle">结合趋势安排节奏</text>
|
||||
</view>
|
||||
<view class="dimension-grid">
|
||||
<block tt:for="{{dimensions}}" tt:key="key">
|
||||
<view class="dimension-item">
|
||||
<view class="dimension-header">
|
||||
<text class="dimension-icon">{{item.icon}}</text>
|
||||
<view>
|
||||
<text class="dimension-title">{{item.title}}</text>
|
||||
<text class="dimension-trend">{{item.trendText}}</text>
|
||||
</view>
|
||||
<text class="dimension-score">{{item.score}}</text>
|
||||
</view>
|
||||
<text class="dimension-insight">{{item.insight}}</text>
|
||||
<text class="dimension-suggestion">{{item.suggestion}}</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="profile-card" tt:if="{{profile}}">
|
||||
<view class="card-title">
|
||||
<text>命盘摘要</text>
|
||||
<text class="card-subtitle">
|
||||
{{(profile.birthProvince ? profile.birthProvince + ' · ' : '') + profile.birthCity}}
|
||||
</text>
|
||||
</view>
|
||||
<view class="profile-row">
|
||||
<text class="profile-label">出生信息</text>
|
||||
<text class="profile-value">{{profile.birthDateTime}}</text>
|
||||
</view>
|
||||
<view class="pillars">
|
||||
<block tt:for="{{profile.birthPillars}}" tt:key="label">
|
||||
<view class="pillar">
|
||||
<text class="pillar-label">{{item.label}}</text>
|
||||
<text class="pillar-value">{{item.value}}</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
<view class="pillars today" tt:if="{{profile.todayPillars.length}}">
|
||||
<block tt:for="{{profile.todayPillars}}" tt:key="label">
|
||||
<view class="pillar">
|
||||
<text class="pillar-label">{{item.label}}</text>
|
||||
<text class="pillar-value">{{item.value}}</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
<view class="elements" tt:if="{{profile.distribution.length}}">
|
||||
<block tt:for="{{profile.distribution}}" tt:key="element">
|
||||
<view class="element-bar">
|
||||
<text class="element-label">{{item.element}}</text>
|
||||
<view class="bar-track">
|
||||
<view class="bar-fill" style="width: {{item.width}};"></view>
|
||||
</view>
|
||||
<text class="element-percent">{{item.percent}}%</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="narrative-card" tt:if="{{narrative}}">
|
||||
<view class="card-title">
|
||||
<text>AI 深度解读</text>
|
||||
</view>
|
||||
<text class="narrative-text">{{narrative}}</text>
|
||||
</view>
|
||||
|
||||
<view class="actions">
|
||||
<button class="primary" bindtap="handleGoHistory">查看历史记录</button>
|
||||
<button class="secondary" bindtap="handleBack">返回上一页</button>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
284
DailyFortuneGuide/pages/result/index.ttss
Normal file
284
DailyFortuneGuide/pages/result/index.ttss
Normal file
@@ -0,0 +1,284 @@
|
||||
.page {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
padding: 24rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.glow-bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: radial-gradient(120% 120% at 50% 0%, rgba(255, 106, 193, 0.2), transparent 70%);
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.summary-card,
|
||||
.lucky-card,
|
||||
.dimension-card,
|
||||
.profile-card,
|
||||
.narrative-card {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-radius: 24rpx;
|
||||
padding: 28rpx;
|
||||
margin-bottom: 28rpx;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.summary-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.summary-title {
|
||||
font-size: 30rpx;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.summary-date {
|
||||
display: block;
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.45);
|
||||
margin-top: 6rpx;
|
||||
}
|
||||
|
||||
.summary-score {
|
||||
font-size: 64rpx;
|
||||
font-weight: 700;
|
||||
color: #ffb85c;
|
||||
}
|
||||
|
||||
.summary-text {
|
||||
margin-top: 24rpx;
|
||||
font-size: 30rpx;
|
||||
line-height: 44rpx;
|
||||
color: #fff7e3;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20rpx;
|
||||
font-size: 30rpx;
|
||||
color: #fff7e3;
|
||||
}
|
||||
|
||||
.card-subtitle {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.element-tag {
|
||||
padding: 8rpx 20rpx;
|
||||
border-radius: 20rpx;
|
||||
background: rgba(255, 184, 92, 0.15);
|
||||
color: #ffb85c;
|
||||
}
|
||||
|
||||
.guide-row {
|
||||
display: flex;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.guide-label {
|
||||
width: 150rpx;
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
.guide-value {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #fff7e3;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
|
||||
.time-slots {
|
||||
margin-top: 16rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.time-slot {
|
||||
padding: 20rpx;
|
||||
border-radius: 18rpx;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
.time-label {
|
||||
font-size: 26rpx;
|
||||
color: #ffead1;
|
||||
}
|
||||
|
||||
.time-period {
|
||||
display: block;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
margin: 8rpx 0;
|
||||
}
|
||||
|
||||
.time-reason {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
.dimension-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.dimension-item {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
border-radius: 20rpx;
|
||||
padding: 20rpx;
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.dimension-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.dimension-icon {
|
||||
font-size: 36rpx;
|
||||
}
|
||||
|
||||
.dimension-title {
|
||||
font-size: 28rpx;
|
||||
color: #fff7e3;
|
||||
}
|
||||
|
||||
.dimension-trend {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.dimension-score {
|
||||
margin-left: auto;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #ffb85c;
|
||||
}
|
||||
|
||||
.dimension-insight {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
line-height: 36rpx;
|
||||
}
|
||||
|
||||
.dimension-suggestion {
|
||||
display: block;
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
.profile-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.profile-label {
|
||||
font-size: 26rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.profile-value {
|
||||
font-size: 26rpx;
|
||||
color: #fff7e3;
|
||||
}
|
||||
|
||||
.pillars {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 12rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.pillars.today {
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.pillar {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 16rpx;
|
||||
padding: 16rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pillar-label {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.pillar-value {
|
||||
font-size: 28rpx;
|
||||
color: #fff7e3;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.elements {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.element-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.element-label {
|
||||
width: 60rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.bar-track {
|
||||
flex: 1;
|
||||
height: 14rpx;
|
||||
border-radius: 8rpx;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.bar-fill {
|
||||
height: 100%;
|
||||
border-radius: 8rpx;
|
||||
background: linear-gradient(90deg, #ffb85c, #ff6ac1);
|
||||
}
|
||||
|
||||
.element-percent {
|
||||
width: 80rpx;
|
||||
text-align: right;
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.narrative-text {
|
||||
font-size: 28rpx;
|
||||
line-height: 44rpx;
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
margin: 40rpx 0 80rpx;
|
||||
}
|
||||
Reference in New Issue
Block a user