diff --git a/src/mobile/common/CommobileComponent.js b/src/mobile/common/CommobileComponent.js index bd60100..c8d0254 100644 --- a/src/mobile/common/CommobileComponent.js +++ b/src/mobile/common/CommobileComponent.js @@ -1,5 +1,6 @@ /* eslint-disable */ import { List, InputItem, Picker, TextareaItem, DatePicker, Checkbox, Toast } from 'antd-mobile-v2'; +import SearchablePicker from '@/mobile/components/searchPicker' import moment from 'moment'; import React, { Component } from 'react'; import { debounce } from 'lodash'; @@ -30,7 +31,8 @@ export default class CommonComponent extends Component { dropDownData: [], // eslint-disable-next-line react/no-unused-state bReGetDropDown: false, - bOpenKeyboard : props.bOpenKeyboard, + bOpenKeyboard: props.bOpenKeyboard, + pickerVisble: false }; this.firstDataIndex = props.showConfig.sName.substring(0, 1); /* 控件首字母(数据格式:字符串) */ @@ -119,7 +121,7 @@ export default class CommonComponent extends Component { dataValue, enabled, dropDownData, sFieldName, bNotEmpty, masterData, } = this.state; // console.log('bOpenKeyboard:', nextProps.bOpenKeyboard); - if(nextProps.bOpenKeyboard !==undefined) { + if (nextProps.bOpenKeyboard !== undefined) { return true; } return nextProps.showConfig !== undefined && (dataValue !== nextState.dataValue || enabled !== nextState.enabled || @@ -253,6 +255,7 @@ export default class CommonComponent extends Component { /** 处理下拉选择事件 */ handleSelectOptionEvent = (newValue) => { + console.log("🚀 ~ CommonComponent ~ newValue:", newValue) /* 下拉新增单独处理 */ let value = newValue; this.isDropdownFilter = true; @@ -277,11 +280,11 @@ export default class CommonComponent extends Component { const returnValue = {}; /* 回带值赋值(sName:value) */ returnValue[this.props.showConfig.sName] = - // eslint-disable-next-line radix - this.firstDataIndex === 'i' ? commonUtils.isEmpty(value) ? undefined : parseInt(value) : - this.firstDataIndex === 'd' ? commonUtils.isEmpty(value) ? '' : this.floatNumberCheck(value) : - this.firstDataIndex === 't' ? commonUtils.isEmpty(value) ? null : value : - this.firstDataIndex === 'b' ? value.target.checked : value === null ? undefined : value; + // eslint-disable-next-line radix + this.firstDataIndex === 'i' ? commonUtils.isEmpty(value) ? undefined : parseInt(value) : + this.firstDataIndex === 'd' ? commonUtils.isEmpty(value) ? '' : this.floatNumberCheck(value) : + this.firstDataIndex === 't' ? commonUtils.isEmpty(value) ? null : value : + this.firstDataIndex === 'b' ? value.target.checked : value === null ? undefined : value; const { sAssignField } = this.props.showConfig; const [changeData] = this.state.dropDownData.filter(item => (!commonUtils.isEmpty(item.sSlaveId) ? item.sSlaveId : item.sId) === value.toString()); if (!commonUtils.isEmpty(sAssignField)) { @@ -310,13 +313,13 @@ export default class CommonComponent extends Component { }; handleFocus = () => { - if(this.props.onFocus) { + if (this.props.onFocus) { this.props.onFocus(this.props.showConfig); } } handleBlur = () => { - if(this.props.onBlur) { + if (this.props.onBlur) { this.props.onBlur(this.props.showConfig); } } @@ -367,8 +370,8 @@ export default class CommonComponent extends Component { }; cancelValue = () => { - const bClear = this.props.showConfig.sName!=='sLocationId' && this.props.showConfig.sName!=='sLocationNo' && this.props.showConfig.sName!=='sLocationName'; - if(bClear) { + const bClear = this.props.showConfig.sName !== 'sLocationId' && this.props.showConfig.sName !== 'sLocationNo' && this.props.showConfig.sName !== 'sLocationName'; + if (bClear) { if (this.inputRef) this.inputRef.clearInput(); } } @@ -387,8 +390,8 @@ export default class CommonComponent extends Component { render() { const { sDateFormat: sDateFormatOld, sFieldValidation, bNotEmpty, bOpenKeyboard } = this.props.showConfig; let newValue = this.props.dataValue; - if(commonUtils.isNotEmptyObject(sFieldValidation)) { - const [length1, length2] = commonUtils.isNotEmptyObject(sFieldValidation) ? sFieldValidation.split(',') :[]; + if (commonUtils.isNotEmptyObject(sFieldValidation)) { + const [length1, length2] = commonUtils.isNotEmptyObject(sFieldValidation) ? sFieldValidation.split(',') : []; if (length2 !== undefined) { newValue = commonUtils.convertFixNum(this.props.dataValue, Number(length2)); } @@ -396,7 +399,7 @@ export default class CommonComponent extends Component { let sTitle = this.props.showConfig.showName; if (bNotEmpty) { /* 必填加星号 */ sTitle =
* {this.props.showConfig.showName}
; - }else { + } else { sTitle =
{this.props.showConfig.showName}
; } const outFormItemProps = { @@ -418,20 +421,32 @@ export default class CommonComponent extends Component { outFormItemProps.onVisibleChange = (visible) => { if (!visible) return; Toast.loading('加载中 ....', 0); - this.getDropDownData(this.props, false).finally( () => { + this.getDropDownData(this.props, false).finally(() => { Toast.hide(); }); } + // input = ( + // + // + // {this.props.iconSettingShow ? + // // eslint-disable-next-line jsx-a11y/alt-text + // : ''} + // {sTitle} + // + // + // ); + input = ( - - - {this.props.iconSettingShow ? - // eslint-disable-next-line jsx-a11y/alt-text - : ''} - {sTitle} - - - ); + + + ) } else if (this.firstDataIndex === 's') { if (this.props.textArea) { /* 大文本输入框 */ input = (); @@ -439,7 +454,7 @@ export default class CommonComponent extends Component { const pdaPro = { disabled: !this.state.enabled, placeholder: this.props.showConfig.placeholder || '请输入或扫码', - onFocus:this.handleFocus, + onFocus: this.handleFocus, virtualkeyboardpolicy: 'manual', inputmode: 'none', }; diff --git a/src/mobile/common/CommobileListEvent.js b/src/mobile/common/CommobileListEvent.js index f84e743..52705bf 100644 --- a/src/mobile/common/CommobileListEvent.js +++ b/src/mobile/common/CommobileListEvent.js @@ -9,7 +9,7 @@ import * as commonUtils from '../../utils/utils'; /* 通用方法 */ import commonConfig from '../../utils/config'; import * as commonFunc from '../../components/Common/commonFunc'; import * as commonServices from '../../services/services'; - +import instructSet from "@/components/Common/CommonInstructSet"; const alert = Modal.alert; export default (ChildComponent) => { @@ -18,7 +18,13 @@ export default (ChildComponent) => { super(props); this.state = { textAreaContent: '', + cameraVisible: false, + videoStream: null, + cameraError: null, + autoCaptureTimer: null, + faceRecognizing: false, }; + this.videoRef = React.createRef(); } async componentWillReceiveProps(nextProps) { @@ -389,10 +395,423 @@ export default (ChildComponent) => { this.handleBatchCancelExamine(); } else if (name === 'BtnAdd') { this.handleAdd(); + } else if (name.includes('BtnScanFace')) { + console.log("🚀 ~ name:", name) + this.startCamera() + } + }; + // 调用扫脸 + startCamera = () => { + navigator.mediaDevices.getUserMedia({ + video: { + facingMode: 'user', + width: { ideal: 640 }, + height: { ideal: 480 }, + }, + }) + .then(stream => { + this.setState({ + cameraVisible: true, + videoStream: stream, + cameraError: null, + autoCaptureTimer: setTimeout(() => { + this.capturePhoto(); + }, 2000), + }, () => { + if (this.videoRef.current) { + this.videoRef.current.srcObject = stream; + this.videoRef.current.play(); + } + }); + }) + .catch(error => { + console.error('无法访问摄像头:', error); + this.setState({ + cameraError: '无法访问摄像头,请检查权限设置', + cameraVisible: false, + }); + Toast.fail('无法访问摄像头,请检查权限'); + }); + }; + capturePhoto = () => { + if (!this.videoRef.current || !this.state.cameraVisible) return; + + const video = this.videoRef.current; + const canvas = document.createElement('canvas'); + canvas.width = video.videoWidth; + canvas.height = video.videoHeight; + const ctx = canvas.getContext('2d'); + ctx.drawImage(video, 0, 0, canvas.width, canvas.height); + + const base64 = canvas.toDataURL('image/jpeg', 0.85).split(',')[1]; + // 不再立即 closeCamera(),而是进入识别状态 + this.setState({ faceRecognizing: true }); + this.processFaceRecognition(base64); + }; + processFaceRecognition = (base64) => { + const url = `${commonConfig.face_host}/face/faceSearch`; + commonServices.postValueService(null, [{ + image: base64, + image_type: "BASE64", + face_field: "age", + option: "COMMON" + }], url) + .then(({ data: dataReturn }) => { + console.log("🚀 ~ dataReturn:", dataReturn) + if (dataReturn?.code === 1 && dataReturn.dataset.rows.length > 0) { + const value = { + sEmployeeNo: dataReturn.dataset.rows[0].sEmployeeNo, + sParentId: dataReturn.dataset.rows[0].sBrandsId, + sId: dataReturn.dataset.rows[0].sSubsidiaryId + }; + this.handleLogin(value, dataReturn.dataset.rows[0]); + } + }) + .finally(() => { + this.closeCamera(); + this.setState({ + cameraVisible: false, + faceRecognizing: false + }); + }); + }; + closeCamera = () => { + if (this.state.videoStream) { + this.state.videoStream.getTracks().forEach(track => track.stop()); + this.setState({ videoStream: null }); + } + if (this.videoRef.current) { + this.videoRef.current.srcObject = null; + } + if (this.state.autoCaptureTimer) { + clearTimeout(this.state.autoCaptureTimer); } }; + handleLogin = (result, dataReturn) => { + const { faceData = [] } = result; + const { slaveConfig, masterData } = this.props; + const btnConfig = slaveConfig.gdsconfigformslave?.find(item => item.sControlName.toLowerCase().includes('btnscanface')); + const { sButtonParam: sButtonParamStr } = btnConfig; + const sButtonParam = commonUtils.convertStrToObj(sButtonParamStr); + const { addData } = sButtonParam; + console.log(this.props, btnConfig, '=====this.props'); + this.handleProcedureCall( + { + btnConfig, + faceData: result, + ...dataReturn, + onSuccess: (_, dataset) => { + console.log("🚀 ~ dataset:", dataset) + const { proData = [] } = dataset.rows[0].dataSet; + const { [`${addData}Data`]: tableData = [], [`${addData}Config`]: config = {} } = this.props; + const copyConfig = config?.gdsconfigformslave?.find(item => item.sControlName.toLowerCase().includes('btnscanface')) + proData.forEach(item => { + const data = commonFunc.getAssignFieldValue(copyConfig?.sAssignField, item) + const index = tableData.findIndex(x => x.sEmployeeNo === item.sEmployeeNo) + if (index !== -1) { + Toast.fail('人员重复,请重新添加', 5); + } else { + tableData.push({ + ...item, + ...data, + sId: commonUtils.createSid(), + handleType: "add", + sParentId: props.masterData.sId, + slaveId: props?.slaveData ? props?.slaveData[0].sId : '' + }) + } + + }); + console.log(tableData, 'tableData'); + + // props.onSaveState({ + // [`${addData}Data`]: tableData, + // mesRefresh: true + // }); + }, + onConfirm: () => { }, + onError: () => { } + + }) + // instructSet({ + // btnConfig, + // faceData: result, + // onSuccess: (_, dataset) => { + // const { proData = [] } = dataset.rows[0].dataSet; + // const { [`${addData}Data`]: tableData = [], [`${addData}Config`]: config = {} } = this.props; + // const copyConfig = config?.gdsconfigformslave?.find(item => item.sControlName.toLowerCase().includes('btnscanface')) + // proData.forEach(item => { + // const data = commonFunc.getAssignFieldValue(copyConfig?.sAssignField, item) + // const index = tableData.findIndex(x => x.sEmployeeNo === item.sEmployeeNo) + // if (index !== -1) { + // message.error('人员重复,请重新添加', 5) + // } else { + // tableData.push({ + // ...item, + // ...data, + // sId: commonUtils.createSid(), + // handleType: "add", + // sParentId: props.masterData.sId, + // slaveId: props?.slaveData ? props?.slaveData[0].sId : '' + // }) + // } + + // }); + + // // props.onSaveState({ + // // [`${addData}Data`]: tableData, + // // mesRefresh: true + // // }); + // }, + // onConfirm: () => { }, + // onError: () => { } + // }); + } + handleProcedureCall = async (params, iFlag) => { + const { + btnConfig = {}, // 按钮配置 + sValue = {}, // 额外参数 + tableData: tableDataSelected, // 传过来的数据 + faceData = {}, // 人脸数据 + onSuccess, + onConfirm, + onError, + nextProps, + sUserId, + sParentId, + sEmployeeNo, + + } = params; + + const currentState = this.props || this.state; + const { slaveSelectedRowKeys = [] } = this.props; + + // 加入mes通用参数 + const { app } = this.props; + const { tableNameCompareJson = {} } = currentState; + const { + sMachineNameSId: sMachineGuid, + sTeamNameSId: sTeamGuid, + sShift + } = app; + const commonData = { + sMachineGuid, + sTeamGuid, + sShift + }; + + const { sButtonParam } = btnConfig; + console.log("🚀 ~ sButtonParam:", sButtonParam) + const btn = commonUtils.convertStrToObj(sButtonParam, {}); + if (commonUtils.isEmptyObject(btn)) { + onSuccess && onSuccess(false); + return; + } + const { sproName: sProName, inMap, sTableName, staticData = {} } = btn; + console.log("🚀 ~ inMap:", inMap, sButtonParam) + + const inParams = []; + const arr = {}; + + if (inMap) { + const inlist = inMap.split(","); + inlist.forEach(item => { + const [ + tableNameOld, + sFieldName, + sFieldNameNew = sFieldName + ] = item.split("."); + + const tableName = tableNameCompareJson[tableNameOld] || tableNameOld; + if (!tableName) return; + if (!arr[tableName]) { + arr[tableName] = []; + } + arr[tableName].push({ sFieldName, sFieldNameNew }); + }); + } - /** 点击新增按钮 */ + // 拼接params参数 + Object.keys(arr).forEach(tableName => { + const addState = { key: tableName }; + if (tableName.includes("master")) { + const { [`${tableName}Data`]: tableData = {} } = currentState; + const allValue = []; + const value = { ...commonData, ...staticData, ...faceData }; + arr[tableName].forEach(({ sFieldName, sFieldNameNew }) => { + value[`${sFieldNameNew}`] = tableData[`${sFieldName}`]; + }); + allValue.push(value); + addState.value = allValue; + inParams.push(addState); + } else { + let filterData = tableDataSelected; + if (commonUtils.isEmptyArr(filterData)) { + if ( + [ + "userinfo", + "currentSelectedMachineTask", + "currentStartWorkMachineTask", + "currentWorkOrderInfo" + ].includes(tableName) + ) { + // 如果是全局变量 + const globalData = commonUtils.getAppData("globalData"); + const tempProps = { + userinfo: app.userinfo, + currentSelectedMachineTask: globalData.currentSelectedMachineTask, + currentStartWorkMachineTask: + globalData.currentStartWorkMachineTask, + currentWorkOrderInfo: globalData.currentWorkOrderInfo + }; + filterData = [tempProps[tableName]]; + } else { + // 如果不是全局变量 + const { + [`${tableName}Data`]: tableData = [], + [`${tableName}SelectedRowKeys`]: selectedRowKeys = [] + } = currentState; + if (selectedRowKeys.length === 0 && nextProps) { + filterData = tableData; + } else { + const iIndex = arr[tableName].findIndex( + item => item.sFieldNameNew === "*" + ); + if (iIndex > -1) { + filterData = tableData; + } else { + filterData = tableData.filter( + item => + true && + (selectedRowKeys.includes(item.sId) || + selectedRowKeys.includes(item.sSlaveId)) + ); + } + } + } + if (sProName === "Sp_Mes_BindMaterials") { + filterData = filterData.filter(item => item.sAdded == "1"); + } + } + const addState = { key: tableName }; + const allValue = []; + filterData.forEach(currData => { + let value = { ...commonData, ...staticData, ...faceData }; + arr[tableName].forEach(({ sFieldName, sFieldNameNew }) => { + if (sFieldNameNew === "*") { + value = { ...value, ...currData }; + delete value.sColumnConfig; + } else { + value[`${sFieldNameNew}`] = currData[`${sFieldName}`]; + } + }); + allValue.push(value); + }); + addState.value = allValue; + inParams.push(addState); + } + }); + + if ( + commonUtils.isNotEmptyStr(sTableName) && + commonUtils.isNotEmptyArr(inParams) + ) { + inParams.forEach(item => { + if (commonUtils.isNotEmptyArr(item.value)) { + item.value.forEach(item1 => { + item1.sTableName = sTableName; + }); + } + }); + } + + const { token } = app; + const { sModelsId } = this.props; + + const { sControlName: sBtnName } = btnConfig; + + if (iFlag !== undefined) { + inParams[0]?.value?.forEach(item => { + item.iFlag = iFlag; + }); + } + + const proInParam = JSON.stringify({ + params: inParams.map(item => ({ + ...item, + sUserName: app.userinfo.sUserName, + value: [{ + sUserId, + sParentId, + sEmployeeNo, + sId: slaveSelectedRowKeys[0], + "sOperate": "start", + ...commonData, + + }] + })), + changeValue: sValue, + sButtonParam: btn + }); + const value = { sProName, sProInParam: proInParam, sBtnName }; + if (iFlag !== undefined) { + value.iFlag = iFlag; + } + + console.log("=====存储过程参数", { + params: inParams, + changeValue: sValue, + sButtonParam: btn + }); + console.log(value, 'value '); + const url = `${commonConfig.server_host + }procedureCall/doGenericProcedureCall?sModelsId=${sModelsId}`; + const returnData = (await commonServices.postValueService( + token, + value, + url + )).data; + const { code, msg, dataset } = returnData; + if (code === 1) { + Toast.info(msg); + onSuccess && onSuccess(true, dataset); + } else if (code === -7) { + // Modal.confirm({ + // title: FriendlyReminder, + // content:
{this.handleGetMsg(msg)}
, + // onOk() { + // this.handleProcedureCall(params, 1); + // }, + // onCancel() { + // onError && onError(); + // } + // }); + } else if (code === -8) { + // Modal.info({ + // title: FriendlyReminder, + // content:
{this.handleGetMsg(msg)}
, + // onOk() { + // onConfirm && onConfirm(); + // }, + // onCancel() { + // onError && onError(); + // } + // }); + } else { + + } + }; + handleGetMsg = str => { + const msgArr = commonUtils.isNotEmptyObject(str) ? str.split("xpm") : ""; + const divStr = []; + if (commonUtils.isNotEmptyArr(msgArr)) { + for (let i = 0; i < msgArr.length; i++) { + divStr.push(

{msgArr[i]}

); + } + } + return divStr; + }; + /** 点击新增按钮 */ handleAdd = () => { const { slaveConfig, dispatch, slaveFilterCondition, slavePagination, slaveOrderBy, formRoute, @@ -612,20 +1031,37 @@ export default (ChildComponent) => { slaveSelectedRowKeys, }); }; + render() { + const { loginCompany, companys, cameraVisible, cameraError } = this.state; return ( - +
+ {cameraVisible && ( +
+
+ )} + +
); } }; diff --git a/src/mobile/components/searchPicker.jsx b/src/mobile/components/searchPicker.jsx new file mode 100644 index 0000000..c9140df --- /dev/null +++ b/src/mobile/components/searchPicker.jsx @@ -0,0 +1,92 @@ +import { Popup, SearchBar, PickerView, Button } from 'antd-mobile'; +import { List,} from 'antd-mobile-v2'; +import { useState, useMemo } from 'react'; +import styles from "./selectInput.less"; +export default function SearchablePicker(props) { + console.log("🚀 ~ SearchablePicker ~ props:", props) + const { onConfirm, initialValue, data, sTitle, onChange, value:newValue } = props; + + const [searchValue, setSearchValue] = useState(''); + const [visible, setVisible] = useState(false) + + // 安全初始化 values + const initialVal = useMemo(() => { + if (!initialValue || !Array.isArray(data)) return []; + const exists = data.some(item => item?.value === initialValue); + return exists ? [initialValue] : []; + }, [initialValue, data]); + + const [values, setValues] = useState(initialVal); + + // 安全过滤选项 + const filteredOptions = useMemo(() => { + const options = Array.isArray(data) ? data : []; + + if (!searchValue.trim()) { + return options; + } + + return options.filter(item => + item && + typeof item.label === 'string' && + item.label.toLowerCase().includes(searchValue.toLowerCase()) + ); + }, [searchValue, data]); // ✅ 必须包含 data + const label = filteredOptions?.find(x=>x.value === newValue[0])?.label || '' + const handleConfirm = () => { + onChange(values); + setVisible(false); + }; + + const handleCancel = () => { + setVisible(false); + }; + + const changeOption = (val) => { + setValues(val); + }; + + return ( +
+ { + setVisible(true) + }} extra={label}> + {props.iconSettingShow ? + // eslint-disable-next-line jsx-a11y/alt-text + : ''} + {sTitle} + + +
+ + +
+ +
+ +
+ + +
+
+ + ); +} \ No newline at end of file diff --git a/src/mobile/components/selectInput.css b/src/mobile/components/selectInput.css index 9e52a66..f8856b8 100644 --- a/src/mobile/components/selectInput.css +++ b/src/mobile/components/selectInput.css @@ -23,3 +23,6 @@ justify-content: space-between; margin: 0.2rem; } +.searchPickerList :global .am-list-line { + justify-content: space-between; +} diff --git a/src/mobile/components/selectInput.less b/src/mobile/components/selectInput.less index e90c011..aeee28f 100644 --- a/src/mobile/components/selectInput.less +++ b/src/mobile/components/selectInput.less @@ -23,4 +23,13 @@ align-items: center; justify-content: space-between; margin: 0.2rem; +} +.searchPickerList{ + :global .am-list-line{ + justify-content: space-between; + // .am-list-extra{ + // text-align: right !important; + // } + } + } \ No newline at end of file diff --git a/src/utils/utils.js b/src/utils/utils.js index 8cac108..c0a3e30 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -29,7 +29,14 @@ export function getCursortPosition(obj) { } return cursorIndex; } - +export function getAppData(name, key) { + const appData = convertStrToObj(localStorage.getItem(`${config.prefix}${name}`)); + if (key === undefined) { + return appData; + } else { + return appData[key]; + } +} /* 为输入框聚焦 */ export function focus(id, e, currentRef = document) { const element = currentRef.querySelector(`#${id}`);