feat: 完善见素起名小程序功能

- 添加收藏锦囊功能,支持查看和删除收藏
- 实现积分系统,每日赠送5次灵感次数
- 添加静心阅读功能,阅读15秒可获得额外次数
- 实现灵感广场,展示用户分享的名字
- 添加字源溯源组件,长按汉字查看详情
- 优化空状态和结语卡片样式统一
- 添加音频控制(静音/风铃/雨落/古琴/白噪音/森林/溪流)
- 优化名字生成逻辑,确保每次返回5个不重复名字
- 修复卡片翻转样式问题
- 移除首页动态提醒气泡
This commit is contained in:
王鹏
2026-04-18 16:56:31 +08:00
parent be1f5722ab
commit 2c47fb8f65
59 changed files with 4643 additions and 145 deletions

View File

@@ -0,0 +1,108 @@
// 字源溯源弹窗组件
Component({
properties: {
visible: {
type: Boolean,
value: false
},
char: {
type: String,
value: ''
}
},
data: {
pinyin: '',
radical: '',
strokes: '',
wuxing: '',
meaning: '',
imagery: '',
poetry: '',
loading: false
},
observers: {
'visible, char': function(visible, char) {
if (visible && char) {
this.loadCharDetail(char);
}
}
},
methods: {
// 加载汉字详情
loadCharDetail(char) {
this.setData({ loading: true });
// 先从本地缓存查找
const cache = wx.getStorageSync(`char_${char}`);
if (cache) {
this.setData({ ...cache, loading: false });
return;
}
// 调用后端接口获取
const apiBaseUrl = getApp().globalData.apiBaseUrl;
wx.request({
url: `${apiBaseUrl}/api/char/detail`,
data: { char },
success: (res) => {
if (res.data && res.data.success) {
const data = res.data.data;
this.setData({ ...data, loading: false });
// 缓存结果
wx.setStorageSync(`char_${char}`, data);
} else {
// 使用默认数据
this.setDefaultData(char);
}
},
fail: () => {
this.setDefaultData(char);
}
});
},
// 设置默认数据
setDefaultData(char) {
// 简单的拼音映射(实际应该从后端获取)
const pinyinMap = {
'兰': 'lán', '泽': 'zé', '芳': 'fāng', '风': 'fēng',
'墨': 'mò', '染': 'rǎn', '清': 'qīng', '欢': 'huān',
'素': 'sù', '简': 'jiǎn', '雅': 'yǎ', '致': 'zhì'
};
this.setData({
pinyin: pinyinMap[char] || '',
radical: '',
strokes: '',
wuxing: '',
meaning: '暂无详细解析,点击"问问 AI"获取深度分析',
imagery: '',
poetry: '',
loading: false
});
},
// 点击遮罩关闭
onMaskTap() {
this.triggerEvent('close');
},
// 阻止冒泡
onContainerTap() {
// 什么都不做,只是阻止冒泡
},
// 点击关闭按钮
onClose() {
this.triggerEvent('close');
},
// 问问 AI
onAskAI() {
this.triggerEvent('askAI', { char: this.data.char });
}
}
});

View File

