| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- <template>
- <view class="personal-card-page">
- <UserInfoCard
- v-if="personalBusinessCardInfo"
- v-model="personalBusinessCardInfo"
- :disabled="identityLocked"
- :gender-columns="genderColumns"
- :degree-columns="degreeColumns"
- :major-columns="majorColumns"
- />
- <PlatformExperienceCard v-if="personalBusinessCardInfo" :data="personalBusinessCardInfo" />
- <ProfessionalSkillCard
- v-if="personalBusinessCardInfo"
- v-model="personalBusinessCardInfo"
- :disabled="currentUserInfo?.faceAuthStatus ?? false"
- />
- <view v-if="personalBusinessCardInfo" class="save-section">
- <button class="save-btn" :disabled="saving" @click="handleSave">
- {{ saving ? '保存中...' : '保存' }}
- </button>
- </view>
- </view>
- </template>
- <script setup lang="ts">
- import { computed, ref } from 'vue'
- import { onLoad } from '@dcloudio/uni-app'
- import { getDictTypeApi } from '@/services/modules/common'
- import type { DictItem } from '@/services/modules/common/type'
- import {
- getPersonalBusinessCardApi,
- savePersonalBusinessCardApi,
- } from '@/services/modules/mine/personalCard/index'
- import type {
- PersonalBusinessCardResponse,
- PersonalCardFilingItem,
- PromotionDrugApiItem,
- PromotionDrugItem,
- SavePersonalBusinessCardRequest,
- } from '@/services/modules/mine/personalCard/type'
- import { useUserStore } from '@/stores/modules/user'
- import PlatformExperienceCard from './components/PlatformExperienceCard.vue'
- import ProfessionalSkillCard from './components/ProfessionalSkillCard.vue'
- import UserInfoCard from './components/UserInfoCard.vue'
- const userStore = useUserStore()
- const currentUserInfo = computed(() => userStore.currentUserInfo)
- const personalBusinessCardInfo = ref<PersonalBusinessCardResponse>()
- const originalIdentity =
- ref<Pick<PersonalBusinessCardResponse, 'realname' | 'idCardNumber' | 'gender'>>()
- const identityLocked = computed(
- () =>
- currentUserInfo.value?.faceAuthStatus === true ||
- personalBusinessCardInfo.value?.isLivenessAuth === 1
- )
- const genderColumns = ref<DictItem[]>([])
- const degreeColumns = ref<DictItem[]>([])
- const majorColumns = ref<DictItem[]>([])
- onLoad(() => {
- initPage()
- })
- async function initPage() {
- await Promise.all([getDict(), getPersonalBusinessCardInfo()])
- }
- async function getPersonalBusinessCardInfo() {
- const userId = currentUserInfo.value?.userId
- if (!userId) return
- const res = await getPersonalBusinessCardApi(userId)
- const data = res.data
- originalIdentity.value = {
- realname: data.realname,
- idCardNumber: data.idCardNumber,
- gender: data.gender,
- }
- personalBusinessCardInfo.value = {
- ...data,
- qualificationsUrl: Array.isArray(data.qualificationsUrl) ? data.qualificationsUrl : [],
- filingList: normalizeFilingList(data.filingList),
- }
- }
- async function getDict() {
- const [genderRes, degreeRes, majorRes] = await Promise.all([
- getDictTypeApi('gender'),
- getDictTypeApi('user_degree'),
- getDictTypeApi('user_filing_major'),
- ])
- genderColumns.value = genderRes?.data ?? []
- degreeColumns.value = degreeRes?.data ?? []
- majorColumns.value = majorRes?.data ?? []
- }
- const saving = ref(false)
- function buildSavePayload(): SavePersonalBusinessCardRequest | null {
- const info = personalBusinessCardInfo.value
- if (!info) return null
- const filingList = Array.isArray(info.filingList) ? info.filingList : []
- const identity = identityLocked.value && originalIdentity.value ? originalIdentity.value : info
- return {
- degree: info.degree ?? null,
- gender: identity.gender ?? null,
- idCardNumber: identity.idCardNumber ?? null,
- qualificationRecordNumber: info.qualificationRecordNumber ?? null,
- qualificationsUrl: Array.isArray(info.qualificationsUrl) ? info.qualificationsUrl : [],
- realname: identity.realname ?? null,
- userId: info.userId,
- majorCategory: normalizeValue(info.majorCategory),
- province: info.province ?? '',
- provinceCode: normalizeValue(info.provinceCode),
- city: info.city ?? '',
- cityCode: normalizeValue(info.cityCode),
- filingDrugUpdates: filingList.map((item) => ({
- entTaxCode: item.entTaxCode ?? '',
- promotionDrugIds: normalizePromotionDrugs(item.promotionDrugs).map((drug) => drug.drugId),
- })),
- }
- }
- const handleSave = async () => {
- if (saving.value) return
- const payload = buildSavePayload()
- if (!payload) {
- uni.showToast({
- title: '数据异常,请重新进入页面',
- icon: 'none',
- })
- return
- }
- if (payload.qualificationRecordNumber && payload.qualificationsUrl.length === 0) {
- uni.showToast({
- title: '请上传资质证书',
- icon: 'none',
- })
- return
- }
- try {
- saving.value = true
- await savePersonalBusinessCardApi(payload)
- uni.showToast({
- title: '提交成功',
- icon: 'success',
- })
- } catch (error) {
- console.error('[PersonalBusinessCard] save failed:', error)
- } finally {
- saving.value = false
- }
- }
- function normalizeFilingList(
- list: PersonalCardFilingItem[] | null | undefined
- ): PersonalCardFilingItem[] {
- if (!Array.isArray(list)) return []
- return list.map((item) => ({
- ...item,
- promotionDrugs: normalizePromotionDrugs(item.promotionDrugs),
- }))
- }
- function normalizePromotionDrugs(
- list: Array<PromotionDrugApiItem | PromotionDrugItem> | null | undefined
- ): PromotionDrugItem[] {
- if (!Array.isArray(list)) return []
- const seen = new Set<string>()
- return list.reduce<PromotionDrugItem[]>((result, item) => {
- const apiItem = item as PromotionDrugApiItem
- const sourceDrugId = apiItem.drugId ?? apiItem.drug_id ?? apiItem.id
- if (sourceDrugId === undefined || sourceDrugId === null || sourceDrugId === '') {
- return result
- }
- const drugId = String(sourceDrugId)
- if (seen.has(drugId)) return result
- seen.add(drugId)
- result.push({
- drugId,
- drugName: apiItem.drugName ?? apiItem.drug_name ?? apiItem.name ?? '',
- })
- return result
- }, [])
- }
- function normalizeValue(value: string | number | null | undefined): string {
- return value === undefined || value === null ? '' : String(value)
- }
- </script>
- <style lang="scss" scoped>
- .personal-card-page {
- min-height: 100vh;
- padding: 24rpx 24rpx 64rpx;
- box-sizing: border-box;
- background: linear-gradient(180deg, #f1f6ff 0%, #f6f7fb 48%, #f7f8fa 100%);
- }
- .save-section {
- margin-top: 8rpx;
- padding: 8rpx 6rpx 32rpx;
- box-sizing: border-box;
- }
- .save-btn {
- display: flex;
- align-items: center;
- justify-content: center;
- width: 100%;
- height: 92rpx;
- padding: 0;
- margin: 0;
- border: none;
- border-radius: 999rpx;
- background: linear-gradient(90deg, #2f84ff 0%, #4ba0ff 100%);
- color: #ffffff;
- font-size: 32rpx;
- font-weight: 600;
- line-height: 92rpx;
- letter-spacing: 2rpx;
- box-shadow:
- 0 14rpx 30rpx rgba(47, 132, 255, 0.26),
- 0 4rpx 10rpx rgba(47, 132, 255, 0.14);
- &::after {
- border: none;
- }
- &[disabled] {
- opacity: 0.68;
- color: #ffffff;
- background: linear-gradient(90deg, #8bbdff 0%, #9dccff 100%);
- box-shadow: 0 8rpx 20rpx rgba(47, 132, 255, 0.14);
- }
- }
- </style>
|