Files
LM/WebContent/view/Login.jsp
2026-03-23 08:59:33 +08:00

310 lines
14 KiB
Plaintext
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.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>读者门户 · 简洁版 (合并读者类型)</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
/* 样式保持不变,省略(实际使用时应保留原有样式) */
* { margin:0; padding:0; box-sizing:border-box; }
body { background:#eef2f6; font-family:'Inter',sans-serif; display:flex; align-items:center; justify-content:center; min-height:100vh; padding:1rem; }
#app { width:100%; max-width:520px; }
.card { background:white; border-radius:28px; box-shadow:0 25px 45px -12px rgba(0,0,0,0.15); padding:2.2rem 2rem; width:100%; }
h2 { font-size:1.9rem; font-weight:600; color:#1a2b3c; margin-bottom:1.5rem; border-bottom:2px solid #f0f4f9; padding-bottom:1rem; }
h3 { font-size:1.2rem; font-weight:500; color:#2c3e50; margin-bottom:1.2rem; }
.field { margin-bottom:1.3rem; }
label { display:block; font-size:0.8rem; font-weight:600; text-transform:uppercase; color:#4a5e74; margin-bottom:0.3rem; }
input, select { width:100%; padding:0.8rem 1rem; font-size:1rem; border:1.5px solid #e2e9f2; border-radius:16px; background:#fff; transition:border 0.15s; outline:none; }
input:focus, select:focus { border-color:#7c8ea0; background:#fafcff; }
button { background:#2c3e50; color:white; border:none; padding:0.9rem 1.5rem; font-size:1rem; font-weight:500; border-radius:40px; cursor:pointer; transition:background 0.15s; width:100%; margin-top:0.3rem; }
button:hover { background:#1d2c3a; }
.secondary-btn { background:white; color:#2c3e50; border:1.5px solid #d0ddee; margin-top:1rem; }
.secondary-btn:hover { background:#f2f6fc; border-color:#a0b8cf; }
.nav-links { display:flex; justify-content:space-between; margin-top:1.5rem; gap:0.5rem; flex-wrap:wrap; }
.nav-link { background:#f0f5fb; color:#2e405b; padding:0.6rem 1.2rem; border-radius:40px; font-size:0.9rem; font-weight:500; cursor:pointer; border:1px solid transparent; transition:background 0.15s; text-align:center; flex:1 1 auto; }
.nav-link:hover { background:#dae2ed; color:#0e1e2f; }
.active-view { margin-bottom:1rem; }
.note { font-size:0.75rem; color:#8f9fb1; margin-top:0.5rem; text-align:center; }
.compact-form { background:#f9fcff; border-radius:20px; padding:1.5rem 1.2rem; margin:0.5rem 0 1rem; }
.nav-link.active-nav { background:#2c3e50; color:white; border-color:#2c3e50; }
.nav-link.active-nav:hover { background:#1d2c3a; }
</style>
</head>
<body>
<div id="app">
<div class="card">
<h2>📖 读者门户</h2>
<!-- 动态视图:读者登录 / 读者注册 / 员工登录 -->
<div class="active-view">
<!-- 读者登录视图 -->
<div v-if="currentView === 'reader-login'">
<h3>👤 读者登录</h3>
<div class="field">
<label>证号</label>
<input v-model="readerLogin.cardNumber" type="text" placeholder="例如R2024001" />
</div>
<div class="field">
<label>姓名</label>
<input v-model="readerLogin.name" type="text" placeholder="你的名字" />
</div>
<button @click="handleReaderLogin">登录</button>
<div class="note">跳转与验证由后端处理</div>
</div>
<!-- 读者注册视图 -->
<div v-else-if="currentView === 'reader-register'">
<h3>📝 注册新读者</h3>
<div class="compact-form">
<div class="field">
<label>证号</label>
<input v-model="registerForm.cardNumber" type="text" placeholder="唯一证号" />
</div>
<div class="field">
<label>姓名</label>
<input v-model="registerForm.name" type="text" placeholder="真实姓名" />
</div>
<div class="field">
<label>年龄(选填)</label>
<input v-model="registerForm.age" type="number" placeholder="可选" min="0" max="120" />
</div>
<div class="field">
<label>读者类型</label>
<select v-model="registerForm.type">
<option>老年</option>
<option>成人</option>
<option>儿童</option>
</select>
</div>
<div class="field">
<label>联系方式</label>
<input v-model="registerForm.contact" type="text" placeholder="手机 / 邮箱" />
</div>
<div class="field">
<label>注册日期</label>
<input v-model="registerForm.regDate" type="date" />
</div>
</div>
<button @click="handleRegister">提交注册</button>
</div>
<!-- 员工登录视图 -->
<div v-else-if="currentView === 'employee-login'">
<h3>🔐 员工登录</h3>
<div class="compact-form">
<div class="field">
<label>员工工号</label>
<input v-model="employeeLogin.employeeCode" type="text" placeholder="员工工号" />
</div>
<div class="field">
<label>姓名</label>
<input v-model="employeeLogin.name" type="text" placeholder="姓名" />
</div>
</div>
<button @click="handleEmployeeLogin">登录</button>
<div class="note">经理页面另有添加用户功能</div>
</div>
</div>
<!-- 导航链接 -->
<div class="nav-links">
<span class="nav-link" @click="switchView('reader-login')" :class="{ 'active-nav': currentView === 'reader-login' }">🔑 读者登录</span>
<span class="nav-link" @click="switchView('reader-register')" :class="{ 'active-nav': currentView === 'reader-register' }"> 注册</span>
<span class="nav-link" @click="switchView('employee-login')" :class="{ 'active-nav': currentView === 'employee-login' }">👔 员工登录</span>
</div>
<div style="margin-top: 1.2rem; text-align: center; font-size:0.8rem; color:#abb9c9;">
点击上方标签切换功能
</div>
</div>
</div>
<script>
(function() {
const { createApp, ref } = Vue;
// 工具函数:获取今日日期字符串 yyyy-MM-dd
const getTodayString = () => {
const d = new Date();
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
// 工具函数:验证日期字符串是否符合 yyyy-MM-dd 格式
const isValidDate = (dateStr) => {
if (!dateStr) return false;
const regex = /^\d{4}-\d{2}-\d{2}$/;
if (!regex.test(dateStr)) return false;
const date = new Date(dateStr);
return !isNaN(date.getTime());
};
const app = createApp({
setup() {
const currentView = ref('reader-login');
// 读者登录数据
const readerLogin = ref({
cardNumber: '',
name: ''
});
// 员工登录数据
const employeeLogin = ref({
employeeCode: '',
name: ''
});
// 注册表单默认值
const getDefaultRegisterForm = () => ({
cardNumber: '',
name: '',
age: '',
type: '成人',
contact: '',
regDate: getTodayString()
});
const registerForm = ref(getDefaultRegisterForm());
// 切换视图时重置数据
const switchView = (view) => {
currentView.value = view;
if (view === 'reader-register') {
registerForm.value = getDefaultRegisterForm();
} else if (view === 'reader-login') {
readerLogin.value = { cardNumber: '', name: '' };
} else if (view === 'employee-login') {
employeeLogin.value = { employeeCode: '', name: '' };
}
};
// 读者登录
const handleReaderLogin = async () => {
if (!readerLogin.value.cardNumber || !readerLogin.value.name) {
alert('请填写证号和姓名');
return;
}
const params = new URLSearchParams({
cardNumber: readerLogin.value.cardNumber,
name: readerLogin.value.name
});
try {
const response = await fetch('${pageContext.request.contextPath}/api/login/reader', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: params
});
const result = await response.json();
if (result.success) {
window.location.href = '${pageContext.request.contextPath}/view/Reader.jsp';
} else {
alert(result.message || '登录失败');
}
} catch (e) {
console.error(e);
alert('网络错误,请检查后端服务是否正常');
}
};
// 读者注册
const handleRegister = async () => {
// 前端基础校验
if (!registerForm.value.cardNumber) {
alert('证号不能为空');
return;
}
if (!registerForm.value.name) {
alert('姓名不能为空');
return;
}
// 年龄如果是空字符串或非数字设为空后端会处理为null
let ageVal = registerForm.value.age;
if (ageVal !== '' && isNaN(Number(ageVal))) {
alert('年龄请输入数字');
return;
}
// 日期处理:如果无效或为空,使用今天日期
let regDateVal = registerForm.value.regDate;
if (!isValidDate(regDateVal)) {
regDateVal = getTodayString();
registerForm.value.regDate = regDateVal; // 同步更新显示
}
const params = new URLSearchParams({
cardNumber: registerForm.value.cardNumber,
name: registerForm.value.name,
age: ageVal,
type: registerForm.value.type,
contact: registerForm.value.contact || '',
regDate: regDateVal
});
try {
const response = await fetch('${pageContext.request.contextPath}/api/register', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: params
});
const result = await response.json();
if (result.success) {
alert('注册成功,请登录');
switchView('reader-login');
} else {
alert(result.message || '注册失败');
}
} catch (e) {
console.error(e);
alert('网络错误,请检查后端服务是否正常');
}
};
// 员工登录
const handleEmployeeLogin = async () => {
if (!employeeLogin.value.employeeCode || !employeeLogin.value.name) {
alert('请填写工号和姓名');
return;
}
const params = new URLSearchParams({
employeeCode: employeeLogin.value.employeeCode,
name: employeeLogin.value.name
});
try {
const response = await fetch('${pageContext.request.contextPath}/api/login/employee', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: params
});
const result = await response.json();
if (result.success) {
window.location.href = '${pageContext.request.contextPath}/view/Work.jsp';
} else {
alert(result.message || '登录失败');
}
} catch (e) {
console.error(e);
alert('网络错误,请检查后端服务是否正常');
}
};
return {
currentView,
readerLogin,
employeeLogin,
registerForm,
switchView,
handleReaderLogin,
handleRegister,
handleEmployeeLogin
};
}
});
app.mount('#app');
})();
</script>
</body>
</html>