|  |  | 
 |  |  |         <el-input v-model="form.name" placeholder="请输入姓名" v-trim /> | 
 |  |  |       </el-form-item> | 
 |  |  |       <el-form-item label="所属组织" prop="companyId"> | 
 |  |  |         <el-cascader v-model="form.company" :options="department" @change="handleChangeCompany" :show-all-levels="false" | 
 |  |  |           clearable filterable :props="departprops"></el-cascader> | 
 |  |  | <!--        <el-cascader v-model="form.company" :options="department" @change="handleChangeCompany" :show-all-levels="false" | 
 |  |  |           clearable filterable :props="departprops"></el-cascader>--> | 
 |  |  | <!--        <el-select v-model="form.companyId"  clearable filterable placeholder="请选择">--> | 
 |  |  | <!--          <template v-for="item in companyList">--> | 
 |  |  | <!--            <el-option  :key="item.id" :label="item.companyNamePath" :value="item.id">--> | 
 |  |  | <!--            </el-option>--> | 
 |  |  | <!--          </template>--> | 
 |  |  | <!--        </el-select>--> | 
 |  |  |         <treeselect | 
 |  |  |             v-model="form.companyId" | 
 |  |  |             placeholder="请选择" | 
 |  |  |             :options="treeData" | 
 |  |  |             :normalizer="normalizeOptions" | 
 |  |  |             :default-expand-level="1" | 
 |  |  |             noChildrenText="没有子选项" | 
 |  |  |             noOptionsText="没有可选项" | 
 |  |  |             noResultsText="没有匹配的结果" /> | 
 |  |  |         <div style="font-size: 12px;color: #F56C6C"> | 
 |  |  |           注:仅支持选择 【{{ companyType === 0 ? '相关方组织' : '内部组织' }}】 | 
 |  |  |         </div> | 
 |  |  |       </el-form-item> | 
 |  |  |       <el-form-item label="选择岗位:" prop="positionId"> | 
 |  |  |         <el-select v-model="form.positionId" clearable filterable placeholder="请选择"> | 
 |  |  |           <el-option v-for="item in positionList" :key="item.id" :label="item.name" :value="item.id"> | 
 |  |  |           </el-option> | 
 |  |  |         </el-select> | 
 |  |  |       </el-form-item> | 
 |  |  |       <el-form-item label="手机号" prop="phone"> | 
 |  |  |         <el-input v-model="form.phone" placeholder="请输入手机号" v-trim /> | 
 |  |  | 
 |  |  |       <el-form-item label="工号" prop="code"> | 
 |  |  |         <el-input v-model="form.code" placeholder="请输入员工工号" v-trim /> | 
 |  |  |       </el-form-item> | 
 |  |  |       <el-form-item label="入职日期" prop="jobDate"> | 
 |  |  |         <el-date-picker v-model="form.jobDate" value-format="yyyy-MM-dd" type="date"> | 
 |  |  |         </el-date-picker> | 
 |  |  |       </el-form-item> | 
 |  |  | <!--      <el-form-item label="是否党员" prop="isDangyuan"> | 
 |  |  |         <el-radio-group v-model="form.isDangyuan"> | 
 |  |  |           <el-radio :label="0">非党员</el-radio> | 
 |  |  |           <el-radio :label="1">党员</el-radio> | 
 |  |  |         </el-radio-group> | 
 |  |  |       </el-form-item>--> | 
 |  |  |       <el-form-item label="人脸照片" prop="faceImgFull"> | 
 |  |  |         <div class="upload_wrap"> | 
 |  |  |           <UploadFaceImg :file="{ 'imgurlfull': form.faceImgFull, 'imgurl': form.faceImg }" :uploadData="uploadData" | 
 |  |  | 
 |  |  |           </div> | 
 |  |  |         </div> | 
 |  |  |       </el-form-item> | 
 |  |  |       <el-form-item> | 
 |  |  |         <div><el-button type="primary" @click="openCamera">采集</el-button></div> | 
 |  |  |       </el-form-item> | 
 |  |  |     </el-form> | 
 |  |  |     <!--  --> | 
 |  |  |     <el-dialog title="拍摄" :visible.sync="paisheModal" width="760px" :close-on-click-modal="false" | 
 |  |  |       :close-on-press-escape="false" append-to-body @close="closeCamera"> | 
 |  |  |       <video v-show="isShowCamera" id="videoCamera" :width="videoWidth" :height="videoHeight" /> | 
 |  |  |       <canvas v-show="!isShowCamera" id="canvasCamera" style="display: none" :width="videoWidth" | 
 |  |  |         :height="videoHeight" /> | 
 |  |  |       <span slot="footer"> | 
 |  |  |         <div> | 
 |  |  |           <el-button @click="closeCamera">取消</el-button> | 
 |  |  |           <el-button v-show="blobFileCamera" type="primary" @click="resetCamera">重拍</el-button> | 
 |  |  |           <el-button v-show="blobFileCamera" :loading="cameraLoading" type="primary" | 
 |  |  |             @click="enterCamera">开始裁剪</el-button> | 
 |  |  |           <el-button v-show="!blobFileCamera" type="primary" @click="setImage">拍摄</el-button> | 
 |  |  |         </div> | 
 |  |  |       </span> | 
 |  |  |     </el-dialog> | 
 |  |  |     <!--  --> | 
 |  |  |     <el-dialog append-to-body :close-on-click-modal="false" title="上传图片" :visible.sync="isShowCropper" width="1000px" | 
 |  |  |       class="icon-dialog-wrapper dialong-com-style"> | 
 |  |  |       <ImageCropper ref="iconShot" v-if="isShowCropper" :imgSrc="blobFileCamera"> | 
 |  |  |       </ImageCropper> | 
 |  |  |       <span slot="footer" class="dialog-footer"> | 
 |  |  |         <el-button v-if="loading">取 消</el-button> | 
 |  |  |         <el-button v-else @click="isShowCropper = false">取 消</el-button> | 
 |  |  |         <el-button :loading="loading" type="primary" @click="uploadIcon">确 定</el-button> | 
 |  |  |       </span> | 
 |  |  |     </el-dialog> | 
 |  |  |   </GlobalWindow> | 
 |  |  | </template> | 
 |  |  |  | 
 |  |  | 
 |  |  | import GlobalWindow from '@/components/common/GlobalWindow' | 
 |  |  | import UploadAvatarImage from '@/components/common/UploadAvatarImage' | 
 |  |  | import UploadFaceImg from '@/components/common/UploadFaceImg' | 
 |  |  | import ImageCropper from '@/components/common/ImageCropper' | 
 |  |  | import { checkMobile, validIdCardNo, validIdCardNoNew } from '@/utils/form' | 
 |  |  | import { allList } from '@/api/business/position' | 
 |  |  | import { upload } from '@/api/system/common' | 
 |  |  | import {companyGetList} from "@/api/business/company"; | 
 |  |  | export default { | 
 |  |  |   name: 'OperaCompanyWindow', | 
 |  |  |   extends: BaseOpera, | 
 |  |  |   components: { GlobalWindow, UploadAvatarImage, UploadFaceImg }, | 
 |  |  |   components: { GlobalWindow, UploadAvatarImage, UploadFaceImg, ImageCropper }, | 
 |  |  |   data() { | 
 |  |  |     return { | 
 |  |  |       isShowCamera: false, | 
 |  |  |       paisheModal: false, | 
 |  |  |       cameraLoading: false, | 
 |  |  |       videoWidth: 700, | 
 |  |  |       videoHeight: 525, | 
 |  |  |       mediaStreamCamera: '', | 
 |  |  |       blobFileCamera: '', | 
 |  |  |       isShowCropper: false, | 
 |  |  |       loading: false, | 
 |  |  |       // 以上是拍摄 | 
 |  |  |       uploadData: { | 
 |  |  |         folder: 'member' | 
 |  |  |       }, | 
 |  |  | 
 |  |  |       }, | 
 |  |  |       companyType: 0, | 
 |  |  |       department: [], | 
 |  |  |       positionList: [], | 
 |  |  |       companyList: [], | 
 |  |  |       // 表单数据 | 
 |  |  |       form: { | 
 |  |  |         id: null, | 
 |  |  | 
 |  |  |         idcardType: 0, | 
 |  |  |         phone: '', | 
 |  |  |         faceImg: '', | 
 |  |  |         jobDate: null, | 
 |  |  |         isDangyuan: 0, | 
 |  |  |         positionId: null, | 
 |  |  |         faceImgFull: '' | 
 |  |  |       }, | 
 |  |  |       treeData: [], | 
 |  |  |       // 验证规则 | 
 |  |  |       rules: { | 
 |  |  |         name: [{ required: true, message: '请输入员工姓名', trigger: 'blur' }], | 
 |  |  | 
 |  |  |     }) | 
 |  |  |   }, | 
 |  |  |   methods: { | 
 |  |  |     // 规范化选项数据的方法 | 
 |  |  |     normalizeOptions(node) { | 
 |  |  |       // node: 原始的选项数据 | 
 |  |  |       // 在这里根据需要进行选项数据的规范化操作,并返回规范化后的选项数据 | 
 |  |  |       // 例如,可以将原始的选项数据转换为符合插件要求的结构 | 
 |  |  |       if (node.childList && !node.childList.length) { | 
 |  |  |         // 去掉children=[]的children属性 | 
 |  |  |         delete node.childList; | 
 |  |  |       } | 
 |  |  |       return { | 
 |  |  |         id: node.id, | 
 |  |  |         label: node.name, | 
 |  |  |         children: node.childList, | 
 |  |  |       }; | 
 |  |  |     }, | 
 |  |  |     getCompany() { | 
 |  |  |       companyGetList({ | 
 |  |  |         model: {type:this.companyType } , | 
 |  |  |         capacity: 10000, | 
 |  |  |         page: 1, | 
 |  |  |       }).then(res => { | 
 |  |  |         this.companyList = res.records || [] | 
 |  |  |  | 
 |  |  |       }) | 
 |  |  |     }, | 
 |  |  |     openCamera() { | 
 |  |  |       this.paisheModal = true | 
 |  |  |       this.isShowCamera = true | 
 |  |  |       this.blobFileCamera = '' | 
 |  |  |       const that = this | 
 |  |  |       this.$nextTick(() => { | 
 |  |  |         var mediaOpts = { audio: false, video: true } | 
 |  |  |         navigator.mediaDevices | 
 |  |  |           .getUserMedia(mediaOpts) | 
 |  |  |           .then(function (stream) { | 
 |  |  |             that.mediaStreamCamera = stream | 
 |  |  |             const video = document.querySelector('#videoCamera') | 
 |  |  |             if ('srcObject' in video) { | 
 |  |  |               video.srcObject = stream | 
 |  |  |             } else { | 
 |  |  |               video.src = | 
 |  |  |                 (window.URL && window.URL.createObjectURL(stream)) || stream | 
 |  |  |             } | 
 |  |  |             video.play() | 
 |  |  |           }) | 
 |  |  |           .catch(function (err) { | 
 |  |  |             console.log(err) | 
 |  |  |           }) | 
 |  |  |       }) | 
 |  |  |     }, | 
 |  |  |     // 重拍 | 
 |  |  |     resetCamera() { | 
 |  |  |       this.isShowCamera = true | 
 |  |  |       this.blobFileCamera = '' | 
 |  |  |       this.openCamera() | 
 |  |  |     }, | 
 |  |  |     // 关闭相机 | 
 |  |  |     closeCamera() { | 
 |  |  |       this.mediaStreamCamera.getVideoTracks().forEach(function (track) { | 
 |  |  |         track.stop() | 
 |  |  |       }) | 
 |  |  |       this.paisheModal = false | 
 |  |  |     }, | 
 |  |  |     // 点击拍摄 | 
 |  |  |     setImage() { | 
 |  |  |       const that = this | 
 |  |  |       this.blobFileCamera = '' | 
 |  |  |       that.isShowCamera = false | 
 |  |  |       const video = document.querySelector('#videoCamera') | 
 |  |  |       const canvas = document.querySelector('#canvasCamera') | 
 |  |  |       canvas | 
 |  |  |         .getContext('2d') | 
 |  |  |         .drawImage(video, 0, 0, that.videoWidth, that.videoHeight) | 
 |  |  |       this.mediaStreamCamera.getVideoTracks().forEach(function (track) { | 
 |  |  |         track.stop() | 
 |  |  |       }) | 
 |  |  |       const dataurl = canvas.toDataURL('image/jpg') | 
 |  |  |       // this.blobFileCamera = that.base64ToFile(dataurl, 'camera') | 
 |  |  |       this.blobFileCamera = dataurl | 
 |  |  |     }, | 
 |  |  |     // 确认拍摄 | 
 |  |  |     enterCamera() { | 
 |  |  |       this.isShowCropper = true | 
 |  |  |       this.paisheModal = false | 
 |  |  |       this.isShowCamera = true | 
 |  |  |     }, | 
 |  |  |     uploadIcon () { | 
 |  |  |       // 获取裁剪后的图片 | 
 |  |  |       this.$refs.iconShot.getImagecropper().getCropBlob((fileData) => { // 获取当前裁剪好的数据 | 
 |  |  |         // 注此时的data是一个Blob数据,部分接口接收的是File转化的FormData数据 | 
 |  |  |         console.log(fileData) | 
 |  |  |         const formData = new FormData() | 
 |  |  |  | 
 |  |  |         formData.append('folder', 'member') | 
 |  |  |         formData.append( | 
 |  |  |             'file', | 
 |  |  |             fileData | 
 |  |  |         ) | 
 |  |  |         this.loading = true | 
 |  |  |         upload(formData).then(res => { | 
 |  |  |           this.loading = false | 
 |  |  |           console.log(res) | 
 |  |  |           // this.file.imgurl = res.imgaddr | 
 |  |  |           // this.file.imgurlfull = res.url | 
 |  |  |           this.$message.success('上传成功') | 
 |  |  |           // this.imageSrc = res.url | 
 |  |  |           // this.updateImg = false | 
 |  |  |           this.form.faceImg = res.imgaddr | 
 |  |  |           this.form.faceImgFull = res.url | 
 |  |  |           this.isShowCropper = false | 
 |  |  |           // this.$emit('uploadSuccess', { imgurl: res.imgaddr, imgurlfull: res.url, name: res.originname }) | 
 |  |  |           // this.$emit('uploadEnd') | 
 |  |  |         }, () => { | 
 |  |  |           this.loading = false | 
 |  |  |         }) | 
 |  |  |       }) | 
 |  |  |     }, | 
 |  |  |     base64ToFile(base64, fileName) { | 
 |  |  |       // 将base64按照 , 进行分割 将前缀  与后续内容分隔开 | 
 |  |  |       const data = base64.split(',') | 
 |  |  |       // 利用正则表达式 从前缀中获取图片的类型信息(image/png、image/jpeg、image/webp等) | 
 |  |  |       const type = data[0].match(/:(.*?);/)[1] | 
 |  |  |       // 从图片的类型信息中 获取具体的文件格式后缀(png、jpeg、webp) | 
 |  |  |       const suffix = type.split('/')[1] | 
 |  |  |       // 使用atob()对base64数据进行解码  结果是一个文件数据流 以字符串的格式输出 | 
 |  |  |       const bstr = window.atob(data[1]) | 
 |  |  |       // 获取解码结果字符串的长度 | 
 |  |  |       let n = bstr.length | 
 |  |  |       // 根据解码结果字符串的长度创建一个等长的整形数字数组 | 
 |  |  |       // 但在创建时 所有元素初始值都为 0 | 
 |  |  |       const u8arr = new Uint8Array(n) | 
 |  |  |       // 将整形数组的每个元素填充为解码结果字符串对应位置字符的UTF-16 编码单元 | 
 |  |  |       while (n--) { | 
 |  |  |         // charCodeAt():获取给定索引处字符对应的 UTF-16 代码单元 | 
 |  |  |         u8arr[n] = bstr.charCodeAt(n) | 
 |  |  |       } | 
 |  |  |       // 利用构造函数创建File文件对象 | 
 |  |  |       // new File(bits, name, options) | 
 |  |  |       const file = new File([u8arr], `${fileName}.${suffix}`, { | 
 |  |  |         type: type | 
 |  |  |       }) | 
 |  |  |       // 将File文件对象返回给方法的调用者 | 
 |  |  |       return file | 
 |  |  |     }, | 
 |  |  |     handleChangeCompany(value) { | 
 |  |  |       if (this.form.company && this.form.company.length > 1) { | 
 |  |  |         this.form.companyId = this.form.company[this.form.company.length - 1] | 
 |  |  | 
 |  |  |       this.title = title | 
 |  |  |       this.department = depart | 
 |  |  |       this.visible = true | 
 |  |  |       this.form = { | 
 |  |  |         id: null, | 
 |  |  |         name: '', | 
 |  |  |         type: '', | 
 |  |  |         company: [], | 
 |  |  |         code: '', | 
 |  |  |         idcardNo: '', | 
 |  |  |         idcardNoNew: '', | 
 |  |  |         linkName: '', | 
 |  |  |         idcardDecode: '', | 
 |  |  |         companyId: null, | 
 |  |  |         idcardType: 0, | 
 |  |  |         phone: '', | 
 |  |  |         faceImg: '', | 
 |  |  |         jobDate: null, | 
 |  |  |         isDangyuan: 0, | 
 |  |  |         positionId: null, | 
 |  |  |         faceImgFull: '' | 
 |  |  |       } | 
 |  |  |       this.companyType = companyType | 
 |  |  |       this.getCompany() | 
 |  |  |       this.getPositionList() | 
 |  |  |       // 新建 | 
 |  |  |       if (target == null) { | 
 |  |  |         this.$nextTick(() => { | 
 |  |  | 
 |  |  |           this.form[this.configData['field.id']] = null | 
 |  |  |           this.form.company = [] | 
 |  |  |         }) | 
 |  |  |  | 
 |  |  |         this.getCompany() | 
 |  |  |         return | 
 |  |  |       } | 
 |  |  |       // 编辑 | 
 |  |  | 
 |  |  |         } | 
 |  |  |       }) | 
 |  |  |     }, | 
 |  |  |     getPositionList() { | 
 |  |  |       allList({}) | 
 |  |  |         .then(res => { | 
 |  |  |           this.positionList = res | 
 |  |  |         }) | 
 |  |  |     }, | 
 |  |  |     // 上传图片 | 
 |  |  |     uploadAvatarSuccess(file) { | 
 |  |  |       this.form.faceImg = file.imgurl | 
 |  |  | 
 |  |  | } | 
 |  |  | </script> | 
 |  |  | <style lang="scss" scoped> | 
 |  |  | .upload_wrap{ | 
 |  |  | .upload_wrap { | 
 |  |  |   display: flex; | 
 |  |  |   align-items: center; | 
 |  |  |   .avatar-uploader{ | 
 |  |  |  | 
 |  |  |   .avatar-uploader { | 
 |  |  |     display: flex; | 
 |  |  |     align-items: center; | 
 |  |  |     justify-content: center; | 
 |  |  |   } | 
 |  |  |   ::v-deep .avatar{ | 
 |  |  |  | 
 |  |  |   ::v-deep .avatar { | 
 |  |  |     max-width: 90px; | 
 |  |  |     max-height: 90px; | 
 |  |  |   } | 
 |  |  |   .content{ | 
 |  |  |  | 
 |  |  |   .content { | 
 |  |  |     display: flex; | 
 |  |  |     flex-direction: column; | 
 |  |  |     justify-content: center; | 
 |  |  | 
 |  |  |     line-height: 24px; | 
 |  |  |   } | 
 |  |  | } | 
 |  |  | </style> | 
 |  |  | </style> |