| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- <template>
- <view class="annual-energy-page">
- <view class="nav-bar">
- <text class="nav-back" @click="goBack">←</text>
- <text class="nav-title">流年能量</text>
- <view class="nav-right"></view>
- </view>
- <view v-if="loading" class="loading-state"><text>加载中...</text></view>
- <view v-else-if="error" class="error-state"><text class="error-text">{{ error }}</text></view>
- <view v-else-if="energy" class="content">
- <view class="year-selector">
- <text class="year-current">{{ energy.year || currentYear }}年</text>
- <text class="year-label">流年能量</text>
- </view>
- <view class="info-card">
- <view class="card-title-bar"><text class="card-title">五维能量分布</text></view>
- <view class="radar-container">
- <canvas canvas-id="energyRadar" id="energyRadar" class="radar-canvas"></canvas>
- </view>
- </view>
- <view class="info-card" v-if="energy.jupiterPhase || energy.saturnPhase">
- <view class="card-title-bar"><text class="card-title">流年星象</text></view>
- <view class="stars-grid">
- <view v-if="energy.jupiterPhase" class="star-item">
- <text class="star-name">木星</text>
- <text class="star-phase">{{ energy.jupiterPhase }}</text>
- </view>
- <view v-if="energy.saturnPhase" class="star-item">
- <text class="star-name">土星</text>
- <text class="star-phase">{{ energy.saturnPhase }}</text>
- </view>
- </view>
- </view>
- <view class="info-card">
- <view class="card-title-bar"><text class="card-title">各维度分析</text></view>
- <view class="dimensions-list">
- <view v-for="(value, key) in energy.dimensions" :key="key" class="dimension-item">
- <view class="dim-header">
- <text class="dim-label">{{ dimLabel(key) }}</text>
- <text class="dim-value">{{ value }}分</text>
- </view>
- <view class="bar-track"><view class="bar-fill" :style="{width: value + '%', background: dimColor(key)}"></view></view>
- </view>
- </view>
- </view>
- <view class="info-card" v-if="energy.highlights && energy.highlights.length > 0">
- <view class="card-title-bar"><text class="card-title">本年重点</text></view>
- <view class="highlight-list">
- <view v-for="(h, idx) in energy.highlights" :key="idx" class="highlight-item">
- <text class="highlight-text">{{ h }}</text>
- </view>
- </view>
- </view>
- </view>
- </view>
- </template>
- <script>
- export default {
- data: function() {
- return { energy: null, loading: false, error: null, memberId: null, currentYear: new Date().getFullYear() }
- },
- onLoad: function(query) { this.memberId = query.memberId; this.loadEnergy() },
- onShow: function() {
- var self = this
- if (self.energy) { self.$nextTick(function() { self.drawRadar() }) }
- },
- methods: {
- loadEnergy: function() {
- var self = this
- if (!self.memberId) { self.error = '参数错误'; return }
- self.loading = true; self.error = null
- self.$store.dispatch('tianpan/loadAnnualEnergy', { memberId: parseInt(self.memberId), year: self.currentYear })
- .then(function(data) { self.energy = data })
- .catch(function(e) { self.error = e.message || '加载失败' })
- .finally(function() { self.loading = false; self.$nextTick(function() { self.drawRadar() }) })
- },
- goBack: function() { uni.navigateBack() },
- drawRadar: function() {
- var self = this
- if (!self.energy || !self.energy.dimensions) return
- var d = self.energy.dimensions
- var w = uni.getWindowInfo().windowWidth
- var size = Math.min(w - 80, 260)
- var ctx = uni.createCanvasContext('energyRadar')
- var cx = size / 2, cy = size / 2, r = size / 2 - 30
- var dims = ['body', 'mind', 'wisdom', 'action', 'wealth']
- var n = dims.length
- var angleStep = Math.PI * 2 / n
- var values = dims.map(function(di) { return (d[di] || 0) / 100 })
- ctx.clearRect(0, 0, size, size)
- for (var i = 1; i <= 4; i++) {
- var rr = r * i / 4
- ctx.beginPath()
- for (var j = 0; j <= n; j++) {
- var a = j * angleStep - Math.PI / 2
- var px = cx + rr * Math.cos(a), py = cy + rr * Math.sin(a)
- if (j === 0) ctx.moveTo(px, py)
- else ctx.lineTo(px, py)
- }
- ctx.closePath(); ctx.strokeStyle = '#E5E7EB'; ctx.lineWidth = 0.5; ctx.stroke()
- }
- for (var k = 0; k < n; k++) {
- var a2 = k * angleStep - Math.PI / 2
- ctx.beginPath(); ctx.moveTo(cx, cy)
- ctx.lineTo(cx + r * Math.cos(a2), cy + r * Math.sin(a2))
- ctx.strokeStyle = '#D1D5DB'; ctx.lineWidth = 0.5; ctx.stroke()
- }
- ctx.beginPath()
- for (var m = 0; m < n; m++) {
- var a3 = m * angleStep - Math.PI / 2
- var vx = cx + r * values[m] * Math.cos(a3), vy = cy + r * Math.sin(a3)
- if (m === 0) ctx.moveTo(vx, vy)
- else ctx.lineTo(vx, vy)
- }
- ctx.closePath(); ctx.fillStyle = 'rgba(249, 115, 22, 0.2)'; ctx.fill()
- ctx.strokeStyle = '#F97316'; ctx.lineWidth = 2; ctx.stroke()
- ctx.draw()
- },
- dimLabel: function(key) { var map = { body: '身', mind: '心', wisdom: '智', action: '行', wealth: '富' }; return map[key] || key },
- dimColor: function(key) { var map = { body: '#10B981', mind: '#EC4899', wisdom: '#8B5CF6', action: '#F97316', wealth: '#3B82F6' }; return map[key] || '#F97316' }
- }
- }
- </script>
- <style scoped>
- .annual-energy-page { min-height: 100vh; background: #F3F4F6; }
- .nav-bar { display: flex; align-items: center; justify-content: space-between; padding: 20px 16px 10px; background: #F97316; }
- .nav-back { font-size: 18px; color: #FFF; }
- .nav-title { font-size: 17px; font-weight: bold; color: #FFF; }
- .nav-right { width: 40px; }
- .loading-state, .error-state { padding: 60px 20px; display: flex; justify-content: center; align-items: center; }
- .error-text { color: #EF4444; font-size: 14px; }
- .content { padding: 12px; }
- .year-selector { text-align: center; padding: 16px 0 8px; }
- .year-current { font-size: 28px; font-weight: bold; color: #F97316; }
- .year-label { font-size: 13px; color: #9CA3AF; display: block; }
- .info-card { background: #FFF; border-radius: 12px; padding: 16px; margin-bottom: 12px; }
- .card-title-bar { margin-bottom: 12px; border-bottom: 1px solid #F3F4F6; padding-bottom: 8px; }
- .card-title { font-size: 15px; font-weight: bold; color: #1F2937; }
- .radar-container { display: flex; justify-content: center; padding: 8px 0; }
- .radar-canvas { width: 260px; height: 260px; }
- .stars-grid { display: flex; gap: 12px; }
- .star-item { flex: 1; background: #FFF7ED; border-radius: 8px; padding: 12px; display: flex; flex-direction: column; align-items: center; }
- .star-name { font-size: 13px; color: #9CA3AF; }
- .star-phase { font-size: 14px; color: #F97316; font-weight: bold; margin-top: 4px; }
- .dimensions-list { display: flex; flex-direction: column; }
- .dimension-item { margin-bottom: 14px; }
- .dim-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; }
- .dim-label { font-size: 13px; color: #374151; font-weight: 500; }
- .dim-value { font-size: 13px; color: #F97316; font-weight: bold; }
- .bar-track { height: 6px; background: #E5E7EB; border-radius: 3px; margin-bottom: 4px; }
- .bar-fill { height: 100%; border-radius: 3px; }
- .highlight-list { display: flex; flex-direction: column; }
- .highlight-item { padding: 6px 0; border-bottom: 1px solid #F3F4F6; }
- .highlight-item:last-child { border-bottom: none; }
- .highlight-text { font-size: 13px; color: #374151; line-height: 1.5; }
- </style>
|