269 lines
11 KiB
JavaScript
269 lines
11 KiB
JavaScript
// 【重要】必须使用 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])
|
||
);
|
||
};
|