构建高效档案整理系统:从零到一的技术实现指南

系统架构与核心技术选型

一个完整的档案整理系统通常由前端界面、后端服务、数据库和文件存储四个核心部分组成。对于中小型项目,推荐采用前后端分离的架构,这能保证系统的可维护性和扩展性。

技术栈选择

后端建议使用Python的Django框架,它自带强大的Admin管理后台和ORM,能快速处理档案的增删改查。数据库使用PostgreSQL,它对全文搜索和JSON字段的支持优于MySQL。前端使用Vue.js 3组合式API,配合Element Plus组件库,能快速搭建用户界面。文件存储使用MinIO,它是一个与Amazon S3 API兼容的开源对象存储服务,可以轻松部署在本地服务器。

环境准备

在开始之前,请确保你的开发环境已安装以下软件:

  • Python 3.9或更高版本
  • Node.js 18.x LTS版本
  • PostgreSQL 14或更高版本
  • Docker与Docker Compose(用于部署MinIO)

使用以下命令检查安装:

python --version
node --version
psql --version
docker --version

后端服务搭建

首先创建项目目录并初始化Python虚拟环境。

mkdir archive_system && cd archive_system
python -m venv venv
Windows系统激活命令:
venv\Scripts\activate
Linux/Mac系统激活命令:
source venv/bin/activate

安装依赖与创建Django项目

安装必要的Python包并创建Django项目和应用。

pip install django django-rest-framework psycopg2-binary python-dotenv
django-admin startproject backend .
python manage.py startapp archives

编辑backend/settings.py文件,配置数据库连接和基础设置。首先在项目根目录创建.env文件,用于存储敏感信息:

SECRET_KEY=your-django-secret-key-here
DB_NAME=archive_db
DB_USER=archive_user
DB_PASSWORD=your_secure_password
DB_HOST=localhost
DB_PORT=5432

然后在settings.py中读取这些配置:

import os
from dotenv import load_dotenv
load_dotenv()
SECRET_KEY = os.getenv('SECRET_KEY')
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.getenv('DB_NAME'),
'USER': os.getenv('DB_USER'),
'PASSWORD': os.getenv('DB_PASSWORD'),
'HOST': os.getenv('DB_HOST'),
'PORT': os.getenv('DB_PORT'),
}
}
INSTALLED_APPS = [
...,
'rest_framework',
'archives',
]
文件上传设置
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
设置允许上传的文件类型和大小
FILE_UPLOAD_MAX_MEMORY_SIZE = 10485760   10MB
DATA_UPLOAD_MAX_MEMORY_SIZE = 10485760

定义数据模型

archives/models.py中定义档案的核心数据模型。

构建高效档案整理系统:从零到一的技术实现指南

from django.db import models
from django.contrib.auth.models import User
class ArchiveCategory(models.Model):
"""档案分类"""
name = models.CharField(max_length=100, unique=True)
code = models.CharField(max_length=20, unique=True)
description = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['code']
def __str__(self):
return f"{self.code} - {self.name}"
class ArchiveItem(models.Model):
"""档案条目"""
STATUS_CHOICES = [
('draft', '草稿'),
('active', '有效'),
('archived', '已归档'),
('destroyed', '已销毁'),
]
title = models.CharField(max_length=200)
archive_number = models.CharField(max_length=50, unique=True)
category = models.ForeignKey(ArchiveCategory, on_delete=models.PROTECT)
content = models.TextField()
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft')
created_by = models.ForeignKey(User, on_delete=models.PROTECT, related_name='created_archives')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
retention_years = models.IntegerField(default=10)
class Meta:
indexes = [
models.Index(fields=['archive_number']),
models.Index(fields=['status']),
models.Index(fields=['created_at']),
]
def __str__(self):
return self.archive_number
class ArchiveAttachment(models.Model):
"""档案附件"""
archive_item = models.ForeignKey(ArchiveItem, on_delete=models.CASCADE, related_name='attachments')
file = models.FileField(upload_to='archive_attachments/%Y/%m/%d/')
original_filename = models.CharField(max_length=255)
file_size = models.IntegerField()
uploaded_at = models.DateTimeField(auto_now_add=True)
def save(self, args, kwargs):
if not self.original_filename:
self.original_filename = self.file.name
self.file_size = self.file.size
super().save(args, kwargs)

创建并应用数据库迁移:

python manage.py makemigrations
python manage.py migrate

创建序列化器与API视图

