|
@@ -0,0 +1,438 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <view class="traditional-container">
|
|
|
|
|
+ <!-- 自定义导航栏 -->
|
|
|
|
|
+ <view class="custom-nav">
|
|
|
|
|
+ <view class="nav-back" @click="goBack">‹ 返回</view>
|
|
|
|
|
+ <text class="nav-title">家庭传统命理</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 加载状态 -->
|
|
|
|
|
+ <view class="loading-state" v-if="loading">
|
|
|
|
|
+ <view class="loading-spinner"></view>
|
|
|
|
|
+ <text>加载中...</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 成员列表 -->
|
|
|
|
|
+ <view class="member-list" v-if="!loading && members && members.length > 0">
|
|
|
|
|
+ <view class="member-card" v-for="member in members" :key="member.memberId">
|
|
|
|
|
+ <!-- 头部 -->
|
|
|
|
|
+ <view class="card-header">
|
|
|
|
|
+ <view class="avatar" :style="{ backgroundColor: member.colorHex || '#6B7280' }">
|
|
|
|
|
+ <text class="avatar-text">{{ member.nickname ? member.nickname.charAt(0) : 'M' }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="member-info">
|
|
|
|
|
+ <text class="member-name">{{ member.nickname || member.name }}</text>
|
|
|
|
|
+ <text class="member-role">{{ getRoleLabel(member.memberType) }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 八字四柱 -->
|
|
|
|
|
+ <view class="section" v-if="member.eightCharacters">
|
|
|
|
|
+ <text class="section-title">八字四柱</text>
|
|
|
|
|
+ <view class="bazi-grid">
|
|
|
|
|
+ <view class="bazi-col" v-for="(val, key) in member.eightCharacters" :key="key">
|
|
|
|
|
+ <text class="bazi-label">{{ getPillarLabel(key) }}</text>
|
|
|
|
|
+ <text class="bazi-value">{{ val }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 五行能量 -->
|
|
|
|
|
+ <view class="section" v-if="member.wuxingElements">
|
|
|
|
|
+ <text class="section-title">五行能量</text>
|
|
|
|
|
+ <view class="wuxing-list">
|
|
|
|
|
+ <view class="wuxing-item" v-for="wx in getWuxingData(member.wuxingElements)" :key="wx.key">
|
|
|
|
|
+ <text class="wuxing-label">{{ wx.label }}</text>
|
|
|
|
|
+ <view class="wuxing-bar-track">
|
|
|
|
|
+ <view class="wuxing-bar-fill" :style="{ width: wx.value + '%', background: wx.color }"></view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <text class="wuxing-value">{{ wx.value }}%</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 生肖星座 -->
|
|
|
|
|
+ <view class="section" v-if="member.zodiacName || member.westernSign">
|
|
|
|
|
+ <text class="section-title">生肖星座</text>
|
|
|
|
|
+ <view class="tag-row">
|
|
|
|
|
+ <view class="tag" v-if="member.zodiacName">
|
|
|
|
|
+ <text>{{ member.zodiacName }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="tag" v-if="member.westernSign">
|
|
|
|
|
+ <text>{{ member.westernSign }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 生命灵数 -->
|
|
|
|
|
+ <view class="section" v-if="member.lifeNumber">
|
|
|
|
|
+ <text class="section-title">生命灵数</text>
|
|
|
|
|
+ <view class="numsoul-display">
|
|
|
|
|
+ <view class="numsoul-number" :style="{ background: getLifeNumberColor(member.lifeNumber) }">
|
|
|
|
|
+ <text>{{ member.lifeNumber }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <text class="numsoul-title">{{ getLifeNumberTitle(member.lifeNumber) }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 五维基础分 -->
|
|
|
|
|
+ <view class="section" v-if="member.dimensionBaseScores">
|
|
|
|
|
+ <text class="section-title">五维基础分</text>
|
|
|
|
|
+ <view class="dimension-bars">
|
|
|
|
|
+ <view class="dim-item" v-for="(val, key) in member.dimensionBaseScores" :key="key">
|
|
|
|
|
+ <text class="dim-label">{{ getDimLabel(key) }}</text>
|
|
|
|
|
+ <view class="dim-bar-track">
|
|
|
|
|
+ <view class="dim-bar-fill" :style="{ width: val + '%', background: getDimColor(key) }"></view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <text class="dim-value">{{ val }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 空状态 -->
|
|
|
|
|
+ <view class="empty-state" v-if="!loading && (!members || members.length === 0)">
|
|
|
|
|
+ <text>暂无家庭成员数据</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script>
|
|
|
|
|
+import { mapState, mapGetters, mapActions } from 'vuex'
|
|
|
|
|
+
|
|
|
|
|
+export default {
|
|
|
|
|
+ data: function() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ loading: false,
|
|
|
|
|
+ members: []
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ computed: {
|
|
|
|
|
+ ...mapState('tianpan', ['loading']),
|
|
|
|
|
+ ...mapGetters('tianpan', ['members'])
|
|
|
|
|
+ },
|
|
|
|
|
+ onLoad: function() {
|
|
|
|
|
+ this.loadMembers()
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ ...mapActions('tianpan', ['loadDashboard']),
|
|
|
|
|
+
|
|
|
|
|
+ loadMembers: function() {
|
|
|
|
|
+ this.loading = true
|
|
|
|
|
+ if (!this.members || this.members.length === 0) {
|
|
|
|
|
+ this.loadDashboard({ year: new Date().getFullYear(), daysAhead: 7 })
|
|
|
|
|
+ .then(this.fetchMembers)
|
|
|
|
|
+ .finally(function() {
|
|
|
|
|
+ this.loading = false
|
|
|
|
|
+ }.bind(this))
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.fetchMembers()
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ fetchMembers: function() {
|
|
|
|
|
+ this.members = this.members || []
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ goBack: function() {
|
|
|
|
|
+ uni.navigateBack()
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ getPillarLabel: function(key) {
|
|
|
|
|
+ var labels = { year: '年柱', month: '月柱', day: '日柱', hour: '时柱' }
|
|
|
|
|
+ return labels[key] || key
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ getWuxingData: function(wuxingElements) {
|
|
|
|
|
+ if (!wuxingElements) return []
|
|
|
|
|
+ var colorMap = { wood: '#10B981', fire: '#FF6B9D', earth: '#FF8C42', metal: '#6366F1', water: '#3B82F6' }
|
|
|
|
|
+ var labelMap = { wood: '木', fire: '火', earth: '土', metal: '金', water: '水' }
|
|
|
|
|
+ var result = []
|
|
|
|
|
+ for (var key in wuxingElements) {
|
|
|
|
|
+ if (wuxingElements.hasOwnProperty(key)) {
|
|
|
|
|
+ result.push({ key: key, label: labelMap[key] || key, value: wuxingElements[key], color: colorMap[key] || '#94A3B8' })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return result.sort(function(a, b) { return b.value - a.value })
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ getRoleLabel: function(type) {
|
|
|
|
|
+ var labels = { parent: '家长', child: '孩子', teacher: '规划师' }
|
|
|
|
|
+ return labels[type] || type
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ getLifeNumberColor: function(num) {
|
|
|
|
|
+ var colors = { 1: '#F97316', 2: '#EC4899', 3: '#8B5CF6', 4: '#F59E0B', 5: '#3B82F6', 6: '#10B981', 7: '#6366F1', 8: '#EF4444', 9: '#14B8A6' }
|
|
|
|
|
+ return colors[num] || '#6B7280'
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ getLifeNumberTitle: function(num) {
|
|
|
|
|
+ var titles = { 1: '开创', 2: '协调', 3: '表达', 4: '稳定', 5: '自由', 6: '责任', 7: '求知', 8: '权力', 9: '博爱' }
|
|
|
|
|
+ return titles[num] || ''
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ getDimLabel: function(key) {
|
|
|
|
|
+ var labels = { body: '身', mind: '心', wisdom: '智', action: '行', wealth: '富' }
|
|
|
|
|
+ return labels[key] || key
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ getDimColor: function(key) {
|
|
|
|
|
+ var colors = { body: '#FF8C42', mind: '#FF6B9D', wisdom: '#6366F1', action: '#10B981', wealth: '#F59E0B' }
|
|
|
|
|
+ return colors[key] || '#6B7280'
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped>
|
|
|
|
|
+.traditional-container {
|
|
|
|
|
+ min-height: 100vh;
|
|
|
|
|
+ background: #FFF8F0;
|
|
|
|
|
+ padding-bottom: 40px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.custom-nav {
|
|
|
|
|
+ background: linear-gradient(135deg, #F97316 0%, #FB923C 100%);
|
|
|
|
|
+ padding: 44px 16px 16px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.nav-back {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ color: #FFFFFF;
|
|
|
|
|
+ margin-right: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.nav-title {
|
|
|
|
|
+ font-size: 18px;
|
|
|
|
|
+ color: #FFFFFF;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.loading-state {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: 120px 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.loading-spinner {
|
|
|
|
|
+ width: 40px;
|
|
|
|
|
+ height: 40px;
|
|
|
|
|
+ border: 4px solid #E5E7EB;
|
|
|
|
|
+ border-top-color: #F97316;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ animation: spin 1s linear infinite;
|
|
|
|
|
+ margin-bottom: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+@keyframes spin {
|
|
|
|
|
+ to { transform: rotate(360deg); }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.member-list {
|
|
|
|
|
+ padding: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.member-card {
|
|
|
|
|
+ background: #FFFFFF;
|
|
|
|
|
+ border-radius: 16px;
|
|
|
|
|
+ padding: 20px;
|
|
|
|
|
+ margin-bottom: 16px;
|
|
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.card-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin-bottom: 20px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.avatar {
|
|
|
|
|
+ width: 64px;
|
|
|
|
|
+ height: 64px;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin-right: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.avatar-text {
|
|
|
|
|
+ color: #FFFFFF;
|
|
|
|
|
+ font-size: 28px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.member-info {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.member-name {
|
|
|
|
|
+ font-size: 18px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #1F2937;
|
|
|
|
|
+ display: block;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.member-role {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #6B7280;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.section {
|
|
|
|
|
+ margin-bottom: 20px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.section-title {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #9CA3AF;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.bazi-grid {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-around;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.bazi-col {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.bazi-label {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #9CA3AF;
|
|
|
|
|
+ margin-bottom: 4px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.bazi-value {
|
|
|
|
|
+ font-size: 24px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #8B5CF6;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.wuxing-list {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.wuxing-item {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.wuxing-label {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ width: 24px;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.wuxing-bar-track {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ height: 8px;
|
|
|
|
|
+ background: #E5E7EB;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.wuxing-bar-fill {
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.wuxing-value {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #6B7280;
|
|
|
|
|
+ width: 36px;
|
|
|
|
|
+ text-align: right;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.tag-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.tag {
|
|
|
|
|
+ background: #F3F4F6;
|
|
|
|
|
+ padding: 6px 16px;
|
|
|
|
|
+ border-radius: 20px;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #374151;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.numsoul-display {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.numsoul-number {
|
|
|
|
|
+ width: 64px;
|
|
|
|
|
+ height: 64px;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ font-size: 28px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #FFFFFF;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.numsoul-title {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ color: #374151;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.dimension-bars {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.dim-item {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.dim-label {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ width: 24px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.dim-bar-track {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ height: 8px;
|
|
|
|
|
+ background: #E5E7EB;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.dim-bar-fill {
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.dim-value {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #6B7280;
|
|
|
|
|
+ width: 36px;
|
|
|
|
|
+ text-align: right;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.empty-state {
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ padding: 120px 0;
|
|
|
|
|
+ color: #9CA3AF;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|