index.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <template>
  2. <view class="personal-card-page">
  3. <UserInfoCard
  4. v-if="personalBusinessCardInfo"
  5. v-model="personalBusinessCardInfo"
  6. :disabled="disabled"
  7. :gender-columns="genderColumns"
  8. :degree-columns="degreeColumns"
  9. />
  10. <PlatformExperienceCard v-if="personalBusinessCardInfo" :data="personalBusinessCardInfo" />
  11. <ProfessionalSkillCard
  12. v-if="personalBusinessCardInfo"
  13. v-model="personalBusinessCardInfo"
  14. :upload-api="uploadCertificate"
  15. />
  16. <view v-if="personalBusinessCardInfo" class="save-section">
  17. <button class="save-btn" :disabled="saving" @click="handleSave">
  18. {{ saving ? '保存中...' : '保存' }}
  19. </button>
  20. </view>
  21. </view>
  22. </template>
  23. <script setup lang="ts">
  24. import { computed, ref } from 'vue'
  25. import { onLoad } from '@dcloudio/uni-app'
  26. import { getDictTypeApi } from '@/services/modules/common'
  27. import type { DictItem } from '@/services/modules/common/type'
  28. import {
  29. getPersonalBusinessCardApi,
  30. savePersonalBusinessCardApi,
  31. } from '@/services/modules/mine/personalCard/index'
  32. import type {
  33. PersonalBusinessCardResponse,
  34. SavePersonalBusinessCardRequest,
  35. } from '@/services/modules/mine/personalCard/type'
  36. import { useUserStore } from '@/stores/modules/user'
  37. import PlatformExperienceCard from './components/PlatformExperienceCard.vue'
  38. import ProfessionalSkillCard from './components/ProfessionalSkillCard.vue'
  39. import UserInfoCard from './components/UserInfoCard.vue'
  40. const userStore = useUserStore()
  41. const currentUserInfo = computed(() => userStore.currentUserInfo)
  42. const personalBusinessCardInfo = ref<PersonalBusinessCardResponse>()
  43. const genderColumns = ref<DictItem[]>([])
  44. const degreeColumns = ref<DictItem[]>([])
  45. onLoad(() => {
  46. initPage()
  47. })
  48. const disabled = ref(false)
  49. async function initPage() {
  50. disabled.value = currentUserInfo.value?.faceAuthStatus ?? false
  51. await Promise.all([getDict(), getPersonalBusinessCardInfo()])
  52. }
  53. async function getPersonalBusinessCardInfo() {
  54. const userId = currentUserInfo.value?.userId
  55. if (!userId) return
  56. const res = await getPersonalBusinessCardApi(userId)
  57. personalBusinessCardInfo.value = res.data
  58. }
  59. async function getDict() {
  60. const [genderRes, degreeRes] = await Promise.all([
  61. getDictTypeApi('gender'),
  62. getDictTypeApi('user_degree'),
  63. ])
  64. genderColumns.value = genderRes?.data ?? []
  65. degreeColumns.value = degreeRes?.data ?? []
  66. }
  67. async function uploadCertificate(filePath: string): Promise<string> {
  68. return filePath
  69. }
  70. const saving = ref(false)
  71. function buildSavePayload(): SavePersonalBusinessCardRequest | null {
  72. const info = personalBusinessCardInfo.value
  73. if (!info) return null
  74. return {
  75. degree: info.degree ?? null,
  76. gender: info.gender ?? null,
  77. idCardNumber: info.idCardNumber ?? null,
  78. qualificationRecordNumber: info.qualificationRecordNumber ?? null,
  79. qualificationsUrl: Array.isArray(info.qualificationsUrl) ? info.qualificationsUrl : [],
  80. realname: info.realname ?? null,
  81. userId: info.userId,
  82. }
  83. }
  84. const handleSave = async () => {
  85. if (saving.value) return
  86. const payload = buildSavePayload()
  87. if (!payload) {
  88. uni.showToast({
  89. title: '数据异常,请重新进入页面',
  90. icon: 'none',
  91. })
  92. return
  93. }
  94. try {
  95. saving.value = true
  96. const res = await savePersonalBusinessCardApi(payload)
  97. if (res.code !== 0) {
  98. uni.showToast({
  99. title: res.msg || '提交失败',
  100. icon: 'none',
  101. })
  102. return
  103. }
  104. uni.showToast({
  105. title: '提交成功',
  106. icon: 'success',
  107. })
  108. } catch (error) {
  109. console.error('[PersonalBusinessCard] save failed:', error)
  110. uni.showToast({
  111. title: '提交失败,请稍后重试',
  112. icon: 'none',
  113. })
  114. } finally {
  115. saving.value = false
  116. }
  117. }
  118. </script>
  119. <style lang="scss" scoped>
  120. .personal-card-page {
  121. min-height: 100vh;
  122. padding: 24rpx 24rpx 64rpx;
  123. box-sizing: border-box;
  124. background: linear-gradient(180deg, #f1f6ff 0%, #f6f7fb 48%, #f7f8fa 100%);
  125. }
  126. .save-section {
  127. margin-top: 8rpx;
  128. padding: 8rpx 6rpx 32rpx;
  129. box-sizing: border-box;
  130. }
  131. .save-btn {
  132. display: flex;
  133. align-items: center;
  134. justify-content: center;
  135. width: 100%;
  136. height: 92rpx;
  137. padding: 0;
  138. margin: 0;
  139. border: none;
  140. border-radius: 999rpx;
  141. background: linear-gradient(90deg, #2f84ff 0%, #4ba0ff 100%);
  142. color: #ffffff;
  143. font-size: 32rpx;
  144. font-weight: 600;
  145. line-height: 92rpx;
  146. letter-spacing: 2rpx;
  147. box-shadow:
  148. 0 14rpx 30rpx rgba(47, 132, 255, 0.26),
  149. 0 4rpx 10rpx rgba(47, 132, 255, 0.14);
  150. &::after {
  151. border: none;
  152. }
  153. &[disabled] {
  154. opacity: 0.68;
  155. color: #ffffff;
  156. background: linear-gradient(90deg, #8bbdff 0%, #9dccff 100%);
  157. box-shadow: 0 8rpx 20rpx rgba(47, 132, 255, 0.14);
  158. }
  159. }
  160. </style>