Files
shz-backend/ruoyi-admin/src/main/resources/static/h5/outdoor-fair/detail.html

222 lines
10 KiB
HTML
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.

<!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 ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[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>