| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- <template>
- <view class="mbr-page">
- <view class="mbr-loading" v-if="loading"><text>加载结果...</text></view>
- <template v-else>
- <view class="mbr-hero">
- <view class="mbr-hero-inner">
- <text class="mbr-type-code">{{ result.typeCode }}</text>
- <text class="mbr-type-name">{{ result.typeName }}</text>
- <text class="mbr-type-desc" v-if="result.profile && result.profile.description">{{ result.profile.description }}</text>
- </view>
- </view>
- <view class="mbr-section">
- <text class="mbr-section-title">四维度雷达</text>
- <view class="mbr-canvas-wrap">
- <canvas type="2d" id="mbtiRadar" class="mbr-canvas" @ready="onCanvasReady"></canvas>
- </view>
- </view>
- <view class="mbr-section" v-if="result.profile">
- <text class="mbr-section-title">画像详情</text>
- <view class="mbr-profile-list">
- <view class="mbr-profile-item" v-for="(val, key) in profileFields" :key="key" v-if="result.profile[key]">
- <text class="mbr-profile-label">{{ val.label }}</text>
- <text class="mbr-profile-value">{{ result.profile[key] }}</text>
- </view>
- </view>
- </view>
- <view class="mbr-section" v-if="result.profile && result.profile.energySuggestion">
- <text class="mbr-section-title">五维联动建议</text>
- <view class="mbr-energy-list">
- <view class="mbr-energy-item" v-for="(sug, dim) in energyMap" :key="dim">
- <view class="mbr-energy-head" :style="{ color: dimColors[dim] }">
- <view class="mbr-energy-dot" :style="{ background: dimColors[dim] }"></view>
- <text class="mbr-energy-label">{{ dimLabels[dim] }}</text>
- </view>
- <text class="mbr-energy-text">{{ sug }}</text>
- </view>
- </view>
- </view>
- <view class="mbr-footer">
- <button class="mbr-btn mbr-btn-primary" @click="goProfile">查看完整百科</button>
- <button class="mbr-btn mbr-btn-outline" @click="retake">重新测评</button>
- </view>
- </template>
- </view>
- </template>
- <script>
- import { getMbtiLatest } from '@/utils/api'
- export default {
- data() {
- return {
- loading: true,
- result: null,
- canvasContext: null,
- canvasWidth: 340,
- canvasHeight: 340,
- dimLabels: { body: '身', mind: '心', wisdom: '智', action: '行', wealth: '富' },
- dimColors: { body: '#FF8C42', mind: '#FF6B9D', wisdom: '#6366F1', action: '#10B981', wealth: '#F59E0B' },
- profileFields: {
- strengths: { label: '优势' },
- weaknesses: { label: '挑战' },
- career_tendency: { label: '职业倾向' },
- family_style: { label: '家庭风格' },
- pairing_notes: { label: '搭配建议' }
- }
- }
- },
- computed: {
- energyMap() {
- return this.result && this.result.profile && this.result.profile.energySuggestion
- ? this.result.profile.energySuggestion
- : {}
- }
- },
- onLoad(options) {
- this.loadResult()
- },
- methods: {
- loadResult() {
- var self = this
- getMbtiLatest().then(function(res) {
- if (res.code === 200 && res.data) self.result = res.data
- self.loading = false
- self.drawRadar()
- }).catch(function() { self.loading = false })
- },
- onCanvasReady(res) {
- if (!res || !res[0] || !res[0].node) return
- var ctx = res[0].node.getContext('2d')
- var dpr = uni.getWindowInfo().pixelRatio
- this.canvasContext = ctx
- this.canvasContext.scale(dpr, dpr)
- this.drawRadar()
- },
- drawRadar() {
- if (!this.canvasContext || !this.result) return
- var ctx = this.canvasContext
- var w = this.canvasWidth, h = this.canvasHeight
- var cx = w / 2, cy = h / 2, r = w * 0.34
- var angleStep = (Math.PI * 2) / 4
- ctx.clearRect(0, 0, w, h)
- ctx.fillStyle = '#FFF8F0'; ctx.fillRect(0, 0, w, h)
- for (var layer = 1; layer <= 3; layer++) {
- ctx.beginPath()
- for (var g = 0; g < 4; g++) {
- var a = g * angleStep - Math.PI / 2
- var gx = cx + r * (layer / 3) * Math.cos(a)
- var gy = cy + r * (layer / 3) * Math.sin(a)
- if (g === 0) ctx.moveTo(gx, gy); else ctx.lineTo(gx, gy)
- }
- ctx.closePath()
- ctx.strokeStyle = 'rgba(99,102,241,0.15)'; ctx.lineWidth = 1; ctx.stroke()
- }
- var labels = ['E/I', 'S/N', 'T/F', 'J/P']
- var colors = ['#6366F1', '#10B981', '#FF6B9D', '#F59E0B']
- for (var j = 0; j < 4; j++) {
- var a2 = j * angleStep - Math.PI / 2
- var lx = cx + r * Math.cos(a2), ly = cy + r * Math.sin(a2)
- ctx.beginPath(); ctx.moveTo(cx, cy); ctx.lineTo(lx, ly)
- ctx.strokeStyle = colors[j] + '44'; ctx.lineWidth = 1; ctx.stroke()
- ctx.fillStyle = colors[j]; ctx.font = 'bold 13px sans-serif'
- ctx.textAlign = 'center'; ctx.textBaseline = 'middle'
- ctx.fillText(labels[j], lx, ly)
- }
- var scores = {
- 'E/I': this.result.eiScore != null ? Math.max(-50, Math.min(50, this.result.eiScore)) : 0,
- 'S/N': this.result.snScore != null ? Math.max(-50, Math.min(50, this.result.snScore)) : 0,
- 'T/F': this.result.tfScore != null ? Math.max(-50, Math.min(50, this.result.tfScore)) : 0,
- 'J/P': this.result.jpScore != null ? Math.max(-50, Math.min(50, this.result.jpScore)) : 0
- }
- var keys = ['E/I', 'S/N', 'T/F', 'J/P']
- ctx.beginPath()
- for (var m = 0; m < 4; m++) {
- var ang = m * angleStep - Math.PI / 2
- var ratio = (scores[keys[m]] + 50) / 100
- var dataR = r * ratio
- var dx = cx + dataR * Math.cos(ang), dy = cy + dataR * Math.sin(ang)
- if (m === 0) ctx.moveTo(dx, dy); else ctx.lineTo(dx, dy)
- }
- ctx.closePath()
- ctx.fillStyle = 'rgba(99,102,241,0.2)'; ctx.fill()
- ctx.strokeStyle = '#6366F1'; ctx.lineWidth = 2; ctx.stroke()
- for (var n = 0; n < 4; n++) {
- var ang2 = n * angleStep - Math.PI / 2
- var ratio2 = (scores[keys[n]] + 50) / 100
- var dataR2 = r * ratio2
- var px = cx + dataR2 * Math.cos(ang2), py = cy + dataR2 * Math.sin(ang2)
- ctx.beginPath(); ctx.arc(px, py, 4, 0, Math.PI * 2)
- ctx.fillStyle = colors[n]; ctx.fill()
- }
- },
- goProfile() { uni.navigateTo({ url: '/pages/family/mbti-profile' }) },
- retake() { uni.navigateTo({ url: '/pages/family/mbti-entry' }) }
- }
- }
- </script>
- <style scoped>
- .mbr-page { min-height: 100vh; background: #F5FAFE; padding: 24rpx 30rpx 120rpx; box-sizing: border-box }
- .mbr-loading { display: flex; justify-content: center; align-items: center; height: 50vh }
- .mbr-hero { border-radius: 24rpx; padding: 40rpx 30rpx; margin-bottom: 24rpx; background: linear-gradient(135deg, #6366F1, #818CF8); box-shadow: 0 6rpx 20rpx rgba(99,102,241,0.25) }
- .mbr-hero-inner { display: flex; flex-direction: column; align-items: center }
- .mbr-type-code { font-size: 88rpx; font-weight: 700; color: #fff; letter-spacing: 8rpx }
- .mbr-type-name { font-size: 32rpx; color: rgba(255,255,255,0.9); margin-top: 8rpx }
- .mbr-type-desc { font-size: 24rpx; color: rgba(255,255,255,0.8); margin-top: 16rpx; text-align: center; max-width: 600rpx }
- .mbr-section { background: #fff; border-radius: 24rpx; padding: 30rpx 26rpx; margin-bottom: 24rpx; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.05) }
- .mbr-section-title { font-size: 30rpx; font-weight: 600; color: #333; margin-bottom: 20rpx }
- .mbr-canvas-wrap { display: flex; justify-content: center }
- .mbr-canvas { width: 340px; height: 340px }
- .mbr-profile-list { display: flex; flex-direction: column }
- .mbr-profile-item { padding: 20rpx 0; border-top: 1rpx solid #F0F0F0 }
- .mbr-profile-item:first-child { border-top: none }
- .mbr-profile-label { display: block; font-size: 24rpx; color: #999; margin-bottom: 8rpx }
- .mbr-profile-value { font-size: 26rpx; color: #333; line-height: 1.5 }
- .mbr-energy-list { display: flex; flex-direction: column; gap: 16rpx }
- .mbr-energy-item { padding: 20rpx; background: #F5FAFE; border-radius: 16rpx }
- .mbr-energy-head { display: flex; align-items: center; margin-bottom: 8rpx }
- .mbr-energy-dot { width: 16rpx; height: 16rpx; border-radius: 50%; margin-right: 10rpx }
- .mbr-energy-label { font-size: 26rpx; font-weight: 600 }
- .mbr-energy-text { font-size: 24rpx; color: #555; line-height: 1.5 }
- .mbr-footer { position: fixed; bottom: 0; left: 0; right: 0; padding: 20rpx 30rpx; background: #fff; border-top: 1rpx solid #F0F0F0; display: flex; gap: 20rpx; box-sizing: border-box }
- .mbr-btn { flex: 1; height: 88rpx; line-height: 88rpx; font-size: 30rpx; border-radius: 44rpx; border: none; text-align: center }
- .mbr-btn-primary { background: linear-gradient(135deg, #6366F1, #818CF8); color: #fff; font-weight: 600 }
- .mbr-btn-outline { background: #fff; color: #6366F1; border: 2rpx solid #6366F1 }
- </style>
|