Files
LM/classes/artifacts/LM_Web_exploded/view/Login.jsp

448 lines
16 KiB
Plaintext
Raw Normal View History

2026-04-08 10:56:37 +08:00
<%@ 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>