取名小程序
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
const config = {
|
||||
apiBaseUrl: "http://127.0.0.1:9291",
|
||||
maxDailyQuota: 10,
|
||||
adUnitId: ""
|
||||
adUnitId: "69nupig8os5l4kcqpz"
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
module.exports = {
|
||||
module.exports = {
|
||||
INVALID_SURNAME: "请输入合法姓氏",
|
||||
FORM_INCOMPLETE: "请完整填写必填项",
|
||||
WATCH_AD_TO_CONTINUE: "观看完整广告后才能生成姓名",
|
||||
QUOTA_EXCEEDED: "今日生成次数已用尽,请明日再试",
|
||||
GENERATION_FAILED: "生成失败,请稍后再试"
|
||||
};
|
||||
GENERATION_FAILED: "生成失败,请稍后再试",
|
||||
CONTENT_RISK: "输入内容存在风险,请调整后重试"
|
||||
};
|
||||
@@ -51,7 +51,7 @@
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
height: 100vh;
|
||||
padding: 48px 32px 120px;
|
||||
padding: 18px 12px 10px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -90,7 +90,8 @@
|
||||
.favorite-card {
|
||||
position: relative;
|
||||
background: linear-gradient(135deg, rgba(22, 28, 54, 0.85), rgba(32, 38, 68, 0.75));
|
||||
border-radius: 24px;
|
||||
border-radius: 14px;
|
||||
margin-top: 10px;
|
||||
padding: 26px 24px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
overflow: hidden;
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
const namingStore = require("../../store/namingStore");
|
||||
const namingStore = require("../../store/namingStore");
|
||||
const messages = require("../../constants/messages");
|
||||
const { validateSurname, generateName } = require("../../services/namingService");
|
||||
const { showRewardedVideoAd } = require("../../utils/adService");
|
||||
const config = require("../../config/index");
|
||||
|
||||
const LOADING_MESSAGES = [
|
||||
"AI 正在推演八字,请稍候...",
|
||||
"结合天干地支,为您筛选契合佳名...",
|
||||
"耐心等待,吉名正在汇聚灵感..."
|
||||
];
|
||||
|
||||
function showToast(title) {
|
||||
if (typeof tt === "undefined" || !tt.showToast) {
|
||||
console.warn("Toast:", title);
|
||||
@@ -25,7 +31,9 @@ Page({
|
||||
birthTime: "",
|
||||
nameLength: "double",
|
||||
isSubmitting: false,
|
||||
quotaRemaining: null
|
||||
quotaRemaining: null,
|
||||
isLoading: false,
|
||||
loadingMessage: ""
|
||||
},
|
||||
onLoad() {
|
||||
const { form, quota } = namingStore.getState();
|
||||
@@ -53,11 +61,13 @@ Page({
|
||||
}
|
||||
validateSurname(surname)
|
||||
.then((response) => {
|
||||
if (!response || response.isValid === false) {
|
||||
showToast(messages.INVALID_SURNAME);
|
||||
const isValid = response ? response.isValid !== false : true;
|
||||
const message = response && response.message ? response.message : messages.INVALID_SURNAME;
|
||||
if (!isValid) {
|
||||
showToast(message);
|
||||
this.setData({
|
||||
surname: "",
|
||||
surnameError: messages.INVALID_SURNAME
|
||||
surnameError: message
|
||||
});
|
||||
namingStore.setForm({ surname: "" });
|
||||
} else {
|
||||
@@ -132,6 +142,7 @@ Page({
|
||||
} else {
|
||||
showToast("广告加载失败,请稍后重试");
|
||||
}
|
||||
this.hideLoadingOverlay();
|
||||
this.setData({ isSubmitting: false });
|
||||
});
|
||||
},
|
||||
@@ -143,7 +154,8 @@ Page({
|
||||
birthTime: this.data.birthTime || "",
|
||||
nameLength: this.data.nameLength
|
||||
};
|
||||
generateName(payload)
|
||||
this.showLoadingOverlay();
|
||||
return generateName(payload)
|
||||
.then((response) => {
|
||||
const results = response && Array.isArray(response.results) ? response.results : [];
|
||||
const analysis = response && response.analysis ? response.analysis : null;
|
||||
@@ -177,11 +189,35 @@ Page({
|
||||
tt.navigateTo({ url: "/pages/result/index" });
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
showToast(messages.GENERATION_FAILED);
|
||||
.catch((error) => {
|
||||
const message = error && error.data && error.data.message;
|
||||
if (message === "CONTENT_RISK") {
|
||||
showToast(messages.CONTENT_RISK);
|
||||
} else if (message === "INVALID_SURNAME") {
|
||||
showToast(messages.INVALID_SURNAME);
|
||||
} else {
|
||||
showToast(messages.GENERATION_FAILED);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.hideLoadingOverlay();
|
||||
this.setData({ isSubmitting: false });
|
||||
});
|
||||
},
|
||||
showLoadingOverlay() {
|
||||
const hint = LOADING_MESSAGES[Math.floor(Math.random() * LOADING_MESSAGES.length)];
|
||||
this.setData({
|
||||
isLoading: true,
|
||||
loadingMessage: hint
|
||||
});
|
||||
},
|
||||
hideLoadingOverlay() {
|
||||
if (!this.data.isLoading) {
|
||||
return;
|
||||
}
|
||||
this.setData({
|
||||
isLoading: false,
|
||||
loadingMessage: ""
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
<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">
|
||||
<view class="title-block">
|
||||
<text class="title">玄名殿</text>
|
||||
|
||||
@@ -4,6 +4,54 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.loading-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 20;
|
||||
background: rgba(6, 10, 22, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
|
||||
.loading-dialog {
|
||||
width: 82%;
|
||||
max-width: 320px;
|
||||
padding: 26px 24px;
|
||||
border-radius: 22px;
|
||||
background: linear-gradient(180deg, rgba(22, 28, 52, 0.95), rgba(12, 18, 36, 0.88));
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
box-shadow: 0 24px 48px rgba(8, 10, 24, 0.4);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
align-items: center;
|
||||
color: rgba(255, 244, 227, 0.9);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid rgba(255, 244, 227, 0.25);
|
||||
border-top-color: #ffd8a0;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 15px;
|
||||
letter-spacing: 2px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.loading-subtext {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 244, 227, 0.6);
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.glow-layer {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
@@ -56,6 +104,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
|
||||
@@ -15,7 +15,8 @@ function showToast(title) {
|
||||
Page({
|
||||
data: {
|
||||
results: [],
|
||||
matchSummary: ""
|
||||
matchSummary: "",
|
||||
elementsChart: []
|
||||
},
|
||||
onLoad() {
|
||||
const { results, analysis } = namingStore.getState();
|
||||
@@ -28,15 +29,39 @@ Page({
|
||||
}, 1000);
|
||||
return;
|
||||
}
|
||||
const summary = analysis && (analysis.matchSummary || analysis.MatchSummary) ? analysis.matchSummary || analysis.MatchSummary : "";
|
||||
const summary = analysis && (analysis.matchSummary || analysis.MatchSummary)
|
||||
? analysis.matchSummary || analysis.MatchSummary
|
||||
: "";
|
||||
const elements = Array.isArray(analysis && (analysis.elementDistribution || analysis.ElementDistribution))
|
||||
? analysis.elementDistribution || analysis.ElementDistribution
|
||||
: [];
|
||||
const total = elements.reduce((acc, current) => {
|
||||
const value = Number(current.count ?? current.Count ?? 0);
|
||||
return acc + (Number.isNaN(value) ? 0 : value);
|
||||
}, 0);
|
||||
const chart = elements.map((item) => {
|
||||
const elementName = item.element || item.Element || "";
|
||||
const countValue = Number(item.count ?? item.Count ?? 0);
|
||||
const count = Number.isNaN(countValue) ? 0 : countValue;
|
||||
const percent = total > 0 ? Math.round((count / total) * 100) : 0;
|
||||
const widthPercent = percent > 0 ? Math.max(percent, 6) : 0;
|
||||
return {
|
||||
label: elementName || "未知",
|
||||
count,
|
||||
percent,
|
||||
percentText: `${percent}%`,
|
||||
percentWidth: `${widthPercent}%`
|
||||
};
|
||||
});
|
||||
const normalized = results.map((item) => ({
|
||||
name: item.name,
|
||||
meaning: item.meaning || "寓意待补充",
|
||||
elementReason: item.elementReason || "五行流转相济"
|
||||
meaning: item.meaning || item.Meaning || "寓意待补充",
|
||||
elementReason: item.elementReason || item.ElementReason || "五行流转相济"
|
||||
}));
|
||||
this.setData({
|
||||
results: normalized,
|
||||
matchSummary: summary
|
||||
matchSummary: summary,
|
||||
elementsChart: chart
|
||||
});
|
||||
},
|
||||
handleFavorite(event) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<view class="page">
|
||||
<view class="page">
|
||||
<view class="glow-layer">
|
||||
<view class="glow glow-one"></view>
|
||||
<view class="glow glow-two"></view>
|
||||
@@ -12,8 +12,22 @@
|
||||
|
||||
<view class="summary" tt:if="{{matchSummary}}">
|
||||
<text class="summary-text">{{matchSummary}}</text>
|
||||
<view class="chart-title">五行占比</view>
|
||||
<block tt:for="{{elementsChart}}" tt:for-item="item" tt:key="label">
|
||||
<view class="chart-row">
|
||||
<view class="chart-label">{{item.label}}</view>
|
||||
<view class="chart-bar">
|
||||
<view class="chart-bar-fill" style="width: {{item.percentWidth}};"></view>
|
||||
</view>
|
||||
<text class="chart-percent">{{item.count}}({{item.percentText}})</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
<!-- <view class="element-section" tt:if="{{elementsChart.length}}">
|
||||
|
||||
</view> -->
|
||||
|
||||
<view class="empty" tt:if="{{!results.length}}">
|
||||
<text>暂无生成结果,请返回主页重新生成。</text>
|
||||
<button class="primary back-button" bindtap="handleBack">返回主页</button>
|
||||
@@ -23,19 +37,23 @@
|
||||
<view class="tip">轻触收藏按钮即可将心仪姓名收入星册</view>
|
||||
<block tt:for="{{results}}" tt:for-index="index" tt:for-item="item" tt:key="name">
|
||||
<view class="result-card">
|
||||
<text class="result-line">{{item.name}}|{{item.meaning}}|{{item.elementReason}}</text>
|
||||
<button
|
||||
class="collect-button"
|
||||
size="mini"
|
||||
bindtap="handleFavorite"
|
||||
data-name="{{item.name}}"
|
||||
data-meaning="{{item.meaning}}"
|
||||
>
|
||||
收藏
|
||||
</button>
|
||||
<view class="result-header">
|
||||
<text class="result-name">{{item.name}}</text>
|
||||
<button
|
||||
class="collect-button"
|
||||
size="mini"
|
||||
bindtap="handleFavorite"
|
||||
data-name="{{item.name}}"
|
||||
data-meaning="{{item.meaning}}"
|
||||
>
|
||||
收藏
|
||||
</button>
|
||||
</view>
|
||||
<text class="result-meaning">{{item.meaning}}</text>
|
||||
<text class="result-reason">{{item.elementReason}}</text>
|
||||
</view>
|
||||
</block>
|
||||
<button class="primary back-button" bindtap="handleBack">再测一批</button>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -102,6 +102,56 @@
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.element-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
background: rgba(18, 24, 46, 0.65);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 16px;
|
||||
padding: 16px 18px;
|
||||
color: rgba(255, 244, 227, 0.85);
|
||||
}
|
||||
|
||||
.chart-title {
|
||||
font-size: 14px;
|
||||
letter-spacing: 3px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.chart-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.chart-label {
|
||||
width: 42px;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 244, 227, 0.78);
|
||||
}
|
||||
|
||||
.chart-bar {
|
||||
flex: 1;
|
||||
height: 10px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chart-bar-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, rgba(255, 205, 146, 0.9), rgba(112, 184, 255, 0.9));
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.chart-percent {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 244, 227, 0.7);
|
||||
min-width: 70px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.result-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -115,11 +165,19 @@
|
||||
backdrop-filter: blur(16px);
|
||||
}
|
||||
|
||||
.result-line {
|
||||
font-size: 15px;
|
||||
color: rgba(255, 244, 227, 0.9);
|
||||
line-height: 1.8;
|
||||
word-break: break-all;
|
||||
.result-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.result-name {
|
||||
font-size: 18px;
|
||||
color: #fdf0da;
|
||||
font-weight: 600;
|
||||
letter-spacing: 3px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.collect-button {
|
||||
@@ -130,7 +188,18 @@
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
color: #fbe6ce;
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.result-meaning {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 244, 227, 0.86);
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.result-reason {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 244, 227, 0.7);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
|
||||
@@ -10,7 +10,7 @@ function post(endpoint, data) {
|
||||
url: `${config.apiBaseUrl}${endpoint}`,
|
||||
method: "POST",
|
||||
data,
|
||||
timeout: 5000,
|
||||
timeout: 60000,
|
||||
success(response) {
|
||||
const { statusCode, data: payload } = response;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
|
||||
Reference in New Issue
Block a user