网站首页/ 信息中心/ 档案百科/

面向中小微企业IT 从零搭建含托管资质合规验证模块的档案软件实操指南

发布时间:2026年09月02日 15:35:28 浏览量:0

一、前置准备清单

本指南基于轻量级Node.js+MongoDB技术栈,无需专业服务器维护,普通Windows/Mac/Linux电脑均可部署,前置条件严格按顺序确认:

1.1 验证环境是否就绪

打开终端(Windows用CMD/PowerShell,Mac/Linux用Terminal),依次输入以下命令,看到对应版本号即成功:

``` node -v 输出示例:v18.20.4 npm -v 输出示例:10.7.0 mongod --version 输出示例:db version v6.0.18 ```

二、项目初始化与核心依赖安装

所有代码/配置可直接复制,需确保路径一致。

2.1 初始化npm项目

输入命令,所有提示直接回车跳过(使用默认配置):

``` npm init -y ```

2.2 安装核心依赖

复制以下命令一次性安装:

``` npm install express mongoose ejs express-session bcryptjs multer pdfkit ```

三、数据库与配置文件编写

3.1 MongoDB数据库初始化

打开MongoDB Compass(安装MongoDB 6.x默认附带),默认连接地址为mongodb://localhost:27017,新建数据库archive_db,新建集合usersarchivesqualification_checks,无需手动添加数据。

3.2 编写完整项目配置

在项目根目录新建config.js,复制以下完整内容:

```javascript module.exports = { // MongoDB连接地址,无账号密码的本地测试环境直接使用 mongoURI: 'mongodb://localhost:27017/archive_db', // session加密密钥(托管资质申请时需替换为复杂密钥,不少于16位) sessionSecret: 'archive_qualification_demo_secret_2024', // 符合DA/T 31.1-2023的文件大小限制(单文件≤500MB,压缩包≤2GB) fileSizeLimit: 500 1024 1024, // 允许上传的档案文件格式 allowedFileTypes: /pdf|jpg|jpeg|tif|tiff/, // 合规报告生成路径(托管资质申请时可指定本地打印路径或NAS路径) reportPath: './reports' }; ```

3.3 确保合规报告目录存在

面向中小微企业IT 从零搭建含托管资质合规验证模块的档案软件实操指南

在项目根目录新建uploadsreports两个空文件夹,uploads用于临时存储上传的档案文件,reports用于存储生成的合规验证报告。

四、三级权限控制与托管资质验证核心逻辑

在项目根目录新建app.js,这是整个项目的入口文件,包含所有核心功能,可直接复制:

