Kaynağa Gözat

解析头像

lifanagju_citu 5 ay önce
ebeveyn
işleme
8442b3a0d3

+ 1 - 0
src/locales/en.js

@@ -226,6 +226,7 @@ export default {
     }
   },
   resume: {
+    avatar: 'Avatar',
     basicInfo: 'Basic Information',
     onlineResume: 'Online resume',
     personalAdvantages: 'Personal Advantages',

+ 1 - 0
src/locales/zh-CN.js

@@ -226,6 +226,7 @@ export default {
     }
   },
   resume: {
+    avatar: '头像',
     basicInfo: '基础信息',
     onlineResume: '在线简历',
     personalAdvantages: '个人优势',

+ 0 - 1
src/utils/index.js

@@ -1,7 +1,6 @@
 export const blobToJson = (blob) => {
   return new Promise((resolve, reject) => {
     const reader = new FileReader()
-
     reader.onload = function (event) {
       const jsonString = event.target.result
       const jsonObject = JSON.parse(jsonString)

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

@@ -0,0 +1,100 @@
+<!--  -->
+<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 fileType = file.name.split('.')[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.dataURL || ''
+  // avatarResult.value = res?.result ? Reflect.get(res.result, '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>

+ 6 - 1
src/views/recruit/personal/PersonalCenter/resume/online/index.vue

@@ -29,7 +29,7 @@
 
   <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="showAnalysis = false" />
+  <resumeAnalysis v-model="showAnalysis" :data="result" :fileUrl="encodeURIComponent(fileUrl)" @close="analysisClose" />
 </template>
 
 <script setup>
@@ -152,6 +152,11 @@ const handleAttachmentSubmit = async (val) => {
   }
 }
 
+const analysisClose = () => {
+  result.value = {}
+  showAnalysis.value = false
+}
+
 </script>
 
 <style scoped lang="scss">

+ 13 - 14
src/views/recruit/personal/PersonalCenter/resume/online/resumeAnalysis.vue

@@ -42,6 +42,7 @@ defineOptions({name: 'position-details-selectResumeDialog'})
 import { watch, computed, shallowRef, ref } from 'vue'
 import { useI18n } from '@/hooks/web/useI18n'
 import IFrame from '@/components/IFrame'
+import avatar from './analysis/avatar.vue'
 import basicInfo from './analysis/basicInfo.vue'
 import selfEvaluation from './analysis/selfEvaluation.vue'
 import educationExp from './analysis/educationExp.vue'
@@ -50,7 +51,7 @@ import trainingExperience from './analysis/trainingExperience.vue'
 import Snackbar from '@/plugins/snackbar'
 import Confirm from '@/plugins/confirm'
 import { saveResumeInfo } from '@/api/recruit/personal/resume'
-import { useUserStore } from '@/store/user'; const userStore = useUserStore()
+import { useUserStore } from '@/store/user'
 const emit = defineEmits(['update:modelValue', 'close'])
 const { t } = useI18n()
 const props = defineProps({
@@ -66,11 +67,12 @@ const props = defineProps({
 })
 
 const exampleList = {
-  person: { text: t('resume.basicInfo'), id: 'person', path: basicInfo, hide: false },
-  advantage: { text: t('resume.personalAdvantages'), id: 'advantage', path: selfEvaluation, hide: false },
-  eduList: { text: t('resume.educationExp'), id: 'eduList', path: educationExp, hide: false },
-  workList: { text: t('resume.workExperience'), id: 'workList', path: workExperience, hide: false },
-  trainList: { text: t('resume.trainingExperience'), id: 'trainList', path: trainingExperience, hide: false },
+  avatar: { text: t('resume.avatar'), id: 'avatar', path: avatar },
+  person: { text: t('resume.basicInfo'), id: 'person', path: basicInfo },
+  advantage: { text: t('resume.personalAdvantages'), id: 'advantage', path: selfEvaluation },
+  eduList: { text: t('resume.educationExp'), id: 'eduList', path: educationExp },
+  workList: { text: t('resume.workExperience'), id: 'workList', path: workExperience },
+  trainList: { text: t('resume.trainingExperience'), id: 'trainList', path: trainingExperience },
 }
 
 const componentRef = ref()
@@ -92,7 +94,7 @@ const getValue = async () => {
     return
   }
   // 处理data
-  const obj = Object.keys(data).length ? {} : null
+  let obj = Object.keys(data).length ? {} : null
   const keyTransform = { // 转换给后端的key
     eduList: 'eduExp',
     workList: 'workExp',
@@ -110,9 +112,8 @@ const getValue = async () => {
         obj[newKey] = data[key]
       }
     })
-    obj.avatar = ""
-    obj.tag = { tagList: [] }
-    obj.jobInterested = []
+    const defaultObj = { avatar: "", person: {}, tag: { tagList: [] }, jobInterested: [], eduExp: [], workExp: [], trainExp: [] } // 必传字段
+    obj = { ...defaultObj, ...obj }
   }
   // console.log('123456:', obj)
   return obj && Object.keys(obj).length ? JSON.stringify(obj) : null
@@ -152,8 +153,9 @@ watch(
     paths.value = []
     if (newVal && Object.keys(newVal)) {
       if (newVal.person?.advantage) newVal.advantage = newVal.person.advantage
+      if (newVal.person?.avatar) newVal.avatar = newVal.person.avatar
       // obj
-      const dealObjKeys = ['person', 'advantage']
+      const dealObjKeys = ['avatar', 'person', 'advantage']
       dealObjKeys.forEach(key => {
         if (newVal[key]) {
           const obj = {...exampleList[key]}
@@ -161,9 +163,6 @@ watch(
           paths.value.push(obj)
         }
       })
-      // const baseInfoItem = { ...exampleList.person }
-      // if (newVal.person) baseInfoItem = newVal.person; paths.value.push(baseInfoItem)
-      // if (newVal.person?.advantage) exampleList.advantage.data = newVal.person.advantage; paths.value.push(exampleList.advantage)
       // arr
       const dealArrKeys = ['eduList', 'workList', 'trainList']
       dealArrKeys.forEach(key => {