浏览代码

Merge branch 'dev' of https://git.citupro.com/zhengnaiwen_citu/menduner into dev

Xiao_123 4 月之前
父节点
当前提交
72b0cea7f1
共有 18 个文件被更改,包括 208 次插入1344 次删除
  1. 36 7
      src/views/recruit/personal/PersonalCenter/resume/analysis/components/educationExp.vue
  2. 36 7
      src/views/recruit/personal/PersonalCenter/resume/analysis/components/trainingExperience.vue
  3. 36 7
      src/views/recruit/personal/PersonalCenter/resume/analysis/components/workExperience.vue
  4. 12 9
      src/views/recruit/personal/PersonalCenter/resume/analysis/index.vue
  5. 0 101
      src/views/recruit/personal/PersonalCenter/resume/online/analysis/avatar.vue
  6. 0 119
      src/views/recruit/personal/PersonalCenter/resume/online/analysis/base.vue
  7. 0 279
      src/views/recruit/personal/PersonalCenter/resume/online/analysis/basicInfo.vue
  8. 0 61
      src/views/recruit/personal/PersonalCenter/resume/online/analysis/eduExp.vue
  9. 0 234
      src/views/recruit/personal/PersonalCenter/resume/online/analysis/educationExp.vue
  10. 0 24
      src/views/recruit/personal/PersonalCenter/resume/online/analysis/evaluation.vue
  11. 0 59
      src/views/recruit/personal/PersonalCenter/resume/online/analysis/selfEvaluation.vue
  12. 0 112
      src/views/recruit/personal/PersonalCenter/resume/online/analysis/trainingExperience.vue
  13. 0 57
      src/views/recruit/personal/PersonalCenter/resume/online/analysis/workExp.vue
  14. 0 203
      src/views/recruit/personal/PersonalCenter/resume/online/analysis/workExperience.vue
  15. 30 6
      src/views/recruit/personal/PersonalCenter/resume/online/components/educationExp.vue
  16. 29 6
      src/views/recruit/personal/PersonalCenter/resume/online/components/trainingExperience.vue
  17. 29 6
      src/views/recruit/personal/PersonalCenter/resume/online/components/workExperience.vue
  18. 0 47
      src/views/recruit/personal/PersonalCenter/resume/online/index.vue

+ 36 - 7
src/views/recruit/personal/PersonalCenter/resume/analysis/components/educationExp.vue

@@ -7,15 +7,20 @@
 defineOptions({ name: 'resumeAnalysis-educationExp'})
 import { debounce } from 'lodash'
 import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, reactive, watch } from 'vue'
+import { ref, reactive, watch, nextTick } from 'vue'
 import { schoolSearchByName, schoolMajorByName } from '@/api/recruit/personal/resume'
 import { dealCanBeInputtedSave, dealCanBeInputtedValueAndLabel } from '@/utils/getText'
