2026-01-31 22:02:01 +08:00
|
|
|
|
<view class="container">
|
2026-02-03 22:41:30 +08:00
|
|
|
|
<!-- 自定义返回按钮 -->
|
|
|
|
|
|
<view class="nav-back" bindtap="handleBack">
|
|
|
|
|
|
<text class="back-icon">⇠</text>
|
|
|
|
|
|
<text class="back-text">返回</text>
|
2026-01-31 22:02:01 +08:00
|
|
|
|
</view>
|
2026-02-03 22:41:30 +08:00
|
|
|
|
<!-- 1. 牌阵选择状态 -->
|
|
|
|
|
|
<view class="spread-select-area" wx:if="{{state === 'spread_select'}}">
|
|
|
|
|
|
<view class="title-area">
|
|
|
|
|
|
<text class="app-title">选择你的牌阵</text>
|
|
|
|
|
|
<text class="instruction">请根据你的困惑选择一个适合的牌阵</text>
|
2026-02-02 21:48:38 +08:00
|
|
|
|
</view>
|
2026-02-03 22:41:30 +08:00
|
|
|
|
<view class="spread-list">
|
|
|
|
|
|
<view class="spread-item" wx:for="{{spreads}}" wx:key="id" bindtap="selectSpread" data-id="{{item.id}}" hover-class="spread-hover">
|
|
|
|
|
|
<text class="spread-name">{{item.name}}</text>
|
|
|
|
|
|
<text class="spread-desc">{{item.description}}</text>
|
|
|
|
|
|
</view>
|
2026-02-02 21:48:38 +08:00
|
|
|
|
</view>
|
2026-01-31 22:02:01 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
|
2026-02-03 22:41:30 +08:00
|
|
|
|
<!-- 2. 洗牌状态 (展示动画) -->
|
|
|
|
|
|
<view class="ritual-area" wx:if="{{state === 'shuffling'}}">
|
|
|
|
|
|
<view class="shuffling-container">
|
|
|
|
|
|
<image class="shuffling-card" wx:for="{{[1,2,3,4,5]}}" wx:key="*this" src="{{cardBackImage}}" mode="aspectFill" style="animation-delay: {{index * 0.2}}s"></image>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<text class="ritual-hint">正在感应你的能量,请保持内心平静...</text>
|
|
|
|
|
|
</view>
|
2026-02-02 21:48:38 +08:00
|
|
|
|
|
2026-02-03 22:41:30 +08:00
|
|
|
|
<!-- 3. 抽牌状态 (展开牌面供选择) -->
|
|
|
|
|
|
<view class="drawing-area" wx:if="{{state === 'drawing'}}">
|
|
|
|
|
|
<view class="title-area">
|
|
|
|
|
|
<text class="app-title">请挑选 {{selectedSpread.cardCount}} 张牌</text>
|
|
|
|
|
|
<text class="instruction">凭直觉选出触动你的卡牌</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<!-- 抽牌槽位(仅占位符) -->
|
|
|
|
|
|
<view class="slots-container {{selectedSpread.id}}">
|
|
|
|
|
|
<view class="slot-item" wx:for="{{selectedSpread.cardCount}}" wx:key="index">
|
|
|
|
|
|
<view class="slot-placeholder">
|
|
|
|
|
|
<text class="slot-num">{{index + 1}}</text>
|
2026-02-02 21:48:38 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
2026-02-03 22:41:30 +08:00
|
|
|
|
<!-- 牌堆:卡牌会直接从这里飞到上方槽位 -->
|
|
|
|
|
|
<view class="fan-deck">
|
|
|
|
|
|
<view
|
|
|
|
|
|
class="fan-card {{helper.isSelected(drawnCardIndices, index) ? 'is-selected' : ''}}"
|
|
|
|
|
|
wx:for="{{20}}"
|
|
|
|
|
|
wx:key="*this"
|
|
|
|
|
|
style="transform: {{helper.getTransform(drawnCardIndices, index, selectedSpread.cardCount)}};"
|
|
|
|
|
|
bindtap="onCardTap"
|
|
|
|
|
|
data-index="{{index}}"
|
|
|
|
|
|
>
|
|
|
|
|
|
<image class="card-back-sm" src="{{cardBackImage}}" mode="aspectFill"></image>
|
2026-02-02 21:48:38 +08:00
|
|
|
|
</view>
|
2026-02-03 22:41:30 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 简单辅助逻辑 -->
|
|
|
|
|
|
<wxs module="helper">
|
|
|
|
|
|
module.exports.isSelected = function(indices, currentIdx) {
|
|
|
|
|
|
return indices.indexOf(currentIdx) !== -1;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
module.exports.getTransform = function(indices, currentIdx, count) {
|
|
|
|
|
|
var pos = indices.indexOf(currentIdx);
|
|
|
|
|
|
if (pos !== -1) {
|
2026-02-04 20:46:57 +08:00
|
|
|
|
// 每排最多5张牌
|
|
|
|
|
|
var maxPerRow = 5;
|
|
|
|
|
|
var row = Math.floor(pos / maxPerRow); // 第几排(0或1)
|
|
|
|
|
|
var col = pos % maxPerRow; // 该排的第几个
|
|
|
|
|
|
var cardsInRow = (row === 0) ? Math.min(count, maxPerRow) : (count - maxPerRow);
|
|
|
|
|
|
|
|
|
|
|
|
// 槽位:宽100rpx + gap 20rpx = 120rpx 间距
|
|
|
|
|
|
var slotWidth = 100;
|
|
|
|
|
|
var gap = 20;
|
|
|
|
|
|
var slotSpacing = slotWidth + gap;
|
|
|
|
|
|
|
|
|
|
|
|
// 计算该排槽位的水平居中偏移
|
|
|
|
|
|
// 从该排中间位置开始计算
|
|
|
|
|
|
var centerOffset = (col - (cardsInRow - 1) / 2) * slotSpacing;
|
|
|
|
|
|
|
|
|
|
|
|
// 垂直偏移计算
|
|
|
|
|
|
// 第一排槽位:向上 -520rpx(已验证接近正确)
|
|
|
|
|
|
// 第二排:需要减少向上的距离
|
|
|
|
|
|
// 槽位高度160 + gap 20 = 180,但实际可能需要微调
|
|
|
|
|
|
var firstRowY = -520;
|
|
|
|
|
|
var secondRowOffset = 200; // 增加偏移量,让第二排更接近fan-deck
|
|
|
|
|
|
var yOffset = firstRowY + (row * secondRowOffset); // row=0: -520, row=1: -320
|
|
|
|
|
|
|
|
|
|
|
|
// 位移并缩小到0.65
|
|
|
|
|
|
return 'translate(' + centerOffset + 'rpx, ' + yOffset + 'rpx) scale(0.65) rotate(0deg)';
|
2026-02-03 22:41:30 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
// 保持在牌堆中的放射状
|
|
|
|
|
|
return 'rotate(' + ((currentIdx - 10) * 8) + 'deg)';
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
</wxs>
|
|
|
|
|
|
<view class="draw-count">{{drawnCardIndices.length}} / {{selectedSpread.cardCount}}</view>
|
|
|
|
|
|
<button class="confirm-draw-btn" wx:if="{{drawnCardIndices.length === selectedSpread.cardCount}}" bindtap="confirmDraw">开启解读</button>
|
|
|
|
|
|
</view>
|
2026-02-02 21:48:38 +08:00
|
|
|
|
|
2026-02-03 22:41:30 +08:00
|
|
|
|
<!-- 4. 翻牌与结果展示状态 -->
|
|
|
|
|
|
<view class="result-area" wx:if="{{state === 'flipping' || state === 'revealed'}}">
|
|
|
|
|
|
<!-- 卡牌阵列 -->
|
|
|
|
|
|
<view class="spread-display {{selectedSpread.id}}">
|
|
|
|
|
|
<view class="card-slot" wx:for="{{drawnCards}}" wx:key="index">
|
|
|
|
|
|
<text class="pos-name">{{selectedSpread.positions[index]}}</text>
|
|
|
|
|
|
<view class="flip-scene" bindtap="revealNext" data-index="{{index}}">
|
|
|
|
|
|
<view class="flip-card {{index < revealedCount ? 'flipped' : ''}}">
|
|
|
|
|
|
<view class="card-face face-back">
|
|
|
|
|
|
<image class="card-image" src="{{cardBackImage}}" mode="widthFix"></image>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="card-face face-front">
|
|
|
|
|
|
<image class="card-image {{item.isReversed ? 'reversed' : ''}}" src="{{item.image}}" mode="widthFix"></image>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<text class="card-name-sm" wx:if="{{index < revealedCount}}">{{item.name}}{{item.isReversed ? '(逆)' : ''}}</text>
|
2026-02-02 21:48:38 +08:00
|
|
|
|
</view>
|
2026-02-03 22:41:30 +08:00
|
|
|
|
</view>
|
2026-02-02 21:48:38 +08:00
|
|
|
|
|
2026-02-03 22:41:30 +08:00
|
|
|
|
<!-- 解读区域 -->
|
|
|
|
|
|
<view class="interpretation-area" wx:if="{{revealedCount === selectedSpread.cardCount}}" animation="{{infoAnimation}}">
|
|
|
|
|
|
<view class="loading-ai" wx:if="{{isAiLoading}}">
|
|
|
|
|
|
<text class="loading-dot">···</text>
|
|
|
|
|
|
<text>正在深度解读能量流向...</text>
|
2026-02-02 21:48:38 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
|
2026-02-03 22:41:30 +08:00
|
|
|
|
<view class="structured-result" wx:else>
|
|
|
|
|
|
<view class="theme-box">
|
|
|
|
|
|
<text class="label">核心主题</text>
|
|
|
|
|
|
<text class="content">{{aiResult.theme}}</text>
|
2026-01-31 22:02:01 +08:00
|
|
|
|
</view>
|
2026-02-02 21:48:38 +08:00
|
|
|
|
|
2026-02-03 22:41:30 +08:00
|
|
|
|
<view class="info-grid">
|
|
|
|
|
|
<view class="info-item">
|
|
|
|
|
|
<text class="label">当前状态</text>
|
|
|
|
|
|
<text class="content">{{aiResult.status}}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="info-item">
|
|
|
|
|
|
<text class="label">潜在影响</text>
|
|
|
|
|
|
<text class="content">{{aiResult.influence}}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="pos-meanings">
|
|
|
|
|
|
<view class="pos-meaning-item" wx:for="{{aiResult.positions}}" wx:key="posName">
|
|
|
|
|
|
<text class="pos-title">{{item.posName}}</text>
|
|
|
|
|
|
<text class="pos-text">{{item.posMeaning}}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
2026-01-31 22:02:01 +08:00
|
|
|
|
|
2026-02-03 22:41:30 +08:00
|
|
|
|
<view class="advice-box">
|
|
|
|
|
|
<text class="label">行动建议</text>
|
|
|
|
|
|
<text class="content">{{aiResult.advice}}</text>
|
|
|
|
|
|
</view>
|
2026-01-31 22:02:01 +08:00
|
|
|
|
|
2026-02-03 22:41:30 +08:00
|
|
|
|
<button class="reset-btn" bindtap="resetSpread">重新开启</button>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|