@@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@@ -0,0 +1,59 @@
<!-- 字源溯源弹窗组件 -->
<view class="char-detail-mask {{visible ? 'show' : ''}}" bindtap="onMaskTap">
<view class="char-detail-container {{visible ? 'show' : ''}}" catchtap="onContainerTap">
<!-- 磨砂玻璃背景 -->
<view class="glass-bg"></view>
<!-- 关闭按钮 -->
<view class="close-btn" bindtap="onClose">×</view>
<!-- 大字展示 -->
<view class="char-display">
<text class="char-text">{{char}}</text>
<view class="char-pinyin">{{pinyin}}</view>
</view>
<!-- 字源解析 -->
<scroll-view class="char-content" scroll-y>
<!-- 基础信息 -->
<view class="info-section">
<view class="info-item">
<text class="label">部首</text>
<text class="value">{{radical || '未知'}}</text>
</view>
<view class="info-item">
<text class="label">笔画</text>
<text class="value">{{strokes || '未知'}}画</text>
</view>
<view class="info-item">
<text class="label">五行</text>
<text class="value">{{wuxing || '未知'}}</text>
</view>
</view>
<!-- 字义解析 -->
<view class="meaning-section">
<view class="section-title">本义</view>
<text class="meaning-text">{{meaning || '暂无解析'}}</text>
</view>
<!-- 意象分析 -->
<view class="imagery-section">
<view class="section-title">起名意象</view>
<text class="imagery-text">{{imagery || '暂无解析'}}</text>
</view>
<!-- 诗词典故 -->
<view class="poetry-section" wx:if="{{poetry}}">
<view class="section-title">诗词典故</view>
<text class="poetry-text">{{poetry}}</text>
</view>
</scroll-view>
<!-- AI 解析按钮 -->
<view class="ai-btn" bindtap="onAskAI">
<text class="ai-icon">✦</text>
<text class="ai-text">问问 AI</text>
</view>
</view>
</view>

View File

@@ -0,0 +1,178 @@
/* 字源溯源弹窗组件 - 磨砂玻璃风格 */
.char-detail-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
z-index: 1000;
}
.char-detail-mask.show {
opacity: 1;
visibility: visible;
}
.char-detail-container {
position: relative;
width: 600rpx;
max-height: 800rpx;
border-radius: 24rpx;
overflow: hidden;
transform: scale(0.9) translateY(20rpx);
transition: all 0.3s ease;
}
.char-detail-container.show {
transform: scale(1) translateY(0);
}
/* 磨砂玻璃背景 */
.glass-bg {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(20rpx);
-webkit-backdrop-filter: blur(20rpx);
}
/* 关闭按钮 */
.close-btn {
position: absolute;
top: 20rpx;
right: 20rpx;
width: 48rpx;
height: 48rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 36rpx;
color: #666;
z-index: 10;
}
/* 大字展示 */
.char-display {
position: relative;
padding: 60rpx 0 40rpx;
text-align: center;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.05);
}
.char-text {
font-size: 120rpx;
font-family: 'KaiTi', 'STKaiti', serif;
color: #2D2D2D;
line-height: 1;
}
.char-pinyin {
margin-top: 16rpx;
font-size: 28rpx;
color: #666;
letter-spacing: 4rpx;
}
/* 内容区域 */
.char-content {
position: relative;
max-height: 400rpx;
padding: 30rpx 40rpx;
}
/* 基础信息 */
.info-section {
display: flex;
justify-content: space-around;
padding: 20rpx 0;
margin-bottom: 30rpx;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.05);
}
.info-item {
text-align: center;
}
.info-item .label {
display: block;
font-size: 22rpx;
color: #999;
margin-bottom: 8rpx;
}
.info-item .value {
display: block;
font-size: 28rpx;
color: #333;
font-weight: 500;
}
/* 章节标题 */
.section-title {
font-size: 26rpx;
color: #2D2D2D;
font-weight: 600;
margin-bottom: 16rpx;
padding-left: 16rpx;
border-left: 4rpx solid #B22222;
}
/* 内容文本 */
.meaning-section,
.imagery-section,
.poetry-section {
margin-bottom: 30rpx;
}
.meaning-text,
.imagery-text,
.poetry-text {
font-size: 28rpx;
color: #555;
line-height: 1.8;
text-align: justify;
}
.poetry-text {
font-style: italic;
color: #666;
}
/* AI 按钮 */
.ai-btn {
position: relative;
margin: 0 40rpx 40rpx;
padding: 24rpx 0;
background: linear-gradient(135deg, #2D2D2D 0%, #444 100%);
border-radius: 40rpx;
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
}
.ai-btn:active {
opacity: 0.9;
}
.ai-icon {
font-size: 28rpx;
color: #fff;
}
.ai-text {
font-size: 28rpx;
color: #fff;
letter-spacing: 4rpx;
}