// 【重要】必须使用 const Component 作为组件变量名 // 安全培训扫码 - H5 分步表单(扫码链接进入) const Component = function () { var useState = React.useState; var useCallback = React.useCallback; var useRef = React.useRef; var useEffect = React.useEffect; var antd = window.antd; var Steps = antd.Steps; var Button = antd.Button; var Input = antd.Input; var message = antd.message; var Progress = antd.Progress; // 当前步骤 1 | 2 | 3 | 4 var stepState = useState(1); var step = stepState[0]; var setStep = stepState[1]; // 第一步:手机号、验证码 var phoneState = useState(''); var verifyCodeState = useState(''); var codeCountdownState = useState(0); var phone = phoneState[0]; var setPhone = phoneState[1]; var verifyCode = verifyCodeState[0]; var setVerifyCode = verifyCodeState[1]; var codeCountdown = codeCountdownState[0]; var setCodeCountdown = codeCountdownState[1]; // 模拟:已完成培训的手机号,再次进入直接显示提车码 var completedPhonesState = useState({ '13800138000': 'TC-2026-8888', '13900139000': 'TC-2026-9999' }); var completedPhones = completedPhonesState[0]; var setCompletedPhones = completedPhonesState[1]; // 第二步:证照上传(用文件名/已上传标记模拟) var idFrontState = useState(null); var idBackState = useState(null); var licenseState = useState(null); var qualificationState = useState(null); var needQualification = false; // 18吨以上车辆必填,此处为可选 // 第三步:视频进度(0-100),是否播放中 var videoProgressState = useState(0); var videoPlayingState = useState(false); var videoProgress = videoProgressState[0]; var setVideoProgress = videoProgressState[1]; var videoPlaying = videoPlayingState[0]; var setVideoPlaying = videoPlayingState[1]; var videoTimerRef = useRef(null); // 第四步:提车码(生成后保存,同一手机再次进入可直接显示) var pickupCodeState = useState(''); var pickupCode = pickupCodeState[0]; var setPickupCode = pickupCodeState[1]; // 获取验证码倒计时 useEffect(function () { if (codeCountdown <= 0) return; var t = setTimeout(function () { setCodeCountdown(function (c) { return c - 1; }); }, 1000); return function () { clearTimeout(t); }; }, [codeCountdown]); // 视频模拟:播放时每 500ms 增加进度,到 100% 停止 useEffect(function () { if (!videoPlaying || videoProgress >= 100) { if (videoProgress >= 100) setVideoPlaying(false); return; } var t = setInterval(function () { setVideoProgress(function (p) { var next = Math.min(100, p + 2); return next; }); }, 500); return function () { clearInterval(t); }; }, [videoPlaying, videoProgress]); // 第一步:验证并进入 var handleStep1Next = useCallback(function () { var p = (phone || '').trim(); var c = (verifyCode || '').trim(); if (!p) { message.warning('请输入手机号'); return; } if (!c) { message.warning('请输入验证码'); return; } // 已完成培训的手机号直接进入第四步 if (completedPhones[p]) { setPickupCode(completedPhones[p]); setStep(4); return; } // 模拟验证成功(任意 4-6 位验证码) if (c.length < 4) { message.warning('请输入正确的验证码'); return; } setStep(2); }, [phone, verifyCode, completedPhones]); var handleSendCode = useCallback(function () { var p = (phone || '').trim(); if (!p || p.length < 11) { message.warning('请输入正确手机号'); return; } if (codeCountdown > 0) return; setCodeCountdown(60); message.success('验证码已发送'); }, [phone, codeCountdown]); // 第二步:上传(模拟点击即视为已上传) var uploadAreaStyle = { border: '1px dashed #d9d9d9', borderRadius: 8, padding: '24px 16px', textAlign: 'center', background: '#fafafa', color: 'rgba(0,0,0,0.65)', fontSize: 14, cursor: 'pointer' }; var uploadDoneStyle = { borderColor: '#52c41a', background: '#f6ffed', color: '#52c41a' }; function renderUpload(label, value, setValue) { var done = value != null && value !== ''; return React.createElement('div', { key: label, style: Object.assign({}, uploadAreaStyle, done ? uploadDoneStyle : {}), onClick: function () { // 模拟选择文件/拍照:点击即视为已上传 setValue(done ? null : label + '-已上传.jpg'); } }, done ? (value + ' ✓') : ('点击上传 ' + label + '(支持现场拍照/本地文件)')); } var allRequiredUploaded = (idFrontState[0] != null && idFrontState[0] !== '') && (idBackState[0] != null && idBackState[0] !== '') && (licenseState[0] != null && licenseState[0] !== '') && (!needQualification || (qualificationState[0] != null && qualificationState[0] !== '')); var handleStep2WatchVideo = useCallback(function () { if (!allRequiredUploaded) { message.warning('请完成全部必填证照上传'); return; } setStep(3); setVideoProgress(0); setVideoPlaying(false); }, [allRequiredUploaded]); // 第三步:播放/暂停,进度到 100% 后可生成提车码 var handleVideoPlayPause = useCallback(function () { if (videoProgress >= 100) return; setVideoPlaying(function (v) { return !v; }); }, [videoProgress]); var handleStep3Generate = useCallback(function () { if (videoProgress < 100) { message.warning('请完整观看安全培训视频'); return; } var code = 'TC-' + new Date().getFullYear() + '-' + Math.floor(1000 + Math.random() * 9000); setPickupCode(code); setCompletedPhones(function (prev) { var next = {}; for (var k in prev) next[k] = prev[k]; next[phone.trim()] = code; return next; }); setStep(4); message.success('提车码已生成'); }, [videoProgress, phone]); // H5 移动端布局 var pageStyle = { maxWidth: 414, margin: '0 auto', minHeight: '100vh', background: '#f5f5f5', padding: '16px', boxSizing: 'border-box' }; var stepIndicatorStyle = { marginBottom: 24 }; var cardStyle = { marginBottom: 16, borderRadius: 12 }; var labelStyle = { display: 'block', marginBottom: 8, fontSize: 15, color: 'rgba(0,0,0,0.85)' }; var inputStyle = { width: '100%', height: 48, fontSize: 16, boxSizing: 'border-box' }; var btnBlockStyle = { width: '100%', height: 48, fontSize: 16, marginTop: 8 }; var stepTitleStyle = { fontSize: 17, fontWeight: 600, marginBottom: 16, color: 'rgba(0,0,0,0.85)' }; var stepsItems = [ { title: '验证' }, { title: '证照' }, { title: '视频' }, { title: '提车码' } ]; // 第一步视图 var step1Content = React.createElement('div', null, React.createElement('div', { style: stepTitleStyle }, '手机号验证'), React.createElement('div', { style: { marginBottom: 16 } }, React.createElement('label', { style: labelStyle }, '手机号'), React.createElement(Input, { placeholder: '请输入手机号', value: phone, onChange: function (e) { setPhone(e.target.value); }, style: inputStyle, maxLength: 11, type: 'tel' }) ), React.createElement('div', { style: { marginBottom: 16 } }, React.createElement('label', { style: labelStyle }, '验证码'), React.createElement('div', { style: { display: 'flex', gap: 8 } }, React.createElement(Input, { placeholder: '请输入验证码', value: verifyCode, onChange: function (e) { setVerifyCode(e.target.value); }, style: Object.assign({}, inputStyle, { flex: 1 }), maxLength: 6 }), React.createElement(Button, { disabled: codeCountdown > 0, onClick: handleSendCode, style: { height: 48, minWidth: 100 } }, codeCountdown > 0 ? codeCountdown + 's' : '获取验证码') ) ), React.createElement(Button, { type: 'primary', size: 'large', style: btnBlockStyle, onClick: handleStep1Next }, '下一步') ); // 第二步视图 var step2Content = React.createElement('div', null, React.createElement('div', { style: stepTitleStyle }, '证照上传'), React.createElement('div', { style: { marginBottom: 12 } }, '请上传以下证照,支持现场拍照或手机本地文件。'), React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 12 } }, renderUpload('身份证正面', idFrontState[0], idFrontState[1]), renderUpload('身份证反面', idBackState[0], idBackState[1]), renderUpload('驾驶证', licenseState[0], licenseState[1]), renderUpload('从业资格证(18吨以上车辆请上传,可选)', qualificationState[0], qualificationState[1]) ), React.createElement(Button, { type: 'primary', size: 'large', style: Object.assign({}, btnBlockStyle, { marginTop: 24 }), onClick: handleStep2WatchVideo, disabled: !allRequiredUploaded }, '观看安全培训视频') ); // 第三步视图:视频区域(不可快进快退,仅暂停/播放) var step3Content = React.createElement('div', null, React.createElement('div', { style: stepTitleStyle }, '安全培训视频'), React.createElement('div', { style: { marginBottom: 8, fontSize: 14, color: 'rgba(0,0,0,0.65)' } }, '请完整观看视频,不支持快进快退。'), React.createElement('div', { style: { background: '#000', borderRadius: 8, overflow: 'hidden', marginBottom: 16, position: 'relative', paddingBottom: '56.25%', height: 0 }, onClick: handleVideoPlayPause }, React.createElement('div', { style: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontSize: 14 } }, videoProgress >= 100 ? '播放完成' : (videoPlaying ? '播放中... 点击暂停' : '点击播放') ) ), React.createElement('div', { style: { marginBottom: 8 } }, React.createElement(Progress, { percent: videoProgress, showInfo: true }) ), React.createElement('div', { style: { display: 'flex', gap: 8 } }, React.createElement(Button, { onClick: handleVideoPlayPause, disabled: videoProgress >= 100 }, videoPlaying ? '暂停' : '播放'), React.createElement(Button, { type: 'primary', disabled: videoProgress < 100, onClick: handleStep3Generate }, '生成提车码') ) ); // 第四步视图 var step4Content = React.createElement('div', { style: { textAlign: 'center', padding: '24px 0' } }, React.createElement('div', { style: stepTitleStyle }, '提车码'), React.createElement('div', { style: { fontSize: 15, color: 'rgba(0,0,0,0.65)', marginBottom: 24 } }, '小程序扫描提车码后自动拉取司机证件信息。提车码在运维完成扫提车码并交车成功后失效。'), React.createElement('div', { style: { fontSize: 28, fontWeight: 700, letterSpacing: 4, padding: '20px', background: '#f0f0f0', borderRadius: 12, marginBottom: 16, userSelect: 'all' } }, pickupCode || '—'), React.createElement('div', { style: { width: 160, height: 160, margin: '0 auto 16px', background: '#f0f0f0', border: '2px dashed #d9d9d9', borderRadius: 8, display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#999', fontSize: 12 } }, '提车码二维码') ); var stepContents = [step1Content, step2Content, step3Content, step4Content]; return React.createElement('div', { style: pageStyle }, React.createElement('div', { style: { padding: '12px 0', marginBottom: 8, fontSize: 18, fontWeight: 600 } }, '安全培训扫码'), React.createElement(Steps, { current: step - 1, style: stepIndicatorStyle, size: 'small', items: stepsItems }), React.createElement('div', { style: { background: '#fff', borderRadius: 12, padding: 20, boxShadow: '0 1px 2px rgba(0,0,0,0.05)' } }, stepContents[step - 1]) ); };