+import Snackbar from '@/plugins/snackbar'
 
 const props = defineProps({
   id: {
     type: String,
     default: ''
   },
+  text: {
+    type: String,
+    default: ''
+  },
   data: {
     type: Object,
     default: () => {}
@@ -65,6 +70,27 @@ const debouncedCallbackMajor = debounce(newValue => {
   getMajorListData(newValue)
 }, 500)
 
+
+const startTimeChange = (v) => {
+  const item1 = items.value.options.find(e => e.key === 'startTime')
+  const item2 = items.value.options.find(e => e.key === 'endTime')
+  if (item1?.value && item2?.value && item1.value > item2.value) {
+    Snackbar.warning('开始时间不能大于结束时间!')
+    nextTick(() => {
+      item1.value = item2.value
+    })
+  }
+}
+const endTimeChange = (v) => {
+  const item1 = items.value.options.find(e => e.key === 'startTime')
+  const item2 = items.value.options.find(e => e.key === 'endTime')
+  if (item1?.value && item2?.value && item1.value > item2.value) {
+    Snackbar.warning('结束时间不能小于开始时间')
+    nextTick(() => {
+      item2.value = item1.value
+    })
+  }
+}
 const items = ref({
   options: [
     {
@@ -132,28 +158,28 @@ const items = ref({
       key: 'startTime',
       mode: 'month', // 时间类型 year month date time
       value: null,
-      default: '2014-01',
-      format: 'YYYY/MM',
+      default: new Date(2014, 1).getTime(),
       labelWidth: 80,
       label: '开始时间 *',
       defaultValue: new Date(2014, 1),
       disabledFutureDates: true,
       col: 6,
-      rules: [v => !!v || '请选择起始时间']
+      rules: [v => !!v || '请选择起始时间'],
+      change: startTimeChange
     },
     {
       type: 'datePicker',
       key: 'endTime',
       mode: 'month', // 时间类型 year month date time
       value: null,
-      default: '2018-01',
-      format: 'YYYY/MM',
+      default: new Date(2018, 1).getTime(),
       defaultValue: new Date(2018, 1),
       disabledFutureDates: true,
       labelWidth: 80,
       label: '结束时间 *',
       col: 6,
-      rules: [v => !!v || '请选择结束时间']
+      rules: [v => !!v || '请选择结束时间'],
+      change: endTimeChange
     },
     {
       type: 'textarea',
@@ -199,6 +225,9 @@ const submit = async () => {
     }
     else obj[e.key] = e.value
   })
+  if (obj.startTime > obj.endTime) {
+    return { id: props.id, data: null, SnackText: `${props.text} 开始时间不能大于结束时间!`}
+  }
   return { id: props.id, data: obj}
 }
 

+ 36 - 7
src/views/recruit/personal/PersonalCenter/resume/analysis/components/trainingExperience.vue

@@ -5,18 +5,44 @@
 
 <script setup>
 defineOptions({ name: 'resumeAnalysis-trainingExperience'})
-import { ref, watch } from 'vue'
+import { ref, watch, nextTick } from 'vue'
+import Snackbar from '@/plugins/snackbar'
 const props = defineProps({
   id: {
     type: String,
     default: ''
   },
+  text: {
+    type: String,
+    default: ''
+  },
   data: {
     type: Object,
     default: () => {}
   }
 })
 
+const startTimeChange = (v) => {
+  const item1 = items.value.options.find(e => e.key === 'startTime')
+  const item2 = items.value.options.find(e => e.key === 'endTime')
+  if (item1?.value && item2?.value && item1.value > item2.value) {
+    Snackbar.warning('开始时间不能大于结束时间!')
+    nextTick(() => {
+      item1.value = item2.value
+    })
+  }
+}
+const endTimeChange = (v) => {
+  const item1 = items.value.options.find(e => e.key === 'startTime')
+  const item2 = items.value.options.find(e => e.key === 'endTime')
+  if (item1?.value && item2?.value && item1.value > item2.value) {
+    Snackbar.warning('结束时间不能小于开始时间')
+    nextTick(() => {
+      item2.value = item1.value
+    })
+  }
+}
+
 const CtFormRef = ref()
 const items = ref({
   options: [
@@ -41,28 +67,28 @@ const items = ref({
       type: 'datePicker',
       key: 'startTime',
       mode: 'month',
-      value: '2020-01',
+      value: new Date(2020, 1).getTime(),
       labelWidth: 80,
-      format: 'YYYY/MM',
       defaultValue: new Date(2020, 1),
       label: '开始时间 *',
       disabledFutureDates: true,
       col: 6,
       flexStyle: 'mr-3',
-      rules: [v => !!v || '请选择培训开始时间']
+      rules: [v => !!v || '请选择培训开始时间'],
+      change: startTimeChange
     },
     {
       type: 'datePicker',
       key: 'endTime',
       mode: 'month',
-      value: '2022-01',
-      format: 'YYYY/MM',
+      value: new Date(2022, 1).getTime(),
       labelWidth: 80,
       defaultValue: new Date(2022, 1),
       label: '结束时间 *',
       disabledFutureDates: true,
       col: 6,
-      rules: [v => !!v || '请选择培训结束时间']
+      rules: [v => !!v || '请选择培训结束时间'],
+      change: endTimeChange
     },
     {
       type: 'textarea',
@@ -100,6 +126,9 @@ const submit = async () => {
   if (!valid) return { id: props.id, data: null}
   const obj = {}
   items.value.options.forEach(e => obj[e.key] = e.value)
+  if (obj.startTime > obj.endTime) {
+    return { id: props.id, data: null, SnackText: `${props.text} 开始时间不能大于结束时间!`}
+  }
   return { id: props.id, data: obj}
 }
 

+ 36 - 7
src/views/recruit/personal/PersonalCenter/resume/analysis/components/workExperience.vue

@@ -22,14 +22,19 @@
 <script setup>
 defineOptions({ name: 'resumeAnalysis-workExperience'})
 import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, reactive, watch } from 'vue'
+import { ref, reactive, watch, nextTick } from 'vue'
 import { dealCanBeInputtedSave, dealCanBeInputtedValueAndLabel } from '@/utils/getText'
+import Snackbar from '@/plugins/snackbar'
 
 const props = defineProps({
   id: {
     type: String,
     default: ''
   },
+  text: {
+    type: String,
+    default: ''
+  },
   data: {
     type: Object,
     default: () => {}
@@ -71,6 +76,27 @@ const handleSoFarChange = (bool, item) => {
   }
 }
 
+const startTimeChange = (v) => {
+  const item1 = items.value.options.find(e => e.key === 'startTime')
+  const item2 = items.value.options.find(e => e.key === 'endTime')
+  if (item1?.value && item2?.value && item1.value > item2.value) {
+    Snackbar.warning('开始时间不能大于结束时间!')
+    nextTick(() => {
+      item1.value = item2.value
+    })
+  }
+}
+const endTimeChange = (v) => {
+  const item1 = items.value.options.find(e => e.key === 'startTime')
+  const item2 = items.value.options.find(e => e.key === 'endTime')
+  if (item1?.value && item2?.value && item1.value > item2.value) {
+    Snackbar.warning('结束时间不能小于开始时间')
+    nextTick(() => {
+      item2.value = item1.value
+    })
+  }
+}
+
 const items = ref({
   options: [
     {
@@ -112,11 +138,11 @@ const items = ref({
       value: null,
       label: '开始时间 *',
       labelWidth: 100,
-      default: '2020-01',
+      default: new Date(2020, 1).getTime(),
       defaultValue: new Date(2020, 1),
       disabledFutureDates: true,
-      format: 'YYYY/MM',
-      rules: [v => !!v || '请选择起始时间']
+      rules: [v => !!v || '请选择起始时间'],
+      change: startTimeChange
     },
     {
       type: 'datePicker',
@@ -124,13 +150,13 @@ const items = ref({
       slotName: 'endTime',
       mode: 'month', // 时间类型 year month date time
       value: null,
-      format: 'YYYY/MM',
-      default: '2022-01',
+      default: new Date(2022, 1).getTime(),
       defaultValue: new Date(2022, 1),
       label: '结束时间 *',
       disabledFutureDates: true,
       labelWidth: 100,
-      rules: [v => !!v || '请选择结束时间']
+      rules: [v => !!v || '请选择结束时间'],
+      change: endTimeChange
     },
     {
       type: 'textarea',
@@ -180,6 +206,9 @@ const submit = async () => {
     }
     else obj[e.key] = e.value
   })
+  if (obj.endTime && obj.startTime > obj.endTime) {
+    return { id: props.id, data: null, SnackText: `${props.text}开始时间不能大于结束时间!`}
+  }
   return { id: props.id, data: obj}
 }
 

+ 12 - 9
src/views/recruit/personal/PersonalCenter/resume/analysis/index.vue

@@ -36,7 +36,7 @@
                 <v-btn v-if="item.id !== 'person'" variant="text" color="error" density="compact" prepend-icon="mdi-delete-outline" @click="del(item)">删除</v-btn>
                 <v-btn v-else disabled variant="text" color="error" density="compact">不可删除</v-btn>
               </div>
-              <component ref="componentRef" :id="item.id" :is="item.path" :data="item.data" />
+              <component ref="componentRef" :id="item.id" :is="item.path" :text="item.text" :data="item.data" />
             </div>
             <!-- 保存 -->
             <div style="position: absolute; bottom: 0; background-color: #fff; z-index: 99; width: 100%; border-top: 1px solid #e4e7eb;" class="py-3 ml-n3 text-center">
@@ -76,6 +76,7 @@ import { saveResumeInfo, resumeParser2 } from '@/api/recruit/personal/resume'
 import { useUserStore } from '@/store/user'
 import attachmentPage from '../attachment'
 import { Base64 } from 'js-base64'
+import { analyzeTestData } from './analyzeTestData.js'
 const { t } = useI18n()
 const props = defineProps({
   data: {
@@ -124,7 +125,7 @@ const transformToLIst = async (result) => {
         for (let index = 0; index < result[key].length; index++) {
           const obj = {...exampleList[key]}
           obj.id = obj.id + '_' + index
-          obj.text = result[key].length > 1 ? obj.text + (index+1) : obj.text
+          obj.text = result[key].length > 1 ? obj.text + '('+ (index+1) +')' : obj.text
           obj.data = result[key][index]
           formLIst.value.push(obj)
         }
@@ -133,7 +134,9 @@ const transformToLIst = async (result) => {
   }
 }
 
-const result = ref({}) // ref(JSON.parse(JSON.stringify(dataObj))) // 测试
+
+// const result = ref({}) // ref(JSON.parse(JSON.stringify(analyzeTestData))) // 测试
+const result = ref(JSON.parse(JSON.stringify(analyzeTestData))) // 测试
 const fileUrl = ref('')
 const showSelect = ref(true)
 const handleAnalysis = async (url) => {
@@ -144,9 +147,8 @@ const handleAnalysis = async (url) => {
   const baseUrl = import.meta.env.VITE_PREVIEW_URL
   fileUrl.value = !url.includes('.pdf') ?  `${baseUrl}/onlinePreview?url=${encodeURIComponent(Base64.encode(url))}` : url
   try {
-    const data = await resumeParser2({ fileUrl: url })
-    result.value = data || {}
-    // result.value = {person: data.person} || {} // 测试
+    // const data = await resumeParser2({ fileUrl: url })
+    // result.value = data || {}
     await transformToLIst(result.value)
   } catch (error) {
     console.log(error)
@@ -157,7 +159,7 @@ const handleAnalysis = async (url) => {
 
 const componentRef = ref()
 const getValue = async () => {
-  let id = ''
+  let id = ''; let SnackText = ''
   let data = {}
   for (let index = 0; index < componentRef.value.length; index++) {
     const e = componentRef.value[index]
@@ -166,11 +168,12 @@ const getValue = async () => {
       data[query.id] = query.data
     } else {
       id = id ? id : query.id
+      SnackText = SnackText ? SnackText : query.SnackText
     }
   }
-  console.log('id:', id)
+  // console.log('id:', id)
   if (id) {
-    Snackbar.warning('请填写完整后提交!')
+    Snackbar.warning(SnackText || '请填写完整后提交!')
     return
   }
   // 处理data

+ 0 - 101
src/views/recruit/personal/PersonalCenter/resume/online/analysis/avatar.vue

@@ -1,101 +0,0 @@
-<!--  -->
-<template>
-  <div class="avatarsBox" @mouseover="showIcon = true" @mouseleave="showIcon = false">
-    <div style="width: 130px; height: 130px;">
-      <v-img :src="getUserAvatar(avatarResult, '1')" width="130" height="130" style="border-radius: 6px;"></v-img>
-      <div v-show="showIcon" @click="openFileInput" class="mdi mdi-camera-outline camera">
-        <input
-          type="file"
-          ref="fileInput"
-          accept="image/png, image/jpg, image/jpeg"
-          style="display: none;"
-          @change="handleUploadFile"
-        />
-      </div>
-    </div>
-  </div>
-  <!-- <Loading :visible="overlay"></Loading> -->
-  <!-- 图片裁剪 -->
-  <ImgCropper :visible="isShowCopper" :image="selectPic" :cropBoxResizable="true" @submit="handleHideCopper" :aspectRatio="1 / 1" @close="isShowCopper = false, selectPic = ''"></ImgCropper>
-</template>
-
-<script setup>
-defineOptions({ name: 'resumeAnalysis-avatar'})
-import { getUserAvatar } from '@/utils/avatar'
-// import { blobToJson } from '@/utils'
-import { ref } from 'vue'
-const props = defineProps({
-  id: {
-    type: String,
-    default: ''
-  },
-  data: {
-    type: String,
-    default: ''
-  }
-})
-
-const showIcon = ref(false)
-
-// 选择文件
-const fileInput = ref()
-const clicked = ref(false)
-const openFileInput = () => {
-  if (clicked.value) return
-  clicked.value = true
-  fileInput.value.click()
-  clicked.value = false
-}
-
-// 上传头像
-const selectPic = ref('')
-const isShowCopper = ref(false)
-const accept = ['jpg', 'png', 'jpeg']
-const handleUploadFile = async (e) => {
-  const file = e.target.files[0]
-  const arr = file.name.split('.')
-  const fileType = arr?.length ? arr[arr.length-1] : ''
-  if (!accept.includes(fileType)) return Snackbar.warning('请上传图片格式')
-  const reader = new FileReader()
-  reader.readAsDataURL(file)
-  reader.onload = () => {
-    selectPic.value = String(reader.result)
-    isShowCopper.value = true
-  }
-}
-
-const avatarResult = ref(props.data)
-
-// 图片裁剪
-const handleHideCopper = async (res) => {
-  isShowCopper.value = false
-  avatarResult.value = res?.result.blobURL || ''
-  // avatarResult.value = res?.result.dataURL || '' // dataURL文件名过长或者过大不成功
-}
-
-const submit = async () => {
-  return { id: props.id, data: avatarResult.value}
-}
-
-defineExpose({
-  id: props.id,
-  submit
-})
-</script>
-<style lang="scss" scoped>
-.avatarsBox {
-  height: 150px;
-  width: 120px;
-  position: relative;
-  cursor: pointer;
-  margin: 0 32px;
-  .camera {
-    color: #fff;
-    font-size: 42px;
-    position: absolute;
-    top: 50%;
-    left: 50%;
-    transform: translate(-50%, -50%);
-  }
-}
-</style>

+ 0 - 119
src/views/recruit/personal/PersonalCenter/resume/online/analysis/base.vue

@@ -1,119 +0,0 @@
-<template>
-  <div class="resume-box mb-3 elevation-2" id="basicInfo">
-    <div class="resume-header">
-      <div class="resume-title">{{ $t('resume.basicInfo') }}</div>
-    </div>
-    <div class="d-flex align-start mt-5">
-      <!-- 头像 -->
-      <div class="avatarsBox">
-        <div style="width: 130px; height: 130px;">
-          <v-img :src="data.avatarData" width="130" height="130" style="border-radius: 6px;"></v-img>
-        </div>
-      </div>
-      <!-- 基础信息 -->
-      <div style="flex: 1;" class="mr-8">
-        <div>
-          <span class="ml-50" style="font-size: 20px; font-weight: 600;color: var(--color-666);">
-            {{ data?.name || data?.phone }}
-          </span>
-          <div class="mt-3 d-flex">
-            <div class="listBox ml-50">
-              <div>
-                <span>性别:</span>
-                <span>{{ data?.genderInf || '' }}</span>
-              </div>
-              <div>
-                <span></span>
-                <span>{{ baseInfo?.phone || userInfo?.phone || $t('common.currentlyUnavailable') }}</span>
-              </div>
-              <div>
-                <span class="mdi mdi-email-outline"></span>
-                <span>{{ baseInfo?.email || $t('common.currentlyUnavailable') }}</span>
-              </div>
-              <div>
-                <span class="mdi mdi-calendar-blank-outline"></span>
-                <span>{{ baseInfo?.expTypeText || $t('common.currentlyUnavailable') }}</span>
-              </div>
-              <div>
-                <span class="mdi mdi-school-outline"></span>
-                <span>{{ baseInfo?.eduTypeText || $t('common.currentlyUnavailable') }}</span>
-              </div>
-              <div>
-                <span class="mdi mdi-tag-outline"></span>
-                <span>{{ baseInfo?.jobStatusText || $t('common.currentlyUnavailable') }}</span>
-              </div>
-              <div>
-                <span class="mdi mdi-cake-variant-outline"></span>
-                <span>{{ baseInfo?.birthdayText || $t('common.currentlyUnavailable') }}</span>
-              </div>
-              <div>
-                <span class="mdi mdi-home-map-marker"></span>
-                <span>{{ baseInfo?.regName || $t('common.currentlyUnavailable') }}</span>
-              </div>
-              <div>
-                <span class="mdi mdi-account-heart"></span>
-                <span>{{ baseInfo?.maritalText || $t('common.currentlyUnavailable') }}</span>
-              </div>
-              <div>
-                <span>{{ $t('resume.firstWorkTime') }}:</span>
-                <span>{{ baseInfo?.firstWorkTimeText || $t('common.currentlyUnavailable') }}</span>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup>
-defineProps({
-  data: Object
-})
-</script>
-
-<style lang="scss" scoped>
-.jobTypeCardBox {
-  position: absolute;
-  top: -22px;
-  left: 0;
-}
-.ml-50 {
-  margin-left: 50px;
-}
-.avatarsBox {
-  height: 150px;
-  width: 120px;
-  position: relative;
-  cursor: pointer;
-  margin: 0 32px;
-  .camera {
-    color: #fff;
-    font-size: 42px;
-    position: absolute;
-    top: 50%;
-    left: 50%;
-    transform: translate(-50%, -50%);
-  }
-}
-
-.listBox {
-  display: flex;
-  flex-wrap: wrap; /* 允许换行 */
-  width: 100%; /* 设置容器宽度 */
-  overflow: hidden;
-  color: var(--color-666);
-  div {
-    width: 50%;
-    margin-bottom: 10px;
-    span {
-      height: 32px;
-      line-height: 32px;
-    }
-    .mdi {
-      font-size: 22px;
-      margin-right: 8px;
-    }
-  }
-}
-</style>

+ 0 - 279
src/views/recruit/personal/PersonalCenter/resume/online/analysis/basicInfo.vue

@@ -1,279 +0,0 @@
-<template>
-  <CtForm ref="CtFormRef" :items="items" style="width: 100%;"></CtForm>
-</template>
-
-<script setup>
-defineOptions({ name: 'resumeAnalysis-basicInfo'})
-import { ref, watch } from 'vue'
-import { checkEmail } from '@/utils/validate'
-import { getDict } from '@/hooks/web/useDictionaries'
-const props = defineProps({
-  id: {
-    type: String,
-    default: ''
-  },
-  data: {
-    type: Object,
-    default: () => ({})
-  }
-})
-
-const CtFormRef = ref()
-const userInfo = ref(JSON.parse(localStorage.getItem('userInfo')))
-const items = ref({
-  options: [
-    {
-      type: 'text',
-      key: 'name',
-      value: null,
-      default: null,
-      label: '中文名 *',
-      col: 6,
-      outlined: true,
-      rules: [
-        value => {
-          if (value) return true
-          return '请输入您的中文名'
-        },
-        value => {
-          var regex = /^[\u4e00-\u9fa5]+$/
-          if (regex.test(value)) return true
-          return '请输入正确的中文名'
-        }
-      ]
-    },
-    {
-      type: 'text',
-      key: 'foreignName',
-      value: null,
-      label: '英文名',
-      col: 6,
-      outlined: true,
-      clearable: true,
-      rules: [
-        value => {
-          if (!value) return true
-          var regex = /^[A-Za-z]+(?:\s[A-Za-z]+)?$/
-          if (regex.test(value)) return true
-          return '请输入正确的英文名'
-        }
-      ]
-    },
-    {
-      type: 'ifRadio',
-      key: 'sex',
-      value: null, // '1' ? '男' : '女'
-      default: '1',
-      label: '性别 *',
-      col: 6,
-      width: 50,
-      dictTypeName: 'menduner_sex',
-      items: [],
-    },
-    {
-      type: 'phoneNumber',
-      key: 'phone',
-      value: null,
-      default: userInfo?.value?.phone || '',
-      label: '电话号码 *',
-      col: 6,
-      outlined: true,
-      rules: [v => !!v || '请填写联系手机号']
-    },
-    {
-      type: 'datePicker',
-      mode: 'date',
-      labelWidth: 80,
-      key: 'birthday',
-      value: '2000-01-01',
-      defaultValue: new Date(2000, 1, 1),
-      label: '出生日期 *',
-      disabledFutureDates: true,
-      col: 6,
-      format: 'YYYY/MM/DD',
-      flexStyle: 'mb-7',
-      outlined: true,
-      rules: [v => !!v || '请选择出生日期']
-    },
-    {
-      type: 'datePicker',
-      mode: 'month',
-      key: 'firstWorkTime',
-      value: '2000-01',
-      disabledFutureDates: true,
-      defaultValue: new Date(2000, 1),
-      format: 'YYYY/MM',
-      labelWidth: 90,
-      flexStyle: 'mb-7',
-      label: '首次工作时间',
-      col: 6,
-      outlined: true
-    },
-    {
-      type: 'text',
-      key: 'email',
-      value: null,
-      default: null,
-      label: '常用邮箱 *',
-      col: 6,
-      outlined: true,
-      rules: [
-        value => {
-          if (value) return true
-          return '请输入联系邮箱'
-        },
-        value => {
-          if (value && !checkEmail(value)) return '请输入正确的电子邮箱'
-          return true
-        }
-      ]
-    },
-    {
-      type: 'autocomplete',
-      key: 'expType',
-      value: null,
-      default: null,
-      label: '工作年限 *',
-      col: 6,
-      outlined: true,
-      itemText: 'label',
-      itemValue: 'value',
-      dictTypeName: 'menduner_exp_type',
-      rules: [v => !!v || '请选择工作年限'],
-      items: []
-    },
-    {
-      type: 'autocomplete',
-      key: 'eduType',
-      value: null,
-      default: null,
-      label: '最高学历 *',
-      col: 6,
-      outlined: true,
-      itemText: 'label',
-      itemValue: 'value',
-      dictTypeName: 'menduner_education_type',
-      rules: [v => !!v || '请选择最高学历'],
-      items: []
-    },
-    {
-      type: 'autocomplete',
-      key: 'jobType',
-      value: null,
-      default: null,
-      label: '求职类型 *',
-      col: 6,
-      outlined: true,
-      itemText: 'label',
-      itemValue: 'value',
-      dictTypeName: 'menduner_job_type',
-      rules: [v => !!v || '请选择求职类型'],
-      items: []
-    },
-    {
-      type: 'autocomplete',
-      key: 'jobStatus',
-      value: null,
-      default: null,
-      label: '求职状态 *',
-      col: 6,
-      outlined: true,
-      itemText: 'label',
-      itemValue: 'value',
-      dictTypeName: 'menduner_job_seek_status',
-      rules: [v => !!v || '请选择求职状态'],
-      items: []
-    },
-    {
-      type: 'autocomplete',
-      key: 'maritalStatus',
-      value: null,
-      default: null,
-      label: '婚姻状况',
-      col: 6,
-      outlined: true,
-      itemText: 'label',
-      itemValue: 'value',
-      dictTypeName: 'menduner_marital_status',
-      items: []
-    },
-    {
-      type: 'cascade',
-      key: 'areaId',
-      value: null,
-      default: null,
-      label: '所在城市',
-      itemText: 'name',
-      itemValue: 'id',
-      required: true,
-      checkStrictly: true,
-      clearable: false,
-      col: 6,
-      items: [],
-    },
-    {
-      type: 'cascade',
-      key: 'regId',
-      value: null,
-      default: null,
-      label: '户籍地',
-      itemText: 'name',
-      itemValue: 'id',
-      checkStrictly: true,
-      required: false,
-      clearable: true,
-      col: 6,
-      items: [],
-    },
-    
-  ]
-})
-
-items.value.options.forEach(async (e, index) => {
-  if ((index + 2) % 2 === 0) e.flexStyle = 'mr-3'
-  if (e.dictTypeName) {
-    const { data } = await getDict(e.dictTypeName)
-    e.items = data
-  }
-})
-
-watch(
-  () => props.data,
-  (newVal) => {
-    if (newVal && Object.keys(newVal)) {
-      items.value.options.forEach(e => {
-        if (newVal[e.key]) e.value = newVal[e.key]
-        else e.value = e.default || null
-      })
-    }
-  },
-  { immediate: true },
-)
-
-const submit = async () => {
-  const { valid } = await CtFormRef.value.formRef.validate()
-  if (!valid) return { id: props.id, data: null}
-  const obj = {}
-  items.value.options.forEach(e => obj[e.key] = e.value)
-  return { id: props.id, data: obj}
-}
-
-defineExpose({
-  id: props.id,
-  submit
-})
-
-getDict('areaTreeData', null, 'areaTreeData').then(({ data }) => {
-  data = data?.length && data || []
-  if (!data?.length) return console.error('areaTreeData获取失败!')
-  const chinaTreeData = data
-  if (!chinaTreeData?.length) return console.error('chinaTreeData获取失败!')
-  const workAreaProvince = items.value.options.find(e => e.key === 'areaId')
-  const regAreaProvince = items.value.options.find(e => e.key === 'regId')
-  if (workAreaProvince?.items) workAreaProvince.items = chinaTreeData
-  if (regAreaProvince?.items) regAreaProvince.items = chinaTreeData
-})
-</script>
-
-<style lang="scss" scoped>
-</style>

+ 0 - 61
src/views/recruit/personal/PersonalCenter/resume/online/analysis/eduExp.vue

@@ -1,61 +0,0 @@
-<template>
-  <div class="resume-box elevation-2 mb-3">
-    <div class="resume-header mb-3">
-      <div class="resume-title">{{ $t('resume.educationExp') }}</div>
-    </div>
-    <div v-for="(item, index) in data.educationObjs" :key="'educationExp' + index" :class="[' mx-n2', {'mt-5': index }]">
-      <div class="educExpItem">
-        <div class="level1 d-flex align-center justify-space-between" style="height: 40px;">
-          <div>
-            <span style="font-size: 18px; font-weight: bold;">{{ item.eduCollege }}</span>
-            <span class="color6 font15 ml-5">
-              <span>{{ item.startDate }}</span>
-              <span class="mx-1">至</span>
-              <span>{{ item.endDate }}</span>
-            </span>
-          </div>
-        </div>
-        <div class="level2 my-2">
-          <span class="color6 font15">{{ item.eduMajor }}</span>
-          <span class="septal-line"  v-if="item.eduMajor && item.eduDegree"></span>
-          <span class="color6 font15">{{ item.eduDegree }}</span>
-        </div>
-        <div class="level3">
-          <span class="color6 font15">
-            在校经历:
-            <p v-if="item.eduContent" v-html="item.eduContent.replace(/\n/g, '</br>')"></p>
-            <span v-else>暂无描述</span>
-          </span>
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup name="EduExp">
-defineProps({
-  data: Object
-})
-</script>
-
-<style scoped lang="scss">
-.font15 { font-size: 15px;; }
-.color9 { color: var(--color-999); }
-.color6 { color: var(--color-666); }
-.educExpItem {
-  cursor: pointer;
-  border-radius: 6px;
-  padding: 2px 10px 8px;
-  &:hover {
-    background-color: var(--color-f8);
-  }
-}
-.educExpItem-edit {
-  border-radius: 6px;
-  padding: 2px 10px 8px;
-  background-color: var(--color-f8);
-}
-:deep(.el-input--large .el-input__wrapper) {
-  background-color: #f8f8f8;
-}
-</style>

+ 0 - 234
src/views/recruit/personal/PersonalCenter/resume/online/analysis/educationExp.vue

@@ -1,234 +0,0 @@
-<!--  -->
-<template>
-  <CtForm ref="CtFormRef" :items="items" style="width: 100%;"></CtForm>
-</template>
-
-<script setup>
-defineOptions({ name: 'resumeAnalysis-educationExp'})
-import { debounce } from 'lodash'
-import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, reactive, watch } from 'vue'
-import { schoolSearchByName, schoolMajorByName } from '@/api/recruit/personal/resume'
-import { dealCanBeInputtedSave, dealCanBeInputtedValueAndLabel } from '@/utils/getText'
-
-const props = defineProps({
-  id: {
-    type: String,
-    default: ''
-  },
-  data: {
-    type: Object,
-    default: () => {}
-  }
-})
-
-const CtFormRef = ref()
-const dictItemsObj = reactive({})
-
-// 学校下拉列表
-const schoolNameInput = ref('')
-const getSchoolListData = async (name) => {
-  const item = items.value.options.find(e => e.key === 'schoolId')
-  if (!item) return
-  if (item.items?.length && (schoolNameInput.value === name)) return // 防抖
-  item[item.itemTextName] = schoolNameInput.value = name
-
-  if (name === null || name === '') { item.items = [] }
-  else {
-    const data = await schoolSearchByName({ name })
-    item.items = data
-  }
-}
-const debouncedCallbackSchool = debounce(newValue => {
-  if (!newValue) return
-  getSchoolListData(newValue)
-}, 500)
-
-// 专业下拉列表
-const majorNameInput = ref('')
-const getMajorListData = async (name) => {
-  const item = items.value.options.find(e => e.key === 'majorId')
-  if (name === '') { // 此接口不支持传空值
-    item.items = []
-    return
-  }
-  if (item.items?.length && (majorNameInput.value === name)) return // 防抖
-  item[item.itemTextName] = majorNameInput.value = name
-  
-  if (name === null || name === '') { item.items = [] }
-  else {
-    const data = await schoolMajorByName({ name })
-    item.items = data
-  }
-}
-const debouncedCallbackMajor = debounce(newValue => {
-  getMajorListData(newValue)
-}, 500)
-
-const items = ref({
-  options: [
-    {
-      type: 'combobox',
-      key: 'schoolId',
-      value: null,
-      default: null,
-      label: '学校名称 *',
-      col: 6,
-      outlined: true,
-      clearable: true,
-      canBeInputted: true, //
-      itemTextName: 'schoolName',
-      itemText: 'value',
-      itemValue: 'key',
-      rules: [v => !!v || '请选择学校名称'],
-      search: debouncedCallbackSchool,
-      items: []
-    },
-    {
-      type: 'combobox',
-      key: 'majorId',
-      value: null,
-      default: null,
-      label: '所学专业 *',
-      col: 6,
-      outlined: true,
-      clearable: true,
-      canBeInputted: true, //
-      itemTextName: 'major',
-      itemText: 'nameCn',
-      itemValue: 'id',
-      rules: [v => !!v || '请选择所学专业'],
-      search: debouncedCallbackMajor,
-      items: []
-    },
-    {
-      type: 'autocomplete',
-      key: 'educationType',
-      value: null,
-      default: null,
-      label: '学历 *',
-      col: 6,
-      outlined: true,
-      itemText: 'label',
-      itemValue: 'value',
-      rules: [v => !!v || '请选择学历'],
-      items: []
-    },
-    {
-      type: 'autocomplete',
-      key: 'educationSystemType',
-      value: null,
-      default: null,
-      label: '学制类型 *',
-      col: 6,
-      outlined: true,
-      itemText: 'label',
-      itemValue: 'value',
-      rules: [v => !!v || '请选择学制类型'],
-      items: dictItemsObj.educationSystemType,
-    },
-    {
-      type: 'datePicker',
-      key: 'startTime',
-      mode: 'month', // 时间类型 year month date time
-      value: null,
-      default: '2014-01',
-      format: 'YYYY/MM',
-      labelWidth: 80,
-      label: '开始时间 *',
-      defaultValue: new Date(2014, 1),
-      disabledFutureDates: true,
-      col: 6,
-      rules: [v => !!v || '请选择起始时间']
-    },
-    {
-      type: 'datePicker',
-      key: 'endTime',
-      mode: 'month', // 时间类型 year month date time
-      value: null,
-      default: '2018-01',
-      format: 'YYYY/MM',
-      defaultValue: new Date(2018, 1),
-      disabledFutureDates: true,
-      labelWidth: 80,
-      label: '结束时间 *',
-      col: 6,
-      rules: [v => !!v || '请选择结束时间']
-    },
-    {
-      type: 'textarea',
-      key: 'content',
-      value: null,
-      default: null,
-      rows: 5,
-      flexStyle: 'mt-5',
-      resize: true,
-      counter: 1600,
-      label: '在校经历',
-      outlined: true
-    },
-  ]
-})
-
-watch(
-  () => props.data,
-  (newVal) => {
-    if (newVal && Object.keys(newVal)) {
-      schoolNameInput.value = newVal.schoolName || null
-      majorNameInput.value = newVal.major || null
-      //
-      items.value.options.forEach(e => {
-        if (newVal[e.key]) e.value = newVal[e.key]
-        else e.value = e.default || null
-        if (e.canBeInputted) { // 特殊处理可输入下拉框
-          dealCanBeInputtedValueAndLabel(e, newVal)
-        }
-      })
-    }
-  },
-  { immediate: true },
-)
-
-const submit = async () => {
-  const { valid } = await CtFormRef.value.formRef.validate()
-  if (!valid) return { id: props.id, data: null}
-  const obj = {}
-  items.value.options.forEach(e => {
-    if (e.canBeInputted) { // 特殊处理可输入下拉框
-      dealCanBeInputtedSave(e, obj)
-    }
-    else obj[e.key] = e.value
-  })
-  return { id: props.id, data: obj}
-}
-
-defineExpose({
-  id: props.id,
-  submit
-})
-
-// 左侧加mr
-items.value.options.forEach((e, index) => {
-  if (((index + 2) % 2 === 0) && Boolean(e.col) && e.col !== 12) e.flexStyle = 'mr-3'
-})
-
-// 获取字典内容
-const dictList = [
-  { type: 'menduner_education_type', key: 'educationType' },
-  { type: 'menduner_education_system_type', key: 'educationSystemType' }
-]
-const getDictData = async (obj) => {
-  const item = items.value.options.find(e => e.key === obj.key)
-  if (item) { //  && !item.items?.length
-    const { data } = await getDict(obj.type)
-    item.items = data || []
-    dictItemsObj[obj.key] = data || []
-  }
-}
-const getOptions = () => {
-  dictList.forEach(obj =>  getDictData(obj))
-}
-getOptions()
-</script>
-<style lang="scss" scoped>
-</style>

+ 0 - 24
src/views/recruit/personal/PersonalCenter/resume/online/analysis/evaluation.vue

@@ -1,24 +0,0 @@
-<template>
-  <div class="resume-box elevation-2 mb-3" id="selfEvaluation">
-    <div class="resume-header">
-      <div class="resume-title">{{ $t('resume.personalAdvantages') }}</div>
-    </div>
-    <div class="content-list mt-3">
-      <div v-if="data.contMyDesc" class="resumeNoDataText" v-html="data.contMyDesc.replace(/\n/g, '</br>')"></div>
-    </div>
-  </div>
-</template>
-
-<script setup>
-defineOptions({ name: 'Evaluation'})
-
-defineProps({
-  data: Object
-})
-</script>
-
-<style scoped lang="scss">
-.content-list {
-  white-space: pre-line;
-}
-</style>

+ 0 - 59
src/views/recruit/personal/PersonalCenter/resume/online/analysis/selfEvaluation.vue

@@ -1,59 +0,0 @@
-<!--  -->
-<template>
-  <div>
-    <v-textarea 
-      v-model="advantage" 
-      :label="$t('resume.dataDefaultPrompt') + $t('resume.personalAdvantages') + '...'" 
-      variant="outlined" 
-      counter="300" 
-      color="primary" 
-      validate-on="input"
-      :rules="advantageRules"
-    ></v-textarea>
-  </div>
-</template>
-
-<script setup>
-defineOptions({ name: 'resumeAnalysis-selfEvaluation'})
-// import Snackbar from '@/plugins/snackbar'
-import DOMPurify from 'dompurify'
-import { ref } from 'vue'
-const props = defineProps({
-  id: {
-    type: String,
-    default: ''
-  },
-  data: {
-    type: String,
-    default: ''
-  }
-})
-
-const advantage = ref(props.data)
-const advantageRules = ref([
-  value => {
-    if (value) return true
-    return '请输入您的个人优势'
-  },
-  value => {
-    if (value?.length <= 300) return true
-    return '请输入2-300个字符'
-  }
-])
-
-const submit = async () => {
-  advantage.value = DOMPurify.sanitize(advantage.value)
-  if (!advantage.value) {
-    // Snackbar.warning('请先输入个人优势!')
-    return { id: props.id, data: null}
-  }
-  return { id: props.id, data: { content: advantage.value}}
-}
-
-defineExpose({
-  id: props.id,
-  submit
-})
-</script>
-<style lang="scss" scoped>
-</style>

+ 0 - 112
src/views/recruit/personal/PersonalCenter/resume/online/analysis/trainingExperience.vue

@@ -1,112 +0,0 @@
-<!--  -->
-<template>
-  <CtForm ref="CtFormRef" :items="items" style="width: 100%;"></CtForm>
-</template>
-
-<script setup>
-defineOptions({ name: 'resumeAnalysis-trainingExperience'})
-import { ref, watch } from 'vue'
-const props = defineProps({
-  id: {
-    type: String,
-    default: ''
-  },
-  data: {
-    type: Object,
-    default: () => {}
-  }
-})
-
-const CtFormRef = ref()
-const items = ref({
-  options: [
-    {
-      type: 'text',
-      key: 'orgName',
-      value: '',
-      col: 6,
-      label: '培训中心 *',
-      flexStyle: 'mr-3',
-      rules: [v => !!v || '请输入培训中心']
-    },
-    {
-      type: 'text',
-      key: 'course',
-      value: '',
-      col: 6,
-      label: '培训课程 *',
-      rules: [v => !!v || '请输入培训课程']
-    },
-    {
-      type: 'datePicker',
-      key: 'startTime',
-      mode: 'month',
-      value: '2020-01',
-      labelWidth: 80,
-      format: 'YYYY/MM',
-      defaultValue: new Date(2020, 1),
-      label: '开始时间 *',
-      disabledFutureDates: true,
-      col: 6,
-      flexStyle: 'mr-3',
-      rules: [v => !!v || '请选择培训开始时间']
-    },
-    {
-      type: 'datePicker',
-      key: 'endTime',
-      mode: 'month',
-      value: '2022-01',
-      format: 'YYYY/MM',
-      labelWidth: 80,
-      defaultValue: new Date(2022, 1),
-      label: '结束时间 *',
-      disabledFutureDates: true,
-      col: 6,
-      rules: [v => !!v || '请选择培训结束时间']
-    },
-    {
-      type: 'textarea',
-      key: 'content',
-      value: '',
-      label: '培训描述',
-      rows: 5,
-      flexStyle: 'mt-5',
-      resize: true,
-      counter: 2000,
-      rules: [
-        value => {
-          if (value?.length <= 2000) return true
-          return '请输入2-2000个字符'
-        }
-      ]
-    }
-  ]
-})
-
-watch(
-  () => props.data,
-  (newVal) => {
-    if (newVal && Object.keys(newVal)) {
-      items.value.options.forEach(e => {
-        if (newVal[e.key]) e.value = newVal[e.key]
-      })
-    }
-  },
-  { immediate: true }
-)
-
-const submit = async () => {
-  const { valid } = await CtFormRef.value.formRef.validate()
-  if (!valid) return { id: props.id, data: null}
-  const obj = {}
-  items.value.options.forEach(e => obj[e.key] = e.value)
-  return { id: props.id, data: obj}
-}
-
-defineExpose({
-  id: props.id,
-  submit
-})
-</script>
-<style lang="scss" scoped>
-</style>

+ 0 - 57
src/views/recruit/personal/PersonalCenter/resume/online/analysis/workExp.vue

@@ -1,57 +0,0 @@
-<template>
-  <div class="resume-box elevation-2 mb-3">
-    <div class="resume-header mb-3">
-      <div class="resume-title">
-        {{ $t('resume.workExperience') }}
-      </div>
-    </div>
-    <div v-for="(item, index) in data.jobExpObjs" :key="'workExperience' + index">
-      <div class="educExpItem">
-        <div class="level1 d-flex align-center justify-space-between" style="height: 40px;">
-          <div>
-            <span style="font-size: 18px; font-weight: bold;">{{ item.jobCpy }}</span>
-            <span class="color6 font15 ml-5">
-              <span>{{ item.startDate }}</span>
-              <span class="mx-1">至</span>
-              <span>{{ item.endDate }}</span>
-            </span>
-          </div>
-        </div>
-        <div class="level2 my-2">
-          <span class="color6 font15">{{ item.jobPosition }}</span>
-        </div>
-        <div class="level3">
-          <span class="color6 font15">{{ $t('resume.jobContent') }}<p v-if="item.jobContent" v-html="item.jobContent.replace(/\n/g, '</br>')"></p></span>
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup name="WorkExp">
-defineProps({
-  data: Object
-})
-</script>
-
-<style scoped lang="scss">
-.font15 { font-size: 15px;; }
-.color9 { color: var(--color-999); }
-.color6 { color: var(--color-666); }
-.educExpItem {
-  cursor: pointer;
-  border-radius: 6px;
-  padding: 2px 10px 8px;
-  &:hover {
-    background-color: var(--color-f8);
-  }
-}
-.educExpItem-edit {
-  border-radius: 6px;
-  padding: 2px 10px 8px;
-  background-color: var(--color-f8);
-}
-:deep(.el-input--large .el-input__wrapper) {
-  background-color: #f8f8f8;
-}
-</style>

+ 0 - 203
src/views/recruit/personal/PersonalCenter/resume/online/analysis/workExperience.vue

@@ -1,203 +0,0 @@
-<!--  -->
-<template>
-  <CtForm ref="CtFormRef" :items="items" style="width: 100%;">
-    <template #endTime="{ item }">
-      <div>
-        <v-checkbox-btn
-          v-model="item.soFar"
-          color="primary"
-          :label="$t('sys.soFar')"
-          class="ml-2"
-          :disabled="false"
-          :style="`line-height: ${item.dense === 'default' ? 56 : item.dense === 'comfortable' ? 48 : 40 }px;`"
-          style="width: 80px;"
-          hide-details
-          @update:modelValue="v => handleSoFarChange(v, item)"
-        ></v-checkbox-btn>
-      </div>
-    </template>
-  </CtForm>
-</template>
-
-<script setup>
-defineOptions({ name: 'resumeAnalysis-workExperience'})
-import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, reactive, watch } from 'vue'
-import { dealCanBeInputtedSave, dealCanBeInputtedValueAndLabel } from '@/utils/getText'
-
-const props = defineProps({
-  id: {
-    type: String,
-    default: ''
-  },
-  data: {
-    type: Object,
-    default: () => {}
-  }
-})
-
-const CtFormRef = ref()
-const dictItemsObj = reactive({})
-dictItemsObj.educationSystemType = [{ label: '全日制', value: '0' }, { label: '非全日制', value: '1' }]
-
-
-// 企业名称下拉列表
-const enterpriseNameInput = ref('')
-const getEnterpriseData = async (name) => {
-  const item = items.value.options.find(e => e.key === 'enterpriseId')
-  if (!item) return
-  if (item.items?.length && (enterpriseNameInput.value === name)) return // 防抖
-  item[item.itemTextName] = enterpriseNameInput.value = name
-  if (name === null || name === '') { item.items = [] }
-  else {
-    const data = await enterpriseSearchByName({ name })
-    item.items = data
-  }
-}
-
-const positionSearch = (name) => {
-  const item = items.value.options.find(e => e.key === 'positionId')
-  if (!item) return
-  item[item.itemTextName] = name
-}
-
-// 《至今》复选框事件
-const handleSoFarChange = (bool, item) => {
-  const opObj = items.value.options.find(e => e.key === item.key)
-  if (opObj) {
-    opObj.value = null
-    opObj.soFar = bool
-    opObj.disabled = bool ? true : false
-  }
-}
-
-const items = ref({
-  options: [
-    {
-      type: 'combobox',
-      key: 'enterpriseId',
-      value: null,
-      default: null,
-      label: '企业名称 *',
-      outlined: true,
-      clearable: true,
-      canBeInputted: true, //
-      itemTextName: 'enterpriseName',
-      itemText: 'value',
-      itemValue: 'key',
-      rules: [v => !!v || '请选择企业名称'],
-      search: getEnterpriseData,
-      items: []
-    },
-    {
-      type: 'combobox',
-      key: 'positionId',
-      value: null,
-      default: null,
-      label: '职位名称 *',
-      outlined: true,
-      clearable: true,
-      canBeInputted: true, //
-      itemTextName: 'positionName',
-      itemText: 'nameCn',
-      itemValue: 'id',
-      rules: [v => !!v || '请选择职位名称'],
-      search: val => positionSearch(val),
-      items: []
-    },
-    {
-      type: 'datePicker',
-      key: 'startTime',
-      mode: 'month', // 时间类型 year month date time
-      value: null,
-      label: '开始时间 *',
-      labelWidth: 100,
-      default: '2020-01',
-      defaultValue: new Date(2020, 1),
-      disabledFutureDates: true,
-      format: 'YYYY/MM',
-      rules: [v => !!v || '请选择起始时间']
-    },
-    {
-      type: 'datePicker',
-      key: 'endTime',
-      slotName: 'endTime',
-      mode: 'month', // 时间类型 year month date time
-      value: null,
-      format: 'YYYY/MM',
-      default: '2022-01',
-      defaultValue: new Date(2022, 1),
-      label: '结束时间 *',
-      disabledFutureDates: true,
-      labelWidth: 100,
-      rules: [v => !!v || '请选择结束时间']
-    },
-    {
-      type: 'textarea',
-      key: 'content',
-      value: null,
-      default: null,
-      rows: 10,
-      resize: true,
-      flexStyle: 'mt-5',
-      counter: 2000,
-      label: '工作内容 *',
-      outlined: true,
-      rules: [v => !!v || '请输入工作内容']
-    },
-  ]
-})
-// 左侧加mr
-// items.value.options.forEach((e, index) => {
-//   if (((index + 2) % 2 === 0) && Boolean(e.col) && e.col !== 12) e.flexStyle = 'mr-3'
-// })
-
-watch(
-  () => props.data,
-  (newVal) => {
-    if (newVal && Object.keys(newVal)) {
-      enterpriseNameInput.value = newVal.enterpriseName
-      //
-      items.value.options.forEach(e => {
-        if (newVal[e.key]) e.value = newVal[e.key]
-        if (e.canBeInputted) { // 特殊处理可输入下拉框
-          dealCanBeInputtedValueAndLabel(e, newVal)
-        }
-      })
-      if (!newVal.endTime) handleSoFarChange(true, {key: 'endTime'})
-    }
-  },
-  { immediate: true },
-)
-
-const submit = async () => {
-  const { valid } = await CtFormRef.value.formRef.validate()
-  if (!valid) return { id: props.id, data: null }
-  const obj = {}
-  items.value.options.forEach(e => {
-    if (e.canBeInputted) { // 特殊处理可输入下拉框
-      dealCanBeInputtedSave(e, obj)
-    }
-    else obj[e.key] = e.value
-  })
-  return { id: props.id, data: obj}
-}
-
-defineExpose({
-  id: props.id,
-  submit
-})
-
-// 岗位treeChildren
-let positionTreeChildrenData = []
-getDict('positionTreeData', null, 'positionTreeData').then(({ data }) => {
-  data = data?.length && data || []
-  data.forEach(e => {
-    if (e?.children?.length) positionTreeChildrenData = positionTreeChildrenData.concat(e.children)
-  })
-  items.value.options.find(e => e.key === 'positionId').items = positionTreeChildrenData
-})
-
-</script>
-<style lang="scss" scoped>
-</style>

+ 30 - 6
src/views/recruit/personal/PersonalCenter/resume/online/components/educationExp.vue

@@ -103,6 +103,27 @@ const debouncedCallbackMajor = debounce(newValue => {
   getMajorListData(newValue)
 }, 500)
 
+const startTimeChange = (v) => {
+  const item1 = formItems.value.options.find(e => e.key === 'startTime')
+  const item2 = formItems.value.options.find(e => e.key === 'endTime')
+  if (item1?.value && item2?.value && item1.value > item2.value) {
+    Snackbar.warning('开始时间不能大于结束时间!')
+    nextTick(() => {
+      item1.value = item2.value
+    })
+  }
+}
+const endTimeChange = (v) => {
+  const item1 = formItems.value.options.find(e => e.key === 'startTime')
+  const item2 = formItems.value.options.find(e => e.key === 'endTime')
+  if (item1?.value && item2?.value && item1.value > item2.value) {
+    Snackbar.warning('结束时间不能小于开始时间')
+    nextTick(() => {
+      item2.value = item1.value
+    })
+  }
+}
+
 const formItems = ref({
   options: [
     {
@@ -170,28 +191,30 @@ const formItems = ref({
       key: 'startTime',
       mode: 'month', // 时间类型 year month date time
       value: null,
-      default: '2014-01',
-      format: 'YYYY/MM',
+      default: new Date(2014, 1).getTime(),
+      // format: 'YYYY/MM',
       labelWidth: 120,
       label: '开始时间 *',
       defaultValue: new Date(2014, 1),
       disabledFutureDates: true,
       col: 6,
-      rules: [v => !!v || '请选择起始时间']
+      rules: [v => !!v || '请选择起始时间'],
+      change: startTimeChange
     },
     {
       type: 'datePicker',
       key: 'endTime',
       mode: 'month', // 时间类型 year month date time
       value: null,
-      default: '2018-01',
-      format: 'YYYY/MM',
+      default: new Date(2018, 1).getTime(),
+      // format: 'YYYY/MM',
       defaultValue: new Date(2018, 1),
       disabledFutureDates: true,
       labelWidth: 120,
       label: '结束时间 *',
       col: 6,
-      rules: [v => !!v || '请选择结束时间']
+      rules: [v => !!v || '请选择结束时间'],
+      change: endTimeChange
     },
     {
       type: 'textarea',
@@ -267,6 +290,7 @@ const handleSave = async () => {
     else obj[e.key] = e.value
   })
   if (!obj.startTime || !obj.endTime) return Snackbar.warning('请选择起始时间!')
+  if (obj.startTime > obj.endTime) return Snackbar.warning('开始时间不能大于结束时间!')
   if (editId.value) obj.id = editId.value
   await saveResumeEduExp(obj)
   Snackbar.success('保存成功!')

+ 29 - 6
src/views/recruit/personal/PersonalCenter/resume/online/components/trainingExperience.vue

@@ -57,6 +57,28 @@ const formPageRef = ref()
 const type = ref('')
 const editId = ref(null)
 const loading = ref(false)
+
+const startTimeChange = (v) => {
+  const item1 = items.value.options.find(e => e.key === 'startTime')
+  const item2 = items.value.options.find(e => e.key === 'endTime')
+  if (item1?.value && item2?.value && item1.value > item2.value) {
+    Snackbar.warning('开始时间不能大于结束时间!')
+    nextTick(() => {
+      item1.value = item2.value
+    })
+  }
+}
+const endTimeChange = (v) => {
+  const item1 = items.value.options.find(e => e.key === 'startTime')
+  const item2 = items.value.options.find(e => e.key === 'endTime')
+  if (item1?.value && item2?.value && item1.value > item2.value) {
+    Snackbar.warning('结束时间不能小于开始时间')
+    nextTick(() => {
+      item2.value = item1.value
+    })
+  }
+}
+
 const items = ref({
   options: [
     {
@@ -80,28 +102,28 @@ const items = ref({
       type: 'datePicker',
       key: 'startTime',
       mode: 'month',
-      value: '2020-01',
+      value: new Date(2014, 1).getTime(),
       labelWidth: 140,
-      format: 'YYYY/MM',
       defaultValue: new Date(2020, 1),
       label: '培训开始时间 *',
       disabledFutureDates: true,
       col: 6,
       flexStyle: 'mr-3',
-      rules: [v => !!v || '请选择培训开始时间']
+      rules: [v => !!v || '请选择培训开始时间'],
+      change: startTimeChange
     },
     {
       type: 'datePicker',
       key: 'endTime',
       mode: 'month',
-      value: '2022-01',
-      format: 'YYYY/MM',
+      value: new Date(2022, 1).getTime(),
       labelWidth: 140,
       defaultValue: new Date(2022, 1),
       label: '培训结束时间 *',
       disabledFutureDates: true,
       col: 6,
-      rules: [v => !!v || '请选择培训结束时间']
+      rules: [v => !!v || '请选择培训结束时间'],
+      change: endTimeChange
     },
     {
       type: 'textarea',
@@ -151,6 +173,7 @@ const handleSave = async () => {
     obj[e.key] = e.value
   })
   if (!obj.startTime || !obj.endTime) return Snackbar.warning('请选择培训起始时间!')
+  if (obj.startTime > obj.endTime) return Snackbar.warning('开始时间不能大于结束时间!')
   if (editId.value) obj.id = editId.value
   try {
     await saveResumeTrainExp(obj)

+ 29 - 6
src/views/recruit/personal/PersonalCenter/resume/online/components/workExperience.vue

@@ -110,6 +110,27 @@ const handleSoFarChange = (bool, item) => {
   }
 }
 
+const startTimeChange = (v) => {
+  const item1 = formItems.value.options.find(e => e.key === 'startTime')
+  const item2 = formItems.value.options.find(e => e.key === 'endTime')
+  if (item1?.value && item2?.value && item1.value > item2.value) {
+    Snackbar.warning('开始时间不能大于结束时间!')
+    nextTick(() => {
+      item1.value = item2.value
+    })
+  }
+}
+const endTimeChange = (v) => {
+  const item1 = formItems.value.options.find(e => e.key === 'startTime')
+  const item2 = formItems.value.options.find(e => e.key === 'endTime')
+  if (item1?.value && item2?.value && item1.value > item2.value) {
+    Snackbar.warning('结束时间不能小于开始时间')
+    nextTick(() => {
+      item2.value = item1.value
+    })
+  }
+}
+
 const formItems = ref({
   options: [
     {
@@ -127,7 +148,8 @@ const formItems = ref({
       itemValue: 'key',
       rules: [v => !!v || '请选择企业名称'],
       search: getEnterpriseData,
-      items: []
+      items: [],
+      change: startTimeChange
     },
     {
       type: 'combobox',
@@ -144,7 +166,8 @@ const formItems = ref({
       itemValue: 'id',
       rules: [v => !!v || '请选择职位名称'],
       search: val => positionSearch(val),
-      items: []
+      items: [],
+      change: endTimeChange
     },
     {
       type: 'datePicker',
@@ -153,10 +176,9 @@ const formItems = ref({
       value: null,
       label: '开始时间 *',
       labelWidth: 120,
-      default: '2020-01',
+      default: new Date(2020, 1).getTime(),
       defaultValue: new Date(2020, 1),
       disabledFutureDates: true,
-      format: 'YYYY/MM',
       col: 6,
       rules: [v => !!v || '请选择起始时间']
     },
@@ -166,8 +188,7 @@ const formItems = ref({
       slotName: 'endTime',
       mode: 'month', // 时间类型 year month date time
       value: null,
-      format: 'YYYY/MM',
-      default: '2022-01',
+      default: new Date(2022, 1).getTime(),
       defaultValue: new Date(2022, 1),
       label: '结束时间 *',
       disabledFutureDates: true,
@@ -256,6 +277,8 @@ const handleSave = async () => {
   })
   const endTimeSofar = formItems.value.options.find(e => e.key === 'endTime').soFar
   if ((!endTimeSofar && (!obj.startTime || !obj.endTime)) || (endTimeSofar && !obj.startTime)) return Snackbar.warning(endTimeSofar && !obj.startTime ? '请选择开始时间' : '请选择起始时间!')
+  if (obj.endTime && obj.startTime > obj.endTime) return Snackbar.warning('开始时间不能大于结束时间!')
+
   if (editId.value) obj.id = editId.value
   await saveResumeWorkExp(obj)
   Snackbar.success('保存成功!')

+ 0 - 47
src/views/recruit/personal/PersonalCenter/resume/online/index.vue

@@ -26,10 +26,6 @@
       />
     </div>
   </div>
-
-  <Loading :visible="loading"></Loading>
-  <selectResumeDialog v-model="showAttachment" title="请选择已有的简历导入" :list="attachmentList" @submit="handleAttachmentSubmit" @close="showAttachment = false" />
-  <resumeAnalysis v-model="showAnalysis" :data="result" :fileUrl="encodeURIComponent(fileUrl)" @close="analysisClose" />
 </template>
 
 <script setup>
@@ -45,18 +41,10 @@ import workExperience from './components/workExperience.vue'
 // import projectExperience from './components/projectExperience.vue'
 import vocationalSkills from './components/vocationalSkills.vue'
 import { resumePersonFillAll, getPersonResumeCv, resumeParser2 } from '@/api/recruit/personal/resume'
-import Snackbar from '@/plugins/snackbar'
-import { useRouter } from 'vue-router'
-import selectResumeDialog from '@/views/recruit/personal/position/components/jobDetails/selectResumeDialog.vue'
-import resumeAnalysis from './resumeAnalysis.vue'
-import { Base64 } from 'js-base64'
-// import { dataObj } from './test.js'
 
-const router = useRouter()
 const { t } = useI18n()
 const scrollBox = ref()
 const tab = ref(0)
-const loading = ref(false)
 const paths = [basicInfo, selfEvaluation, jobIntention, educationExp, workExperience, vocationalSkills, trainingExperience]
 const items = ref([
   { text: t('resume.basicInfo'), id: 'basicInfo', status: false },
@@ -119,43 +107,8 @@ const getAttachmentList = async () => {
 getAttachmentList()
 
 // 导入附件简历
-const showAttachment = ref(false)
 const handleImportAttachment = () => {
   window.open('/recruit/personal/resume/analysis')
-  // if (!attachmentList.value.length) {
-  //   Snackbar.warning('请先上传附件简历')
-  //   router.push('/recruit/personal/personalCenter/resume/attachment')
-  //   return
-  // }
-  // showAnalysis.value = false
-  // showAttachment.value = true
-}
-
-const result = ref({}) // ref(JSON.parse(JSON.stringify(dataObj))) // 测试
-const fileUrl = ref('')
-const showAnalysis = ref(false)
-const handleAttachmentSubmit = async (val) => {
-  if (!val) return
-  const url = attachmentList.value.find(e => e.id === val).url
-  const baseUrl = import.meta.env.VITE_PREVIEW_URL
-  fileUrl.value = !url.includes('.pdf') ?  `${baseUrl}/onlinePreview?url=${encodeURIComponent(Base64.encode(url))}` : url
-  showAttachment.value = false
-  loading.value = true
-  try {
-    const data = await resumeParser2({ fileUrl: fileUrl.value })
-    result.value = data || {}
-    // result.value = {person: data.person} || {} // 测试
-    showAnalysis.value = true
-  } catch (error) {
-    console.log(error)
-  } finally {
-    loading.value = false
-  }
-}
-
-const analysisClose = () => {
-  result.value = {}
-  showAnalysis.value = false
 }
 
 </script>