还是之前做的那个网页,https://ask.csdn.net/questions/8633740
想再做一些修改,原本的网页上,添加新记录是在最顶部,而且没有修改旧记录的功能。
我想把新增和修改两个功能从主页面中独立出来,用模态窗口做合适吗?因为新增和修改时还要选择员工,也是模态窗口,两层嵌套,是不是不太好?
还是用单独的网页来实现? 是否可以同一个网页复用?因为里面控件是相同的。如果用单独网页的话,希望做到用户在网址中直接输入新增和修改网页的网址时不能直接访问,只能通过请休假页面中的新增和修改按钮点击进入。
这是现在网页打开的效果图:

package.json文件内容
{
"name": "leave-test1",
"version": "1.0.0",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"body-parser": "^2.2.0",
"connect-flash": "^0.1.1",
"dotenv": "^17.2.1",
"ejs": "^3.1.10",
"express": "^5.1.0",
"express-session": "^1.18.2",
"mssql": "^11.0.1"
}
}
env文件内容
DB_USER=sa
DB_PASSWORD=password
DB_SERVER=192.168.1.4
DB_NAME=Database
app.js 文件内容
const express = require('express');
const bodyParser = require('body-parser');
const session = require('express-session');
const flash = require('connect-flash');
const sql = require('mssql');
const path = require('path');
const { log } = require('console');
require('dotenv').config();
const app = express();
const PORT = process.env.PORT || 3000;
// 数据库配置
const dbConfig = {
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
server: process.env.DB_SERVER,
database: process.env.DB_NAME,
options: {
encrypt: false,//true时为https 加密访问,mssql不支持
trustServerCertificate: true,
port:1433
}
};
// 中间件
app.use(bodyParser.urlencoded({ extended: true }));
app.use(session({
secret: 'leave-system-secret',
resave: false,
saveUninitialized: true
}));
app.use(flash());
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.use(express.static(path.join(__dirname, 'public')));
// 路由 - 查询请假记录
app.get('/', async (req, res) => {
try {
const pool = await sql.connect(dbConfig);
const result = await pool.request()
.query('SELECT * FROM LeaveApplications ORDER BY StartDate DESC');
res.render('leave', {
leaves: result.recordset,
messages: req.flash()
});
} catch (err) {
console.error("数据库连接或者查询错误",err);
req.flash('error', '查询请假记录失败');
res.render('leave', { leaves: [], messages: req.flash() });
}
});
// 路由 - 新增请假记录
app.post('/leave', async (req, res) => {
const { employeeName, leaveType, startDate, endDate, reason } = req.body;
try {
const pool = await sql.connect(dbConfig);
await pool.request()
.input('employeeName', sql.NVarChar, employeeName)
.input('leaveType', sql.NVarChar, leaveType)
.input('startDate', sql.Date, startDate)
.input('endDate', sql.Date, endDate)
.input('reason', sql.NVarChar, reason)
.query(`INSERT INTO LeaveApplications
(EmployeeName, LeaveType, StartDate, EndDate, Reason)
VALUES (@employeeName, @leaveType, @startDate, @endDate, @reason)`);
req.flash('success', '请假申请提交成功');
} catch (err) {
req.flash('error', '提交请假申请失败');
} finally {
res.redirect('/');
}
});
// 路由 - 条件查询请假记录
app.get('/search', async (req, res) => {
const { employeeName, leaveType, startDate } = req.query;
try {
const pool = await sql.connect(dbConfig);
let query = 'SELECT * FROM LeaveApplications WHERE 1=1';
const request = pool.request();
if (employeeName) {
query += ' AND EmployeeName LIKE @employeeName';
request.input('employeeName', sql.NVarChar, `%${employeeName}%`);
}
if (leaveType) {
query += ' AND LeaveType = @leaveType';
request.input('leaveType', sql.NVarChar, leaveType);
}
if (startDate) {
query += ' AND StartDate >= @startDate';
request.input('startDate', sql.Date, startDate);
}
query += ' ORDER BY StartDate DESC';
const result = await request.query(query);
res.render('index', {
leaves: result.recordset,
messages: req.flash()
});
} catch (err) {
console.error('查询错误:', err);
req.flash('error', '查询请假记录失败: ' + err.message);
res.render('leave', { leaves: [], messages: req.flash() });
}
});
// 添加员工查询API
app.get('/api/employees', async (req, res) => {
const { q } = req.query;
try {
const pool = await sql.connect(dbConfig);
const result = await pool.request()
.input('keyword', sql.NVarChar, `%${q}%`)
.query(`
select EmployeeNumber, EmployeeName, EmployeeID, EmployeeDept, EmployeePosition
from LeaveApplications
where EmployeeName LIKE @keyword OR EmployeeNumber LIKE @keyword
`);
//LIMIT 50
res.json(result.recordset);
} catch (err) {
console.error('员工查询错误:', err);
res.status(500).json({ error: '查询失败' });
}
});
// 打开模态框
function openSearchModal() {
document.getElementById('searchModal').style.display = 'block';
}
// 关闭模态框
function closeSearchModal() {
document.getElementById('searchModal').style.display = 'none';
}
// 查询员工
async function searchEmployees() {
const keyword = document.getElementById('searchInput').value;
if (!keyword) {
alert('请输入查询关键词');
return;
}
try {
const response = await fetch(`/api/employees?q=${encodeURIComponent(keyword)}`);
const employees = await response.json();
const resultsTable = document.getElementById('searchResults');
resultsTable.innerHTML = '';
employees.forEach(emp => {
const row = document.createElement('tr');
row.className = 'hover:bg-gray-50';
row.innerHTML = `
<td class="px-6 py-4 whitespace-nowrap">${emp.EmployeeName}</td>
<td class="px-6 py-4 whitespace-nowrap">${emp.EmployeeNumber}</td>
<td class="px-6 py-4 whitespace-nowrap">${emp.EmployeeDept}</td>
<td class="px-6 py-4 whitespace-nowrap">${emp.EmployeePosition}</td>
<td class="px-6 py-4 whitespace-nowrap">
<button onclick="selectEmployee('${emp.EmployeeName}', '${emp.EmployeeNumber}', '${emp.EmployeeID}', '${emp.EmployeeDept}', '${emp.EmployeePosition}')"
class="text-blue-500 hover:text-blue-700">选择</button>
</td>
`;
resultsTable.appendChild(row);
});
} catch (error) {
console.error('查询失败:', error);
alert('查询失败,请稍后重试');
}
}
// 选择员工
function selectEmployee(name, number, id, department, position) {
document.getElementById('employeeName').value = name;
document.getElementById('employeeName').dataset.id = id;
console.log('id is :' + id);
document.querySelector('input[name="employeeNumber"]').value = number;
document.querySelector('input[name="employeeDept"]').value = department;
document.querySelector('input[name="employeePosition"]').value = position;
closeSearchModal();
}
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});