Files
ONE-OS/web端/安全培训扫码.jsx

269 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 【重要】必须使用 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])
);
};