traditional-mirror.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. <template>
  2. <view class="mirror-container">
  3. <!-- 加载状态 -->
  4. <view class="loading-state" v-if="loading">
  5. <text>加载中...</text>
  6. </view>
  7. <template v-if="!loading && dataLoaded">
  8. <!-- 八字四柱 -->
  9. <view class="mirror-section">
  10. <view class="section-header">
  11. <text class="section-icon">&#x2637;</text>
  12. <text class="section-title">八字四柱</text>
  13. </view>
  14. <view class="bazi-grid" v-if="eightChars">
  15. <view class="bazi-column" v-for="(pillar, key) in eightChars" :key="key">
  16. <text class="bazi-pillar-label">{{ pillarLabel(key) }}</text>
  17. <text class="bazi-pillar-value">{{ pillar }}</text>
  18. </view>
  19. </view>
  20. <view class="empty-data" v-else>
  21. <text>暂未设置出生信息,无法排八字</text>
  22. </view>
  23. </view>
  24. <!-- 五行能量 -->
  25. <view class="mirror-section">
  26. <view class="section-header">
  27. <text class="section-icon">&#x267E;</text>
  28. <text class="section-title">五行能量</text>
  29. </view>
  30. <view class="wuxing-list" v-if="wuxingData">
  31. <view class="wuxing-item" v-for="wx in wuxingData" :key="wx.key">
  32. <text class="wuxing-label">{{ wx.label }}</text>
  33. <view class="wuxing-bar-track">
  34. <view class="wuxing-bar-fill" :style="{ width: wx.value + '%', background: wx.color }"></view>
  35. </view>
  36. <text class="wuxing-value">{{ wx.value }}%</text>
  37. </view>
  38. </view>
  39. <!-- 五行解读 -->
  40. <view class="reading-card" v-if="wuxingReading">
  41. <text class="reading-label">五行解读</text>
  42. <text class="reading-text" v-if="wuxingReading.personalTrait">{{ wuxingReading.personalTrait }}</text>
  43. <text class="reading-text" v-if="wuxingReading.mindGrowthAdvice">{{ wuxingReading.mindGrowthAdvice }}</text>
  44. </view>
  45. </view>
  46. <!-- 太阳星座 -->
  47. <view class="mirror-section" v-if="zodiac">
  48. <view class="section-header">
  49. <text class="section-icon">&#x2600;</text>
  50. <text class="section-title">太阳星座</text>
  51. </view>
  52. <view class="zodiac-display">
  53. <text class="zodiac-name">{{ zodiac }}</text>
  54. </view>
  55. </view>
  56. <!-- 生命灵数 -->
  57. <view class="mirror-section" v-if="numSoulData">
  58. <view class="section-header">
  59. <text class="section-icon">&#x1F52E;</text>
  60. <text class="section-title">生命灵数</text>
  61. </view>
  62. <view class="numsoul-display">
  63. <view class="numsoul-number" :style="{ background: numSoulData.colorHex || '#FF6B9D' }">
  64. <text class="numsoul-num">{{ lifeNumber }}</text>
  65. </view>
  66. <view class="numsoul-info">
  67. <text class="numsoul-title">{{ numSoulData.title || '' }}</text>
  68. <text class="numsoul-keywords" v-if="numSoulData.keywords">{{ numSoulData.keywords }}</text>
  69. <text class="numsoul-advice" v-if="numSoulData.mindGrowthAdvice">{{ numSoulData.mindGrowthAdvice }}</text>
  70. </view>
  71. </view>
  72. </view>
  73. </template>
  74. <!-- 无数据 -->
  75. <view class="empty-state" v-if="!loading && !dataLoaded">
  76. <text class="empty-icon">&#x1F4AD;</text>
  77. <text class="empty-text">暂无传统文化数据</text>
  78. </view>
  79. </view>
  80. </template>
  81. <script>
  82. import config from '../../config'
  83. export default {
  84. data() {
  85. return {
  86. loading: true,
  87. dataLoaded: false,
  88. eightChars: null,
  89. wuxingElements: null,
  90. zodiac: '',
  91. lifeNumber: null,
  92. wuxingReading: null,
  93. numSoulData: null,
  94. wuxingConfig: {
  95. wood: { label: '木', color: '#10B981' },
  96. fire: { label: '火', color: '#FF6B9D' },
  97. earth: { label: '土', color: '#FF8C42' },
  98. metal: { label: '金', color: '#6366F1' },
  99. water: { label: '水', color: '#3B82F6' }
  100. },
  101. pillarLabels: { year: '年柱', month: '月柱', day: '日柱', hour: '时柱' }
  102. }
  103. },
  104. computed: {
  105. wuxingData() {
  106. if (!this.wuxingElements) return null
  107. var keys = ['wood', 'fire', 'earth', 'metal', 'water']
  108. var result = []
  109. for (var i = 0; i < keys.length; i++) {
  110. var k = keys[i]
  111. if (this.wuxingElements[k] !== undefined) {
  112. result.push({
  113. key: k,
  114. label: this.wuxingConfig[k].label,
  115. color: this.wuxingConfig[k].color,
  116. value: this.wuxingElements[k]
  117. })
  118. }
  119. }
  120. return result.sort(function(a, b) { return b.value - a.value })
  121. }
  122. },
  123. onLoad() {
  124. this.loadData()
  125. },
  126. methods: {
  127. loadData() {
  128. var self = this
  129. var app = getApp()
  130. var memberId = this.$mp.query.memberId || app.globalData.currentChildId
  131. if (!memberId) {
  132. // Try to get from storage
  133. memberId = uni.getStorageSync('currentChildId')
  134. }
  135. if (!memberId) {
  136. self.loading = false
  137. return
  138. }
  139. uni.request({
  140. url: config.API_BASE_URL + '/api/mind/traditional/mirror',
  141. method: 'POST',
  142. data: { memberId: memberId, memberType: 'child' },
  143. success: function(res) {
  144. self.loading = false
  145. if (res.data && res.data.code === 200 && res.data.data) {
  146. var d = res.data.data
  147. self.eightChars = d.eightCharacters || null
  148. self.wuxingElements = d.wuxingElements || null
  149. self.zodiac = d.zodiac || ''
  150. self.lifeNumber = d.lifeNumber || null
  151. self.wuxingReading = d.wuxingReading || null
  152. self.numSoulData = d.numSoul || null
  153. self.dataLoaded = !!(self.eightChars || self.wuxingElements || self.zodiac || self.numSoulData)
  154. } else {
  155. self.dataLoaded = false
  156. }
  157. },
  158. fail: function() {
  159. self.loading = false
  160. }
  161. })
  162. },
  163. pillarLabel(key) {
  164. return this.pillarLabels[key] || key
  165. }
  166. }
  167. }
  168. </script>
  169. <style scoped>
  170. .mirror-container {
  171. min-height: 100vh;
  172. background: #F8F6F0;
  173. padding-bottom: 40rpx;
  174. }
  175. .loading-state {
  176. display: flex;
  177. align-items: center;
  178. justify-content: center;
  179. padding: 120rpx 0;
  180. color: #999;
  181. font-size: 28rpx;
  182. }
  183. .mirror-section {
  184. margin: 24rpx 32rpx;
  185. background: #fff;
  186. border-radius: 20rpx;
  187. padding: 28rpx;
  188. box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04);
  189. }
  190. .section-header {
  191. display: flex;
  192. align-items: center;
  193. margin-bottom: 20rpx;
  194. }
  195. .section-icon {
  196. font-size: 36rpx;
  197. margin-right: 12rpx;
  198. }
  199. .section-title {
  200. font-size: 30rpx;
  201. font-weight: 600;
  202. color: #333;
  203. }
  204. .bazi-grid {
  205. display: flex;
  206. justify-content: space-around;
  207. padding: 16rpx 0;
  208. }
  209. .bazi-column {
  210. display: flex;
  211. flex-direction: column;
  212. align-items: center;
  213. }
  214. .bazi-pillar-label {
  215. font-size: 22rpx;
  216. color: #999;
  217. margin-bottom: 8rpx;
  218. }
  219. .bazi-pillar-value {
  220. font-size: 36rpx;
  221. font-weight: 700;
  222. color: #8B5CF6;
  223. background: #F5F0FF;
  224. padding: 12rpx 16rpx;
  225. border-radius: 12rpx;
  226. }
  227. .wuxing-list {
  228. display: flex;
  229. flex-direction: column;
  230. gap: 16rpx;
  231. }
  232. .wuxing-item {
  233. display: flex;
  234. align-items: center;
  235. gap: 16rpx;
  236. }
  237. .wuxing-label {
  238. font-size: 28rpx;
  239. font-weight: 600;
  240. width: 48rpx;
  241. text-align: center;
  242. }
  243. .wuxing-bar-track {
  244. flex: 1;
  245. height: 24rpx;
  246. background: #F0F0F0;
  247. border-radius: 12rpx;
  248. overflow: hidden;
  249. }
  250. .wuxing-bar-fill {
  251. height: 100%;
  252. border-radius: 12rpx;
  253. }
  254. .wuxing-value {
  255. font-size: 24rpx;
  256. color: #666;
  257. width: 60rpx;
  258. text-align: right;
  259. }
  260. .reading-card {
  261. margin-top: 20rpx;
  262. padding: 16rpx;
  263. background: #FFFBEB;
  264. border-radius: 12rpx;
  265. border-left: 6rpx solid #F59E0B;
  266. }
  267. .reading-label {
  268. font-size: 24rpx;
  269. font-weight: 600;
  270. color: #D97706;
  271. display: block;
  272. margin-bottom: 8rpx;
  273. }
  274. .reading-text {
  275. font-size: 24rpx;
  276. color: #666;
  277. line-height: 1.6;
  278. display: block;
  279. margin-top: 8rpx;
  280. }
  281. .zodiac-display {
  282. display: flex;
  283. align-items: center;
  284. justify-content: center;
  285. padding: 20rpx;
  286. }
  287. .zodiac-name {
  288. font-size: 40rpx;
  289. font-weight: 700;
  290. color: #F59E0B;
  291. }
  292. .numsoul-display {
  293. display: flex;
  294. gap: 24rpx;
  295. align-items: center;
  296. }
  297. .numsoul-number {
  298. width: 100rpx;
  299. height: 100rpx;
  300. border-radius: 50%;
  301. display: flex;
  302. align-items: center;
  303. justify-content: center;
  304. flex-shrink: 0;
  305. }
  306. .numsoul-num {
  307. font-size: 44rpx;
  308. font-weight: 700;
  309. color: #fff;
  310. }
  311. .numsoul-info {
  312. flex: 1;
  313. }
  314. .numsoul-title {
  315. font-size: 28rpx;
  316. font-weight: 600;
  317. color: #333;
  318. display: block;
  319. }
  320. .numsoul-keywords {
  321. font-size: 24rpx;
  322. color: #666;
  323. display: block;
  324. margin-top: 6rpx;
  325. }
  326. .numsoul-advice {
  327. font-size: 24rpx;
  328. color: #8B5CF6;
  329. display: block;
  330. margin-top: 8rpx;
  331. line-height: 1.5;
  332. }
  333. .empty-data {
  334. padding: 20rpx;
  335. text-align: center;
  336. color: #999;
  337. font-size: 24rpx;
  338. }
  339. .empty-state {
  340. display: flex;
  341. flex-direction: column;
  342. align-items: center;
  343. padding: 120rpx 32rpx;
  344. }
  345. .empty-icon {
  346. font-size: 80rpx;
  347. margin-bottom: 20rpx;
  348. }
  349. .empty-text {
  350. font-size: 28rpx;
  351. color: #999;
  352. }
  353. </style>