```javascript const express = require('express'); const mongoose = require('mongoose'); const ejs = require('ejs'); const session = require('express-session'); const bcrypt = require('bcryptjs'); const multer = require('multer'); const PDFDocument = require('pdfkit'); const fs = require('fs'); const path = require('path'); const config = require('./config'); const app = express(); const PORT = 3000; // 连接MongoDB mongoose.connect(config.mongoURI) .then(() => console.log('MongoDB连接成功')) .catch(err => console.error('MongoDB连接失败:', err)); // 配置模板引擎 app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, 'views')); // 配置中间件 app.use(express.urlencoded({ extended: true })); app.use(express.static(path.join(__dirname, 'public'))); app.use(session({ secret: config.sessionSecret, resave: false, saveUninitialized: false, cookie: { maxAge: 3600000 8 } // session有效期8小时,符合档案管理安全要求 })); // 配置multer文件上传 const storage = multer.diskStorage({ destination: (req, file, cb) => cb(null, './uploads'), filename: (req, file, cb) => { // 文件名格式:档案类型-档案编号-当前时间戳.后缀 const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() 1E9); cb(null, req.body.archiveType + '-' + req.body.archiveNo + '-' + uniqueSuffix + path.extname(file.originalname)); } }); const upload = multer({ storage: storage, limits: { fileSize: config.fileSizeLimit }, fileFilter: (req, file, cb) => { const extname = config.allowedFileTypes.test(path.extname(file.originalname).toLowerCase()); if (extname) return cb(null, true); cb(new Error('仅允许上传PDF/JPG/TIFF格式的档案文件')); } }); // 定义用户模型(三级权限:admin=系统管理员,input=档案录入员,read=档案查阅员) const UserSchema = new mongoose.Schema({ username: { type: String, required: true, unique: true }, password: { type: String, required: true }, role: { type: String, required: true, enum: ['admin', 'input', 'read'] } }); const User = mongoose.model('User', UserSchema); // 定义档案模型 const ArchiveSchema = new mongoose.Schema({ archiveType: { type: String, required: true }, archiveNo: { type: String, required: true, unique: true }, title: { type: String, required: true }, creator: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }, uploadTime: { type: Date, default: Date.now }, filePath: { type: String, required: true } }); const Archive = mongoose.model('Archive', ArchiveSchema); // 初始化默认系统管理员(首次运行后可删除/修改密码) const initAdmin = async () => { try { const existingAdmin = await User.findOne({ role: 'admin' }); if (!existingAdmin) { const hashedPassword = await bcrypt.hash('admin123456', 10); const newAdmin = new User({ username: 'admin', password: hashedPassword, role: 'admin' }); await newAdmin.save(); console.log('默认管理员创建成功:用户名admin,密码admin123456(请立即修改)'); } } catch (err) { console.error('初始化管理员失败:', err); } }; initAdmin(); // 托管资质前置验证逻辑 app.get('/qualification-check', async (req, res) => { // 仅系统管理员可访问 if (!req.session.user || req.session.user.role !== 'admin') return res.redirect('/login'); try { const users = await User.find(); const archives = await Archive.find().populate('creator'); let complianceScore = 0; let complianceItems = [ { name: '三级权限配置完成', passed: users.some(u => u.role === 'admin') && users.some(u => u.role === 'input') && users.some(u => u.role === 'read'), score: 30 }, { name: '用户密码加密存储', passed: true, score: 20 }, // bcryptjs已实现 { name: 'session有效期符合要求', passed: true, score: 20 }, // 已配置8小时 { name: '档案文件格式/大小限制', passed: true, score: 20 }, // multer已实现 { name: '至少上传1份测试档案', passed: archives.length > 0, score: 10 } ]; complianceItems.forEach(item => { if (item.passed) complianceScore += item.score; }); // 生成合规验证报告PDF const reportName = '资质前置验证-' + Date.now() + '.pdf'; const reportFullPath = path.join(config.reportPath, reportName); const doc = new PDFDocument(); doc.pipe(fs.createWriteStream(reportFullPath)); doc.fontSize(20).text('档案托管服务资质前置验证报告', { align: 'center' }); doc.moveDown(); doc.fontSize(14).text(`验证时间:${new Date().toLocaleString('zh-CN')}`); doc.text(`合规总分:${complianceScore}/100`); doc.moveDown(); doc.fontSize(12).text('验证明细:'); complianceItems.forEach(item => { doc.moveDown(); doc.text(`${item.name}:${item.passed ? '通过' : '未通过'}(${item.score}分)`); }); doc.end(); res.render('qualification-check', { user: req.session.user, complianceScore, complianceItems, reportName }); } catch (err) { console.error('资质验证失败:', err); res.status(500).send('资质验证失败,请稍后重试'); } }); // 其余登录、注册、档案上传查阅等基础功能代码(仅保留托管资质申请必须的) app.get('/', (req, res) => req.session.user ? res.redirect('/dashboard') : res.redirect('/login')); app.get('/login', (req, res) => res.render('login', { error: '' })); app.post('/login', async (req, res) => { try { const user = await User.findOne({ username: req.body.username }); if (!user || !await bcrypt.compare(req.body.password, user.password)) { return res.render('login', { error: '用户名或密码错误' }); } req.session.user = user; res.redirect('/dashboard'); } catch (err) { res.status(500).send('登录失败,请稍后重试'); } }); app.get('/logout', (req, res) => { req.session.destroy(); res.redirect('/login'); }); app.get('/dashboard', (req, res) => { if (!req.session.user) return res.redirect('/login'); res.render('dashboard', { user: req.session.user }); }); app.get('/add-user', (req, res) => { if (!req.session.user || req.session.user.role !== 'admin') return res.redirect('/login'); res.render('add-user', { user: req.session.user, error: '' }); }); app.post('/add-user', async (req, res) => { if (!req.session.user || req.session.user.role !== 'admin') return res.redirect('/login'); try { const hashedPassword = await bcrypt.hash(req.body.password, 10); const newUser = new User({ username: req.body.username, password: hashedPassword, role: req.body.role }); await newUser.save(); res.redirect('/dashboard'); } catch (err) { res.render('add-user', { user: req.session.user, error: '用户名已存在' }); } }); // 启动服务器 app.listen(PORT, () => console.log(`服务器启动成功,请访问 http://localhost:${PORT}`)); ```

五、前端模板编写

在项目根目录新建views文件夹,依次创建以下5个EJS模板:

5.1 login.ejs(登录页面)

复制以下内容:

```html 档案管理系统登录 档案管理系统登录

<%= error %>





```

5.2 dashboard.ejs(工作台)

复制以下内容:

```html 档案管理系统工作台 工作台(当前用户:<%= user.username %>,角色:<%= user.role === 'admin' ? '系统管理员' : user.role === 'input' ? '档案录入员' : '档案查阅员' %>) ```

5.3 add-user.ejs(添加用户页面)

复制以下内容:

```html 添加用户 添加用户

<%= error %>







返回工作台
```

5.4 qualification-check.ejs(资质验证页面)

复制以下内容:

```html 托管资质前置验证 托管资质前置验证

合规总分:<%= complianceScore %>/100

验证明细:

<% if
商标档案管理系统:别再让商标资产“睡大觉”了!
商标档案管理系统:别再让商标资产“睡大觉”了!
你有没有发现,很多公司花大价钱注册了一堆商标,结果呢?这些商标就像被扔进了仓库角落的旧文件,没人记得、没人维护,甚至快过期了都无人知晓。这事儿吧,说白了就是管理上的一笔“糊涂账”。
2026年09月02日 15:35:28
土木工程建筑业企业档案培训:实用干货全揭秘
土木工程建筑业企业档案培训:实用干货全揭秘
哎,各位土木届的搬砖人、包工头、资料员们,终于挖到个能救咱们半条命的宝贝了——今天要唠的就是跟咱们每天离不开的“工地隐形生命线”有关的【土木工程建筑业企业档案培训】!我可不是啥自媒体瞎忽悠,我是真踩过...
2026年09月02日 15:35:28
微信咨询
电话联系
QQ客服
微信咨询一对一服务
服务热线: 028-8744 4417
QQ客服: 2305721818