archives目录下创建serializers.py

from rest_framework import serializers
from .models import ArchiveCategory, ArchiveItem, ArchiveAttachment
class ArchiveCategorySerializer(serializers.ModelSerializer):
class Meta:
model = ArchiveCategory
fields = '__all__'
class ArchiveAttachmentSerializer(serializers.ModelSerializer):
class Meta:
model = ArchiveAttachment
fields = ['id', 'original_filename', 'file_size', 'uploaded_at']
class ArchiveItemSerializer(serializers.ModelSerializer):
category_name = serializers.CharField(source='category.name', read_only=True)
attachments = ArchiveAttachmentSerializer(many=True, read_only=True)
class Meta:
model = ArchiveItem
fields = '__all__'
read_only_fields = ['created_by', 'created_at', 'updated_at']

创建views.py

from rest_framework import viewsets, permissions, filters
from rest_framework.decorators import action
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend
from .models import ArchiveCategory, ArchiveItem
from .serializers import ArchiveCategorySerializer, ArchiveItemSerializer
class ArchiveCategoryViewSet(viewsets.ModelViewSet):
queryset = ArchiveCategory.objects.all()
serializer_class = ArchiveCategorySerializer
permission_classes = [permissions.IsAuthenticated]
filter_backends = [filters.SearchFilter]
search_fields = ['name', 'code']
class ArchiveItemViewSet(viewsets.ModelViewSet):
queryset = ArchiveItem.objects.all()
serializer_class = ArchiveItemSerializer
permission_classes = [permissions.IsAuthenticated]
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_fields = ['category', 'status']
search_fields = ['title', 'archive_number', 'content']
ordering_fields = ['created_at', 'updated_at']
def perform_create(self, serializer):
serializer.save(created_by=self.request.user)
@action(detail=True, methods=['post'])
def change_status(self, request, pk=None):
item = self.get_object()
new_status = request.data.get('status')
if new_status in dict(ArchiveItem.STATUS_CHOICES):
item.status = new_status
item.save()
return Response({'status': 'success'})
return Response({'error': 'Invalid status'}, status=400)

配置URL路由,在archives/urls.py中:

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from . import views
router = DefaultRouter()
router.register(r'categories', views.ArchiveCategoryViewSet)
router.register(r'items', views.ArchiveItemViewSet)
urlpatterns = [
path('', include(router.urls)),
]

在项目主urls.py中包含此路由:

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('archives.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

前端界面开发

在项目根目录创建前端应用。

cd ..
npx vue create frontend --no-git
选择手动配置,勾选:Router, Vuex, CSS Pre-processors (Sass/SCSS)
cd frontend
npm install element-plus axios vue-axios

配置Axios与API服务

创建src/services/api.js

import axios from 'axios'
const apiClient = axios.create({
baseURL: 'http://localhost:8000/api/',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
}
})
// 请求拦截器,添加认证token
apiClient.interceptors.request.use(
config => {
const token = localStorage.getItem('auth_token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
error => {
return Promise.reject(error)
}
)
export default {
// 档案分类相关
getCategories() {
return apiClient.get('/categories/')
},
createCategory(data) {
return apiClient.post('/categories/', data)
},
// 档案条目相关
getArchiveItems(params) {
return apiClient.get('/items/', { params })
},
getArchiveItem(id) {
return apiClient.get(`/items/${id}/`)
},
createArchiveItem(data) {
return apiClient.post('/items/', data)
},
updateArchiveItem(id, data) {
return apiClient.put(`/items/${id}/`, data)
},
deleteArchiveItem(id) {
return apiClient.delete(`/items/${id}/`)
},
changeItemStatus(id, status) {
return apiClient.post(`/items/${id}/change_status/`, { status })
}
}

创建档案管理组件

创建src/views/ArchiveList.vue



文件存储服务部署

使用Docker Compose部署MinIO对象存储服务。创建docker-compose.yml

version: '3.8'
services:
minio:
image: minio/minio:latest
container_name: archive_minio
ports:
- "9000:9000"   API端口
- "9001:9001"   控制台端口
environment:
MINIO_ROOT_USER: archiveadmin
MINIO_ROOT_PASSWORD: your_minio_password_here            
AI咨询
热线电话

028-85154420

15388110056

全国售前咨询电话

扫码咨询
安答联动微信公众号二维码

微信扫码关注安答联动

申请试用
热线电话
申请试用

安答联动档案管理系统