这个是uploadCoffeeScore页面的内容<template> <view :class=...

Creado el: 26 de mayo de 2026

Respondido usando GPT-5.5 Thinking por Chat01

Pregunta

这个是uploadCoffeeScore页面的内容<template>
<view :class="['app-container', theme]">
<view class="content">
<view class="overlay">
<view class="header" :style="{ paddingTop: statusBarHeight + 'px', height: headerBarHeight + 'px' }">
<view class="header-inner">
<view class="left-box" @click="navigateBack">
<uni-icons type="left" color="#111111" size="26" />
</view>

text
<view class="center-box"> <text class="title-text">简历制作</text> </view> <view class="right-box"></view> </view> </view> <scroll-view scroll-y @scroll="handlePageScroll" class="page-scroll"> <view class="page-wrap"> <view class="top-card"> <view class="top-title-row"> <text class="top-title">咖值分上传配置</text> <text class="top-desc-mini">请完整填写基础信息</text> </view> <view class="module-badge-row"> <text class="module-badge-label">当前模块</text> <text class="module-badge-value">{{ currentModuleLabel }}</text> </view> <text class="top-desc"> 当前页面会保存基础资料、头像、职业方向、报价、自我评价及梦想信息,并根据入口仅展示对应模块; 默认模式下继续兼容成长咖、青春咖、职业咖、资质模板、模卡、视频等模块。 </text> </view> <view class="field-card"> <view class="field-row"> <text class="field-label">简历类型</text> <text class="field-value activeText">全息简历</text> </view> </view> <view class="avatar-card"> <view class="avatar-head" @click="isAvatarExpanded = !isAvatarExpanded"> <view class="avatar-head-left"> <text class="field-label">头像</text> <text class="field-desc">1张,用于简历封面展示</text> </view> <uni-icons :type="isAvatarExpanded ? 'down' : 'up'" color="#8a8f99" size="18" /> </view> <view v-if="isAvatarExpanded" class="avatar-body"> <view class="avatar-sample"> <image class="avatar-sample-img" src="https://img0.baidu.com/it/u=133135383,1058619707&fm=253&app=138&f=JPEG?w=800&h=1428" mode="aspectFill" /> <text class="avatar-sample-text">示例</text> </view> <view class="avatar-upload-box"> <view v-for="(image, index) in displayAvatarList" :key="`avatar-${index}`" class="avatar-upload-item" @click="handleAvatarClick(image, index)"> <view v-if="!image" class="add-button"> <text class="add-text">+</text> </view> <view v-else class="image-container"> <image class="uploaded-image" :src="image" mode="aspectFill" /> <view class="delete-icon" @click.stop="deleteAvatar(index)"> <text class="delete-text">×</text> </view> </view> </view> </view> </view> </view> <view class="group-title">基础信息</view> <view class="field-card"> <view class="field-row"> <text class="field-label">姓名</text> <input v-model.trim="username" class="field-input" type="text" placeholder="请输入姓名" placeholder-style="color:#a0a6b2" /> </view> </view> <view class="field-card"> <view class="field-row"> <text class="field-label">性别</text> <view class="field-action"> <picker mode="selector" :range="genderOptions" :value="genderIndex" @change="changeGender"> <view class="picker-text">{{ selectedGender || '请选择' }}</view> </picker> <uni-icons type="right" color="#8a8f99" size="16" /> </view> </view> </view> <view class="field-card"> <view class="field-row"> <text class="field-label">出生日期</text> <view class="field-action"> <picker mode="date" :value="birthday" :start="startDate" :end="endDate" @change="bindDateChange"> <view class="picker-text">{{ birthday || '请选择' }}</view> </picker> <uni-icons type="right" color="#8a8f99" size="16" /> </view> </view> </view> <view class="field-card"> <view class="field-row"> <text class="field-label">身高</text> <view class="input-with-unit"> <input v-model.trim="userHeight" class="field-input" type="number" placeholder="请输入身高" placeholder-style="color:#a0a6b2" /> <text class="unit-text">cm</text> </view> </view> </view> <view class="field-card"> <view class="field-row"> <text class="field-label">体重</text> <view class="input-with-unit"> <input v-model.trim="userWeight" class="field-input" type="digit" placeholder="请输入体重" placeholder-style="color:#a0a6b2" /> <text class="unit-text">kg</text> </view> </view> </view> <view class="field-card"> <view class="field-row"> <text class="field-label">座右铭</text> <input v-model.trim="userMotto" class="field-input" type="text" placeholder="请输入座右铭" placeholder-style="color:#a0a6b2" /> </view> </view> <view class="field-card" @click="showCityPicker"> <view class="field-row"> <text class="field-label">目前所在地</text> <view class="field-action"> <text class="picker-text ellipsis-text">{{ addressText || '请选择' }}</text> <uni-icons type="right" color="#8a8f99" size="16" /> </view> </view> </view> <mpvue-city-picker ref="cityPickerRef" :pickerValueDefault="pickerValueDefault" @change="onCityChange" @cancel="onCityCancel" @confirm="onCityConfirm" /> <view class="field-card"> <view class="field-row"> <text class="field-label">联系电话</text> <input v-model.trim="userPhone" class="field-input" type="number" placeholder="请输入联系电话" placeholder-style="color:#a0a6b2" /> </view> </view> <view class="field-card"> <view class="field-row"> <text class="field-label">三围</text> <input v-model.trim="userMeasurements" class="field-input" type="text" placeholder="例如 84/62/90" placeholder-style="color:#a0a6b2" /> </view> </view> <view class="field-card"> <view class="field-row"> <text class="field-label">星座</text> <view class="field-action"> <picker mode="selector" :range="constellationOptions" :value="constellationIndex" @change="bindConstellationChange"> <view class="picker-text">{{ selectedConstellation || '请选择' }}</view> </picker> <uni-icons type="right" color="#8a8f99" size="16" /> </view> </view> </view> <view class="field-card"> <view class="field-row"> <text class="field-label">宗教信仰</text> <input v-model.trim="userReligion" class="field-input" type="text" placeholder="请输入宗教信仰" placeholder-style="color:#a0a6b2" /> </view> </view> <view class="field-card"> <view class="field-row"> <text class="field-label">电子邮箱</text> <input v-model.trim="userEmail" class="field-input" type="text" placeholder="请输入邮箱地址" placeholder-style="color:#a0a6b2" /> </view> </view> <!-- 当前职业 --> <view class="career-card"> <view class="career-header" @click="isCareerExpanded = !isCareerExpanded"> <view class="career-header-left"> <text class="field-label">当前职业</text> <text class="career-summary ellipsis-text"> {{ getSubmitJobIntention() || '请选择或自定义职业' }} </text> </view> <uni-icons :type="isCareerExpanded ? 'up' : 'down'" color="#8a8f99" size="18" /> </view> <view v-if="isCareerExpanded" class="career-body"> <text class="career-tip">可展开三级职业,也可直接手动输入其他职业</text> <view class="career-mode-row"> <view class="career-mode-item" :class="{ active: !isCustomCareer }" @click="switchCareerMode(false)"> 系统职业 </view> <view class="career-mode-item" :class="{ active: isCustomCareer }" @click="switchCareerMode(true)"> 自定义输入 </view> </view> <view v-if="isCustomCareer" class="career-custom-box"> <input v-model.trim="customCareerText" class="career-custom-input" type="text" placeholder="请输入意向职业" placeholder-style="color:#a0a6b2" /> </view> <view v-else> <view v-for="(item, index) in safeCareerTree" :key="item.id || `career-top-${index}`" class="career-top-item"> <view class="career-top-row" :class="{ active: activeTopIndex === index }" @click="handleTopCareerClick(item, index)"> <text class="career-top-name">{{ item.name }}</text> <view class="career-top-right"> <text v-if="selectedTopId === item.id && selectedJobText" class="career-selected-text"> {{ selectedJobText }} </text> <uni-icons :type="activeTopIndex === index ? 'up' : 'down'" color="#8a8f99" size="18" /> </view> </view> <view v-if="activeTopIndex === index" class="career-sub-wrap"> <scroll-view scroll-x class="career-second-scroll"> <view class="career-chip-row"> <view v-for="(second, secondIndex) in currentSecondList" :key="second.id || `career-second-${secondIndex}`" class="career-chip" :class="{ active: selectedSecondId === second.id }" @click.stop="handleSecondCareerClick(second, secondIndex)"> {{ second.name }} </view> </view> </scroll-view> <view v-if="currentThirdList.length" class="career-third-box"> <view v-for="(third, thirdIndex) in currentThirdList" :key="third.id || `career-third-${thirdIndex}`" class="career-third-row" @click.stop="handleThirdCareerClick(third)"> <text class="career-third-name">{{ third.name }}</text> <view class="career-check-dot" :class="{ active: selectedThirdId === third.id }"></view> </view> </view> </view> </view> </view> </view> </view> <view class="career-card"> <view class="career-header" @click="isCareerExpanded = !isCareerExpanded"> <view class="career-header-left"> <text class="field-label">意向职业</text> <text class="career-summary ellipsis-text"> {{ getSubmitJobIntention() || '请选择或自定义职业' }} </text> </view> <uni-icons :type="isCareerExpanded ? 'up' : 'down'" color="#8a8f99" size="18" /> </view> <view v-if="isCareerExpanded" class="career-body"> <text class="career-tip">可展开三级职业,也可直接手动输入其他职业</text> <view class="career-mode-row"> <view class="career-mode-item" :class="{ active: !isCustomCareer }" @click="switchCareerMode(false)"> 系统职业 </view> <view class="career-mode-item" :class="{ active: isCustomCareer }" @click="switchCareerMode(true)"> 自定义输入 </view> </view> <view v-if="isCustomCareer" class="career-custom-box"> <input v-model.trim="customCareerText" class="career-custom-input" type="text" placeholder="请输入意向职业" placeholder-style="color:#a0a6b2" /> </view> <view v-else> <view v-for="(item, index) in safeCareerTree" :key="item.id || `career-top-${index}`" class="career-top-item"> <view class="career-top-row" :class="{ active: activeTopIndex === index }" @click="handleTopCareerClick(item, index)"> <text class="career-top-name">{{ item.name }}</text> <view class="career-top-right"> <text v-if="selectedTopId === item.id && selectedJobText" class="career-selected-text"> {{ selectedJobText }} </text> <uni-icons :type="activeTopIndex === index ? 'up' : 'down'" color="#8a8f99" size="18" /> </view> </view> <view v-if="activeTopIndex === index" class="career-sub-wrap"> <scroll-view scroll-x class="career-second-scroll"> <view class="career-chip-row"> <view v-for="(second, secondIndex) in currentSecondList" :key="second.id || `career-second-${secondIndex}`" class="career-chip" :class="{ active: selectedSecondId === second.id }" @click.stop="handleSecondCareerClick(second, secondIndex)"> {{ second.name }} </view> </view> </scroll-view> <view v-if="currentThirdList.length" class="career-third-box"> <view v-for="(third, thirdIndex) in currentThirdList" :key="third.id || `career-third-${thirdIndex}`" class="career-third-row" @click.stop="handleThirdCareerClick(third)"> <text class="career-third-name">{{ third.name }}</text> <view class="career-check-dot" :class="{ active: selectedThirdId === third.id }"></view> </view> </view> </view> </view> </view> </view> </view> <!-- 成长咖模块 --> <view v-if="showSection('growth')" class="module-section"> <view class="module-section-head" :class="{ active: currentModuleType === 'growth' }"> <text class="module-section-title">成长咖模块</text> <text class="module-section-desc">成长经历、奖项、成长方向等内容</text> </view> <view v-for="(item, index) in growthCoffeeModules" :key="item.id || `growth-${index}`" class="module-wrap"> <Growthcoffee :getwinLevelArray="winLevelList" :getthreeGoodStudentLevelArray="threeGoodStudentLevelList" :PersonalObject="personalObject" :getaccomplishmentLevelArray="accomplishmentLevelList" :item="item" :diploma="educationalLevelList" :scholarship="scholarshipLevelList" /> </view> </view> <!-- 青春咖模块 --> <view v-if="showSection('youth')" class="module-section"> <view class="module-section-head" :class="{ active: currentModuleType === 'youth' }"> <text class="module-section-title">青春咖模块</text> <text class="module-section-desc">青春阶段、校园经历、展示内容</text> </view> <view v-for="(item, index) in youthCoffeeModules" :key="item.id || `youth-${index}`" class="module-wrap"> <Youthcoffee :getthreeGoodStudentLevelArray="threeGoodStudentLevelList" :StudentTarget="studentTarget" :PersonalObject="personalObject" :getaccomplishmentLevelArray="accomplishmentLevelArraySafe" :item="item" :diploma="educationalLevelList" :scholarship="scholarshipLevelList" /> </view> </view> <!-- 简历模块 --> <view v-if="showSection('resume')" class="module-section"> <view class="module-section-head" :class="{ active: currentModuleType === 'resume' }"> <text class="module-section-title">简历模块</text> <text class="module-section-desc">简历核心展示信息</text> </view> <view v-for="(item, index) in resumeModules" :key="item.id || `resume-${index}`" class="module-wrap"> <ResumePage :item="item" :downfunction="downfunction" /> </view> </view> <!-- 资质模板模块 --> <view v-if="showSection('qualification')" class="module-section"> <view class="module-section-head" :class="{ active: currentModuleType === 'qualification' }"> <text class="module-section-title">资质模板模块</text> <text class="module-section-desc">证书、资质、项目类型配置</text> </view> <view v-for="(item, index) in qualificationModules" :key="item.id || `qualification-${index}`" class="module-wrap"> <QualificationTemplate :item="item" :getaccomplishmentLevelArray="accomplishmentLevelList" :getitemTypeArray="itemTypeList" /> </view> </view> <!-- 职业咖模块 --> <view v-if="showSection('professional')" class="module-section"> <view class="module-section-head" :class="{ active: currentModuleType === 'professional' }"> <text class="module-section-title">职业咖模块</text> <text class="module-section-desc">团队、职业经历、职业方向</text> </view> <view v-for="(item, index) in professionalModules" :key="item.id || `professional-${index}`" class="module-wrap"> <Professionalcoffee :getworkTeamTypeArray="workTeamTypeList" :TeamObject="teamObject" :getwinLevelArray="winLevelList" :newobjData="newobjData" :item="item" :getaccomplishmentLevelArray="accomplishmentLevelList" :getitemTypeArray="itemTypeList" /> </view> </view> <!-- 模卡模块 --> <view v-if="showSection('muckup')" class="module-section"> <view class="module-section-head" :class="{ active: currentModuleType === 'muckup' }"> <text class="module-section-title">模卡模块</text> <text class="module-section-desc">模卡资料、图片展示、形象信息</text> </view> <view v-for="(item, index) in muckupModules" :key="item.id || `muckup-${index}`" class="module-wrap"> <muckupPage :item="item" :downfunction="downfunction" :hide-video-tag="isPageScrolling" /> </view> </view> <!-- 视频模块 --> <view v-if="showSection('video')" class="module-section"> <view class="module-section-head" :class="{ active: currentModuleType === 'video' }"> <text class="module-section-title">视频模块</text> <text class="module-section-desc">自我介绍视频、展示视频等</text> </view> <view v-for="(item, index) in videoModules" :key="item.id || `video-${index}`" class="module-wrap"> <mySelfVideo :item="item" :isshowvideo="isshowvideo" :hide-video-tag="isPageScrolling" /> </view> </view> <view class="group-title">扩展信息</view> <view class="field-card"> <view class="field-row"> <text class="field-label required-label">报价</text> <view class="input-with-unit"> <input v-model.trim="quotation" class="field-input" type="digit" placeholder="请输入报价" placeholder-style="color:#a0a6b2" /> <text class="unit-text">示例 230/天</text> </view> </view> </view> <view class="group-title">补充描述</view> <view class="textarea-card"> <view class="textarea-head"> <text class="field-label">自我评价</text> <text class="count-text">{{ evaluateLength }}/200</text> </view> <textarea v-model="evaluate" class="textarea-box" placeholder="请输入自我评价" maxlength="200" @input="onEvaluateInput" /> </view> <view class="textarea-card"> <view class="textarea-head"> <text class="field-label">你的梦想</text> <text class="count-text">{{ dreamLength }}/500</text> </view> <textarea v-model="userDream" class="textarea-box textarea-large" placeholder="请输入你的梦想" maxlength="500" @input="onDreamInput" /> </view> <view class="bottom-space"></view> </view> </scroll-view> <view class="footer"> <view class="footer-btn secondary-btn" :class="{ disabled: submitting }" @click="submitBasicinformation"> <text class="secondary-text">{{ submitting ? '提交中...' : '提交资料' }}</text> </view> <view class="footer-btn submit-btn" :class="{ disabled: scoring }" @click="testCoffeeScore"> <text class="submit-text">{{ scoring ? '计算中...' : '测试咖值分' }}</text> </view> </view> <view v-if="scoreDialogVisible" class="dialog-mask" @click="scoreDialogVisible = false"> <view class="dialog-card" @click.stop> <view class="dialog-close" @click="scoreDialogVisible = false"> <uni-icons type="closeempty" size="20" color="#666666" /> </view> <view class="dialog-title">测试完成</view> <view class="dialog-content">恭喜你完成了咖值分测试,当前分数是</view> <view class="dialog-score">{{ showScore }} 分</view> <view class="dialog-btn" @click="scoreDialogVisible = false">我知道了</view> </view> </view> </view> </view> </view>
</template> <script setup> import { ref, computed, nextTick, onBeforeUnmount } from 'vue' import { onLoad, onShow } from '@dcloudio/uni-app' import { storeToRefs } from 'pinia' import { useMainStore } from '@/store/index.js' import ajax from '@/api/ajax.js' import { getStatusBarHeight, getTitleBarHeight } from '@/utils/system.js' import mpvueCityPicker from '@/components/mpvue-citypicker/mpvueCityPicker.vue' import ResumePage from '@/components/ResumePage/ResumePage.vue' import muckupPage from '@/components/muck-upPage/muck-upPage.vue' import mySelfVideo from '@/components/mySelfVideo/mySelfVideo.vue' import Growthcoffee from '@/components/Growthcoffee/Growthcoffee.vue' import QualificationTemplate from '@/components/QualificationTemplate.vue' import Youthcoffee from '@/components/Youthcoffee/Youthcoffee.vue' import Professionalcoffee from '@/components/Professionalcoffee/Professionalcoffee.vue' const mainStore = useMainStore() const { theme } = storeToRefs(mainStore) const statusBarHeight = ref(getStatusBarHeight()) const headerBarHeight = ref(getTitleBarHeight()) const cityPickerRef = ref(null) const consumerId = ref( uni.getStorageSync('consumerId') || uni.getStorageSync('performerId') || '' ) const performerObj = ref({}) const submitting = ref(false) const scoring = ref(false) const downfunction = ref(false) const isshowvideo = ref(false) const scoreDialogVisible = ref(false) const showScore = ref(0) const isAvatarExpanded = ref(true) const avatarList = ref([]) const avatarUrl = ref('') const parameterList = ref([]) const educationalLevelList = ref([]) const scholarshipLevelList = ref([]) const accomplishmentLevelList = ref([]) const itemTypeList = ref([]) const workTeamTypeList = ref([]) const threeGoodStudentLevelList = ref([]) const winLevelList = ref([]) const personalObject = ref({}) const studentTarget = ref({}) const newobjData = ref({}) const teamObject = ref({}) const genderOptions = ['男', '女'] const genderIndex = ref(-1) const constellationOptions = [ '水瓶座', '双鱼座', '白羊座', '金牛座', '双子座', '巨蟹座', '狮子座', '处女座', '天秤座', '天蝎座', '射手座', '摩羯座' ] const constellationIndex = ref(-1) const username = ref('') const birthday = ref(getDate()) const userHeight = ref('') const userWeight = ref('') const userMotto = ref('') const addressText = ref('') const pickerValueDefault = ref([0, 0, 1]) const userPhone = ref('') const userMeasurements = ref('') const userReligion = ref('') const userEmail = ref('') const evaluate = ref('') const userDream = ref('') const quotation = ref('') const isCareerExpanded = ref(true) const isCustomCareer = ref(false) const customCareerText = ref('') const careerTree = ref([]) const activeTopIndex = ref(-1) const activeSecondIndex = ref(-1) const selectedTopId = ref('') const selectedSecondId = ref('') const selectedThirdId = ref('') const selectedJobIds = ref([]) const selectedJobText = ref('') const pendingJobPathIds = ref([]) const pendingJobPathNames = ref([]) const currentModuleType = ref('all') const moduleTypeMap = { all: '全部模块', growth: '成长咖模块', youth: '青春咖模块', resume: '简历模块', qualification: '资质模板模块', professional: '职业咖模块', muckup: '模卡模块', video: '视频模块' } const isPageScrolling = ref(false) let scrollTimer = null function handlePageScroll() { isPageScrolling.value = true if (scrollTimer) clearTimeout(scrollTimer) scrollTimer = setTimeout(() => { isPageScrolling.value = false }, 180) } onBeforeUnmount(() => { if (scrollTimer) { clearTimeout(scrollTimer) scrollTimer = null } }) function safeArray(arr) { return Array.isArray(arr) ? arr.filter(item => item && typeof item === 'object') : [] } function findByCode(list, code) { return safeArray(list).find(item => item.code === code) || null } function findChildByCode(parent, code) { return safeArray(parent?.childrenParameterArray).find(item => item.code === code) || null } function mapSafeIds(list) { return safeArray(list).map(item => item.id).filter(Boolean) } function mapSafeNames(list) { return safeArray(list).map(item => item.name).filter(Boolean) } function normalizeModuleType(value) { const val = String(value || 'all').toLowerCase() return moduleTypeMap[val] ? val : 'all' } function showSection(type) { return currentModuleType.value === 'all' || currentModuleType.value === type } const currentModuleLabel = computed(() => moduleTypeMap[currentModuleType.value] || '全部模块') const selectedGender = computed(() => { return genderIndex.value > -1 ? genderOptions[genderIndex.value] : '' }) const selectedConstellation = computed(() => { return constellationIndex.value > -1 ? constellationOptions[constellationIndex.value] : '' }) const evaluateLength = computed(() => evaluate.value.length) const dreamLength = computed(() => userDream.value.length) const displayAvatarList = computed(() => { if (avatarList.value.length > 0) return avatarList.value if (avatarUrl.value) return [avatarUrl.value] return [null] }) const safeParameterList = computed(() => safeArray(parameterList.value)) const growthCoffeeModules = computed(() => safeParameterList.value.filter(item => item.code === 'performerFileTypeCode_3') ) const youthCoffeeModules = computed(() => safeParameterList.value.filter(item => item.code === 'performerFileTypeCode_3') ) const resumeModules = computed(() => safeParameterList.value.filter(item => item.code === 'performerFileTypeCode_4') ) const qualificationModules = computed(() => safeParameterList.value.filter(item => item.code === 'performerFileTypeCode_5') ) const professionalModules = computed(() => safeParameterList.value.filter(item => item.code === 'performerFileTypeCode_5') ) const muckupModules = computed(() => safeParameterList.value.filter(item => item.code === 'performerFileTypeCode_2') ) const videoModules = computed(() => safeParameterList.value.filter(item => item.code === 'performerFileTypeCode_1') ) const accomplishmentLevelArraySafe = computed(() => safeArray(accomplishmentLevelList.value)) const safeCareerTree = computed(() => safeArray(careerTree.value)) const currentSecondList = computed(() => { if (activeTopIndex.value < 0) return [] const topItem = safeCareerTree.value[activeTopIndex.value] || null return safeArray(topItem?.childrenArray) }) const currentThirdList = computed(() => { if (activeSecondIndex.value < 0) return [] const secondItem = currentSecondList.value[activeSecondIndex.value] || null return safeArray(secondItem?.childrenArray) }) const startDate = computed(() => getDate('start')) const endDate = computed(() => getDate('end')) function showToast(title) { uni.showToast({ title, icon: 'none' }) } function navigateBack() { uni.navigateBack() } function getDate(type) { const date = new Date() let year = date.getFullYear() let month = date.getMonth() + 1 let day = date.getDate() if (type === 'start') year = year - 60 else if (type === 'end') year = year + 2 month = month > 9 ? month : `0${month}` day = day > 9 ? day : `0${day}` return `${year}-${month}-${day}` } function changeGender(e) { genderIndex.value = Number(e?.detail?.value ?? -1) } function bindDateChange(e) { birthday.value = e?.detail?.value || '' } function bindConstellationChange(e) { constellationIndex.value = Number(e?.detail?.value ?? -1) } function onEvaluateInput(e) { evaluate.value = e?.detail?.value || '' } function onDreamInput(e) { userDream.value = e?.detail?.value || '' } function showCityPicker() { cityPickerRef.value?.show?.() } function onCityChange(e) { addressText.value = extractCityLabel(e) } function onCityConfirm(e) { addressText.value = extractCityLabel(e) } function onCityCancel() {} function extractCityLabel(e) { if (!e) return '' if (typeof e.label === 'string' && e.label) return e.label if (Array.isArray(e.labelList) && e.labelList.length) return e.labelList.join('-') if (Array.isArray(e.value) && e.value.length) return e.value.join('-') if (e.province || e.city || e.area) { return [e.province, e.city, e.area].filter(Boolean).join('-') } return '' } function handleAvatarClick(image, index) { if (!image) { chooseAvatar() return } previewAvatar(index) } function chooseAvatar() { uni.chooseImage({ count: 1, sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success: (res) => { const tempPath = res?.tempFilePaths?.[0] if (!tempPath) return avatarList.value = [tempPath] uploadAvatar(tempPath) }, fail: (err) => { console.log('chooseAvatar fail', err) showToast('选择图片失败') } }) } function previewAvatar(index) { const urls = displayAvatarList.value.filter(Boolean) if (!urls.length) return uni.previewImage({ current: urls[index] || urls[0], urls }) } function deleteAvatar(index) { uni.showModal({ title: '确认删除', content: '您确定要删除这张图片吗?', success: (res) => { if (!res.confirm) return avatarList.value.splice(index, 1) if (!avatarList.value.length) { avatarUrl.value = '' uni.removeStorageSync('avatarUrl') } uni.showToast({ title: '删除成功', icon: 'success' }) } }) } function uploadAvatar(filePath) { uni.showLoading({ title: '上传中...' }) uni.uploadFile({ url: `${getApp().globalData.serverUrl}updateAvatarUrl`, filePath, name: 'avatarFile', formData: { consumerId: consumerId.value }, header: { 'Content-Type': 'multipart/form-data' }, success: (res) => { uni.hideLoading() let data = {} try { data = JSON.parse(res.data) } catch (error) { console.log('uploadAvatar parse error', error) } if (data.result === 'success') { avatarUrl.value = data.avatarUrl || filePath avatarList.value = [avatarUrl.value] uni.setStorageSync('avatarUrl', avatarUrl.value) uni.showToast({ title: '更换头像成功', icon: 'success' }) } else { showToast(data.msg || '上传失败') } }, fail: (err) => { uni.hideLoading() console.log('uploadAvatar fail', err) showToast('上传失败') } }) } function switchCareerMode(flag) { isCustomCareer.value = flag if (flag) { activeTopIndex.value = -1 activeSecondIndex.value = -1 selectedTopId.value = '' selectedSecondId.value = '' selectedThirdId.value = '' selectedJobIds.value = [] selectedJobText.value = '' } else { customCareerText.value = '' ensureDefaultCareerSelection() } } function applyCareerSelection(topItem, secondItem, thirdItem) { const ids = [] const names = [] selectedTopId.value = topItem?.id || '' selectedSecondId.value = secondItem?.id || '' selectedThirdId.value = thirdItem?.id || '' if (topItem?.id) { ids.push(topItem.id) names.push(topItem.name) } if (secondItem?.id) { ids.push(secondItem.id) names.push(secondItem.name) } if (thirdItem?.id) { ids.push(thirdItem.id) names.push(thirdItem.name) } selectedJobIds.value = ids selectedJobText.value = names.join(' / ') } function handleTopCareerClick(item, index) { if (!item) return activeTopIndex.value = index activeSecondIndex.value = -1 applyCareerSelection(item, null, null) } function handleSecondCareerClick(item, secondIndex) { if (!item) return activeSecondIndex.value = secondIndex const topItem = safeCareerTree.value[activeTopIndex.value] || null applyCareerSelection(topItem, item, null) } function handleThirdCareerClick(item) { if (!item) return const topItem = safeCareerTree.value[activeTopIndex.value] || null const secondItem = currentSecondList.value[activeSecondIndex.value] || null applyCareerSelection(topItem, secondItem, item) } function ensureDefaultCareerSelection() { if (!safeCareerTree.value.length) return if (selectedJobIds.value.length) return const defaultIndex = safeCareerTree.value.findIndex(item => item?.name === '云演咖') const finalIndex = defaultIndex > -1 ? defaultIndex : 0 const topItem = safeCareerTree.value[finalIndex] || null activeTopIndex.value = finalIndex activeSecondIndex.value = -1 applyCareerSelection(topItem, null, null) } function syncCareerSelectionFromLoaded() { if (!safeCareerTree.value.length) return const ids = pendingJobPathIds.value const names = pendingJobPathNames.value if (!ids.length && !names.length) { if (!customCareerText.value && !selectedJobText.value && !isCustomCareer.value) { ensureDefaultCareerSelection() } return } let topIndex = -1 let secondIndex = -1 let thirdIndex = -1 let topItem = null let secondItem = null let thirdItem = null topIndex = safeCareerTree.value.findIndex(item => { return (ids[0] && item?.id === ids[0]) || (names[0] && item?.name === names[0]) }) if (topIndex > -1) { topItem = safeCareerTree.value[topIndex] const secondList = safeArray(topItem?.childrenArray) secondIndex = secondList.findIndex(item => { return (ids[1] && item?.id === ids[1]) || (names[1] && item?.name === names[1]) }) if (secondIndex > -1) { secondItem = secondList[secondIndex] const thirdList = safeArray(secondItem?.childrenArray) thirdIndex = thirdList.findIndex(item => { return (ids[2] && item?.id === ids[2]) || (names[2] && item?.name === names[2]) }) if (thirdIndex > -1) { thirdItem = thirdList[thirdIndex] } } activeTopIndex.value = topIndex activeSecondIndex.value = secondIndex applyCareerSelection(topItem, secondItem, thirdItem) } } async function getThreelevellinkagedata() { try { const res = await ajax.post({ url: 'jobTypeParameterTree', method: 'post', data: {} }) if (res?.data?.result !== 'success') { showToast('获取意向职业失败') return } careerTree.value = safeArray(res?.data?.parameterArray) syncCareerSelectionFromLoaded() ensureDefaultCareerSelection() } catch (error) { console.log('getThreelevellinkagedata error', error) showToast('获取意向职业失败') } } async function Obtaintemplatedata() { try { const res = await ajax.post({ url: 'performerFileParameterArray', data: {} }) if (res?.data?.result !== 'success') return parameterList.value = safeArray(res?.data?.parameterArray) educationalLevelList.value = safeArray(res?.data?.qualificationArray) scholarshipLevelList.value = safeArray(res?.data?.scholarshipLevelArray) accomplishmentLevelList.value = safeArray(res?.data?.accomplishmentLevelArray) workTeamTypeList.value = safeArray(res?.data?.workTeamTypeArray) itemTypeList.value = safeArray(res?.data?.itemTypeArray) threeGoodStudentLevelList.value = safeArray(res?.data?.threeGoodStudentLevelArray) winLevelList.value = safeArray(res?.data?.winLevelArray) const qualificationItem = findByCode(parameterList.value, 'performerFileTypeCode_5') personalObject.value = findChildByCode(qualificationItem, 'performerFileTypeCode_5_1') || {} const educationItem = findByCode(parameterList.value, 'performerFileTypeCode_3') studentTarget.value = findChildByCode(educationItem, 'performerFileTypeCode_3_6') || {} newobjData.value = findChildByCode(educationItem, 'performerFileTypeCode_3_4') || {} const resumeItem = findByCode(parameterList.value, 'performerFileTypeCode_4') teamObject.value = findChildByCode(resumeItem, 'performerFileTypeCode_4_2') || {} } catch (error) { console.log('Obtaintemplatedata error', error) } } async function Personalinformationdisplay() { try { await ajax.post({ url: 'performerFileTypeShow', method: 'POST', data: { id: consumerId.value } }) } catch (error) { console.log('Personalinformationdisplay error', error) } } function normalizeGenderToIndex(sex) { if (sex === 1 || sex === '1' || sex === '男') return 0 if (sex === 0 || sex === '0' || sex === '女') return 1 return -1 } function normalizeConstellationIndex(starSign) { if (!starSign) return -1 if (typeof starSign === 'number') { return starSign >= 0 && starSign < constellationOptions.length ? starSign : -1 } const num = Number(starSign) if (!Number.isNaN(num) && num >= 0 && num < constellationOptions.length) { return num } return constellationOptions.findIndex(item => item === starSign) } async function Personnelinformationdisplay() { try { const res = await ajax.post({ url: 'performerBaseShow', method: 'POST', data: { performerId: consumerId.value } }) if (res?.data?.result !== 'success') return const data = res?.data?.performerObject || {} performerObj.value = data username.value = data.name || '' genderIndex.value = normalizeGenderToIndex(data.sex) birthday.value = data.birthday || birthday.value userHeight.value = data.stature ? String(data.stature) : '' userWeight.value = data.weight ? String(data.weight) : '' userMotto.value = data.motto || '' addressText.value = data.address || '' userPhone.value = data.mobilePhone ? String(data.mobilePhone) : (data.phone ? String(data.phone) : '') userMeasurements.value = data.measurements || '' constellationIndex.value = normalizeConstellationIndex(data.starSign) userReligion.value = data.religion || '' userEmail.value = data.email || '' evaluate.value = data.profile || '' userDream.value = data.dream || '' quotation.value = data.price ? String(data.price) : '' avatarUrl.value = data.avatarUrl || uni.getStorageSync('avatarUrl') || '' if (avatarUrl.value) { avatarList.value = [avatarUrl.value] } const arr = safeArray(data.jobIntentionArray) if (arr.length) { pendingJobPathIds.value = mapSafeIds(arr) pendingJobPathNames.value = mapSafeNames(arr) isCustomCareer.value = false customCareerText.value = '' syncCareerSelectionFromLoaded() } else if (data.jobIntention) { isCustomCareer.value = true customCareerText.value = data.jobIntention selectedJobIds.value = [] selectedJobText.value = '' } } catch (error) { console.log('Personnelinformationdisplay error', error) showToast('网络错误') } } function getSubmitJobIntention() { if (isCustomCareer.value) { return customCareerText.value.trim() } if (selectedJobText.value) { return selectedJobText.value.trim() } const fallback = safeCareerTree.value.find(item => item?.name === '云演咖') return fallback?.name || '' } function getSubmitJobIds() { if (isCustomCareer.value) return [] if (selectedJobIds.value.length) return selectedJobIds.value const fallback = safeCareerTree.value.find(item => item?.name === '云演咖') return fallback?.id ? [fallback.id] : [] } function validateBasicInfo({ requirePrice = false } = {}) { const checks = [{ ok: !!displayAvatarList.value.filter(Boolean).length, msg: '请上传头像' }, { ok: !!username.value.trim(), msg: '请填写姓名' }, { ok: !!selectedGender.value, msg: '请选择性别' }, { ok: !!birthday.value, msg: '请选择出生日期' }, { ok: !!userHeight.value.trim(), msg: '请填写身高' }, { ok: !!userWeight.value.trim(), msg: '请填写体重' }, { ok: !!userMotto.value.trim(), msg: '请填写座右铭' }, { ok: !!addressText.value.trim(), msg: '请选择目前所在地' }, { ok: !!userPhone.value.trim(), msg: '请填写联系电话' }, { ok: !!userMeasurements.value.trim(), msg: '请填写三围' }, { ok: !!selectedConstellation.value, msg: '请选择星座' }, { ok: !!userReligion.value.trim(), msg: '请填写宗教信仰' }, { ok: !!userEmail.value.trim(), msg: '请填写电子邮箱' }, { ok: !!getSubmitJobIntention(), msg: '请填写意向职业' }, { ok: !!evaluate.value.trim(), msg: '请填写自我评价' }, { ok: !!userDream.value.trim(), msg: '请填写你的梦想' } ] if (requirePrice) { checks.push({ ok: !!quotation.value.trim(), msg: '请填写报价' }) } for (const item of checks) { if (!item.ok) { showToast(item.msg) return false } } if (!/^\d{2,3}(\.\d+)?$/.test(userHeight.value.trim())) { showToast('身高格式不正确') return false } if (!/^\d{2,3}(\.\d+)?$/.test(userWeight.value.trim())) { showToast('体重格式不正确') return false } if (!/^1\d{10}$/.test(userPhone.value.trim())) { showToast('联系电话格式不正确') return false } if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(userEmail.value.trim())) { showToast('邮箱格式不正确') return false } if (requirePrice && !/^\d+(\.\d+)?$/.test(quotation.value.trim())) { showToast('报价格式不正确') return false } return true } function buildPayload({ includePrice = false } = {}) { const payload = { id: consumerId.value, name: username.value.trim(), sex: selectedGender.value === '男' ? 1 : 0, birthday: birthday.value, stature: userHeight.value.trim(), weight: userWeight.value.trim(), motto: userMotto.value.trim(), address: addressText.value.trim(), phone: userPhone.value.trim(), mobilePhone: userPhone.value.trim(), measurements: userMeasurements.value.trim(), starSign: selectedConstellation.value, religion: userReligion.value.trim(), email: userEmail.value.trim(), jobIntention: getSubmitJobIntention(), profile: evaluate.value.trim(), dream: userDream.value.trim(), jobIntentionIds: getSubmitJobIds() } if (includePrice) { payload.price = quotation.value.trim() } return payload } async function submitBasicinformation() { if (submitting.value) return if (!consumerId.value) { showToast('缺少用户ID') return } if (!validateBasicInfo()) return submitting.value = true try { const res = await ajax.post({ url: 'performerNew', method: 'post', data: buildPayload() }) if (res?.data?.result === 'success') { uni.showToast({ title: '提交成功', icon: 'success' }) return } showToast(res?.data?.msg || '提交失败') } catch (error) { console.log('submitBasicinformation error', error) showToast('提交失败') } finally { submitting.value = false } } async function testCoffeeScore() { if (scoring.value) return if (!consumerId.value) { showToast('缺少用户ID') return } if (!validateBasicInfo({ requirePrice: true })) return scoring.value = true try { const res = await ajax.post({ url: 'performerNew', method: 'post', data: buildPayload({ includePrice: true }) }) if (res?.data?.result === 'success') { showScore.value = Number(res?.data?.baseScoreSum || 0) scoreDialogVisible.value = true return } showToast(res?.data?.msg || '测试失败') } catch (error) { console.log('testCoffeeScore error', error) showToast('测试失败') } finally { scoring.value = false } } onLoad(async (options) => { currentModuleType.value = normalizeModuleType(options?.moduleType) await Promise.allSettled([ Obtaintemplatedata(), getThreelevellinkagedata(), Personnelinformationdisplay(), Personalinformationdisplay() ]) await nextTick() }) onShow(() => { Personalinformationdisplay() }) </script> <style lang="scss" scoped> @import '@/assets/styles/global.scss'; .app-container { min-height: 100vh; background: #f7f8fc; } .content { min-height: 100vh; position: relative; background: linear-gradient(180deg, #fdf7ea 0%, #f7f8fc 38%, #f7f8fc 100%); } .overlay { position: absolute; inset: 0; display: flex; flex-direction: column; } .header { width: 94%; margin: 0 auto; flex-shrink: 0; } .header-inner { position: relative; display: flex; align-items: center; justify-content: center; height: 100%; } .left-box, .right-box { position: absolute; top: 0; bottom: 0; width: 120rpx; display: flex; align-items: center; } .left-box { left: 0; justify-content: flex-start; } .right-box { right: 0; justify-content: flex-end; } .center-box { flex: none; } .title-text { font-size: 34rpx; font-weight: 600; color: #111111; } .page-scroll { flex: 1; height: 0; } .page-wrap { width: 94%; margin: 0 auto; padding: 20rpx 0 0; box-sizing: border-box; } .top-card, .field-card, .avatar-card, .textarea-card, .module-wrap, .career-card { margin-top: 16rpx; padding: 24rpx; border-radius: 24rpx; background: rgba(255, 255, 255, 0.94); box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04); } .top-card { margin-top: 0; } .top-title-row { display: flex; align-items: center; justify-content: space-between; gap: 20rpx; } .top-title { font-size: 32rpx; font-weight: 600; color: #1f2329; } .top-desc-mini { font-size: 22rpx; color: #8a8f99; } .module-badge-row { margin-top: 18rpx; display: flex; align-items: center; gap: 16rpx; } .module-badge-label { font-size: 24rpx; color: #8a8f99; } .module-badge-value { padding: 10rpx 22rpx; border-radius: 999rpx; font-size: 24rpx; font-weight: 600; color: #1e160b; background: linear-gradient(135deg, #d7983e 0%, #edd9a1 100%); } .top-desc { display: block; margin-top: 14rpx; font-size: 24rpx; color: #8a8f99; line-height: 1.6; } .group-title { margin-top: 24rpx; padding: 6rpx 6rpx 0; font-size: 28rpx; font-weight: 600; color: #20242b; } .field-row { display: flex; align-items: center; justify-content: space-between; gap: 20rpx; min-height: 44rpx; } .field-label { flex-shrink: 0; font-size: 28rpx; font-weight: 600; color: #20242b; } .required-label::before { content: '*'; color: #d7983e; margin-right: 6rpx; } .field-value, .field-desc, .count-text, .picker-text { font-size: 24rpx; color: #8a8f99; } .field-action { display: flex; align-items: center; gap: 10rpx; min-width: 0; flex-shrink: 0; } .field-input { flex: 1; min-width: 0; height: 44rpx; font-size: 26rpx; color: #20242b; text-align: right; } .ellipsis-text { max-width: 380rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .activeText { background: linear-gradient(135deg, #d89838 0%, #ceb87e 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; display: inline-block; } .input-with-unit { display: flex; align-items: center; justify-content: flex-end; gap: 10rpx; flex: 1; } .unit-text { font-size: 24rpx; color: #8a8f99; } .avatar-head { display: flex; align-items: center; justify-content: space-between; } .avatar-head-left { display: flex; align-items: center; gap: 12rpx; } .avatar-sample-text { margin-top: 10rpx; font-size: 22rpx; color: #8a8f99; } .avatar-body { margin-top: 22rpx; display: flex; align-items: center; justify-content: space-between; gap: 24rpx; } .avatar-sample { width: 180rpx; display: flex; flex-direction: column; align-items: center; flex-shrink: 0; } .avatar-sample-img { width: 120rpx; height: 120rpx; border-radius: 18rpx; background: #eef1f5; } .avatar-upload-box { flex: 1; display: flex; justify-content: flex-end; } .avatar-upload-item { width: 120rpx; height: 120rpx; border-radius: 18rpx; overflow: hidden; background: linear-gradient(to bottom, #000000, #292525); position: relative; } .add-button { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background: rgba(255, 255, 255, 0.12); } .add-text { font-size: 72rpx; color: #ffffff; line-height: 1; } .image-container, .uploaded-image { width: 100%; height: 100%; } .uploaded-image { display: block; } .delete-icon { position: absolute; right: 8rpx; top: 8rpx; width: 36rpx; height: 36rpx; border-radius: 50%; background: rgba(0, 0, 0, 0.55); display: flex; align-items: center; justify-content: center; } .delete-text { color: #fff; font-size: 22rpx; line-height: 1; } .career-header { display: flex; align-items: center; justify-content: space-between; gap: 20rpx; } .career-header-left { flex: 1; min-width: 0; display: flex; align-items: center; gap: 16rpx; } .career-summary { flex: 1; font-size: 24rpx; color: #8a8f99; text-align: right; } .career-body { margin-top: 20rpx; } .career-tip { display: block; font-size: 22rpx; color: #8a8f99; margin-bottom: 20rpx; } .career-mode-row { display: flex; gap: 16rpx; margin-bottom: 20rpx; } .career-mode-item { padding: 12rpx 24rpx; border-radius: 999rpx; font-size: 24rpx; color: #6f7782; background: #f3f5f8; } .career-mode-item.active { color: #1e160b; background: linear-gradient(135deg, #d7983e 0%, #edd9a1 100%); } .career-custom-box { margin-bottom: 16rpx; } .career-custom-input { width: 100%; height: 88rpx; padding: 0 24rpx; box-sizing: border-box; border-radius: 18rpx; background: #f7f8fc; font-size: 26rpx; color: #20242b; } .career-top-item+.career-top-item { margin-top: 16rpx; } .career-top-row { display: flex; align-items: center; justify-content: space-between; gap: 16rpx; padding: 22rpx 24rpx; border-radius: 18rpx; background: #f7f8fc; } .career-top-row.active { background: linear-gradient(180deg, #fff7e6 0%, #fffaf0 100%); border: 1rpx solid rgba(215, 152, 62, 0.18); } .career-top-name { font-size: 26rpx; font-weight: 600; color: #20242b; } .career-top-right { display: flex; align-items: center; gap: 12rpx; min-width: 0; } .career-selected-text { max-width: 260rpx; font-size: 22rpx; color: #8a8f99; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .career-sub-wrap { margin-top: 14rpx; padding: 18rpx; border-radius: 18rpx; background: #f7f8fc; } .career-second-scroll { width: 100%; white-space: nowrap; } .career-chip-row { display: inline-flex; align-items: center; gap: 14rpx; padding-right: 8rpx; } .career-chip { display: inline-flex; align-items: center; justify-content: center; padding: 16rpx 22rpx; border-radius: 14rpx; background: #ffffff; color: #6f7782; font-size: 24rpx; border: 1rpx solid #edf0f4; } .career-chip.active { background: #352e37; color: #ffffff; border-color: #352e37; } .career-third-box { margin-top: 16rpx; border-radius: 16rpx; background: #ffffff; overflow: hidden; } .career-third-row { display: flex; align-items: center; justify-content: space-between; gap: 20rpx; padding: 20rpx 18rpx; border-bottom: 1rpx solid #eef1f5; } .career-third-row:last-child { border-bottom: none; } .career-third-name { font-size: 25rpx; color: #20242b; } .career-check-dot { width: 24rpx; height: 24rpx; border-radius: 50%; background: #c4c8cf; flex-shrink: 0; } .career-check-dot.active { background: #d6b266; } .module-section { margin-top: 24rpx; } .module-section-head { margin-bottom: 14rpx; padding: 22rpx 24rpx; border-radius: 22rpx; background: rgba(255, 255, 255, 0.92); box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04); display: flex; flex-direction: column; gap: 8rpx; } .module-section-head.active { background: linear-gradient(180deg, #fff7e6 0%, #fffaf0 100%); border: 1rpx solid rgba(215, 152, 62, 0.18); box-shadow: 0 12rpx 28rpx rgba(215, 152, 62, 0.08); } .module-section-title { font-size: 30rpx; font-weight: 700; color: #20242b; } .module-section-desc { font-size: 22rpx; color: #8a8f99; line-height: 1.6; } .module-wrap { overflow: hidden; padding: 0; } .textarea-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16rpx; } .textarea-box { width: 100%; height: 160rpx; padding: 18rpx 20rpx; box-sizing: border-box; border-radius: 18rpx; background: #f7f8fc; font-size: 26rpx; color: #20242b; line-height: 1.7; } .textarea-large { height: 220rpx; } .bottom-space { height: 210rpx; } .footer { position: fixed; left: 0; right: 0; bottom: 0; padding: 20rpx 30rpx calc(env(safe-area-inset-bottom) + 20rpx); background: linear-gradient(180deg, rgba(247, 248, 252, 0) 0%, #f7f8fc 32%); display: flex; gap: 18rpx; } .footer-btn { flex: 1; height: 88rpx; border-radius: 44rpx; display: flex; align-items: center; justify-content: center; } .submit-btn { background: linear-gradient(135deg, #d7983e 0%, #edd9a1 100%); box-shadow: 0 10rpx 24rpx rgba(215, 152, 62, 0.22); } .secondary-btn { background: #ffffff; border: 1rpx solid rgba(215, 152, 62, 0.3); box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.04); } .footer-btn.disabled { opacity: 0.65; } .submit-text { font-size: 30rpx; font-weight: 600; color: #1e160b; } .secondary-text { font-size: 30rpx; font-weight: 600; color: #b67c22; } .dialog-mask { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.4); display: flex; align-items: center; justify-content: center; z-index: 999; padding: 40rpx; box-sizing: border-box; } .dialog-card { position: relative; width: 100%; max-width: 620rpx; padding: 36rpx 30rpx 30rpx; border-radius: 28rpx; background: #ffffff; text-align: center; } .dialog-close { position: absolute; right: 20rpx; top: 20rpx; width: 44rpx; height: 44rpx; display: flex; align-items: center; justify-content: center; } .dialog-title { font-size: 34rpx; font-weight: 700; color: #20242b; } .dialog-content { margin-top: 16rpx; font-size: 26rpx; color: #6f7782; line-height: 1.6; } .dialog-score { margin-top: 20rpx; font-size: 48rpx; font-weight: 700; background: linear-gradient(135deg, #d89838 0%, #ceb87e 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .dialog-btn { margin-top: 26rpx; height: 78rpx; border-radius: 39rpx; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, #d7983e 0%, #edd9a1 100%); color: #1e160b; font-size: 28rpx; font-weight: 600; } </style> 修改这里的东西<!-- 当前职业 -->
text
<view class="career-card"> <view class="career-header" @click="isCareerExpanded = !isCareerExpanded"> <view class="career-header-left"> <text class="field-label">当前职业</text> <text class="career-summary ellipsis-text"> {{ getSubmitJobIntention() || '请选择或自定义职业' }} </text> </view> <uni-icons :type="isCareerExpanded ? 'up' : 'down'" color="#8a8f99" size="18" /> </view> <view v-if="isCareerExpanded" class="career-body"> <text class="career-tip">可展开三级职业,也可直接手动输入其他职业</text> <view class="career-mode-row"> <view class="career-mode-item" :class="{ active: !isCustomCareer }" @click="switchCareerMode(false)"> 系统职业 </view> <view class="career-mode-item" :class="{ active: isCustomCareer }" @click="switchCareerMode(true)"> 自定义输入 </view> </view> <view v-if="isCustomCareer" class="career-custom-box"> <input v-model.trim="customCareerText" class="career-custom-input" type="text" placeholder="请输入意向职业" placeholder-style="color:#a0a6b2" /> </view> <view v-else> <view v-for="(item, index) in safeCareerTree" :key="item.id || `career-top-${index}`" class="career-top-item"> <view class="career-top-row" :class="{ active: activeTopIndex === index }" @click="handleTopCareerClick(item, index)"> <text class="career-top-name">{{ item.name }}</text> <view class="career-top-right"> <text v-if="selectedTopId === item.id && selectedJobText" class="career-selected-text"> {{ selectedJobText }} </text> <uni-icons :type="activeTopIndex === index ? 'up' : 'down'" color="#8a8f99" size="18" /> </view> </view> <view v-if="activeTopIndex === index" class="career-sub-wrap"> <scroll-view scroll-x class="career-second-scroll"> <view class="career-chip-row"> <view v-for="(second, secondIndex) in currentSecondList" :key="second.id || `career-second-${secondIndex}`" class="career-chip" :class="{ active: selectedSecondId === second.id }" @click.stop="handleSecondCareerClick(second, secondIndex)"> {{ second.name }} </view> </view> </scroll-view> <view v-if="currentThirdList.length" class="career-third-box"> <view v-for="(third, thirdIndex) in currentThirdList" :key="third.id || `career-third-${thirdIndex}`" class="career-third-row" @click.stop="handleThirdCareerClick(third)"> <text class="career-third-name">{{ third.name }}</text> <view class="career-check-dot" :class="{ active: selectedThirdId === third.id }"></view> </view> </view> </view> </view> </view> </view> </view> <view class="career-card"> <view class="career-header" @click="isCareerExpanded = !isCareerExpanded"> <view class="career-header-left"> <text class="field-label">意向职业</text> <text class="career-summary ellipsis-text"> {{ getSubmitJobIntention() || '请选择或自定义职业' }} </text> </view> <uni-icons :type="isCareerExpanded ? 'up' : 'down'" color="#8a8f99" size="18" /> </view> <view v-if="isCareerExpanded" class="career-body"> <text class="career-tip">可展开三级职业,也可直接手动输入其他职业</text> <view class="career-mode-row"> <view class="career-mode-item" :class="{ active: !isCustomCareer }" @click="switchCareerMode(false)"> 系统职业 </view> <view class="career-mode-item" :class="{ active: isCustomCareer }" @click="switchCareerMode(true)"> 自定义输入 </view> </view> <view v-if="isCustomCareer" class="career-custom-box"> <input v-model.trim="customCareerText" class="career-custom-input" type="text" placeholder="请输入意向职业" placeholder-style="color:#a0a6b2" /> </view> <view v-else> <view v-for="(item, index) in safeCareerTree" :key="item.id || `career-top-${index}`" class="career-top-item"> <view class="career-top-row" :class="{ active: activeTopIndex === index }" @click="handleTopCareerClick(item, index)"> <text class="career-top-name">{{ item.name }}</text> <view class="career-top-right"> <text v-if="selectedTopId === item.id && selectedJobText" class="career-selected-text"> {{ selectedJobText }} </text> <uni-icons :type="activeTopIndex === index ? 'up' : 'down'" color="#8a8f99" size="18" /> </view> </view> <view v-if="activeTopIndex === index" class="career-sub-wrap"> <scroll-view scroll-x class="career-second-scroll"> <view class="career-chip-row"> <view v-for="(second, secondIndex) in currentSecondList" :key="second.id || `career-second-${secondIndex}`" class="career-chip" :class="{ active: selectedSecondId === second.id }" @click.stop="handleSecondCareerClick(second, secondIndex)"> {{ second.name }} </view> </view> </scroll-view> <view v-if="currentThirdList.length" class="career-third-box"> <view v-for="(third, thirdIndex) in currentThirdList" :key="third.id || `career-third-${thirdIndex}`" class="career-third-row" @click.stop="handleThirdCareerClick(third)"> <text class="career-third-name">{{ third.name }}</text> <view class="career-check-dot" :class="{ active: selectedThirdId === third.id }"></view> </view> </view> </view> </view> </view> </view> </view>这俩一对一改成多选多对对 6.performerNew新的个人基本信息提交

入口参数
String id, 个人id不能为空
String name, 姓名
Integer sex, 性别(0女,1男)
Date birthday, 生日
Float stature, 身高
Float weight, 体重
String motto, 座右铭
String address, 目前所在地
String measurements, 三围
String starSign, 星座
String religion, 宗教信仰
String email, 电子邮件
String jobIntention, 求职意向
String profile, 自我介绍
String dream梦想
Integer workYear,工作年限
String[] workIds 选择当前职业id数组
String[] jobIntentionIds 选择的求职意向id数组
返回值
baseScoreSum 个人基础分
这个 String[] jobIntentionIds 选择的求职意向id数组 有了现在多选加了这个 String[] workIds 选择当前职业id数组 返回方法和 html 模版就行 返回局部的代码功能
你帮我加上这些功能 然后 写一个完整的页面 可以直接替换的页面

Pensamiento

Successfully created text document 'Upload Coffee Score Multi Select' which will be referenced in all future messages with the unique identifier textdoc_id: '6a1500adc8bc8191b33eb55aacaa9f2a'

Important: This identifier is for tool calls only to reference or update this document. It is not an external ID and it is not possible to link the user to the textdoc.

Thought for 4m 28s

Respuesta

已整理成完整可替换页面,放在右侧代码文档里:uploadCoffeeScore_multi_select.vue

这版主要改了:

  1. 当前职业意向职业 拆成两套独立状态,不再共用 isCareerExpanded / selectedJobIds / selectedJobText
  2. 两个职业都支持多选,已选项以标签展示,可单个删除或清空。
  3. 提交 performerNew 时新增:
    js
    workIds: getCareerSubmitIds('work'), jobIntentionIds: getCareerSubmitIds('intention')
  4. 新增 workYear 工作年限字段,并提交:
    js
    payload.workYear = Number(workYear.value.trim())
  5. 兼容老数据回显:如果后端还是返回原来的 jobIntentionArray 路径数组,也会自动压缩成最后一级职业回显。
  6. 当前职业自定义时我额外带了:
    js
    workName: getCareerSubmitText('work')
    如果后端不接收这个字段,可以直接删掉这几行;系统职业提交主要靠 workIds

Compartir este Q&A