feat: 新增员工行为画像算法与费用风险标签体系
后端新增员工行为画像算法模块,支持标签规则引擎和评分计算, 完善员工模型、银行信息、序列化和导入逻辑,优化报销审批流 和工作流常量,增强 Hermes 同步和知识同步能力,前端新增费 用画像详情弹窗、雷达图和风险卡片组件,完善登录页和工作台 样式,优化文档中心和归档中心交互,补充单元测试。
This commit is contained in:
@@ -5,6 +5,7 @@ from app.models.approval import ApprovalRecord
|
||||
from app.models.audit_log import AuditLog
|
||||
from app.models.budget import BudgetAllocation, BudgetReservation, BudgetTransaction
|
||||
from app.models.employee_change_log import EmployeeChangeLog
|
||||
from app.models.employee_behavior_profile import EmployeeBehaviorProfileSnapshot
|
||||
from app.models.employee import Employee
|
||||
from app.models.financial_record import (
|
||||
AccountsPayableRecord,
|
||||
@@ -37,6 +38,7 @@ __all__ = [
|
||||
"BudgetReservation",
|
||||
"BudgetTransaction",
|
||||
"Employee",
|
||||
"EmployeeBehaviorProfileSnapshot",
|
||||
"EmployeeChangeLog",
|
||||
"ExpenseClaim",
|
||||
"ExpenseClaimItem",
|
||||
|
||||
@@ -32,6 +32,9 @@ class Employee(Base):
|
||||
grade: Mapped[str] = mapped_column(String(20), default="P3", index=True)
|
||||
cost_center: Mapped[str | None] = mapped_column(String(50), nullable=True)
|
||||
finance_owner_name: Mapped[str | None] = mapped_column(String(100), nullable=True)
|
||||
bank_name: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
||||
bank_account_no: Mapped[str | None] = mapped_column(String(80), nullable=True)
|
||||
bank_account_name: Mapped[str | None] = mapped_column(String(100), nullable=True)
|
||||
password_hash: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
||||
employment_status: Mapped[str] = mapped_column(String(30), default="在职", index=True)
|
||||
sync_state: Mapped[str] = mapped_column(String(30), default="已同步")
|
||||
|
||||
62
server/src/app/models/employee_behavior_profile.py
Normal file
62
server/src/app/models/employee_behavior_profile.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, Index, Integer, String, func
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.types import JSON
|
||||
|
||||
from app.db.base_class import Base
|
||||
|
||||
|
||||
class EmployeeBehaviorProfileSnapshot(Base):
|
||||
__tablename__ = "employee_behavior_profile_snapshots"
|
||||
__table_args__ = (
|
||||
Index(
|
||||
"ix_employee_behavior_profile_latest",
|
||||
"subject_id",
|
||||
"profile_type",
|
||||
"window_days",
|
||||
"expense_type_scope",
|
||||
"calculated_at",
|
||||
),
|
||||
)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
|
||||
subject_type: Mapped[str] = mapped_column(String(30), default="employee", index=True)
|
||||
subject_id: Mapped[str] = mapped_column(String(100), index=True)
|
||||
subject_name: Mapped[str] = mapped_column(String(100), index=True)
|
||||
department_id: Mapped[str | None] = mapped_column(String(100), nullable=True, index=True)
|
||||
department_name: Mapped[str | None] = mapped_column(String(100), nullable=True, index=True)
|
||||
position: Mapped[str | None] = mapped_column(String(100), nullable=True)
|
||||
grade: Mapped[str | None] = mapped_column(String(30), nullable=True, index=True)
|
||||
|
||||
profile_type: Mapped[str] = mapped_column(String(50), index=True)
|
||||
window_days: Mapped[int] = mapped_column(Integer, index=True)
|
||||
expense_type_scope: Mapped[str] = mapped_column(String(50), default="overall", index=True)
|
||||
peer_group_key: Mapped[str] = mapped_column(String(255), default="")
|
||||
peer_group_fallback_level: Mapped[int] = mapped_column(Integer, default=0)
|
||||
|
||||
profile_score: Mapped[int] = mapped_column(Integer, default=0)
|
||||
profile_level: Mapped[str] = mapped_column(String(30), default="normal", index=True)
|
||||
metrics_json: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict)
|
||||
basis_codes_json: Mapped[list[Any]] = mapped_column(JSON, default=list)
|
||||
source_task_type: Mapped[str] = mapped_column(
|
||||
String(80), default="employee_behavior_profile_scan"
|
||||
)
|
||||
source_task_log_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("hermes_task_execution_logs.id"),
|
||||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
algorithm_version: Mapped[str] = mapped_column(
|
||||
String(80), default="employee_behavior_profile.v1"
|
||||
)
|
||||
calculated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), index=True
|
||||
)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
source_task_log = relationship("HermesTaskExecutionLog")
|
||||
Reference in New Issue
Block a user