222 lines
10 KiB
HTML
222 lines
10 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||
<title>户外招聘会</title>
|
||
<style>
|
||
:root {
|
||
color: #172033;
|
||
background: #f4f7fb;
|
||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
|
||
}
|
||
* { box-sizing: border-box; }
|
||
body { margin: 0; background: #f4f7fb; }
|
||
.page { min-height: 100vh; padding: 18px 14px 28px; }
|
||
.hero {
|
||
padding: 22px 18px;
|
||
color: #fff;
|
||
background: linear-gradient(135deg, #1f6feb, #14866d);
|
||
border-radius: 8px;
|
||
box-shadow: 0 10px 28px rgba(31, 111, 235, .18);
|
||
}
|
||
.hero h1 { margin: 0 0 10px; font-size: 24px; line-height: 1.25; letter-spacing: 0; }
|
||
.hero p { margin: 4px 0 0; font-size: 14px; line-height: 1.7; opacity: .92; }
|
||
.section { margin-top: 14px; padding: 16px; background: #fff; border-radius: 8px; box-shadow: 0 8px 22px rgba(23, 32, 51, .06); }
|
||
.section h2 { margin: 0 0 12px; font-size: 17px; line-height: 1.4; letter-spacing: 0; }
|
||
.meta { display: grid; gap: 8px; }
|
||
.meta div { display: flex; gap: 10px; font-size: 14px; line-height: 1.55; }
|
||
.meta span:first-child { flex: 0 0 86px; color: #667085; }
|
||
.meta span:last-child { min-width: 0; flex: 1; word-break: break-word; }
|
||
.photo { width: 100%; margin-top: 14px; border-radius: 8px; object-fit: cover; }
|
||
.loading, .error { padding: 28px 16px; color: #667085; text-align: center; font-size: 14px; line-height: 1.7; }
|
||
.error { color: #b42318; }
|
||
.actions { display: grid; grid-template-columns: 1fr; gap: 10px; margin-top: 14px; }
|
||
.btn {
|
||
display: flex; align-items: center; justify-content: center;
|
||
min-height: 44px; padding: 10px 14px; color: #fff; background: #1f6feb;
|
||
border: 0; border-radius: 8px; font-size: 15px; text-decoration: none; width: 100%;
|
||
}
|
||
.btn.checkin { background: #14866d; }
|
||
/* 签到弹窗 */
|
||
.mask { position: fixed; inset: 0; background: rgba(23,32,51,.45); display: none; z-index: 50; }
|
||
.mask.show { display: block; }
|
||
.dialog {
|
||
position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
|
||
width: calc(100vw - 56px); max-width: 380px; background: #fff;
|
||
border-radius: 10px; padding: 18px 16px; z-index: 51; display: none;
|
||
box-shadow: 0 18px 48px rgba(23,32,51,.22);
|
||
}
|
||
.dialog.show { display: block; }
|
||
.dialog h3 { margin: 0 0 4px; font-size: 17px; }
|
||
.dialog .sub { margin: 0 0 14px; font-size: 13px; color: #667085; }
|
||
.field { margin-bottom: 12px; }
|
||
.field label { display: block; margin-bottom: 6px; font-size: 14px; color: #344054; }
|
||
.field input {
|
||
width: 100%; min-height: 42px; padding: 8px 12px; border: 1px solid #d0d5dd;
|
||
border-radius: 8px; font-size: 15px; background: #fff; box-sizing: border-box;
|
||
}
|
||
.field input:focus { outline: none; border-color: #1f6feb; }
|
||
.dialog-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 4px; }
|
||
.btn.ghost { color: #475467; background: #f2f4f7; }
|
||
.toast {
|
||
position: fixed; left: 50%; top: 24px; transform: translateX(-50%);
|
||
padding: 10px 16px; border-radius: 8px; font-size: 14px; color: #fff;
|
||
background: #14866d; z-index: 60; display: none; max-width: 80vw; text-align: center;
|
||
}
|
||
.toast.error { background: #b42318; }
|
||
.toast.show { display: block; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<main class="page" id="app">
|
||
<div class="loading">正在加载...</div>
|
||
</main>
|
||
<script>
|
||
(function () {
|
||
var app = document.getElementById('app');
|
||
var fairId = new URLSearchParams(window.location.search).get('fairId');
|
||
var pageFairId = null;
|
||
|
||
function text(value) {
|
||
return value === null || value === undefined || value === '' ? '暂无' : String(value);
|
||
}
|
||
|
||
function escapeHtml(value) {
|
||
return text(value).replace(/[&<>"']/g, function (ch) {
|
||
return ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[ch];
|
||
});
|
||
}
|
||
|
||
// 页面和 API 使用不同的代理前缀:
|
||
// 页面:/shihezi/h5/...
|
||
// API:/api/shihezi/...
|
||
function publicBase() {
|
||
var path = window.location.pathname;
|
||
var idx = path.indexOf('/h5/');
|
||
return idx > 0 ? path.slice(0, idx) : '';
|
||
}
|
||
|
||
function apiBase() {
|
||
return '/api' + publicBase();
|
||
}
|
||
|
||
function render(data) {
|
||
var fair = data.fair || {};
|
||
pageFairId = (fair.id !== null && fair.id !== undefined) ? fair.id : fairId;
|
||
document.title = text(fair.title);
|
||
app.innerHTML =
|
||
'<section class="hero">' +
|
||
'<h1>' + escapeHtml(fair.title) + '</h1>' +
|
||
'<p>' + escapeHtml(fair.hostUnit) + '</p>' +
|
||
'<p>' + escapeHtml(fair.address) + '</p>' +
|
||
'</section>' +
|
||
'<div class="actions">' +
|
||
'<button type="button" class="btn checkin" id="checkinBtn">签到</button>' +
|
||
'</div>' +
|
||
'<section class="section">' +
|
||
'<h2>招聘会信息</h2>' +
|
||
'<div class="meta">' +
|
||
'<div><span>举办时间</span><span>' + escapeHtml(fair.holdTime) + '</span></div>' +
|
||
'<div><span>截止时间</span><span>' + escapeHtml(fair.endTime) + '</span></div>' +
|
||
'<div><span>招聘会类型</span><span>' + escapeHtml(fair.fairType) + '</span></div>' +
|
||
'<div><span>举办区域</span><span>' + escapeHtml(fair.region) + '</span></div>' +
|
||
'<div><span>举办场地</span><span>' + escapeHtml(fair.venueName) + '</span></div>' +
|
||
'<div><span>展位数量</span><span>' + escapeHtml(fair.boothCount) + '</span></div>' +
|
||
'</div>' +
|
||
(fair.photoUrl ? '<img class="photo" src="' + escapeHtml(fair.photoUrl) + '" alt="招聘会照片">' : '') +
|
||
'</section>' +
|
||
'<div class="mask" id="checkinMask"></div>' +
|
||
'<div class="dialog" id="checkinDialog">' +
|
||
'<h3>签到</h3>' +
|
||
'<p class="sub">请填写您的姓名和手机号完成签到</p>' +
|
||
'<div class="field">' +
|
||
'<label for="checkinName">姓名</label>' +
|
||
'<input type="text" id="checkinName" placeholder="请输入姓名" autocomplete="name">' +
|
||
'</div>' +
|
||
'<div class="field">' +
|
||
'<label for="checkinPhone">手机号</label>' +
|
||
'<input type="tel" id="checkinPhone" placeholder="请输入手机号" autocomplete="tel" maxlength="11">' +
|
||
'</div>' +
|
||
'<div class="dialog-actions">' +
|
||
'<button type="button" class="btn ghost" id="checkinCancel">取消</button>' +
|
||
'<button type="button" class="btn checkin" id="checkinSubmit">提交签到</button>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="toast" id="checkinToast"></div>';
|
||
bindCheckIn();
|
||
}
|
||
|
||
function showToast(msg, isError) {
|
||
var toast = document.getElementById('checkinToast');
|
||
if (!toast) return;
|
||
toast.textContent = msg;
|
||
toast.className = 'toast show' + (isError ? ' error' : '');
|
||
setTimeout(function () { toast.className = 'toast' + (isError ? ' error' : ''); }, 2400);
|
||
}
|
||
|
||
function openCheckIn() {
|
||
var mask = document.getElementById('checkinMask');
|
||
var dialog = document.getElementById('checkinDialog');
|
||
if (mask && dialog) { mask.className = 'mask show'; dialog.className = 'dialog show'; }
|
||
}
|
||
|
||
function closeCheckIn() {
|
||
var mask = document.getElementById('checkinMask');
|
||
var dialog = document.getElementById('checkinDialog');
|
||
if (mask) mask.className = 'mask';
|
||
if (dialog) dialog.className = 'dialog';
|
||
}
|
||
|
||
function bindCheckIn() {
|
||
var openBtn = document.getElementById('checkinBtn');
|
||
var cancelBtn = document.getElementById('checkinCancel');
|
||
var mask = document.getElementById('checkinMask');
|
||
var submitBtn = document.getElementById('checkinSubmit');
|
||
if (openBtn) openBtn.onclick = openCheckIn;
|
||
if (cancelBtn) cancelBtn.onclick = closeCheckIn;
|
||
if (mask) mask.onclick = closeCheckIn;
|
||
if (submitBtn) submitBtn.onclick = submitCheckIn;
|
||
}
|
||
|
||
function submitCheckIn() {
|
||
var name = (document.getElementById('checkinName') || {}).value;
|
||
var phone = (document.getElementById('checkinPhone') || {}).value;
|
||
if (!name || !name.trim()) { showToast('请输入姓名', true); return; }
|
||
if (!phone || !/^\d{11}$/.test(phone.trim())) { showToast('请输入正确的11位手机号', true); return; }
|
||
if (!pageFairId) { showToast('缺少招聘会信息', true); return; }
|
||
var submitBtn = document.getElementById('checkinSubmit');
|
||
if (submitBtn) submitBtn.disabled = true;
|
||
fetch(apiBase() + '/app/outdoor-fair/check-in', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ fairId: Number(pageFairId), name: name.trim(), phone: phone.trim() })
|
||
}).then(function (res) { return res.json(); }).then(function (body) {
|
||
if (submitBtn) submitBtn.disabled = false;
|
||
if (body && body.code === 200) { closeCheckIn(); showToast('签到成功'); }
|
||
else { showToast((body && body.msg) || '签到失败', true); }
|
||
}).catch(function () {
|
||
if (submitBtn) submitBtn.disabled = false;
|
||
showToast('网络异常,请重试', true);
|
||
});
|
||
}
|
||
|
||
if (!fairId) {
|
||
app.innerHTML = '<div class="error">缺少招聘会参数</div>';
|
||
return;
|
||
}
|
||
fetch(apiBase() + '/app/outdoor-fair/' + encodeURIComponent(fairId)).then(function (res) {
|
||
return res.json();
|
||
}).then(function (body) {
|
||
if (body.code !== 200) {
|
||
throw new Error(body.msg || '加载失败');
|
||
}
|
||
render(body.data || {});
|
||
}).catch(function (err) {
|
||
app.innerHTML = '<div class="error">' + escapeHtml(err.message) + '</div>';
|
||
});
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|