Files
ks-app-employment-service/pages/complete-info/company-info.vue
2025-10-22 13:15:10 +08:00

901 lines
28 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<AppLayout title="企业信息">
<view class="company-info-container">
<!-- 头部信息 -->
<view class="header-info">
<view class="progress-text">企业信息完善度</view>
<view class="progress-value">{{ completionPercentage }}%</view>
</view>
<!-- 表单内容 -->
<view class="form-content">
<!-- 企业名称 -->
<view class="form-item">
<view class="label">企业名称</view>
<input
class="input-field"
v-model="formData.companyName"
placeholder="请输入企业名称"
@input="updateCompletion"
/>
</view>
<!-- 统一社会信用代码 -->
<view class="form-item">
<view class="label">统一社会信用代码</view>
<input
class="input-field"
v-model="formData.socialCreditCode"
placeholder="请输入统一社会信用代码"
maxlength="18"
@input="updateCompletion"
/>
</view>
<!-- 企业注册地点 -->
<view class="form-item clickable" @click="selectLocation">
<view class="label">企业注册地点</view>
<view class="input-content">
<text class="input-text" :class="{ placeholder: !formData.registeredAddress }">
{{ formData.registeredAddress || '请选择注册地点' }}
</text>
<uni-icons type="arrowright" size="16" color="#999"></uni-icons>
</view>
</view>
<!-- 企业信息介绍 -->
<view class="form-item clickable" @click="editCompanyIntro">
<view class="label">企业信息介绍</view>
<view class="input-content">
<text class="input-text intro-text" :class="{ placeholder: !formData.companyIntro }">
{{ formData.companyIntro || '请输入企业介绍' }}
</text>
<uni-icons type="arrowright" size="16" color="#999"></uni-icons>
</view>
</view>
<!-- 企业法人姓名 -->
<view class="form-item">
<view class="label">企业法人姓名</view>
<input
class="input-field"
v-model="formData.legalPersonName"
placeholder="请输入法人姓名"
@input="updateCompletion"
/>
</view>
<!-- 企业类型 -->
<view class="form-item clickable" @click="selectEnterpriseType">
<view class="label">企业类型</view>
<view class="input-content">
<input class="input-con" v-model="formData.natureText" disabled placeholder="请选择企业类型" />
<uni-icons type="arrowright" size="16" color="#999"></uni-icons>
</view>
</view>
<!-- 是否是就业见习基地 -->
<view class="form-item clickable" @click="selectEmploymentBase">
<view class="label">是否是就业见习基地</view>
<view class="input-content">
<text class="input-text" :class="{ placeholder: formData.enterpriseType === null }">
{{ formData.enterpriseType === null ? '请选择' : (formData.enterpriseType ? '是' : '否') }}
</text>
<uni-icons type="arrowright" size="16" color="#999"></uni-icons>
</view>
</view>
<!-- 法人身份证号 -->
<view class="form-item">
<view class="label">法人身份证号</view>
<input
class="input-field"
v-model="formData.legalIdCard"
placeholder="请输入法人身份证号"
maxlength="18"
@input="updateCompletion"
/>
</view>
<!-- 法人联系方式 -->
<view class="form-item">
<view class="label">法人联系方式</view>
<input
class="input-field"
v-model="formData.legalPhone"
placeholder="请输入法人联系方式"
maxlength="11"
@input="updateCompletion"
/>
</view>
<!-- 本地重点发展产业 -->
<view class="form-item clickable" @click="selectIndustry">
<view class="label">本地重点发展产业</view>
<view class="input-content">
<text class="input-text" :class="{ placeholder: !formData.industryType }">
{{ formData.industryType || '请选择产业类型' }}
</text>
<uni-icons type="arrowright" size="16" color="#999"></uni-icons>
</view>
</view>
<!-- 是否是本地企业 -->
<view class="form-item clickable" @click="selectLocalCompany">
<view class="label">是否是本地重点发展产业</view>
<view class="input-content">
<text class="input-text" :class="{ placeholder: formData.isLocalCompany === null }">
{{ formData.isLocalCompany === null ? '请选择' : (formData.isLocalCompany ? '是' : '否') }}
</text>
<uni-icons type="arrowright" size="16" color="#999"></uni-icons>
</view>
</view>
<!-- 联系人信息列表 -->
<view class="contact-section">
<view class="section-title">联系人信息</view>
<!-- 每个联系人作为一个分组 -->
<view
class="contact-group"
v-for="(contact, index) in formData.companyContactList"
:key="index"
>
<view class="group-header">
<text>联系人{{ index + 1 }}</text>
<view
class="delete-btn"
@click="deleteContact(index)"
v-if="formData.companyContactList.length > 1"
>
<uni-icons type="trash" size="16" color="#ff4757"></uni-icons>
<text class="delete-text">删除</text>
</view>
</view>
<view class="form-item">
<view class="label">联系人姓名</view>
<input
class="input-field"
v-model="contact.contactPerson"
placeholder="请输入联系人姓名"
@input="updateCompletion"
/>
</view>
<view class="form-item">
<view class="label">联系人电话</view>
<input
class="input-field"
v-model="contact.contactPersonPhone"
placeholder="请输入联系人电话"
@input="updateCompletion"
/>
</view>
</view>
</view>
<!-- 添加联系人按钮 -->
<view class="add-contact-btn" @click="addContact" v-if="formData.companyContactList.length < 3">
<uni-icons type="plus" size="20" color="#256BFA"></uni-icons>
<text>添加联系人</text>
</view>
</view>
<!-- 底部按钮 -->
<view class="bottom-actions">
<button class="cancel-btn" @click="cancel">取消</button>
<button class="confirm-btn" @click="confirm">确认</button>
</view>
</view>
<!-- 弹窗组件 -->
<uni-popup ref="popup" type="center">
<view class="popup-content">
<view class="popup-title">{{ popupTitle }}</view>
<input
v-if="popupType === 'text'"
class="popup-input"
v-model="popupValue"
:placeholder="popupPlaceholder"
/>
<textarea
v-if="popupType === 'textarea'"
class="popup-textarea"
v-model="popupValue"
:placeholder="popupPlaceholder"
maxlength="500"
></textarea>
<view class="popup-actions">
<button class="popup-cancel" @click="closePopup">取消</button>
<button class="popup-confirm" @click="confirmPopup">确定</button>
</view>
</view>
</uni-popup>
<!-- 地址选择器 -->
<area-cascade-picker ref="areaPicker"></area-cascade-picker>
<!-- 滚动选择器 -->
<SelectPopup ref="selectPopupRef"></SelectPopup>
</AppLayout>
</template>
<script setup>
import { ref, reactive, computed, inject } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import AreaCascadePicker from '@/components/area-cascade-picker/area-cascade-picker.vue'
import SelectPopup from '@/components/selectPopup/selectPopup.vue'
import useDictStore from '@/stores/useDictStore'
const { $api } = inject('globalFunction')
const dictStore = useDictStore()
// 表单数据
const formData = reactive({
companyName: '',
socialCreditCode: '',
registeredAddress: '',
registeredAddressName: '',
longitude: null,
latitude: null,
companyIntro: '',
legalPersonName: '',
nature: '', // 企业类型
natureText: '', // 企业类型显示文本
enterpriseType: null, // 是否是就业见习基地 (true/false/null)
legalIdCard: '', // 法人身份证号
legalPhone: '', // 法人联系方式
industryType: '', // 是否是本地重点发展产业
isLocalCompany: null, // 是否是本地企业 (true/false/null)
companyContactList: [
{ contactPerson: '', contactPersonPhone: '' }
]
})
// 弹窗相关
const popup = ref(null)
const popupTitle = ref('')
const popupType = ref('text') // text | textarea
const popupValue = ref('')
const popupPlaceholder = ref('')
const currentEditField = ref('')
// 地址选择器引用
const areaPicker = ref(null)
// 滚动选择器引用
const selectPopupRef = ref(null)
// 创建本地的 openSelectPopup 函数
const openSelectPopup = (config) => {
if (selectPopupRef.value) {
selectPopupRef.value.open(config);
}
}
// 产业类型选项数据
const industryOptions = [
'人工智能',
'生物医药',
'新能源',
'高端装备制造',
'其他'
]
// 备用企业类型选项(当字典数据加载失败时使用)
const fallbackEnterpriseTypes = [
{ label: '有限责任公司', value: '1' },
{ label: '股份有限公司', value: '2' },
{ label: '个人独资企业', value: '3' },
{ label: '合伙企业', value: '4' },
{ label: '外商投资企业', value: '5' },
{ label: '其他', value: '6' }
]
// 企业类型选项数据从字典中获取
const enterpriseTypeOptions = computed(() => {
const natureData = dictStore.state?.nature || []
console.log('企业类型选项数据:', natureData)
return natureData
})
// 完成度计算
const completionPercentage = computed(() => {
const fields = [
formData.companyName,
formData.socialCreditCode,
formData.registeredAddress,
formData.companyIntro,
formData.legalPersonName,
formData.nature,
formData.enterpriseType !== null ? 'filled' : '',
formData.legalIdCard,
formData.legalPhone,
formData.industryType,
formData.isLocalCompany !== null ? 'filled' : ''
]
// 检查联系人信息
const hasContact = formData.companyContactList.some(contact => contact.contactPerson && contact.contactPersonPhone)
const filledFields = fields.filter(field => field && field.trim()).length + (hasContact ? 1 : 0)
const totalFields = fields.length + 1
return Math.round((filledFields / totalFields) * 100)
})
// 更新完成度
const updateCompletion = () => {
// 完成度会自动通过computed更新
}
// 选择注册地点
const selectLocation = () => {
// 打开五级联动地址选择器
areaPicker.value?.open({
title: '选择企业注册地点',
maskClick: true,
success: (addressData) => {
// addressData 包含: address, province, city, district, street, community
formData.registeredAddress = addressData.address
formData.registeredAddressName = addressData.address
// 可以保存详细的地址信息
formData.provinceCode = addressData.province?.code
formData.provinceName = addressData.province?.name
formData.cityCode = addressData.city?.code
formData.cityName = addressData.city?.name
formData.districtCode = addressData.district?.code
formData.districtName = addressData.district?.name
formData.streetCode = addressData.street?.code
formData.streetName = addressData.street?.name
formData.communityCode = addressData.community?.code
formData.communityName = addressData.community?.name
updateCompletion()
$api.msg('地址选择成功')
}
})
}
// 处理地图选择返回的地址
const handleLocationSelected = (locationData) => {
formData.registeredAddress = locationData.address
formData.registeredAddressName = locationData.name
formData.longitude = locationData.longitude
formData.latitude = locationData.latitude
updateCompletion()
}
// 编辑企业介绍
const editCompanyIntro = () => {
currentEditField.value = 'companyIntro'
popupTitle.value = '企业信息介绍'
popupType.value = 'textarea'
popupValue.value = formData.companyIntro
popupPlaceholder.value = '请输入企业介绍'
popup.value?.open()
}
// 选择产业类型
const selectIndustry = () => {
uni.showActionSheet({
itemList: industryOptions,
success: (res) => {
formData.industryType = industryOptions[res.tapIndex]
updateCompletion()
$api.msg('产业类型选择成功')
}
})
}
// 选择企业类型
const selectEnterpriseType = () => {
console.log('点击企业类型,当前数据:', enterpriseTypeOptions.value)
console.log('字典store状态:', dictStore.state.nature)
// 获取企业类型选项,优先使用字典数据,失败时使用备用数据
let options = enterpriseTypeOptions.value
if (!options || !options.length) {
console.log('企业类型数据为空,尝试重新加载')
// 尝试重新加载字典数据
dictStore.getDictData().then(() => {
if (dictStore.state.nature && dictStore.state.nature.length > 0) {
selectEnterpriseType() // 递归调用
} else {
// 使用备用数据
console.log('使用备用企业类型数据')
options = fallbackEnterpriseTypes
showEnterpriseTypeSelector(options)
}
}).catch(() => {
// 使用备用数据
console.log('字典加载失败,使用备用企业类型数据')
options = fallbackEnterpriseTypes
showEnterpriseTypeSelector(options)
})
return
}
showEnterpriseTypeSelector(options)
}
// 显示企业类型选择器
const showEnterpriseTypeSelector = (options) => {
console.log('企业类型选项列表:', options)
openSelectPopup({
title: '企业类型',
maskClick: true,
data: [options],
success: (_, [value]) => {
console.log('选择的企业类型:', value)
formData.nature = value.value
formData.natureText = value.label
updateCompletion()
$api.msg('企业类型选择成功')
}
})
}
// 选择是否是就业见习基地
const selectEmploymentBase = () => {
uni.showActionSheet({
itemList: ['是', '否'],
success: (res) => {
formData.enterpriseType = res.tapIndex === 0
updateCompletion()
$api.msg('选择成功')
}
})
}
// 选择是否是本地企业
const selectLocalCompany = () => {
uni.showActionSheet({
itemList: ['是', '否'],
success: (res) => {
formData.isLocalCompany = res.tapIndex === 0
updateCompletion()
$api.msg('选择成功')
}
})
}
// 添加联系人
const addContact = () => {
if (formData.companyContactList.length < 3) {
formData.companyContactList.push({ contactPerson: '', contactPersonPhone: '' })
}
}
// 删除联系人
const deleteContact = (index) => {
if (formData.companyContactList.length <= 1) {
$api.msg('至少需要保留一个联系人')
return
}
uni.showModal({
title: '确认删除',
content: '确定要删除这个联系人吗?',
success: (res) => {
if (res.confirm) {
formData.companyContactList.splice(index, 1)
updateCompletion()
$api.msg('联系人已删除')
}
}
})
}
// 关闭弹窗
const closePopup = () => {
popup.value?.close()
popupValue.value = ''
}
// 确认弹窗
const confirmPopup = () => {
const field = currentEditField.value
if (field === 'companyIntro') {
formData.companyIntro = popupValue.value
}
updateCompletion()
closePopup()
}
// 取消
const cancel = () => {
uni.navigateBack()
}
// 确认提交
const confirm = () => {
// 验证必填字段
if (!formData.companyName.trim()) {
$api.msg('请输入企业名称')
return
}
if (!formData.socialCreditCode.trim()) {
$api.msg('请输入统一社会信用代码')
return
}
if (!formData.registeredAddress.trim()) {
$api.msg('请选择注册地点')
return
}
if (!formData.companyIntro.trim()) {
$api.msg('请输入企业介绍')
return
}
if (!formData.legalPersonName.trim()) {
$api.msg('请输入法人姓名')
return
}
if (!formData.nature.trim()) {
$api.msg('请选择企业类型')
return
}
if (formData.enterpriseType === null) {
$api.msg('请选择是否是就业见习基地')
return
}
if (!formData.legalIdCard.trim()) {
$api.msg('请输入法人身份证号')
return
}
if (!formData.legalPhone.trim()) {
$api.msg('请输入法人联系方式')
return
}
if (!formData.industryType.trim()) {
$api.msg('请选择产业类型')
return
}
if (formData.isLocalCompany === null) {
$api.msg('请选择是否是本地企业')
return
}
// 验证身份证号格式
const idCardRegex = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
if (!idCardRegex.test(formData.legalIdCard)) {
$api.msg('请输入正确的身份证号')
return
}
// 验证法人电话格式
const phoneRegex = /^1[3-9]\d{9}$/
if (!phoneRegex.test(formData.legalPhone)) {
$api.msg('请输入正确的法人联系方式')
return
}
// 验证至少有一个联系人
const hasValidContact = formData.companyContactList.some(contact =>
contact.contactPerson.trim() && contact.contactPersonPhone.trim()
)
if (!hasValidContact) {
$api.msg('请至少添加一个联系人信息')
return
}
// 验证联系人电话格式
for (let contact of formData.companyContactList) {
if (contact.contactPerson.trim() && contact.contactPersonPhone.trim()) {
if (!phoneRegex.test(contact.contactPersonPhone)) {
$api.msg('请输入正确的手机号码')
return
}
}
}
// 提交数据
uni.showLoading({ title: '保存中...' })
// 构建提交数据,按照要求的字段映射
const companyData = {
name: formData.companyName,
code: formData.socialCreditCode,
registeredAddress: formData.registeredAddress,
description: formData.companyIntro,
legalPerson: formData.legalPersonName,
nature: formData.nature,
enterpriseType: formData.enterpriseType,
legalIdCard: formData.legalIdCard,
legalPhone: formData.legalPhone,
industryType: formData.industryType,
isLocalCompany: formData.isLocalCompany,
companyContactList: formData.companyContactList.filter(contact => contact.contactPerson.trim() && contact.contactPersonPhone.trim())
}
// 调用新的接口地址数据格式为company数组
const submitData = {
company: companyData
}
$api.createRequest('/app/user/registerUser', submitData, 'post')
.then((resData) => {
uni.hideLoading()
$api.msg('企业信息保存成功')
// 跳转到首页或企业相关页面
uni.reLaunch({
url: '/pages/index/index'
})
})
.catch((err) => {
uni.hideLoading()
$api.msg(err.msg || '保存失败,请重试')
})
}
onLoad(async (options) => {
console.log('企业信息补全页面开始加载')
try {
// 初始化字典数据
await dictStore.getDictData()
console.log('字典数据加载完成:', {
nature: dictStore.state.nature,
complete: dictStore.complete
})
} catch (error) {
console.error('字典数据加载失败:', error)
$api.msg('数据加载失败,请重试')
}
console.log('企业信息补全页面加载完成')
})
// 暴露方法给其他页面调用
defineExpose({
handleLocationSelected
})
</script>
<style lang="stylus" scoped>
.company-info-container
min-height: 100vh
background: #f5f5f5
padding-bottom: 120rpx
.header-info
background: #fff
padding: 40rpx 32rpx
display: flex
justify-content: space-between
align-items: center
margin-bottom: 20rpx
.progress-text
font-size: 32rpx
color: #000000
font-weight: 500
.progress-value
font-size: 32rpx
color: #256BFA
font-weight: 600
.form-content
background: #fff
margin-bottom: 20rpx
.form-item
padding: 32rpx
border-bottom: 1rpx solid #f0f0f0
display: flex
justify-content: space-between
align-items: center
&:last-child
border-bottom: none
&.clickable
cursor: pointer
.label
font-size: 28rpx
color: #000000
min-width: 200rpx
.input-field
flex: 1
font-size: 28rpx
color: #333
text-align: right
&::placeholder
color: #999
font-size: 26rpx
.input-con
flex: 1
font-size: 28rpx
color: #333
text-align: right
background: transparent
border: none
outline: none
&::placeholder
color: #999
font-size: 26rpx
.input-content
flex: 1
display: flex
justify-content: space-between
align-items: center
.input-text
font-size: 28rpx
color: #333
flex: 1
text-align: right
&.placeholder
color: #999
font-size: 26rpx
&.intro-text
max-height: 80rpx
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
.contact-section
margin-top: 20rpx
.section-title
padding: 32rpx
font-size: 32rpx
color: #333
font-weight: 500
background: #fff
border-bottom: 1rpx solid #f0f0f0
.contact-group
background: #fff
margin-bottom: 20rpx
border-radius: 16rpx
overflow: hidden
.group-header
padding: 24rpx 32rpx
font-size: 28rpx
color: #000000
background: #f8f9fa
font-weight: 500
border-bottom: 1rpx solid #e8e8e8
display: flex
justify-content: space-between
align-items: center
.delete-btn
display: flex
align-items: center
padding: 8rpx 16rpx
background: #fff5f5
border: 1rpx solid #ff4757
border-radius: 8rpx
cursor: pointer
.delete-text
margin-left: 8rpx
font-size: 24rpx
color: #ff4757
.form-item
border-bottom: 1rpx solid #f0f0f0
&:last-child
border-bottom: none
.add-contact-btn
padding: 32rpx
display: flex
align-items: center
justify-content: center
color: #256BFA
font-size: 28rpx
background: #fff
border-top: 1rpx solid #f0f0f0
text
margin-left: 12rpx
.bottom-actions
position: fixed
bottom: 0
left: 0
right: 0
background: #fff
padding: 20rpx 32rpx
display: flex
gap: 20rpx
box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.1)
.cancel-btn, .confirm-btn
flex: 1
height: 80rpx
border-radius: 40rpx
font-size: 32rpx
border: none
.cancel-btn
background: #f5f5f5
color: #666
.confirm-btn
background: #256BFA
color: #fff
// 弹窗样式
.popup-content
width: 600rpx
background: #fff
border-radius: 20rpx
padding: 40rpx
.popup-title
font-size: 36rpx
color: #333
font-weight: 500
margin-bottom: 30rpx
text-align: center
.popup-input, .popup-textarea
width: 100%
padding: 20rpx
border: 1rpx solid #e0e0e0
border-radius: 10rpx
font-size: 28rpx
margin-bottom: 30rpx
box-sizing: border-box
text-align: center
.popup-textarea
height: 200rpx
.popup-actions
display: flex
gap: 20rpx
.popup-cancel, .popup-confirm
flex: 1
height: 70rpx
border-radius: 35rpx
font-size: 28rpx
border: none
.popup-cancel
background: #f5f5f5
color: #666
.popup-confirm
background: #256BFA
color: #fff
// 按钮重置样式
button::after
border: none
</style>