diff --git a/src/assets/images/faceH5/img4.png b/src/assets/images/faceH5/img4.png new file mode 100644 index 0000000..11a521f Binary files /dev/null and b/src/assets/images/faceH5/img4.png differ diff --git a/src/main.js b/src/main.js index d62eca7..e98b236 100644 --- a/src/main.js +++ b/src/main.js @@ -34,9 +34,7 @@ import 'viewerjs/dist/viewer.css' import Print from 'vue-print-nb' // import Vconsole from 'vconsole' - // const vConsole = new Vconsole() - // export default vConsole // 加载用户主题 diff --git a/src/router/index.js b/src/router/index.js index 7a9efbb..22b5d26 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -9,7 +9,7 @@ import { filterAsyncRouter } from '@/store/modules/permission' NProgress.configure({ showSpinner: false })// NProgress Configuration -const whiteList = ['/login', '/faceRegisterH5', '/faceError', '/faceSuccess', '/faceRegistered', '/faceSelfRegister']// no redirect whitelist +const whiteList = ['/login', '/faceRegisterH5', '/faceError', '/faceSuccess', '/faceRegistered', '/faceSelfRegister', '/faceFail']// no redirect whitelist router.beforeEach((to, from, next) => { if (to.meta.title) { diff --git a/src/router/routers.js b/src/router/routers.js index 493be39..b032d72 100644 --- a/src/router/routers.js +++ b/src/router/routers.js @@ -122,6 +122,11 @@ export const constantRouterMap = [ meta: { title: '人脸信息自助采集', noCache: true }, component: (resolve) => require(['@/views/faceRegisterH5/selfRegister'], resolve), hidden: true + }, + { path: '/faceFail', + meta: { title: '人脸信息自助采集', noCache: true }, + component: (resolve) => require(['@/views/faceRegisterH5/fail'], resolve), + hidden: true } ] diff --git a/src/utils/upload.js b/src/utils/upload.js index ffdb1e0..e5ecea6 100644 --- a/src/utils/upload.js +++ b/src/utils/upload.js @@ -155,3 +155,23 @@ export function uploadPerson(api, file, params) { } return axios.post(api, data, config) } + +export function uploadFaceImgBase64(api, base64String) { + // 注意:如果base64字符串包含前缀(如data:image/jpeg;base64,), + // 可能需要根据后端要求决定是否去除 + // const pureBase64 = base64String.replace(/^data:image\/\w+;base64,/, '') + + return axios({ + url: api + '/api/fileRelevant/uploadFaceImgBase64', + method: 'post', + data: { + base64String: base64String // 这里的键名要和后端接口要求的参数名一致 + }, + headers: { + 'Authorization': getToken(), + 'Content-Type': 'application/json' // 以JSON格式发送 + // 如果后端要求form-data格式,可以使用multipart/form-data + // 'Content-Type': 'multipart/form-data' + } + }) +} diff --git a/src/views/faceRecognition/faceRecLog.vue b/src/views/faceRecognition/faceRecLog.vue index c0f42c3..d8f6c65 100644 --- a/src/views/faceRecognition/faceRecLog.vue +++ b/src/views/faceRecognition/faceRecLog.vue @@ -8,6 +8,10 @@ + + + + - - - - diff --git a/src/views/faceRecognition/personInfoManage.vue b/src/views/faceRecognition/personInfoManage.vue index 8f4b60a..89259e2 100644 --- a/src/views/faceRecognition/personInfoManage.vue +++ b/src/views/faceRecognition/personInfoManage.vue @@ -80,26 +80,7 @@ 选择上传照片 - - 摄像头拍摄 - - - -
-
@@ -173,15 +162,16 @@ import pagination from '@crud/Pagination' import FaceSearch from './module/faceSearch' import SelfRegister from './module/selfRegister' import BatchImport from './module/batchImport' +import Camera from './module/camera' // import { exportFile } from '@/utils/index' // import qs from 'qs' import { mapGetters } from 'vuex' -import { upload } from '@/utils/upload' +import { upload, uploadFaceImgBase64 } from '@/utils/upload' const defaultForm = { personId: null, libcode: null, barcode: null, personName: null, personPhotoUrl: null, idCard: null, phone: null, personSex: 1, personType: 0, personPhotoBase64: null } export default { name: 'PersonInfoManage', - components: { pagination, crudOperation, rrOperation, FaceSearch, SelfRegister, BatchImport }, + components: { pagination, crudOperation, rrOperation, FaceSearch, SelfRegister, BatchImport, Camera }, cruds() { return CRUD({ title: '人员信息', idField: 'personId', url: 'api/person/initPersonInfo', crudMethod: { ...crudFace }, optShow: { add: true, @@ -225,12 +215,7 @@ export default { imageUrl: null, selfRegisterVisible: false, faceSearchVisible: false, - - // 摄像头相关状态 - showCamera: false, - stream: null, - videoElement: null, - canvasElement: null + cameraVisible: false } }, computed: { @@ -239,25 +224,30 @@ export default { 'user' ]) }, - watch: { - // 监听摄像头显示状态变化 - showCamera(val) { - if (val) { - this.openCamera() - } else { - this.stopStream() - } - } - }, - beforeDestroy() { - // 组件销毁时确保停止流 - this.stopStream() - }, created() { }, mounted() { }, methods: { + showCamera() { + this.cameraVisible = true + this.$nextTick(() => { + this.$refs.cameraRefs.checkBrowserSupport() + this.$refs.cameraRefs.enumerateDevices() + }) + }, + handleCamera() { + if (this.$refs.cameraRefs && this.$refs.cameraRefs.imgValue) { + uploadFaceImgBase64(this.baseApi, this.$refs.cameraRefs.imgValue).then(res => { + console.log(res) + if (res.data.code === 200) { + this.form.personPhotoUrl = res.data.data + this.imageUrl = this.$refs.cameraRefs.imgValue + this.handleClose() + } + }) + } + }, updatePerson() { this.crud.refresh() }, @@ -311,10 +301,10 @@ export default { }, // 提交前做的操作 [CRUD.HOOK.afterValidateCU](crud) { - // if (crud.form.personPhotoUrl === '' || crud.form.personPhotoUrl === null) { - // this.$message({ message: '请选择上传照片', type: 'error', offset: 8 }) - // return false - // } + if (crud.form.personPhotoUrl === '' || crud.form.personPhotoUrl === null) { + this.$message({ message: '请选择上传照片', type: 'error', offset: 8 }) + return false + } console.log(crud.form) return true }, @@ -438,67 +428,12 @@ export default { this.$refs.faceSearchRefs.searchPerson = {} this.$refs.faceSearchRefs.btnLoading = false } - }, - // 摄像头相关方法 - async openCamera() { - try { - // 获取视频元素和画布元素 - this.videoElement = document.getElementById('video') - this.canvasElement = document.getElementById('canvas') - - // 请求摄像头权限 - this.stream = await navigator.mediaDevices.getUserMedia({ - video: { width: 400, height: 300 }, - audio: false - }) - - this.videoElement.srcObject = this.stream - } catch (error) { - this.$message.error('无法访问摄像头:' + error.message) - console.error('摄像头访问错误:', error) - } - }, - - takePhoto() { - if (!this.videoElement || !this.canvasElement) return - - // 设置画布尺寸与视频一致 - this.canvasElement.width = this.videoElement.videoWidth - this.canvasElement.height = this.videoElement.videoHeight - - // 将视频帧绘制到画布 - const context = this.canvasElement.getContext('2d') - context.drawImage(this.videoElement, 0, 0) - - // 将画布内容转换为base64格式 - const imageData = this.canvasElement.toDataURL('image/jpeg') - - // 更新图片显示并保存 - this.imageUrl = imageData - this.form.photo = imageData - - // 停止视频流 - this.stopStream() - }, - - resetCamera() { - // 关闭当前流并重新打开摄像头 - this.stopStream() - this.openCamera() - }, - - closeCamera() { - // 停止流并隐藏摄像头区域 - this.stopStream() - this.showCamera = false - }, - - stopStream() { - if (this.stream) { - this.stream.getTracks().forEach(track => { - track.stop() - }) - this.stream = null + this.cameraVisible = false + if (this.$refs.cameraRefs) { + this.$refs.cameraRefs.stopStream() + this.$refs.cameraRefs.imgValue = '' + this.$refs.cameraRefs.errorMessage = '' + this.$refs.cameraRefs.showVideo = false } } } @@ -551,35 +486,4 @@ export default { border-color: #909399; color: #909399; } - -.camera-container { - margin-top: 20px; - padding: 15px; - border: 1px solid #e6e6e6; - border-radius: 4px; -} - -.camera-buttons { - margin-top: 15px; - display: flex; - gap: 10px; - justify-content: center; -} - -.right-user-img { - margin-left: 30px; - text-align: center; -} - -.right-user-img img { - width: 200px; - height: 260px; - object-fit: cover; - border: 1px solid #e6e6e6; - margin-bottom: 15px; -} - -.upload-btn input { - display: none; -} diff --git a/src/views/faceRegisterH5/fail.vue b/src/views/faceRegisterH5/fail.vue new file mode 100644 index 0000000..d180a4b --- /dev/null +++ b/src/views/faceRegisterH5/fail.vue @@ -0,0 +1,44 @@ + + + + + + diff --git a/src/views/faceRegisterH5/selfRegister.vue b/src/views/faceRegisterH5/selfRegister.vue index 93e9cff..71b4228 100644 --- a/src/views/faceRegisterH5/selfRegister.vue +++ b/src/views/faceRegisterH5/selfRegister.vue @@ -127,17 +127,18 @@ export default { console.log('params', params) FetchEditReaderFace(params).then(res => { console.log('res', res) - if (res) { + if (res.code === 200) { this.$router.push({ path: '/faceSuccess', query: { 'strLibcode': this.personInfo.libcode } }) } else { this.$router.push({ - path: '/faceError', + path: '/faceFail', query: { 'strLibcode': this.personInfo.libcode } }) } + // faceFail this.submitLoading = false }).catch(err => { console.log(err) @@ -152,10 +153,11 @@ export default { input.onchange = (e) => { const file = e.target.files[0] if (file) { - this.imageUrl = URL.createObjectURL(file) + // this.imageUrl = URL.createObjectURL(file) upload(this.baseApi + '/api/fileRelevant/uploadFaceImg', file).then(res => { console.log(res) if (res.data.code === 200) { + this.imageUrl = this.baseApi + '/api/fileRelevant/getImg?imgType=3&imgId=' + res.data.data this.form.personPhotoUrl = res.data.data } })