lifanagju_citu пре 4 дана
родитељ
комит
5124978b8b

+ 9 - 0
src/api/menduner/system/talentMap/labeling.ts

@@ -61,6 +61,15 @@ export const talentLabelingApi = {
 		})
 	},
 
+	// 结构化数据源 创建名片(不传递文件)
+	createBusinessCardPost: async (data: any) => {
+		return await request.post({ 
+			url: `/api/parse/add-business-card`,
+			baseURL: import.meta.env.VITE_BASE_URL,
+			data
+		})
+	},
+
 	// 非结构化数据源 更新名片
 	updateBusinessCard: async (data: any, id: any) => {
 		return await request.put({ 

+ 30 - 0
src/utils/formatter.ts

@@ -5,3 +5,33 @@ import { floatToFixed2 } from '@/utils'
 export const fenToYuanFormat = (_, __, cellValue: any, ___) => {
   return `¥${floatToFixed2(cellValue)}`
 }
+
+/**
+ * 校验手机号码格式(支持国际号码)
+ * @param {string} phoneNumber - 待校验的手机号码
+ * @returns {boolean} - 返回是否有效的布尔值
+ */
+// 测试用例
+// console.log(validatePhoneNumber("13800138000"));      // true - 中国手机号
+// console.log(validatePhoneNumber("+8613800138000"));   // true - 带国际码的中国手机号
+// console.log(validatePhoneNumber("008613800138000"));  // true - 带国际码的中国手机号
+// console.log(validatePhoneNumber("+1 212-555-1234"));  // true - 美国号码
+// console.log(validatePhoneNumber("+44 20 7946 0958")); // true - 英国号码
+// console.log(validatePhoneNumber("+81 3-1234-5678"));  // true - 日本号码
+// console.log(validatePhoneNumber("12345"));            // false - 过短
+// console.log(validatePhoneNumber("abcdefg"));          // false - 非数字
+export const validatePhoneNumber = (phoneNumber: any, isReturn = false): any => {
+  // 去除所有空格、连字符等非数字字符
+  const cleanedNumber = phoneNumber.replace(/\D/g, '');
+  
+  // 国际号码正则(简化版,匹配大多数国际号码格式)
+  // 格式:可选的国家码(1-3位数字) + 7-15位数字
+  const internationalPattern = /^(?:\+?(\d{1,3}))?[-. (]*(\d{7,15})$/;
+  
+  // 中国手机号码正则
+  const chinaPattern = /^(?:(?:\+|00)86)?1[3-9]\d{9}$/;
+  
+  // 检查是否符合中国号码或国际号码格式
+  if (isReturn) { return { cleanedNumber, valid: chinaPattern.test(cleanedNumber) || internationalPattern.test(cleanedNumber) } }
+  else return chinaPattern.test(cleanedNumber) || internationalPattern.test(cleanedNumber);
+}

+ 17 - 1
src/utils/transform/date.js

@@ -1,4 +1,4 @@
-// 时间戳转换为年月日时分秒
+// 时间戳转换为年月日时分秒 timestampToDate
 export const timesTampChange = (timestamp, format = 'Y-M-D h:m:s') => {
   if (!timestamp) return ''
   const date = new Date(timestamp)
@@ -25,6 +25,22 @@ export const getTimeStamp = (str) => {
   return date.getTime()
 }
 
+// 时间戳转换为年龄
+export const timestampToAge = (timestamp) => {
+  if (!timestamp) return null
+  const birthDate = new Date(timestamp);
+  const currentDate = new Date();
+  let age = currentDate.getFullYear() - birthDate.getFullYear();
+  const monthDiff = currentDate.getMonth() - birthDate.getMonth();
+  // 如果当前月份小于出生月份,或者月份相同但日期未到生日
+  if (monthDiff < 0 || (monthDiff === 0 && currentDate.getDate() < birthDate.getDate())) {
+    age--;
+  }
+  return age;
+}
+
+
+
 // 传入一个时间戳返回这个日期的最早时间点以及最晚时间点 输出:[1721232000000, 1721318399999]
 export const getDayBounds = (timestamp) => {
   const date = new Date(timestamp)

+ 85 - 35
src/views/menduner/system/talentMap/components/FormPage.vue

@@ -39,7 +39,7 @@
             <!-- <el-input v-model="formQuery.birthday" placeholder="请输入出生日期" /> -->
             <el-date-picker
               v-model="formQuery.birthday"
-              :value-format="valueFormat"
+              value-format="YYYY-MM-DD"
               type="date"
               placeholder="请选择出生日期"
               :disabledDate="disabledDates"
@@ -83,7 +83,7 @@
         </el-col>
         <el-col :span="24">
           <el-form-item label="手机号码1" prop="mobile">
-            <el-input v-model="formQuery.mobile[0]" placeholder="请输入手机号码" />
+            <el-input v-model="formQuery.mobile[0]" placeholder="请输入手机号码" @change="val => mobileChange(val, 0)" />
           </el-form-item>
         </el-col>
         
@@ -91,12 +91,12 @@
       <el-row :gutter="10">
         <el-col :span="24">
           <el-form-item label="手机号码2" prop="mobile">
-            <el-input v-model="formQuery.mobile[1]" placeholder="请输入手机号码" />
+            <el-input v-model="formQuery.mobile[1]" placeholder="请输入手机号码" @change="val => mobileChange(val, 1)" />
           </el-form-item>
         </el-col>
         <el-col :span="24">
           <el-form-item label="手机号码3" prop="mobile">
-            <el-input v-model="formQuery.mobile[2]" placeholder="请输入手机号码" />
+            <el-input v-model="formQuery.mobile[2]" placeholder="请输入手机号码" @change="val => mobileChange(val, 2)" />
           </el-form-item>
         </el-col>
       </el-row>
@@ -181,20 +181,22 @@
           </el-form-item>
         </el-col>
       </el-row>
-      <el-row v-if="formType === 'edit'">
-        <div class="m-title">系统信息</div>
-      </el-row>
-      <el-form-item label="状态" v-if="formType === 'edit'">
-         <el-tag v-if="itemData.status" :type="itemData.status === 'active' ? 'success' : 'danger'">
-          {{ itemData.status === 'active' ? '已启用' : '已禁用' }}
-        </el-tag>
-      </el-form-item>
-      <el-form-item label="创建时间" v-if="formType === 'edit'">
-        <el-tag v-if="itemData.created_at" type="primary" effect="light">{{ itemData.created_at }}</el-tag>
-      </el-form-item>
-      <el-form-item label="更新时间" v-if="formType === 'edit'">
-        <el-tag v-if="itemData.updated_at" type="primary" effect="light">{{ itemData.updated_at }}</el-tag>
-      </el-form-item>
+      <template v-if="formType === 'edit'">
+        <el-row>
+          <div class="m-title">系统信息</div>
+        </el-row>
+        <el-form-item label="状态" v-if="itemData.status">
+          <el-tag :type="itemData.status === 'active' ? 'success' : 'danger'">
+            {{ itemData.status === 'active' ? '已启用' : '已禁用' }}
+          </el-tag>
+        </el-form-item>
+        <el-form-item label="创建时间">
+          <el-tag type="primary" effect="light">{{ itemData?.created_at || '--' }}</el-tag>
+        </el-form-item>
+        <el-form-item label="更新时间">
+          <el-tag type="primary" effect="light">{{ itemData?.updated_at || '--' }}</el-tag>
+        </el-form-item>
+      </template>
     </el-form>
 	</div>
 </template>
@@ -207,7 +209,9 @@ import { getDict } from '@/hooks/web/useDictionaries'
 import { cloneDeep } from 'lodash-es'
 import { TalentMap } from '@/api/menduner/system/talentMap'
 import { Delete, Plus } from '@element-plus/icons-vue'
+import { validatePhoneNumber } from '@/utils/formatter'
 
+const message = useMessage() // 消息弹窗
 const props = defineProps({
   itemData: Object,
   formType: String
@@ -215,12 +219,12 @@ const props = defineProps({
 
 const loading = ref(false)
 const dialogVisible = ref(false) // 弹窗的是否展示
-const formQuery = ref({
+const defaultQuery = {
   name_zh: undefined,
   name_en: undefined,
   title_zh: undefined,
   title_en: undefined,
-  mobile: undefined,
+  mobile: ['', '', ''],
   phone: undefined,
   email: undefined,
   hotel_zh: undefined,
@@ -239,24 +243,22 @@ const formQuery = ref({
   age: undefined,
   native_place: undefined,
   career_path: []
-})
+}
+const formQuery = ref(cloneDeep(defaultQuery))
 const careerTrajectory = ref([{ hotel_zh: null,  title_zh: null, date: null }])
 
-// 保持手机号码数量为三个
-function splitStringToArray(str) {
-  const parts = str.split(',').map(item => item.trim());
-  let result = [];
-  for (let i = 0; i < 3; i++) {
-    result.push(parts[i] || ''); // 如果元素不存在则使用空字符串
+// 渲染完成后赋值
+onMounted(() => {
+  if (props.itemData) {
+    setFormData(props.itemData)
   }
-  return result;
-}
-
+})
 
-if (props.itemData) {
-	formQuery.value = cloneDeep(props.itemData)
-	careerTrajectory.value = cloneDeep(props.itemData?.career_path) ?? []
-  formQuery.value.mobile = splitStringToArray(formQuery.value.mobile)
+const mobileChange = (val, index) => {
+  const { cleanedNumber, valid } = validatePhoneNumber(val, true)
+  formQuery.value.mobile[index] = cleanedNumber
+  val = cleanedNumber
+  if (!valid) message.warning('输入的手机号码格式不正确,请重新输入!')
 }
 
 const addCareer = () => {
@@ -275,7 +277,6 @@ const disabledDates = (date) => {
   return date.getTime() > Date.now()
 }
 
-const valueFormat = 'YYYY-MM-DD'
 // 自动填充年龄
 const birthdayChange = (val) => {
   if (!val) return
@@ -288,7 +289,56 @@ const birthdayChange = (val) => {
   formQuery.value.age = age;
 }
 
+// 保持手机号码数量为三个
+function splitStringToArray(str) {
+  const MAX_PHONE_NUMBERS = 3;
+  const result = Array(MAX_PHONE_NUMBERS).fill('');
+  if (!str) return result;
+  const parts = String(str).split(',').map(item => item.trim()).slice(0, MAX_PHONE_NUMBERS);
+  parts.forEach((part, index) => {
+    result[index] = part || '';
+  });
+  return result;
+}
+
+const setFormData = (data) => {
+  if (!formQuery.value || !data || 
+      !Object.keys(formQuery.value).length || 
+      !Object.keys(data).length) {
+    return;
+  }
+  Object.entries(formQuery.value).forEach(([key]) => {
+    const value = data[key];
+    switch (key) {
+      case 'mobile':
+        formQuery.value[key] = Array.isArray(value) 
+          ? splitStringToArray(value.join(',')) 
+          : value 
+            ? splitStringToArray(value)
+            : ['', '', ''];
+        break;
+      case 'career_path':
+        formQuery.value[key] = value || [];
+        break;
+      default:
+        formQuery.value[key] = value ?? null;
+    }
+  });
+  careerTrajectory.value = cloneDeep(data.career_path ?? []);
+}
+
+const resetFormData = (data) => {
+  formQuery.value = cloneDeep(defaultQuery)
+}
+
+// const getFormData = () => {
+//   return {
+//     ...formQuery.value
+//   }
+// }
+
 defineExpose({
+	setFormData,
 	formQuery
 })
 </script>

+ 5 - 5
src/views/menduner/system/talentMap/details/components/search.vue

@@ -53,17 +53,17 @@
       <el-table-column label="联系电话" align="center" prop="user.phone" width="120px" />
       <el-table-column label="求职状态" align="center" prop="person.jobStatus" width="130px">
         <template #default="scope">
-          <dict-tag :type="DICT_TYPE.MENDUNER_JOB_SEEK_STATUS" :value="scope.row.person?.jobStatus" />
+          <dict-tag v-if="scope.row.person?.jobStatus" :type="DICT_TYPE.MENDUNER_JOB_SEEK_STATUS" :value="scope.row.person?.jobStatus" />
         </template>
       </el-table-column>
       <el-table-column label="学历" align="center" prop="person.eduType">
         <template #default="scope">
-          <dict-tag :type="DICT_TYPE.MENDUNER_EDUCATION_TYPE" :value="scope.row.person?.eduType" />
+          <dict-tag v-if="scope.row.person?.eduType" :type="DICT_TYPE.MENDUNER_EDUCATION_TYPE" :value="scope.row.person?.eduType" />
         </template>
       </el-table-column>
       <el-table-column label="工作经验" align="center" prop="person.expType">
         <template #default="scope">
-          <dict-tag :type="DICT_TYPE.MENDUNER_EXP_TYPE" :value="scope.row.person?.expType" />
+          <dict-tag v-if="scope.row.person?.expType" :type="DICT_TYPE.MENDUNER_EXP_TYPE" :value="scope.row.person?.expType" />
         </template>
       </el-table-column>
       <el-table-column label="操作" align="center" fixed="right" min-width="60">
@@ -115,8 +115,8 @@ const getList = async () => {
   loading.value = true
   try {
     const data = await PersonInfoApi.getPersonInfoPage(queryParams)
-    list.value = data.list
-    total.value = data.total
+    list.value = data?.list || []
+    total.value = data?.total || 0
   } finally {
     loading.value = false
   }

+ 70 - 85
src/views/menduner/system/talentMap/details/index.vue

@@ -47,7 +47,7 @@
             </el-upload>
           </el-tab-pane>
           <el-tab-pane label="人员搜索" name="personnelSearch">
-            <Search @detail="handleDetail" :searchName="result?.person?.name" />
+            <Search @detail="handleDetail" :searchName="formData?.name_zh || formData?.name_en || ''" />
           </el-tab-pane>
         </el-tabs>
       </el-col>
@@ -56,15 +56,10 @@
         <div ref="content" :style="{'height': height, 'overflow-y': 'auto'}">
           <el-tabs type="border-card">
             <el-tab-pane label="简历解析内容">
-              <Info ref="InfoRef" v-model="result.person" :areaTreeData="areaTreeData" :isEdit="isEdit" />
-              <JobIntention v-model="result.person.jobInterestedList" :isEdit="isEdit" @change="handleUpdateJobIntention" />
-              <Edu v-model="result.eduList" :isEdit="isEdit"  />
-              <Exp v-model="result.workList" :isEdit="isEdit" />
-              <Training v-model="result.trainList" :isEdit="isEdit" />
+              <FormPage ref="FormPageRef" :formType="isEdit ? 'edit' : 'create'" :itemData="formData" />
               <div class="text-center m-t-30px">
                 <el-affix position="bottom" :offset="20">
-                  <!-- <el-button @click="push('/headhunting/menduner/system/talentMap/talentMap')" type="warning" plain size="large" class="!w-120px">取 消</el-button> -->
-                  <el-button v-if="id === 'add'" type="primary" @click="handleSave" size="large" class="!w-120px">保 存</el-button>
+                  <el-button type="primary" @click="handleSave" size="large" class="!w-120px">保 存</el-button>
                 </el-affix>
               </div>
             </el-tab-pane>
@@ -73,14 +68,8 @@
                 <template #header>
                   <CardTitle title="已有标签" />
                 </template>
-                <m-tags v-if="Object.keys(result).length" :data="result?.resume?.skillsObjs" />
+                <m-tags v-if="formData && Object.keys(formData).length" :data="formData?.skillsObjs" />
               </el-card>
-              <!-- <el-card shadow="never" class="m-t-10px">
-                <template #header>
-                  <CardTitle title="推荐标签" />
-                </template>
-                <TagsRecommend />
-              </el-card> -->
             </el-tab-pane>
           </el-tabs>
         </div>
@@ -97,23 +86,18 @@ import { useUpload } from '@/components/UploadFile/src/useUpload'
 import { commonApi } from '@/api/menduner/common'
 import { Base64 } from 'js-base64'
 import { getDict } from '@/hooks/web/useDictionaries'
-import DefaultData from './defaultData'
-import { cloneDeep } from 'lodash-es';
-
-import Info from './components/info.vue'
-import Edu from './components/edu.vue'
-import Exp from './components/exp.vue'
-import JobIntention from './components/jobIntention.vue'
-import Training from './components/training.vue'
 import MTags from './components/tags.vue'
-import TagsRecommend from './components/tagsRecommend.vue'
+// import DefaultData from './defaultData'
+import { cloneDeep } from 'lodash-es';
+import { timesTampChange, timestampToAge } from '@/utils/transform/date'
+import FormPage from '@/views/menduner/system/talentMap/components/FormPage.vue'
 import Search from './components/search.vue'
+import { talentLabelingApi } from '@/api/menduner/system/talentMap/labeling'
 
-const { push } = useRouter()
+const { back } = useRouter()
 const loading = ref(false)
 const activeName = ref('resumeAnalysis')
 const saveLoading = ref(false)
-const result = ref(cloneDeep(DefaultData))
 const fileUrl = ref('') // https://minio.menduner.com/dev/person/229988673960153088/attachment/ee3eb21f45e13ede3557a03d18585ed80c5b4212ac5634e3436e309afaa8fe6a.pdf
 const uploadRef = ref()
 const fileList = ref([])
@@ -121,7 +105,7 @@ const data = ref({ path: '' })
 const { uploadUrl, httpRequest } = useUpload()
 
 /** 初始化 */
-const InfoRef = ref()
+// const InfoRef = ref()
 const content = ref()
 const message = useMessage() // 消息弹窗
 const height = ref(0)
@@ -134,21 +118,8 @@ const isEdit = ref(false)
 const drawer = ref(false)
 
 const resumeTxt = ref([])
-
-// 地区树状列表
-const areaTreeData = ref([])
-const getDictData = async () => {
-  const { data } = await getDict('areaTreeData', {}, 'areaTreeData')
-  const obj = data.find(e => e.name === '中国')
-  const list = obj?.children ? obj.children.map(e =>{
-    // 市辖区直接显示区
-    const municipality = e.children && e.children.length && e.children[0].name === '市辖区'
-    if (municipality && e.children[0].children?.length) e.children = e.children[0].children
-    return e
-  }) : []
-  areaTreeData.value = list.length ? list : []
-}
-getDictData()
+const formData = ref({})
+const FormPageRef = ref(null)
 
 // 获取人才详情
 const getTalentMap = async () => {
@@ -159,8 +130,7 @@ const getTalentMap = async () => {
     if (data.person?.resumeUrl) {
       fileUrl.value = !data.person?.resumeUrl.includes('.pdf') ?  `${baseUrl}/onlinePreview?url=${encodeURIComponent(Base64.encode(data.person?.resumeUrl))}` : data.person?.resumeUrl
     } else activeName.value = 'personnelSearch'
-    result.value = data
-    result.value.person.interestedAreaIdList = result.value.person.interestedAreaIdList && result.value.person.interestedAreaIdList.length ? result.value.person.interestedAreaIdList.map(e => Number(e)) : []
+    setItemDataValue(data)
   } catch (error) {
     console.log(error)
   } finally {
@@ -173,7 +143,7 @@ onMounted(async () => {
   if (id && id !== 'add') {
     isEdit.value = true
     await getTalentMap()
-  } else result.value = cloneDeep(DefaultData)
+  }
 })
 
 // 简历解析
@@ -181,8 +151,7 @@ const getResumeParser = async (url) => {
   loading.value = true
   try {
     const data = await commonApi.resumeParser({ fileUrl: url })
-    result.value = data
-    result.value.person.interestedAreaIdList = result.value.person.interestedAreaIdList && result.value.person.interestedAreaIdList.length ? result.value.person.interestedAreaIdList.map(e => Number(e)) : []
+    setItemDataValue(data)
   } finally {
     loading.value = false
   }
@@ -217,7 +186,6 @@ const submitFormSuccess = () => {
 // 查看文本信息
 const handleText = () => {
   drawer.value = true
-  resumeTxt.value = result.value.resume.rawText.split('\n')
 }
 
 // 重新上传简历
@@ -226,63 +194,80 @@ const handleResetUpload = async () => {
   fileUrl.value = ''
   data.value.path = ''
   fileList.value = []
-  result.value = cloneDeep(DefaultData)
+  setItemDataValue()
+}
+
+const setItemDataValue = (data) => {
+  formData.value = {
+    name_zh: data?.person?.name || '',
+    email: data?.person?.email || '',
+    mobile: data?.person?.phone || '',
+    birthday: data?.person?.birthday ? timesTampChange(data.person.birthday, 'Y-M-D') : '',
+    age: data?.person?.birthday ? timestampToAge(data.person.birthday) : null,
+    career_path: data?.workList ? data.workList.map(e => {
+      return {
+        hotel_zh: e?.enterpriseName || null,
+        title_zh: e?.positionName || null,
+        date: e?.startTime ? timesTampChange(e.startTime, 'Y-M-D') : null
+      }
+    }) : [],
+    created_at: data?.person?.createTime ? timesTampChange(data.person.createTime, 'Y-M-D') : null,
+    updated_at: data?.person?.updateTime ? timesTampChange(data.person.updateTime, 'Y-M-D') : null,
+  }
+  resumeTxt.value = data?.resume?.rawText?.split('\n') || ''
+  if (FormPageRef.value?.setFormData) FormPageRef.value.setFormData(formData.value)
 }
 
 // 搜索-查看详情
-const keyList = ['person', 'eduList', 'workList', 'trainList']
 const handleDetail = async (userId) => {
   if (!userId) return message.warning('请先选择人才!')
   try {
     const data = await TalentMap.getTalentMapDetail(userId)
-    if (data && data.person && data.person.id) delete data.person.id
-    keyList.forEach(key => result.value[key] = data[key])
+    // 去除id
+    setItemDataValue(data, true)
   } catch {}
 }
 
 // 新增人才
-const arrKey = ['eduList', 'workList', 'trainList']
+const formLoading = ref(false)
+const uploadFile = ref(null)
 const handleSave = async () => {
-  if (result.value?.resume) delete result.value.resume
-  if (!fileUrl.value) {
-    arrKey.forEach(key => {
-      if (result.value[key] && result.value[key].length) result.value[key].forEach(item => delete item.id)
-    })
+  const params = { ...FormPageRef.value.formQuery }
+  if (!params.name_zh) return message.warning('请填写姓名!')
+  
+  // 数组转为字符串保存
+  if (Array.isArray(params?.mobile)) {
+    params.mobile = params.mobile.filter(i => Boolean(i)).map(j => String(j).replace(/,|,/g, '')).join(',');
   }
-  console.log(result.value, 'result-add')
-
-  // 效验基本信息中必填项是否有填写
-  if (!result.value?.person?.name) {
-    message.notifyWarning('请填写用户姓名后再提交!')
-    InfoRef.value.formRef.validate()
-    content.value.scrollTo({ top: -100, behavior: 'smooth' })
-    return
-  }
-
-  saveLoading.value = true
+  console.log(params, 'handleSubmit')
   try {
-    await TalentMap.createTalentMapInfo(result.value)
-    message.success('新增成功!')
-    result.value = cloneDeep(DefaultData)
-    push('/headhunting/menduner/system/talentMap/talentMap')
-  } catch (error) {
-    console.log(error)
-  } finally {
-    saveLoading.value = false
-  }
-}
+    formLoading.value = true
+    let result = {}
+    if (!id || id === 'add') { // 新增
+      // uploadFile.value.append('card_data', JSON.stringify(params))
+      result = await talentLabelingApi.createBusinessCardPost(params)
+      message.success('新增成功')
+      back()
 
-// 查看详情-编辑求职意向
-const handleUpdateJobIntention = async (val, type) => {
-  try {
-    await TalentMap.updateTalentMapInfo(result.value.person)
-    message.success((type === 'add' ? '新增' : type === 'edit' ? '编辑' : '删除') + '成功')
+      if (result.code === 202 || result.message.includes('疑似重复')) {
+        if (!result.data?.main_card?.id) return
+        
+        await message.confirm('发现与当前名片的疑似重复数据,去处理')
+        mergeFormRef.value.open(result.data?.main_card?.id)
+      }
+    } else { // 编辑
+      await talentLabelingApi.updateBusinessCard(params, id)
+      message.success('更新成功')
+      back()
+    }
   } catch (error) {
-    console.log(error)
+    console.log('更新失败', error)
   } finally {
+    uploadFile.value = null
     formLoading.value = false
   }
 }
+
 </script>
 <style lang="scss" scoped>
 :deep(.drawer) {

+ 4 - 1
src/views/menduner/system/talentMap/maintenance/gather/businessCard/index.vue

@@ -260,7 +260,10 @@ const FormPageRef = ref(null)
 const mergeFormRef = ref() // 合并表单 Ref
 const handleSave = async () => {
   const params = FormPageRef.value.formQuery
-  params.mobile = params.mobile.filter(item => Boolean(item)).map(item => String(item).replace(/,|,/g, '')).join(',');
+  // 数组转为字符串保存
+  if (Array.isArray(params?.mobile)) {
+    params.mobile = params.mobile.filter(i => Boolean(i)).map(j => String(j).replace(/,|,/g, '')).join(',');
+  }
   console.log(params, 'handleSubmit')
   try {
     formLoading.value = true