123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- <template>
- <div style="width: 100%;">
- <CtForm ref="formPageRef" :items="items">
- <!-- 头像 -->
- <template #avatar="{ item }">
- <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>
- import { getDict } from '@/hooks/web/useDictionaries'
- defineOptions({name: 'dialogExtend-InfoForm'})
- import { reactive, ref } from 'vue'
- import { getUserAvatar } from '@/utils/avatar'
- import { uploadFile } from '@/api/common'
- import Snackbar from '@/plugins/snackbar'
- import { useI18n } from '@/hooks/web/useI18n'; const { t } = useI18n()
- import { isValidIdCard18 } from '@/utils/validate'
- import { getSchoolList, getDepartmentListBySchoolId, getMajorList } from '@/api/recruit/personal/student'
- const props = defineProps({
- option: {
- type: Object,
- default: () => {}
- }
- })
- const setInfo = ref(props.option?.setInfo ? props.option.setInfo : {})
- const formPageRef = ref()
- let query = reactive({})
- // 图片裁剪
- const selectPic = ref('')
- const isShowCopper = ref(false)
- const male = ref('1')
- const showIcon = ref(false)
- // 专业名称下拉列表
- let majorName = null
- const getMajorData = async (name) => {
- const item = items.value.options.find(e => e.key === 'majorId')
- if (!item) return
- if (item.items?.length && (majorName === name)) return // 防抖
- majorName = name
- if (name) {
- const data = await getMajorList({ name })
- item.items = data
- }
- }
- const items = ref({
- options: [
- {
- slotName: 'avatar',
- key: 'avatar',
- value: '',
- flexStyle: 'align-center mb-3'
- },
- {
- type: 'text',
- key: 'name',
- value: '',
- default: null,
- label: '姓名 *',
- outlined: true,
- rules: [
- value => {
- if (value) return true
- return '请输入您的中文名'
- },
- value => {
- var regex = /^[\u4e00-\u9fa5]+$/
- if (regex.test(value)) return true
- return '请输入正确的中文名'
- }
- ]
- },
- {
- type: 'autocomplete',
- key: 'sex',
- value: '1', // '1' ? '男' : '女'
- default: '1',
- label: '性别 *',
- outlined: true,
- dictTypeName: 'menduner_sex',
- rules: [v => !!v || '请选择性别'],
- items: [],
- change: val => male.value = val
- },
- {
- type: 'phoneNumber',
- key: 'phone',
- value: '',
- clearable: true,
- label: '联系手机号 *',
- rules: [v => !!v || '请填写联系手机号']
- },
- {
- type: 'datePicker',
- mode: 'date',
- labelWidth: 80,
- key: 'birthday',
- value: new Date(1990, 0, 1).getTime(), // 月份是从 0 开始的
- label: '出生日期 *',
- disabledFutureDates: true,
- format: 'YYYY/MM/DD',
- flexStyle: 'mb-7',
- outlined: true,
- rules: [v => !!v || '请选择出生日期']
- },
- {
- type: 'autocomplete',
- key: 'schoolId',
- value: null,
- default: null,
- label: '就读学校 *',
- outlined: true,
- itemText: 'name',
- itemValue: 'schoolId',
- rules: [v => !!v || '请选择就读学校'],
- items: [],
- change: e => getDepartmentList(e, 'schoolDeptId', 0),
- },
- {
- type: 'autocomplete',
- key: 'schoolDeptId',
- value: null,
- default: null,
- label: '所在院系 *',
- outlined: true,
- itemText: 'name',
- itemValue: 'id',
- rules: [v => !!v || '请选择所在院系'],
- change: e => getDepartmentList(e, 'schoolClassId', 2),
- items: []
- },
- {
- type: 'combobox',
- key: 'schoolClassId',
- value: null,
- label: '所在班级 *',
- outlined: true,
- clearable: true,
- canBeInputted: true,
- itemTextName: 'schoolClassName',
- itemText: 'name',
- itemValue: 'id',
- rules: [v => !!v || '请选择所在班级'],
- items: []
- },
- {
- type: 'autocomplete',
- key: 'majorId',
- value: null,
- label: '所学专业 *',
- outlined: true,
- itemText: 'nameCn',
- itemValue: 'id',
- rules: [v => !!v || '请选择所学专业'],
- search: e => getMajorData(e),
- items: []
- },
- {
- type: 'text',
- key: 'studentNo',
- value: '',
- default: null,
- label: '学号 *',
- outlined: true,
- rules: [v => !!v || '请填写学号']
- },
- {
- type: 'text',
- key: 'emergencyContactName',
- value: '',
- default: null,
- label: '紧急联系人姓名',
- outlined: true
- },
- {
- type: 'phoneNumber',
- key: 'emergencyContactPhone',
- value: '',
- clearable: true,
- label: '紧急联系人手机号'
- },
- ]
- })
- // 学校下拉列表
- const getSchoolListData = async () => {
- const item = items.value.options.find(e => e.key === 'schoolId')
- if (!item) return
- const data = await getSchoolList()
- item.items = data || []
- }
- getSchoolListData()
- // 根据学校id获取院系、班级列表
- const getDepartmentList = async (id, key, type) => {
- const item = items.value.options.find(e => e.key === key)
- if (!item) return
- let params = { type } // type: 0院系|1专业|2班级
- // 查院系用schoolId,查班级用parentId
- if (key === 'schoolDeptId') params.schoolId = id
- else params.parentId = id
- const data = await getDepartmentListBySchoolId(params)
- item.items = data || []
- }
- // 选择文件
- 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 arr = file.name.split('.')
- const fileType = arr?.length ? arr[arr.length-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)
- if (item) {
- const apiType = dictTypeName === 'positionSecondData' ? 'positionSecondData' : 'dict'
- const { data } = await getDict(dictTypeName, apiType === 'dict' ? null : {}, apiType)
- item.items = data
- }
- }
- const userInfo = ref(localStorage.getItem('userInfo') ? JSON.parse(localStorage.getItem('userInfo')) : {})
- const baseInfo = ref(localStorage.getItem('baseInfo') ? JSON.parse(localStorage.getItem('baseInfo')) : {})
- items.value.options.forEach((e) => {
- if (e.dictTypeName) getDictData(e.dictTypeName, e.key) // 查字典set options
- if (userInfo.value && userInfo.value[e.key]) e.value = userInfo.value[e.key] // 人才信息回显
- if (baseInfo.value && baseInfo.value[e.key]) e.value = baseInfo.value[e.key] // 人才信息回显
- if (e.key === 'sex' && e.value === '0') e.value = e.default
- if (setInfo.value[e.key]) e.value = setInfo.value[e.key]
- })
- const getQuery = async () => {
- const { valid } = await formPageRef.value.formRef.validate()
- if (!valid) {
- Snackbar.warning('请填写完整个人信息!')
- return false
- }
- const obj = {}
- items.value.options.forEach(e => {
- if (Object.prototype.hasOwnProperty.call(e, 'data')) return obj[e.key] = e.data
- if (e.key === 'schoolClassId') {
- const classObj = e.items.find(k => k[e.itemValue] === e.value)
- if (!classObj) {
- obj[e.key] = null
- obj[e.itemTextName] = e.value
- } else obj[e.key] = e.value
- } else obj[e.key] = e.value === '' ? null : e.value
- })
- if (!obj.avatar) obj.avatar = getUserAvatar(null, obj.sex)
- query = Object.assign(query, obj)
- return query
- }
- defineExpose({
- getQuery
- })
- </script>
- <style scoped lang="scss">
- .avatarsBox {
- height: 80px;
- width: 80px;
- position: relative;
- cursor: pointer;
- // margin: 32px;
- // margin-right: 40px;
- margin: 0 40px 0 32px;
- .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>
|