Commit 123e5ac13ef36e2f1c0ec1274e6018eba2cfdd34
1 parent
220d4368
手机端新增人脸登陆;
Showing
2 changed files
with
103 additions
and
8 deletions
src/mobile/login/LoginMobile.js
| @@ -13,7 +13,8 @@ import * as commonServices from '../../services/services'; | @@ -13,7 +13,8 @@ import * as commonServices from '../../services/services'; | ||
| 13 | import * as commonFunc from '../../components/Common/commonFunc'; | 13 | import * as commonFunc from '../../components/Common/commonFunc'; |
| 14 | import AppUtil from '../../utils/AppUtil'; | 14 | import AppUtil from '../../utils/AppUtil'; |
| 15 | import * as commonUtils from '../../utils/utils'; | 15 | import * as commonUtils from '../../utils/utils'; |
| 16 | - | 16 | +// import VConsole from 'vconsole'; |
| 17 | +// let vConsole; | ||
| 17 | 18 | ||
| 18 | // eslint-disable-next-line prefer-destructuring | 19 | // eslint-disable-next-line prefer-destructuring |
| 19 | const alert = Modal.alert; | 20 | const alert = Modal.alert; |
| @@ -124,8 +125,13 @@ class LoginMobile extends React.Component { | @@ -124,8 +125,13 @@ class LoginMobile extends React.Component { | ||
| 124 | ); | 125 | ); |
| 125 | } | 126 | } |
| 126 | } | 127 | } |
| 128 | + // vConsole = new VConsole(); | ||
| 127 | } | 129 | } |
| 128 | 130 | ||
| 131 | + // componentWillUnmount() { | ||
| 132 | + // vConsole.destroy(); | ||
| 133 | + // } | ||
| 134 | + | ||
| 129 | onChange = (name, newValue) => { | 135 | onChange = (name, newValue) => { |
| 130 | if (name === 'username') { | 136 | if (name === 'username') { |
| 131 | this.setState({ username: newValue }); | 137 | this.setState({ username: newValue }); |
| @@ -138,7 +144,82 @@ class LoginMobile extends React.Component { | @@ -138,7 +144,82 @@ class LoginMobile extends React.Component { | ||
| 138 | loginCompany: value, | 144 | loginCompany: value, |
| 139 | }); | 145 | }); |
| 140 | } | 146 | } |
| 141 | - handleLogin = async () => { | 147 | + |
| 148 | + takeTenPhotos = () => { | ||
| 149 | + if (!window.plus) { | ||
| 150 | + return Promise.reject(new Error('请在 HBuilder 打包的 App 中运行')); | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + return new Promise((resolve, reject) => { | ||
| 154 | + // 调用系统相机拍照(尽量指定前置) | ||
| 155 | + plus.camera.getCamera(1).captureImage( | ||
| 156 | + (imagePath) => { | ||
| 157 | + // 直接用 FileReader 读取逻辑路径(如 _doc/...),无需 resolve | ||
| 158 | + const reader = new plus.io.FileReader(); | ||
| 159 | + reader.onload = (e) => { | ||
| 160 | + const img = new Image(); | ||
| 161 | + img.onload = () => { | ||
| 162 | + const canvas = document.createElement('canvas'); | ||
| 163 | + canvas.width = 268; | ||
| 164 | + canvas.height = 214; | ||
| 165 | + const ctx = canvas.getContext('2d'); | ||
| 166 | + ctx.drawImage(img, 0, 0, 268, 214); | ||
| 167 | + // 转为 JPEG,质量 0.85,去掉前缀 | ||
| 168 | + const base64 = canvas.toDataURL('image/jpeg', 0.85).split(',')[1]; | ||
| 169 | + resolve(base64); | ||
| 170 | + }; | ||
| 171 | + img.onerror = () => reject(new Error('图片解析失败')); | ||
| 172 | + | ||
| 173 | + img.src = e.target.result; // Data URL 安全加载 | ||
| 174 | + }; | ||
| 175 | + reader.onerror = (e) => reject(new Error('读取照片失败: ' + e.target.error.message)); | ||
| 176 | + | ||
| 177 | + plus.io.resolveLocalFileSystemURL(imagePath, (entry) => { | ||
| 178 | + entry.file((file) => { | ||
| 179 | + reader.readAsDataURL(file.fullPath); // 关键:直接读逻辑路径 | ||
| 180 | + | ||
| 181 | + }) | ||
| 182 | + }); | ||
| 183 | + }, | ||
| 184 | + (error) => { | ||
| 185 | + reject(new Error('拍照失败: ' + error.message)); | ||
| 186 | + }, | ||
| 187 | + { | ||
| 188 | + filename: `_doc/camera/face_${Date.now()}.jpg`, | ||
| 189 | + format: 'jpg' | ||
| 190 | + } | ||
| 191 | + ); | ||
| 192 | + }); | ||
| 193 | + }; | ||
| 194 | + | ||
| 195 | + handleFaceLogin = () => { | ||
| 196 | + this.takeTenPhotos() | ||
| 197 | + .then(base64List => { | ||
| 198 | + // 这里可以上传到你的 face/detectFaces 接口 | ||
| 199 | + const url = `${commonConfig.face_host}/face/faceSearch`; | ||
| 200 | + commonServices.postValueService(null, [{ | ||
| 201 | + image: base64List, | ||
| 202 | + image_type: "BASE64", | ||
| 203 | + face_field: "age", | ||
| 204 | + option: "COMMON" | ||
| 205 | + }], url).then(({ data: dataReturn }) => { | ||
| 206 | + // console.log('=====dataReturn', dataReturn); | ||
| 207 | + if (dataReturn.code === 1) { | ||
| 208 | + const value = {}; | ||
| 209 | + value.sEmployeeNo = dataReturn.dataset.rows[0].sEmployeeNo; | ||
| 210 | + value.sParentId = dataReturn.dataset.rows[0].sBrandsId; | ||
| 211 | + value.sId = dataReturn.dataset.rows[0].sSubsidiaryId; | ||
| 212 | + this.handleLogin(value); | ||
| 213 | + } else { | ||
| 214 | + Toast.fail(dataReturn.msg); | ||
| 215 | + } | ||
| 216 | + }) | ||
| 217 | + }) | ||
| 218 | + .catch(err => { | ||
| 219 | + console.error('拍摄过程出错:', err); | ||
| 220 | + }); | ||
| 221 | + } | ||
| 222 | + handleLogin = async (valueBase) => { | ||
| 142 | const { dispatch, app } = this.props; | 223 | const { dispatch, app } = this.props; |
| 143 | const { loginCompany, companys } = this.state; | 224 | const { loginCompany, companys } = this.state; |
| 144 | let sParentId = ''; | 225 | let sParentId = ''; |
| @@ -150,12 +231,16 @@ class LoginMobile extends React.Component { | @@ -150,12 +231,16 @@ class LoginMobile extends React.Component { | ||
| 150 | return; | 231 | return; |
| 151 | } | 232 | } |
| 152 | this.props.form.validateFields(async () => { | 233 | this.props.form.validateFields(async () => { |
| 153 | - const value = {}; | ||
| 154 | - value.username = this.state.username; | ||
| 155 | - value.password = this.state.userpwd; | ||
| 156 | - value.sParentId = this.state.sParentId; | ||
| 157 | - // value.company = this.state.loginCompany; | ||
| 158 | - value.sId = this.state.sId; | 234 | + let value = {}; |
| 235 | + if (valueBase) { | ||
| 236 | + value = valueBase; | ||
| 237 | + } else { | ||
| 238 | + value.username = this.state.username; | ||
| 239 | + value.password = this.state.userpwd; | ||
| 240 | + value.sParentId = this.state.sParentId; | ||
| 241 | + // value.company = this.state.loginCompany; | ||
| 242 | + value.sId = this.state.sId; | ||
| 243 | + } | ||
| 159 | const url = `${commonConfig.server_host}userlogin/${sParentId}/${loginCompany}?sLoginType=phoneLogin`; | 244 | const url = `${commonConfig.server_host}userlogin/${sParentId}/${loginCompany}?sLoginType=phoneLogin`; |
| 160 | const dataReturn = (await commonServices.postValueService(null, value, url)).data; | 245 | const dataReturn = (await commonServices.postValueService(null, value, url)).data; |
| 161 | if (dataReturn.code === 1) { | 246 | if (dataReturn.code === 1) { |
| @@ -200,6 +285,7 @@ class LoginMobile extends React.Component { | @@ -200,6 +285,7 @@ class LoginMobile extends React.Component { | ||
| 200 | let sLanguage = commonUtils.isNotEmptyArr(companys) ? companys[0].sLanguage : 'sChinese'; | 285 | let sLanguage = commonUtils.isNotEmptyArr(companys) ? companys[0].sLanguage : 'sChinese'; |
| 201 | const settingTitle = sLanguage === 'sEnglish' ? 'server settings' :'服务器设置'; | 286 | const settingTitle = sLanguage === 'sEnglish' ? 'server settings' :'服务器设置'; |
| 202 | const loginTitle = sLanguage === 'sEnglish' ? 'Login' :'登录'; | 287 | const loginTitle = sLanguage === 'sEnglish' ? 'Login' :'登录'; |
| 288 | + const loginFaceTitle = sLanguage === 'sEnglish' ? 'Face Login' :'人脸登录'; | ||
| 203 | const pleaseInputUser = sLanguage === 'sEnglish' ? 'please Input User' :'请输入用户'; | 289 | const pleaseInputUser = sLanguage === 'sEnglish' ? 'please Input User' :'请输入用户'; |
| 204 | const pleaseInputPassword = sLanguage === 'sEnglish' ? 'please Input Password' :'请输入密码'; | 290 | const pleaseInputPassword = sLanguage === 'sEnglish' ? 'please Input Password' :'请输入密码'; |
| 205 | 291 | ||
| @@ -263,6 +349,9 @@ class LoginMobile extends React.Component { | @@ -263,6 +349,9 @@ class LoginMobile extends React.Component { | ||
| 263 | <Button type="primary" onClick={this.handleLogin.bind(this)} style={{ backgroundColor: "#5e81e5" }}> | 349 | <Button type="primary" onClick={this.handleLogin.bind(this)} style={{ backgroundColor: "#5e81e5" }}> |
| 264 | {loginTitle} | 350 | {loginTitle} |
| 265 | </Button> | 351 | </Button> |
| 352 | + <Button type="primary" onClick={this.handleFaceLogin.bind(this)} style={{ backgroundColor: "#5e81e5" }}> | ||
| 353 | + {loginFaceTitle} | ||
| 354 | + </Button> | ||
| 266 | </div> | 355 | </div> |
| 267 | {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} | 356 | {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} |
| 268 | <a | 357 | <a |
src/mobile/login/LoginMobile.less