Initial certificate system
This commit is contained in:
19
backend/app/models/__init__.py
Normal file
19
backend/app/models/__init__.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from app.models.admin import AdminUser, Role
|
||||
from app.models.certificate import Certificate, CertificateAccessToken, ProjectCourse
|
||||
from app.models.import_batch import ImportBatch, ImportBatchRow
|
||||
from app.models.learner import Learner, LearnerNameHistory, LearnerPhoneHistory
|
||||
from app.models.log import OperationLog
|
||||
|
||||
__all__ = [
|
||||
"AdminUser",
|
||||
"Certificate",
|
||||
"CertificateAccessToken",
|
||||
"ImportBatch",
|
||||
"ImportBatchRow",
|
||||
"Learner",
|
||||
"LearnerNameHistory",
|
||||
"LearnerPhoneHistory",
|
||||
"OperationLog",
|
||||
"ProjectCourse",
|
||||
"Role",
|
||||
]
|
||||
27
backend/app/models/admin.py
Normal file
27
backend/app/models/admin.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class Role(Base):
|
||||
__tablename__ = "roles"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
code: Mapped[str] = mapped_column(String(64), unique=True, index=True)
|
||||
name: Mapped[str] = mapped_column(String(64))
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
|
||||
|
||||
class AdminUser(Base):
|
||||
__tablename__ = "admin_users"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
username: Mapped[str] = mapped_column(String(64), unique=True, index=True)
|
||||
password_hash: Mapped[str] = mapped_column(String(255))
|
||||
role_code: Mapped[str] = mapped_column(String(64), index=True)
|
||||
status: Mapped[str] = mapped_column(String(32), default="active")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
59
backend/app/models/certificate.py
Normal file
59
backend/app/models/certificate.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from datetime import date, datetime
|
||||
|
||||
from sqlalchemy import Date, DateTime, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class ProjectCourse(Base):
|
||||
__tablename__ = "project_courses"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
code: Mapped[str] = mapped_column(String(16), unique=True, index=True)
|
||||
name: Mapped[str] = mapped_column(String(128))
|
||||
default_certificate_name: Mapped[str] = mapped_column(String(128), default="培训结业证书")
|
||||
default_course_name: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
||||
default_stage_name: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
||||
default_issuer_name: Mapped[str] = mapped_column(String(128), default="本公司")
|
||||
status: Mapped[str] = mapped_column(String(32), default="active")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
|
||||
class Certificate(Base):
|
||||
__tablename__ = "certificates"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
learner_id: Mapped[int] = mapped_column(index=True)
|
||||
project_code: Mapped[str] = mapped_column(String(16), index=True)
|
||||
certificate_no: Mapped[str] = mapped_column(String(64), unique=True, index=True)
|
||||
certificate_name: Mapped[str] = mapped_column(String(128))
|
||||
class_name: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
||||
course_name: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
||||
stage_name: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
||||
issue_date: Mapped[date] = mapped_column(Date)
|
||||
issuer_name: Mapped[str] = mapped_column(String(128))
|
||||
status: Mapped[str] = mapped_column(String(32), default="valid")
|
||||
pdf_status: Mapped[str] = mapped_column(String(32), default="not_generated")
|
||||
pdf_file_path: Mapped[str | None] = mapped_column(String(512), nullable=True)
|
||||
public_token_id: Mapped[int | None] = mapped_column(nullable=True)
|
||||
qr_token_id: Mapped[int | None] = mapped_column(nullable=True)
|
||||
remark: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
|
||||
class CertificateAccessToken(Base):
|
||||
__tablename__ = "certificate_access_tokens"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
certificate_id: Mapped[int] = mapped_column(index=True)
|
||||
token_hash: Mapped[str] = mapped_column(String(128), unique=True, index=True)
|
||||
token_value: Mapped[str] = mapped_column(String(128), unique=True, index=True)
|
||||
token_type: Mapped[str] = mapped_column(String(32))
|
||||
status: Mapped[str] = mapped_column(String(32), default="active")
|
||||
created_reason: Mapped[str] = mapped_column(String(128), default="initial")
|
||||
revoked_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
last_access_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
35
backend/app/models/import_batch.py
Normal file
35
backend/app/models/import_batch.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, Integer, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class ImportBatch(Base):
|
||||
__tablename__ = "import_batches"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
filename: Mapped[str] = mapped_column(String(255))
|
||||
file_path: Mapped[str] = mapped_column(String(512))
|
||||
status: Mapped[str] = mapped_column(String(32), default="uploaded")
|
||||
total_rows: Mapped[int] = mapped_column(Integer, default=0)
|
||||
valid_rows: Mapped[int] = mapped_column(Integer, default=0)
|
||||
failed_rows: Mapped[int] = mapped_column(Integer, default=0)
|
||||
conflict_rows: Mapped[int] = mapped_column(Integer, default=0)
|
||||
error_report_path: Mapped[str | None] = mapped_column(String(512), nullable=True)
|
||||
created_by: Mapped[int | None] = mapped_column(nullable=True, index=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
|
||||
class ImportBatchRow(Base):
|
||||
__tablename__ = "import_batch_rows"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
batch_id: Mapped[int] = mapped_column(index=True)
|
||||
row_no: Mapped[int] = mapped_column(Integer)
|
||||
status: Mapped[str] = mapped_column(String(32))
|
||||
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
raw_json: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
44
backend/app/models/learner.py
Normal file
44
backend/app/models/learner.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class Learner(Base):
|
||||
__tablename__ = "learners"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
phone: Mapped[str] = mapped_column(String(32), unique=True, index=True)
|
||||
current_name: Mapped[str] = mapped_column(String(64), index=True)
|
||||
id_type: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
||||
id_no_encrypted: Mapped[str | None] = mapped_column(String(256), nullable=True)
|
||||
id_no_masked: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
student_no: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
status: Mapped[str] = mapped_column(String(32), default="active")
|
||||
remark: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
|
||||
class LearnerNameHistory(Base):
|
||||
__tablename__ = "learner_name_histories"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
learner_id: Mapped[int] = mapped_column(index=True)
|
||||
name: Mapped[str] = mapped_column(String(64))
|
||||
source: Mapped[str] = mapped_column(String(64), default="import")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
|
||||
|
||||
class LearnerPhoneHistory(Base):
|
||||
__tablename__ = "learner_phone_histories"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
learner_id: Mapped[int] = mapped_column(index=True)
|
||||
old_phone: Mapped[str] = mapped_column(String(32))
|
||||
new_phone: Mapped[str] = mapped_column(String(32))
|
||||
reason: Mapped[str] = mapped_column(String(255))
|
||||
changed_by: Mapped[int | None] = mapped_column(nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
19
backend/app/models/log.py
Normal file
19
backend/app/models/log.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class OperationLog(Base):
|
||||
__tablename__ = "operation_logs"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
admin_user_id: Mapped[int | None] = mapped_column(nullable=True, index=True)
|
||||
action: Mapped[str] = mapped_column(String(64), index=True)
|
||||
object_type: Mapped[str] = mapped_column(String(64), index=True)
|
||||
object_id: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
ip_address: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
detail_json: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
Reference in New Issue
Block a user