index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. <template>
  2. <view class="wisdom-container">
  3. <!-- 1. 品牌头部 -->
  4. <PageBanner theme="wisdom"
  5. tagline="学以启智 · 慧及未来"
  6. quote="知者不惑,仁者不忧" />
  7. <!-- 2. 游客专属区块 -->
  8. <template v-if="!isLoggedIn">
  9. <LoginGuideCard
  10. title="登录后查看全家智慧成长数据"
  11. :items="[
  12. '查看全家认知能量数据和测评报告',
  13. '记录每日成长,获取智慧能量',
  14. '参与认知训练,提升综合能力'
  15. ]" />
  16. <WisdomTips />
  17. </template>
  18. <!-- 3. 五维能量条(登录后) -->
  19. <FamilyEnergyBar
  20. v-if="isLoggedIn"
  21. dimensionCode="wisdom"
  22. :sandboxData="sandboxData"
  23. :dualDimension="dualDimension" />
  24. <!-- 4. 家庭成员关系图谱(登录后) -->
  25. <FamilyRelationGraph
  26. v-if="isLoggedIn && familyMembersVisible.length > 0"
  27. dimensionCode="wisdom"
  28. :selfId="activeChildId"
  29. :members="familyMembersVisible"
  30. :energyMap="energyMapForGraph"
  31. :intimacyMap="intimacyMapForGraph"
  32. @memberTap="goMemberDetail" />
  33. <!-- 5. 用户快捷入口 -->
  34. <UserQuickEntry
  35. v-if="isLoggedIn"
  36. :userName="userName"
  37. roleName="家长"
  38. :currentChildName="activeChildName"
  39. :children="children"
  40. @childChanged="onChildChanged"
  41. @scrollTo="scrollToSection" />
  42. <!-- 6. 功能入口 -->
  43. <view class="func-section" v-if="sectionVisible('func_entries')">
  44. <view class="func-grid">
  45. <view class="func-item" v-for="item in funcList" :key="item.label" @click="onFuncClick(item)">
  46. <view class="func-icon-wrap">
  47. <text class="func-icon">{{ item.icon }}</text>
  48. </view>
  49. <text class="func-label">{{ item.label }}</text>
  50. </view>
  51. </view>
  52. </view>
  53. <!-- 7. 认知摘要区(登录后) -->
  54. <view class="section" v-if="isLoggedIn">
  55. <view class="section-header">
  56. <text class="section-title">认知概览</text>
  57. <text class="section-more" @click="goCognitiveReport">查看详情 ›</text>
  58. </view>
  59. <view class="cognition-summary" v-if="cognitiveReport">
  60. <view class="summary-main">
  61. <text class="summary-score">{{ cognitiveReport.overallScore || '--' }}</text>
  62. <text class="summary-label">综合认知评分</text>
  63. </view>
  64. <view class="summary-detail">
  65. <text class="summary-dan">DAN等级: {{ cognitiveReport.danLevel || '-' }}</text>
  66. <text class="summary-min" v-if="lowestDimension">
  67. 待提升: {{ lowestDimension.label }} ({{ lowestDimension.score }})
  68. </text>
  69. </view>
  70. </view>
  71. <view class="cognition-empty" v-else>
  72. <text class="empty-tip">暂无认知测评数据</text>
  73. <text class="empty-sub">完成DAN评估后查看详细报告</text>
  74. </view>
  75. </view>
  76. <!-- 8. 自己出题入口卡(登录后) -->
  77. <view class="section highlight-card" v-if="isLoggedIn" @click="goSelfQuiz">
  78. <view class="highlight-card-inner">
  79. <view class="highlight-card-left">
  80. <text class="highlight-icon">✏️</text>
  81. </view>
  82. <view class="highlight-card-right">
  83. <text class="highlight-title">自己出题自己答</text>
  84. <text class="highlight-desc">元认知训练:自己出题、自己判分,提升学习能力</text>
  85. </view>
  86. <text class="highlight-arrow">›</text>
  87. </view>
  88. </view>
  89. <!-- 9. 训练中心入口卡(登录后) -->
  90. <view class="section highlight-card" v-if="isLoggedIn" @click="goTrainingHub">
  91. <view class="highlight-card-inner">
  92. <view class="highlight-card-left">
  93. <text class="highlight-icon">🧠</text>
  94. </view>
  95. <view class="highlight-card-right">
  96. <text class="highlight-title">认知训练中心</text>
  97. <text class="highlight-desc">舒尔特方格 · 猜数字 — 多维度认知训练游戏</text>
  98. </view>
  99. <text class="highlight-arrow">›</text>
  100. </view>
  101. </view>
  102. <!-- 10. 维度任务 -->
  103. <DimensionTasks
  104. v-if="isLoggedIn"
  105. dimensionCode="wisdom"
  106. :tasks="dimensionTasks"
  107. @taskClick="onTaskClick"
  108. @moreTasks="goTasks" />
  109. <!-- 11. 维度活动 -->
  110. <DimensionActivities
  111. dimensionCode="wisdom"
  112. :activities="dimensionActivities"
  113. @activityClick="goActivityDetail"
  114. @moreActivities="goMoreActivities" />
  115. <!-- 12. 维度商品 -->
  116. <DimensionProducts
  117. dimensionCode="wisdom"
  118. :products="dimensionProducts"
  119. @productClick="goProductDetail"
  120. @moreProducts="goMoreProducts" />
  121. <!-- 13. 智慧小贴士 -->
  122. <view class="section" v-if="sectionVisible('wisdom_tips')">
  123. <view class="section-header">
  124. <text class="section-title">智慧小贴士</text>
  125. </view>
  126. <view class="tips-list">
  127. <view class="tip-card" v-for="item in wisdomTips" :key="item.id">
  128. <text class="tip-title">{{ item.title }}</text>
  129. <text class="tip-summary">{{ item.summary }}</text>
  130. </view>
  131. </view>
  132. </view>
  133. <!-- 14. 快捷操作按钮 -->
  134. <view class="section quick-actions" v-if="isLoggedIn">
  135. <view class="action-btn" @click="goCognitiveReport">
  136. <text class="action-icon">📊</text>
  137. <text class="action-text">认知报告</text>
  138. </view>
  139. <view class="action-btn" @click="goTrainingHub">
  140. <text class="action-icon">🧠</text>
  141. <text class="action-text">认知训练</text>
  142. </view>
  143. <view class="action-btn" @click="goAssessment">
  144. <text class="action-icon">📋</text>
  145. <text class="action-text">测评预约</text>
  146. </view>
  147. </view>
  148. <!-- 底部占位 -->
  149. <view class="bottom-spacer"></view>
  150. </view>
  151. </template>
  152. <script>
  153. import PageBanner from '../../components/PageBanner.vue'
  154. import LoginGuideCard from '../../components/LoginGuideCard.vue'
  155. import WisdomTips from '../../components/WisdomTips.vue'
  156. import FamilyEnergyBar from '../../components/FamilyEnergyBar.vue'
  157. import UserQuickEntry from '../../components/UserQuickEntry.vue'
  158. import DimensionTasks from '../../components/DimensionTasks.vue'
  159. import DimensionActivities from '../../components/DimensionActivities.vue'
  160. import DimensionProducts from '../../components/DimensionProducts.vue'
  161. import FamilyRelationGraph from '../../components/FamilyRelationGraph.vue'
  162. import { getVisibleSections, getChildren, getTodayTasksByCategory, getActivityList, getProductsByDomain, getFamilyEnergySandbox, getAssessmentLatestResult } from '../../utils/api.js'
  163. export default {
  164. components: { PageBanner, LoginGuideCard, WisdomTips, FamilyEnergyBar, UserQuickEntry, DimensionTasks, DimensionActivities, DimensionProducts, FamilyRelationGraph },
  165. data() {
  166. return {
  167. isLoggedIn: false,
  168. role: null,
  169. activeChildId: null,
  170. activeChildName: '',
  171. userName: '',
  172. children: [],
  173. familyMembersVisible: [],
  174. sandboxData: null,
  175. dualDimension: null,
  176. visibleSections: [],
  177. cognitiveReport: null,
  178. lowestDimension: null,
  179. dimensionTasks: [],
  180. dimensionActivities: [],
  181. dimensionProducts: [],
  182. funcList: [
  183. { icon: '\u{1F4CA}', label: '认知报告', needLogin: true, page: '/pages/wisdom/cognitive-report' },
  184. { icon: '\u{270F}\uFE0F', label: '自己出题', needLogin: true, page: '/pages/wisdom/self-quiz' },
  185. { icon: '\u{1F9E0}', label: '训练中心', needLogin: true, page: '/pages/wisdom/training-hub' },
  186. { icon: '\u{1F3AF}', label: '测评预约', needLogin: false, page: '/pages/assessment/apply' },
  187. { icon: '\u{1F4D6}', label: '阅读天地', needLogin: false, page: '/pages/mind/articles' }
  188. ],
  189. wisdomTips: [
  190. { id: 1, title: '认知发展的关键期', summary: '儿童认知发展存在关键期窗口,抓住每个阶段的核心能力培养机会。' },
  191. { id: 2, title: '元认知训练的意义', summary: '教会孩子"学会如何学习",通过自我监控和反思提升学习效率。' },
  192. { id: 3, title: '专注力的培养方法', summary: '从短时间专注起步,逐步延长专注时长,配合舒尔特方格等训练工具。' },
  193. { id: 4, title: '多维度认知刺激', summary: '综合运用视、听、触等多种感官刺激,促进大脑神经网络全面发展。' }
  194. ]
  195. }
  196. },
  197. computed: {
  198. energyMapForGraph: function() {
  199. var map = {}
  200. if (this.sandboxData && this.sandboxData.members) {
  201. for (var i = 0; i < this.sandboxData.members.length; i++) {
  202. var m = this.sandboxData.members[i]
  203. map[m.memberId || m.id] = {
  204. bodyScore: m.bodyScore || 0,
  205. mindScore: m.mindScore || 0,
  206. actionScore: m.actionScore || 0
  207. }
  208. }
  209. }
  210. return map
  211. },
  212. intimacyMapForGraph: function() {
  213. return {}
  214. }
  215. },
  216. onShow() {
  217. var token = uni.getStorageSync('token')
  218. this.isLoggedIn = !!token
  219. if (this.isLoggedIn) {
  220. this.role = uni.getStorageSync('currentRole') || uni.getStorageSync('role') || null
  221. this.userName = uni.getStorageSync('nickname') || uni.getStorageSync('userName') || '家长'
  222. }
  223. this.loadSectionConfig()
  224. if (this.isLoggedIn) {
  225. this.loadChildren()
  226. this.loadFamilyMembersVisible()
  227. this.loadCognitiveReport()
  228. }
  229. this.loadDimensionActivities()
  230. this.loadDimensionProducts()
  231. },
  232. methods: {
  233. loadSectionConfig: function() {
  234. var baseSections = ['func_entries', 'wisdom_tips']
  235. if (!uni.getStorageSync('token')) {
  236. this.visibleSections = baseSections
  237. return
  238. }
  239. var role = uni.getStorageSync('currentRole') || uni.getStorageSync('role') || null
  240. var self = this
  241. getVisibleSections({ pageKey: 'wisdom', role: role }).then(function(res) {
  242. if (res.code === 200 && res.data) {
  243. var keys = res.data.map(function(s) { return s.sectionKey })
  244. var merged = baseSections.slice()
  245. keys.forEach(function(k) { if (merged.indexOf(k) === -1) merged.push(k) })
  246. self.visibleSections = merged
  247. }
  248. }).catch(function(e) {
  249. self.visibleSections = ['func_entries', 'wisdom_tips']
  250. })
  251. },
  252. loadChildren: function() {
  253. var self = this
  254. getChildren().then(function(res) {
  255. if (res.code === 200 && res.data) {
  256. self.children = res.data
  257. if (self.children.length > 0) {
  258. var activeId = uni.getStorageSync('currentChildId')
  259. if (activeId) {
  260. for (var i = 0; i < self.children.length; i++) {
  261. if (self.children[i].id == activeId) {
  262. self.activeChildId = activeId
  263. self.activeChildName = self.children[i].nickname || self.children[i].name || ''
  264. break
  265. }
  266. }
  267. }
  268. if (!self.activeChildId) {
  269. self.activeChildId = self.children[0].id
  270. self.activeChildName = self.children[0].nickname || self.children[0].name || ''
  271. uni.setStorageSync('currentChildId', self.activeChildId)
  272. }
  273. }
  274. }
  275. }).catch(function(e) {})
  276. },
  277. loadFamilyMembersVisible: function() {
  278. var self = this
  279. getFamilyEnergySandbox().then(function(res) {
  280. if (res && res.data) {
  281. self.sandboxData = res.data.sandboxData || null
  282. self.dualDimension = res.data.dualDimension || null
  283. if (res.data.members) {
  284. self.familyMembersVisible = res.data.members
  285. }
  286. }
  287. }).catch(function(e) {})
  288. },
  289. loadCognitiveReport: function() {
  290. var self = this
  291. var childId = this.activeChildId
  292. if (!childId) return
  293. getAssessmentLatestResult(childId).then(function(res) {
  294. if (res.code === 200 && res.data) {
  295. self.cognitiveReport = res.data
  296. self.findLowestDimension(res.data)
  297. }
  298. }).catch(function(e) {})
  299. },
  300. findLowestDimension: function(report) {
  301. var dims = [
  302. { key: 'perceptionScore', label: '感知能力' },
  303. { key: 'focusScore', label: '专注力' },
  304. { key: 'memoryScore', label: '记忆力' },
  305. { key: 'logicScore', label: '逻辑思维' },
  306. { key: 'spatialScore', label: '空间思维' },
  307. { key: 'processingSpeedScore', label: '加工速度' }
  308. ]
  309. var lowest = null
  310. var minVal = Infinity
  311. for (var i = 0; i < dims.length; i++) {
  312. var val = report[dims[i].key]
  313. if (val !== null && val !== undefined && val < minVal) {
  314. minVal = val
  315. lowest = { label: dims[i].label, score: val }
  316. }
  317. }
  318. this.lowestDimension = lowest
  319. },
  320. onChildChanged: function(childId) {
  321. this.activeChildId = childId
  322. uni.setStorageSync('currentChildId', childId)
  323. for (var i = 0; i < this.children.length; i++) {
  324. if (this.children[i].id == childId) {
  325. this.activeChildName = this.children[i].nickname || this.children[i].name || ''
  326. break
  327. }
  328. }
  329. this.loadFamilyMembersVisible()
  330. this.loadCognitiveReport()
  331. },
  332. loadDimensionTasks: function() {
  333. var self = this
  334. var childId = this.activeChildId
  335. if (!childId) return
  336. getTodayTasksByCategory(childId, 'wisdom').then(function(res) {
  337. if (res && res.data) {
  338. self.dimensionTasks = res.data.slice(0, 5)
  339. }
  340. }).catch(function(e) {})
  341. },
  342. loadDimensionActivities: function() {
  343. var self = this
  344. getActivityList({ dimensionCode: 'wisdom', page: 1, size: 5 }).then(function(res) {
  345. if (res && res.data) {
  346. self.dimensionActivities = res.data.records || res.data
  347. }
  348. }).catch(function(e) {})
  349. },
  350. loadDimensionProducts: function() {
  351. var self = this
  352. getProductsByDomain('wisdom', 1, 4).then(function(res) {
  353. if (res && res.data) {
  354. self.dimensionProducts = res.data.records || res.data
  355. }
  356. }).catch(function(e) {})
  357. },
  358. sectionVisible: function(key) {
  359. return this.visibleSections.length === 0 || this.visibleSections.indexOf(key) !== -1
  360. },
  361. onFuncClick: function(item) {
  362. if (item.needLogin && !this.isLoggedIn) {
  363. uni.showModal({
  364. title: '提示',
  365. content: '请先登录后使用此功能',
  366. success: function(res) { if (res.confirm) uni.navigateTo({ url: '/pages/login/login' }) }
  367. })
  368. return
  369. }
  370. if (item.page) {
  371. var nativeTabs = ['/pages/tasks/tasks', '/pages/index/index', '/pages/body/index', '/pages/mind/index', '/pages/action/index', '/pages/wisdom/index', '/pages/profile/profile']
  372. if (nativeTabs.indexOf(item.page) !== -1) {
  373. uni.switchTab({ url: item.page })
  374. } else {
  375. uni.navigateTo({ url: item.page })
  376. }
  377. }
  378. },
  379. scrollToSection: function(section) {},
  380. goMemberDetail: function(memberId) {
  381. uni.navigateTo({ url: '/pages/wisdom/member-wisdom-detail?memberId=' + memberId })
  382. },
  383. goCognitiveReport: function() {
  384. uni.navigateTo({ url: '/pages/wisdom/cognitive-report' })
  385. },
  386. goSelfQuiz: function() {
  387. uni.navigateTo({ url: '/pages/wisdom/self-quiz' })
  388. },
  389. goTrainingHub: function() {
  390. uni.navigateTo({ url: '/pages/wisdom/training-hub' })
  391. },
  392. goAssessment: function() {
  393. uni.navigateTo({ url: '/pages/assessment/apply' })
  394. },
  395. onTaskClick: function(task) {},
  396. goTasks: function() { uni.switchTab({ url: '/pages/tasks/tasks' }) },
  397. goActivityDetail: function(id) {},
  398. goMoreActivities: function() {},
  399. goProductDetail: function(id) {
  400. var token = uni.getStorageSync('token')
  401. if (token) {
  402. uni.navigateTo({ url: '/pages/discover/product-detail/product-detail?id=' + id })
  403. } else {
  404. uni.navigateTo({ url: '/pages/login/login?redirect=' + encodeURIComponent('/pages/wisdom/index') })
  405. }
  406. },
  407. goMoreProducts: function() {}
  408. }
  409. }
  410. </script>
  411. <style scoped>
  412. .wisdom-container {
  413. min-height: 100vh;
  414. background: #f5f7fa;
  415. padding-bottom: 120rpx;
  416. }
  417. .func-section {
  418. margin: -40rpx 20rpx 0;
  419. position: relative;
  420. z-index: 2;
  421. }
  422. .func-grid {
  423. background: #fff;
  424. border-radius: 24rpx;
  425. padding: 30rpx 16rpx;
  426. display: flex;
  427. box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.06);
  428. }
  429. .func-item {
  430. flex: 1;
  431. display: flex;
  432. flex-direction: column;
  433. align-items: center;
  434. }
  435. .func-item:active {
  436. opacity: 0.7;
  437. }
  438. .func-icon-wrap {
  439. width: 88rpx;
  440. height: 88rpx;
  441. border-radius: 50%;
  442. background: #FFF8E1;
  443. display: flex;
  444. align-items: center;
  445. justify-content: center;
  446. margin-bottom: 10rpx;
  447. }
  448. .func-icon {
  449. font-size: 40rpx;
  450. }
  451. .func-label {
  452. font-size: 24rpx;
  453. color: #333;
  454. font-weight: 500;
  455. }
  456. /* ===== Section ===== */
  457. .section {
  458. margin: 20rpx 20rpx;
  459. }
  460. .section-header {
  461. display: flex;
  462. justify-content: space-between;
  463. align-items: center;
  464. margin-bottom: 20rpx;
  465. }
  466. .section-title {
  467. font-size: 30rpx;
  468. font-weight: bold;
  469. color: #333;
  470. }
  471. .section-more {
  472. font-size: 24rpx;
  473. color: #999;
  474. }
  475. /* ===== 认知概览 ===== */
  476. .cognition-summary {
  477. background: linear-gradient(135deg, #FFD700, #FFA500);
  478. border-radius: 20rpx;
  479. padding: 30rpx;
  480. display: flex;
  481. flex-direction: row;
  482. align-items: center;
  483. }
  484. .summary-main {
  485. text-align: center;
  486. margin-right: 30rpx;
  487. padding-right: 30rpx;
  488. border-right: 2rpx solid rgba(255,255,255,0.3);
  489. }
  490. .summary-score {
  491. font-size: 60rpx;
  492. font-weight: bold;
  493. color: #fff;
  494. display: block;
  495. }
  496. .summary-label {
  497. font-size: 22rpx;
  498. color: rgba(255,255,255,0.85);
  499. display: block;
  500. margin-top: 4rpx;
  501. }
  502. .summary-detail {
  503. flex: 1;
  504. }
  505. .summary-dan {
  506. font-size: 28rpx;
  507. color: #fff;
  508. font-weight: bold;
  509. display: block;
  510. margin-bottom: 8rpx;
  511. }
  512. .summary-min {
  513. font-size: 24rpx;
  514. color: rgba(255,255,255,0.85);
  515. display: block;
  516. }
  517. .cognition-empty {
  518. background: #fff;
  519. border-radius: 16rpx;
  520. padding: 40rpx;
  521. text-align: center;
  522. box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
  523. }
  524. .empty-tip {
  525. font-size: 26rpx;
  526. color: #999;
  527. display: block;
  528. }
  529. .empty-sub {
  530. font-size: 22rpx;
  531. color: #ccc;
  532. margin-top: 6rpx;
  533. display: block;
  534. }
  535. /* ===== 高亮卡片 ===== */
  536. .highlight-card {
  537. margin: 20rpx;
  538. }
  539. .highlight-card-inner {
  540. display: flex;
  541. flex-direction: row;
  542. align-items: center;
  543. background: linear-gradient(135deg, #FFF8E1, #fff);
  544. border: 2rpx solid #FFD700;
  545. border-radius: 20rpx;
  546. padding: 24rpx;
  547. }
  548. .highlight-card:active {
  549. opacity: 0.8;
  550. }
  551. .highlight-card-left {
  552. width: 72rpx;
  553. height: 72rpx;
  554. border-radius: 18rpx;
  555. background: #FFD700;
  556. display: flex;
  557. align-items: center;
  558. justify-content: center;
  559. margin-right: 20rpx;
  560. }
  561. .highlight-icon {
  562. font-size: 36rpx;
  563. }
  564. .highlight-card-right {
  565. flex: 1;
  566. }
  567. .highlight-title {
  568. font-size: 28rpx;
  569. font-weight: bold;
  570. color: #B8860B;
  571. display: block;
  572. margin-bottom: 4rpx;
  573. }
  574. .highlight-desc {
  575. font-size: 22rpx;
  576. color: #999;
  577. display: block;
  578. }
  579. .highlight-arrow {
  580. font-size: 36rpx;
  581. color: #ccc;
  582. margin-left: 10rpx;
  583. }
  584. /* ===== 小贴士 ===== */
  585. .tips-list {
  586. display: flex;
  587. flex-direction: column;
  588. }
  589. .tip-card {
  590. background: #fff;
  591. border-radius: 16rpx;
  592. padding: 24rpx;
  593. margin-bottom: 16rpx;
  594. box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
  595. border-left: 6rpx solid #FFD700;
  596. }
  597. .tip-title {
  598. font-size: 26rpx;
  599. font-weight: bold;
  600. color: #333;
  601. display: block;
  602. margin-bottom: 8rpx;
  603. }
  604. .tip-summary {
  605. font-size: 24rpx;
  606. color: #999;
  607. line-height: 1.5;
  608. display: block;
  609. }
  610. /* ===== 快捷操作 ===== */
  611. .quick-actions {
  612. display: flex;
  613. flex-direction: row;
  614. justify-content: space-around;
  615. margin: 20rpx;
  616. }
  617. .action-btn {
  618. display: flex;
  619. flex-direction: column;
  620. align-items: center;
  621. background: #fff;
  622. border-radius: 16rpx;
  623. padding: 20rpx 30rpx;
  624. box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
  625. flex: 1;
  626. margin: 0 8rpx;
  627. }
  628. .action-btn:active {
  629. opacity: 0.7;
  630. }
  631. .action-icon {
  632. font-size: 36rpx;
  633. margin-bottom: 8rpx;
  634. }
  635. .action-text {
  636. font-size: 22rpx;
  637. color: #333;
  638. }
  639. .bottom-spacer {
  640. height: 20rpx;
  641. }
  642. </style>