|
@@ -1,7 +1,30 @@
|
|
|
<template>
|
|
|
<div style="width: 100%;">
|
|
|
- <CtForm ref="formPageRef" :items="items"></CtForm>
|
|
|
+ <CtForm ref="formPageRef" :items="items">
|
|
|
+ <!-- 头像 -->
|
|
|
+ <template #avatar="{ item }">
|
|
|
+ <!-- <div class="d-flex flex-column">
|
|
|
+ <div class="d-flex align-center">
|
|
|
+ </div>
|
|
|
+ </div> -->
|
|
|
+ <div style="color: #7a7a7a; min-width: 52px;">头像:</div>
|
|
|
+ <div class="avatarsBox" @mouseover="showIcon = true" @mouseleave="showIcon = false">
|
|
|
+ <v-avatar class="elevation-5" size=80 :image="getUserAvatar(item.value, male)"></v-avatar>
|
|
|
+ <div v-show="showIcon" @click="openFileInput" v-bind="$attrs" class="mdi mdi-camera-outline">
|
|
|
+ <input
|
|
|
+ type="file"
|
|
|
+ ref="fileInput"
|
|
|
+ accept="image/png, image/jpg, image/jpeg"
|
|
|
+ style="display: none;"
|
|
|
+ @change="handleUploadFile"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div style="font-size: 14px; color: var(--color-999);">只支持JPG、JPEG、PNG类型的图片,大小不超过20M</div>
|
|
|
+ </template>
|
|
|
+ </CtForm>
|
|
|
</div>
|
|
|
+ <ImgCropper :visible="isShowCopper" :image="selectPic" :cropBoxResizable="true" @submit="handleHideCopper" :aspectRatio="1 / 1" @close="isShowCopper = false"></ImgCropper>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
@@ -10,6 +33,10 @@ defineOptions({name: 'necessaryInfo-InfoForm'})
|
|
|
import { reactive, ref } from 'vue'
|
|
|
import { checkEmail } from '@/utils/validate'
|
|
|
import { enterpriseSearchByName } from '@/api/recruit/personal/resume'
|
|
|
+import { getUserAvatar } from '@/utils/avatar'
|
|
|
+import { uploadFile } from '@/api/common'
|
|
|
+import Snackbar from '@/plugins/snackbar'
|
|
|
+import { useI18n } from '@/hooks/web/useI18n'; const { t } = useI18n()
|
|
|
|
|
|
const props = defineProps({
|
|
|
option: {
|
|
@@ -37,9 +64,21 @@ const getEnterpriseData = async (name) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// 图片裁剪
|
|
|
+const selectPic = ref('')
|
|
|
+const isShowCopper = ref(false)
|
|
|
+
|
|
|
+const male = ref('1')
|
|
|
+const showIcon = ref(false)
|
|
|
let positionName = null
|
|
|
const items = ref({
|
|
|
options: [
|
|
|
+ {
|
|
|
+ slotName: 'avatar',
|
|
|
+ key: 'avatar',
|
|
|
+ value: '',
|
|
|
+ flexStyle: 'align-center'
|
|
|
+ },
|
|
|
{
|
|
|
type: 'text',
|
|
|
key: 'name',
|
|
@@ -68,7 +107,8 @@ const items = ref({
|
|
|
outlined: true,
|
|
|
dictTypeName: 'menduner_sex',
|
|
|
rules: [v => !!v || '请选择性别'],
|
|
|
- items: []
|
|
|
+ items: [],
|
|
|
+ change: val => male.value = val
|
|
|
},
|
|
|
{
|
|
|
type: 'phoneNumber',
|
|
@@ -200,6 +240,56 @@ const items = ref({
|
|
|
]
|
|
|
})
|
|
|
|
|
|
+
|
|
|
+// 选择文件
|
|
|
+const fileInput = ref()
|
|
|
+const clicked = ref(false)
|
|
|
+const openFileInput = () => {
|
|
|
+ if (clicked.value) return
|
|
|
+ clicked.value = true
|
|
|
+ fileInput.value.click()
|
|
|
+ clicked.value = false
|
|
|
+}
|
|
|
+
|
|
|
+// 上传头像
|
|
|
+const accept = ['jpg', 'png', 'jpeg']
|
|
|
+const handleUploadFile = async (e) => {
|
|
|
+ const file = e.target.files[0]
|
|
|
+ if (!file) return
|
|
|
+
|
|
|
+ const fileType = file.name.split('.')[1]
|
|
|
+ if (!accept.includes(fileType)) return Snackbar.warning('请上传图片格式文件')
|
|
|
+
|
|
|
+ const size = file.size
|
|
|
+ if (size / (1024*1024) > 20) {
|
|
|
+ Snackbar.warning(t('common.fileSizeExceed'))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const reader = new FileReader()
|
|
|
+ reader.readAsDataURL(file)
|
|
|
+ reader.onload = () => {
|
|
|
+ selectPic.value = String(reader.result)
|
|
|
+ isShowCopper.value = true
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleHideCopper = (data) => {
|
|
|
+ isShowCopper.value = false
|
|
|
+ if (data) {
|
|
|
+ const { file } = data
|
|
|
+ if (!file) return
|
|
|
+
|
|
|
+ const formData = new FormData()
|
|
|
+ formData.append('file', file)
|
|
|
+ formData.append('path', 'img')
|
|
|
+ uploadFile(formData).then(async ({ data }) => {
|
|
|
+ if (!data) return
|
|
|
+ items.value.options.find(e => e.key === 'avatar').value = data
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// 获取字典内容
|
|
|
const getDictData = async (dictTypeName, key) => {
|
|
|
const item = items.value.options.find(e => e.key === key)
|
|
@@ -255,6 +345,7 @@ const getQuery = async () => {
|
|
|
if (Object.prototype.hasOwnProperty.call(e, 'data')) return obj[e.key] = e.data
|
|
|
obj[e.key] = e.value === '' ? null : e.value
|
|
|
})
|
|
|
+ if (!obj.avatar) obj.avatar = getUserAvatar(null, obj.sex)
|
|
|
query = Object.assign(query, obj)
|
|
|
dealQuery()
|
|
|
return query
|
|
@@ -263,4 +354,29 @@ const getQuery = async () => {
|
|
|
defineExpose({
|
|
|
getQuery
|
|
|
})
|
|
|
-</script>
|
|
|
+</script>
|
|
|
+<style scoped lang="scss">
|
|
|
+.avatarsBox {
|
|
|
+ height: 80px;
|
|
|
+ width: 80px;
|
|
|
+ position: relative;
|
|
|
+ cursor: pointer;
|
|
|
+ margin: 32px;
|
|
|
+ margin-right: 40px;
|
|
|
+ .img {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ .mdi {
|
|
|
+ font-size: 42px;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+ div {
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ border-radius: 50%;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|