| <template> | 
|   <GlobalWindow :title="title" width="60%" :visible.sync="visible" :confirm-working="isWorking" @confirm="confirm"> | 
|     <el-form :model="form" ref="form" :rules="rules"> | 
|       <el-form-item label="姓名" prop="name"> | 
|         <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-select v-model="form.companyId"  clearable filterable placeholder="请选择"> | 
|           <template v-for="item in companyList"> | 
|             <el-option  v-if="item.countNum && item.countNum>0" :key="item.id" :label="item.companyNamePath" :value="item.id"> | 
|             </el-option> | 
|           </template> | 
|         </el-select> | 
|         <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 /> | 
|         <div style="color: #F56C6C;font-size: 12px">注:员工手机号将作为平台登录账号,初始密码为系统默认密码配置项</div> | 
|       </el-form-item> | 
|       <el-form-item label="身份证号" v-if="form.id == null"> | 
|         <el-input v-model="form.idcardNo" placeholder="请输入身份证号" v-trim /> | 
|       </el-form-item> | 
|       <el-form-item label="修改身份证号" v-if="form.id != null"> | 
|         <el-input v-model="form.idcardNoNew" placeholder="可修改身份证号" v-trim /> | 
|         <div style="font-size: 12px" v-if="form.id != null"> | 
|           注:当前身份证号为<span style="color: #F56C6C">【{{ form.idcardDecode }}】</span>,如需修改,请在输入栏填写新的身份证号! | 
|         </div> | 
|       </el-form-item> | 
|       <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" | 
|             @uploadSuccess="uploadAvatarSuccess" @uploadEnd="isUploading = false" @uploadBegin="isUploading = true" /> | 
|           <div class="content"> | 
|             <div>1、请选择浅色或中性背景,使用均匀光线拍照。</div> | 
|             <div>2、请保持面部正对镜头,勿遮挡面部,保持中立表情。</div> | 
|             <div>3、请避免后期修图,确保人脸轮廓清晰、完整,尽可能减少非脸部内容占比。</div> | 
|           </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> | 
|   | 
| <script> | 
| import BaseOpera from '@/components/base/BaseOpera' | 
| 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, ImageCropper }, | 
|   data() { | 
|     return { | 
|       isShowCamera: false, | 
|       paisheModal: false, | 
|       cameraLoading: false, | 
|       videoWidth: 700, | 
|       videoHeight: 525, | 
|       mediaStreamCamera: '', | 
|       blobFileCamera: '', | 
|       isShowCropper: false, | 
|       loading: false, | 
|       // 以上是拍摄 | 
|       uploadData: { | 
|         folder: 'member' | 
|       }, | 
|       departprops: { | 
|         label: 'name', | 
|         value: 'id', | 
|         checkStrictly: true | 
|       }, | 
|       companyType: 0, | 
|       department: [], | 
|       positionList: [], | 
|       companyList: [], | 
|       // 表单数据 | 
|       form: { | 
|         id: null, | 
|         name: '', | 
|         type: '', | 
|         company: [], | 
|         code: '', | 
|         idcardNo: '', | 
|         idcardNoNew: '', | 
|         linkName: '', | 
|         idcardDecode: '', | 
|         companyId: null, | 
|         idcardType: 0, | 
|         phone: '', | 
|         faceImg: '', | 
|         jobDate: null, | 
|         isDangyuan: 0, | 
|         positionId: null, | 
|         faceImgFull: '' | 
|       }, | 
|       // 验证规则 | 
|       rules: { | 
|         name: [{ required: true, message: '请输入员工姓名', trigger: 'blur' }], | 
|         phone: [{ required: true, validator: checkMobile, trigger: 'blur' }], | 
|         companyId: [{ required: true, message: '请选择所属组织' }], | 
|         idcardNo: [{ required: true, validator: validIdCardNo, message: '请输入身份证号', trigger: 'blur' }], | 
|         idcardNoNew: [{ required: false, validator: validIdCardNoNew, trigger: 'blur' }] | 
|       } | 
|     } | 
|   }, | 
|   created() { | 
|     this.config({ | 
|       api: '/business/member.js', | 
|       'field.id': 'id' | 
|     }) | 
|   }, | 
|   methods: { | 
|     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] | 
|       } | 
|     }, | 
|     /** | 
|      * 打开窗口 | 
|      * @title 窗口标题 | 
|      * @target 编辑的对象 | 
|      */ | 
|     open(title, target, depart, companyType) { | 
|       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.$refs.form.resetFields() | 
|           this.form[this.configData['field.id']] = null | 
|           this.form.company = [] | 
|         }) | 
|   | 
|         this.getCompany() | 
|         return | 
|       } | 
|       // 编辑 | 
|       var that = this | 
|       this.$nextTick(() => { | 
|         for (const key in this.form) { | 
|           this.form[key] = target[key] | 
|           this.form.idcardNo = '' | 
|         } | 
|         this.form.company = [] | 
|         if (target.companyId && target.companyPath) { | 
|           var array = target.companyPath.split('/') | 
|           array.forEach(item => { | 
|             if (item && item != null && item != '') { | 
|               that.form.company.push(parseInt(item)) | 
|             } | 
|           }) | 
|         } | 
|       }) | 
|     }, | 
|     getPositionList() { | 
|       allList({}) | 
|         .then(res => { | 
|           this.positionList = res | 
|         }) | 
|     }, | 
|     // 上传图片 | 
|     uploadAvatarSuccess(file) { | 
|       this.form.faceImg = file.imgurl | 
|       this.form.faceImgFull = file.imgurlfull | 
|     } | 
|   } | 
| } | 
| </script> | 
| <style lang="scss" scoped> | 
| .upload_wrap { | 
|   display: flex; | 
|   align-items: center; | 
|   | 
|   .avatar-uploader { | 
|     display: flex; | 
|     align-items: center; | 
|     justify-content: center; | 
|   } | 
|   | 
|   ::v-deep .avatar { | 
|     max-width: 90px; | 
|     max-height: 90px; | 
|   } | 
|   | 
|   .content { | 
|     display: flex; | 
|     flex-direction: column; | 
|     justify-content: center; | 
|     font-size: 12px; | 
|     color: #999999; | 
|     margin-left: 12px; | 
|     line-height: 24px; | 
|   } | 
| } | 
| </style> |