index.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. <template>
  2. <view class="assignment-page">
  3. <view class="page-header">
  4. <text class="page-title">三本账认领</text>
  5. <text class="page-desc">认领一本账,成为做账专家或通用支援</text>
  6. </view>
  7. <view class="book-list">
  8. <view class="book-card" v-for="(book, idx) in books" :key="idx">
  9. <view class="book-header">
  10. <text class="book-icon">{{ book.icon }}</text>
  11. <view class="book-info">
  12. <text class="book-name">{{ book.label }}</text>
  13. <text class="book-desc">{{ book.desc }}</text>
  14. </view>
  15. </view>
  16. <view v-if="isClaimed(book.type)" class="claimed-badge">已认领</view>
  17. <view v-else class="claim-actions">
  18. <view class="role-select">
  19. <text class="role-label">角色:</text>
  20. <radio-group @change="onRoleChange($event, book.type)">
  21. <label class="role-option"><radio value="expert" :checked="selectedRole[book.type] === 'expert'" color="#F97316" />做账专家</label>
  22. <label class="role-option"><radio value="support" :checked="selectedRole[book.type] === 'support'" color="#F97316" />通用支援</label>
  23. </radio-group>
  24. </view>
  25. <button class="claim-btn" @click="handleClaim(book.type)" :loading="claiming[book.type]">认领</button>
  26. </view>
  27. </view>
  28. </view>
  29. </view>
  30. </template>
  31. <script>
  32. import { claimAssignment, getMyAssignments } from '@/utils/api.js'
  33. import { guardPage } from '@/utils/guard.js'
  34. export default {
  35. data() {
  36. return {
  37. books: [
  38. { type: 'wealth', label: '财富账', icon: '💰', desc: '记录家庭财务数据与分析' },
  39. { type: 'health', label: '健康账', icon: '❤️', desc: '记录家庭健康数据与管理' },
  40. { type: 'growth', label: '成长账', icon: '🌱', desc: '记录家庭成长数据与规划' }
  41. ],
  42. myAssignments: [],
  43. selectedRole: { wealth: 'expert', health: 'expert', growth: 'expert' },
  44. claiming: { wealth: false, health: false, growth: false }
  45. }
  46. },
  47. onShow() {
  48. if (!guardPage()) return
  49. this.loadAssignments()
  50. },
  51. methods: {
  52. loadAssignments() {
  53. var self = this
  54. getMyAssignments().then(function(resp) {
  55. self.myAssignments = resp.data || []
  56. }).catch(function() {})
  57. },
  58. isClaimed(type) {
  59. return this.myAssignments.some(function(a) { return a.bookType === type })
  60. },
  61. onRoleChange(e, type) {
  62. this.$set(this.selectedRole, type, e.detail.value)
  63. },
  64. handleClaim(type) {
  65. if (this.claiming[type]) return
  66. this.$set(this.claiming, type, true)
  67. var self = this
  68. claimAssignment({
  69. bookType: type,
  70. role: this.selectedRole[type],
  71. useSample: 0
  72. }).then(function() {
  73. uni.showToast({ title: '认领成功', icon: 'success' })
  74. self.loadAssignments()
  75. }).catch(function(err) {
  76. uni.showToast({ title: (err && err.message) || '认领失败', icon: 'none' })
  77. }).finally(function() {
  78. self.$set(self.claiming, type, false)
  79. })
  80. }
  81. }
  82. }
  83. </script>
  84. <style scoped>
  85. .assignment-page { min-height: 100vh; background: #F5F5F5; padding: 32rpx; }
  86. .page-header { margin-bottom: 32rpx; }
  87. .page-title { display: block; font-size: 40rpx; font-weight: 700; color: #1E293B; margin-bottom: 8rpx; }
  88. .page-desc { display: block; font-size: 26rpx; color: #64748B; }
  89. .book-card { background: #FFF; border-radius: 16rpx; padding: 32rpx; margin-bottom: 24rpx; }
  90. .book-header { display: flex; align-items: center; margin-bottom: 20rpx; }
  91. .book-icon { font-size: 48rpx; margin-right: 20rpx; }
  92. .book-name { display: block; font-size: 30rpx; font-weight: 600; color: #1E293B; }
  93. .book-desc { display: block; font-size: 24rpx; color: #64748B; margin-top: 4rpx; }
  94. .claimed-badge { background: #F0FDF4; color: #22C55E; font-size: 26rpx; font-weight: 500; padding: 12rpx 24rpx; border-radius: 8rpx; text-align: center; }
  95. .claim-actions { border-top: 1rpx solid #F1F5F9; padding-top: 20rpx; }
  96. .role-select { margin-bottom: 16rpx; }
  97. .role-label { font-size: 26rpx; color: #64748B; }
  98. .role-option { font-size: 26rpx; color: #1E293B; margin-right: 24rpx; }
  99. .claim-btn { width: 100%; height: 76rpx; line-height: 76rpx; background: #F97316; color: #FFF; font-size: 28rpx; font-weight: 500; border-radius: 38rpx; border: none; }
  100. .claim-btn:active { opacity: 0.85; }
  101. </style>