init: 数字员工平台初始代码

包含前端(Vue3 + VueFlow 画布)、后端(Go)、文档体系。
- 工作台画布:节点拖放、连线模式、右键菜单、AI 助手
- 后端:连接器 API、专员种子数据
- 导航:左侧导航、工坊、市场、控制台
This commit is contained in:
eaiadmin
2026-08-18 20:19:58 +08:00
commit 4e8817d768
239 changed files with 48631 additions and 0 deletions
@@ -0,0 +1,23 @@
package model
import "time"
// AiCallLog AI 调用日志(审计 + 按用户算力点计费)
// 精简自 pj034 ai_call_logs:去掉 company_id / input_asset / cost_cny / billing_mode 等电商与多租户字段。
type AiCallLog struct {
ID uint `gorm:"primaryKey" json:"id"`
UserID uint `gorm:"not null;index" json:"user_id"`
Capability string `gorm:"size:32;not null;index" json:"capability"` // ai_chat / text_gen / embed
Provider string `gorm:"size:32" json:"provider"`
RouteID string `gorm:"size:64" json:"route_id"`
Model string `gorm:"size:64" json:"model"`
TokensInput int `gorm:"default:0" json:"tokens_input"`
TokensOutput int `gorm:"default:0" json:"tokens_output"`
CreditsCharged int `gorm:"default:0" json:"credits_charged"` // 实扣点数(0 = 未扣)
Status string `gorm:"size:16;not null;index" json:"status"` // success / failed
ErrorMessage string `gorm:"size:512" json:"error_message,omitempty"`
LatencyMs int `gorm:"default:0" json:"latency_ms"`
CreatedAt time.Time `json:"created_at"`
}
func (AiCallLog) TableName() string { return "ai_call_log" }
@@ -0,0 +1,20 @@
package model
import "time"
// Certificate 考试合格证书:正式考试通过后自动颁发,供培训验收与留存。
// 每张证书对应一条正式考试记录(同一学员同一试卷仅一次正式考,故不会重复发证)。
type Certificate struct {
ID uint `gorm:"primaryKey" json:"id"`
UserID uint `gorm:"not null;index" json:"user_id"`
ExamRecordID uint `gorm:"not null;index" json:"exam_record_id"`
UserName string `gorm:"size:64;not null" json:"user_name"`
ExamName string `gorm:"size:128;not null" json:"exam_name"`
Score int `gorm:"not null" json:"score"`
TotalScore int `gorm:"not null" json:"total_score"`
PassScore int `gorm:"not null" json:"pass_score"`
CertNo string `gorm:"size:64;not null;uniqueIndex" json:"cert_no"`
IssuedAt time.Time `gorm:"not null" json:"issued_at"`
}
func (Certificate) TableName() string { return "certificate" }
@@ -0,0 +1,24 @@
package model
import "time"
// Course 课程表
type Course struct {
ID uint `gorm:"primaryKey" json:"id"`
Code string `gorm:"size:32;uniqueIndex;not null" json:"code"`
Name string `gorm:"size:128;not null" json:"name"`
Category string `gorm:"size:32;not null;index" json:"category"` // capital_script/qualification_logic/ai_public_course/ai_platform_matching
TargetCustomers string `gorm:"type:text" json:"target_customers"`
ForbiddenCustomers string `gorm:"type:text" json:"forbidden_customers"`
Scripts string `gorm:"type:text" json:"scripts"`
SalesProcess string `gorm:"type:text" json:"sales_process"`
ObjectionHandling string `gorm:"type:text" json:"objection_handling"`
DeliveryPitfalls string `gorm:"type:text" json:"delivery_pitfalls"`
ReportRules string `gorm:"type:text" json:"report_rules"`
RelatedProductID *uint `gorm:"index" json:"related_product_id"`
Status string `gorm:"size:16;not null;default:active;index" json:"status"` // active / inactive
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (Course) TableName() string { return "course" }
@@ -0,0 +1,16 @@
package model
import "time"
// Department 部门字典表:企业组织架构,供用户「部门」字段选择与按部门学情统计。
// 用户以 user.department 字符串归属(历史兼容),部门改名时后端同步该字符串。
type Department struct {
ID uint `gorm:"primaryKey" json:"id"`
Name string `gorm:"size:64;not null;uniqueIndex" json:"name"`
Description string `gorm:"size:255;default:''" json:"description"`
Status string `gorm:"size:16;not null;default:active;index" json:"status"` // active / inactive
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (Department) TableName() string { return "department" }
@@ -0,0 +1,22 @@
package model
import "time"
// ExamPaper 考试配置表
type ExamPaper struct {
ID uint `gorm:"primaryKey" json:"id"`
Name string `gorm:"size:128;not null" json:"name"`
Type string `gorm:"size:16;not null;index" json:"type"` // self_test / formal
Domain string `gorm:"size:64;not null" json:"domain"` // 抽题知识域,逗号分隔
QuestionCount int `gorm:"not null" json:"question_count"`
TotalScore int `gorm:"not null" json:"total_score"`
PassScore int `gorm:"not null" json:"pass_score"`
DurationMinutes int `gorm:"not null" json:"duration_minutes"`
Randomize bool `gorm:"not null" json:"randomize"`
PositionID *uint `gorm:"index" json:"position_id"` // 关联岗位考试,可空;设置后按岗位知识映射抽题
Status string `gorm:"size:16;not null;default:active;index" json:"status"` // active / inactive
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (ExamPaper) TableName() string { return "exam_paper" }
@@ -0,0 +1,21 @@
package model
import "time"
// ExamRecord 考试记录表
type ExamRecord struct {
ID uint `gorm:"primaryKey" json:"id"`
UserID uint `gorm:"not null;index" json:"user_id"`
PaperID uint `gorm:"not null;index" json:"paper_id"`
ExamName string `gorm:"size:128;not null" json:"exam_name"`
Score int `gorm:"not null" json:"score"`
TotalScore int `gorm:"not null" json:"total_score"`
PassScore int `gorm:"not null" json:"pass_score"`
Passed bool `gorm:"not null;index" json:"passed"`
CorrectCount int `gorm:"not null" json:"correct_count"`
WrongCount int `gorm:"not null" json:"wrong_count"`
DetailJSON string `gorm:"type:text;not null" json:"detail_json"` // 答题明细 JSON
SubmittedAt time.Time `gorm:"not null;index" json:"submitted_at"`
}
func (ExamRecord) TableName() string { return "exam_record" }
@@ -0,0 +1,17 @@
package model
import "time"
// KnowledgeChunk 知识块表(AI 检索最小单元)
type KnowledgeChunk struct {
ID uint `gorm:"primaryKey" json:"id"`
MediaFileID *uint `gorm:"index" json:"media_file_id"` // 与 knowledge_source_id 二选一
KnowledgeSourceID *uint `gorm:"index" json:"knowledge_source_id"` // 与 media_file_id 二选一
SourceType string `gorm:"size:32;not null" json:"source_type"` // pdf/doc/md
SourceID string `gorm:"size:64" json:"source_id"`
ChunkIndex int `gorm:"not null" json:"chunk_index"`
Content string `gorm:"type:text;not null" json:"content"`
CreatedAt time.Time `json:"created_at"`
}
func (KnowledgeChunk) TableName() string { return "knowledge_chunk" }
@@ -0,0 +1,22 @@
package model
import "time"
// KnowledgeSource 结构化知识源表
type KnowledgeSource struct {
ID uint `gorm:"primaryKey" json:"id"`
Title string `gorm:"size:256;not null" json:"title"`
FilePath string `gorm:"size:512;uniqueIndex;not null" json:"file_path"`
Category string `gorm:"size:64;not null;index" json:"category"` // general/capital_consulting/qualification_counseling/ai_consulting/ai_tools_platform
Domain string `gorm:"size:16;not null;default:product" json:"domain"` // company / product / sales
SourceVersion string `gorm:"size:32;not null" json:"source_version"`
AuditStatus string `gorm:"size:16;not null;default:pending;index" json:"audit_status"` // pending / approved / rejected
AuditBy *uint `json:"audit_by"`
AuditAt *time.Time `json:"audit_at"`
RejectReason string `gorm:"size:512" json:"reject_reason"`
Ingested bool `gorm:"not null;default:false" json:"ingested"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (KnowledgeSource) TableName() string { return "knowledge_source" }
@@ -0,0 +1,15 @@
package model
import "time"
// LearningProgress 学习进度表:记录员工是否已浏览公司介绍 / 产品 / 课程
type LearningProgress struct {
ID uint `gorm:"primaryKey" json:"id"`
UserID uint `gorm:"uniqueIndex:idx_learning;not null" json:"user_id"`
ItemType string `gorm:"uniqueIndex:idx_learning;size:16;not null" json:"item_type"` // company / product / course
ItemID uint `gorm:"uniqueIndex:idx_learning;not null" json:"item_id"` // company 固定 0
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (LearningProgress) TableName() string { return "learning_progress" }
@@ -0,0 +1,26 @@
package model
import "time"
// MediaFile 素材文件表
type MediaFile struct {
ID uint `gorm:"primaryKey" json:"id"`
Filename string `gorm:"size:256;not null" json:"filename"`
StoredName string `gorm:"size:64;not null" json:"stored_name"`
StoredPath string `gorm:"size:512;not null" json:"stored_path"`
FileExt string `gorm:"size:16;not null" json:"file_ext"`
FileSize int64 `gorm:"not null" json:"file_size"`
Status string `gorm:"size:16;not null;default:pending;index" json:"status"` // pending / approved / rejected
Source string `gorm:"size:16;not null" json:"source"` // employee / admin
SubmitterID uint `gorm:"not null;index" json:"submitter_id"`
BindType string `gorm:"size:16;not null;default:none" json:"bind_type"` // company / product / course / none
BindID *uint `gorm:"index" json:"bind_id"`
Remark string `gorm:"size:512" json:"remark"` // 提交备注(员工素材建议)
RejectReason string `gorm:"size:512" json:"reject_reason"`
AuditBy *uint `json:"audit_by"`
AuditAt *time.Time `json:"audit_at"`
Extracted bool `gorm:"not null;default:false;index" json:"extracted"`
CreatedAt time.Time `json:"created_at"`
}
func (MediaFile) TableName() string { return "media_file" }
@@ -0,0 +1,23 @@
package model
import "time"
// MistakeRecord 错题本(学员自助工具,非学情分析)
// 按 (user_id, question_id, source) 去重:同一学员同一题同一种考试只保留一条,
// 再次答错时更新作答与解析并将 resolved 重置为 false。
type MistakeRecord struct {
ID uint `gorm:"primaryKey" json:"id"`
UserID uint `gorm:"not null;index" json:"user_id"`
QuestionID uint `gorm:"not null;index" json:"question_id"`
Source string `gorm:"size:16;not null;index" json:"source"` // self_test / formal
QuestionType string `gorm:"size:16;not null" json:"question_type"` // single/multiple/judge/essay(冗余,供错题本独立展示)
QuestionStem string `gorm:"type:text;not null" json:"question_stem"`
UserAnswer string `gorm:"type:text" json:"user_answer"` // JSON 序列化的作答
CorrectAnswer string `gorm:"type:text" json:"correct_answer"` // JSON 序列化的正确答案 / 评分标准
Explanation string `gorm:"type:text;default:''" json:"explanation"`
Resolved bool `gorm:"not null;default:false;index" json:"resolved"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (MistakeRecord) TableName() string { return "mistake_record" }
@@ -0,0 +1,17 @@
package model
import "time"
// Notification 站内消息通知:考试发布 / 考试通过发证 / 岗位设置等事件推送给学员。
type Notification struct {
ID uint `gorm:"primaryKey" json:"id"`
UserID uint `gorm:"not null;index" json:"user_id"`
Type string `gorm:"size:32;not null;index" json:"type"` // exam_publish / exam_pass / position_set
Title string `gorm:"size:128;not null" json:"title"`
Content string `gorm:"type:text;not null" json:"content"`
Link string `gorm:"size:128;default:''" json:"link"` // 前端跳转路由
Read bool `gorm:"not null;default:false;index" json:"read"`
CreatedAt time.Time `json:"created_at"`
}
func (Notification) TableName() string { return "notification" }
@@ -0,0 +1,17 @@
package model
import "time"
// PointEvent 学习积分流水(游戏化成长值,逐笔可审计)
// 用户学习/考试/错题掌握等行为触发加分,积分总额冗余在 user.learning_points。
type PointEvent struct {
ID uint `gorm:"primaryKey" json:"id"`
UserID uint `gorm:"not null;index" json:"user_id"`
EventType string `gorm:"size:32;not null;index" json:"event_type"` // first_company/first_product/first_course/self_test/formal_pass/mistake_resolved
Points int `gorm:"not null" json:"points"`
RefType string `gorm:"size:32;default:''" json:"ref_type"` // company/product/course/paper/mistake
RefID uint `gorm:"default:0" json:"ref_id"`
CreatedAt time.Time `json:"created_at"`
}
func (PointEvent) TableName() string { return "point_event" }
@@ -0,0 +1,27 @@
package model
import "time"
// 岗位知识要求级别(对齐 pj006 的 L1-L4 词汇)
const (
LevelL1 = "L1" // 入门级:概念/定义/标准流程
LevelL2 = "L2" // 稳定执行级:标准应用/独立执行
LevelL3 = "L3" // 复杂处理级:跨场景迁移/带教
LevelL4 = "L4" // 体系策略级:方案设计/组织约束
)
// ValidLevels 合法级别集合
var ValidLevels = map[string]bool{LevelL1: true, LevelL2: true, LevelL3: true, LevelL4: true}
// Position 岗位表
type Position struct {
ID uint `gorm:"primaryKey" json:"id"`
Code string `gorm:"size:32;uniqueIndex;not null" json:"code"`
Name string `gorm:"size:64;not null" json:"name"`
Description string `gorm:"type:text" json:"description"`
Status string `gorm:"size:16;not null;default:active;index" json:"status"` // active / inactive
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (Position) TableName() string { return "position" }
@@ -0,0 +1,18 @@
package model
import "time"
// PositionExamBlueprint 岗位考试蓝图:规定岗位考试的题型构成(按域+题型各抽多少题)。
// 题目本身不携带 L1-L4 级别字段,故蓝图按 domain + type 维度抽样,不做级别加权。
// 蓝图存在时,pickQuestions 优先按蓝图组卷;否则回退到岗位知识映射圈定题池抽题。
type PositionExamBlueprint struct {
ID uint `gorm:"primaryKey" json:"id"`
PositionID uint `gorm:"not null;index" json:"position_id"`
Domain string `gorm:"size:16;not null;default:''" json:"domain"` // company/product/sales,空=不限(在岗位范围内)
Type string `gorm:"size:16;not null" json:"type"` // single/multiple/judge/essay
Count int `gorm:"not null" json:"count"` // 该域该题型抽取数量
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (PositionExamBlueprint) TableName() string { return "position_exam_blueprint" }
@@ -0,0 +1,20 @@
package model
import "time"
// PositionKnowledge 岗位知识要求(岗位 ↔ 知识域/课程/产品 映射)
// domain 必填;course_id / product_id 可选(三者共同圈定岗位应学范围)。
type PositionKnowledge struct {
ID uint `gorm:"primaryKey" json:"id"`
PositionID uint `gorm:"not null;index" json:"position_id"`
Domain string `gorm:"size:16;not null;index" json:"domain"` // company / product / sales
CourseID *uint `gorm:"index" json:"course_id"` // 绑定具体课程,可空
ProductID *uint `gorm:"index" json:"product_id"` // 绑定具体产品,可空
RequiredLevel string `gorm:"size:16;not null;default:L1" json:"required_level"` // L1/L2/L3/L4
Weight float64 `gorm:"not null;default:1" json:"weight"`
IsMandatory bool `gorm:"not null;default:true" json:"is_mandatory"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (PositionKnowledge) TableName() string { return "position_knowledge" }
@@ -0,0 +1,24 @@
package model
import "time"
// Product 产品表
type Product struct {
ID uint `gorm:"primaryKey" json:"id"`
Code string `gorm:"size:32;uniqueIndex;not null" json:"code"`
Name string `gorm:"size:128;not null" json:"name"`
Category string `gorm:"size:32;not null;index" json:"category"` // capital_consulting/qualification_counseling/ai_consulting/ai_tools_platform
Tags string `gorm:"size:256;default:''" json:"tags"`
Description string `gorm:"type:text" json:"description"`
Pricing string `gorm:"type:text" json:"pricing"`
CommissionRecommend string `gorm:"size:128;default:''" json:"commission_recommend"`
CommissionNegotiate string `gorm:"size:128;default:''" json:"commission_negotiate"`
PublicCourseBonus string `gorm:"size:128;default:''" json:"public_course_bonus"`
VersionRisk string `gorm:"type:text" json:"version_risk"`
ReportRules string `gorm:"type:text" json:"report_rules"`
Status string `gorm:"size:16;not null;default:active;index" json:"status"` // active / inactive
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (Product) TableName() string { return "product" }
@@ -0,0 +1,20 @@
package model
import "time"
// Question 题目表
type Question struct {
ID uint `gorm:"primaryKey" json:"id"`
Domain string `gorm:"size:16;not null;index" json:"domain"` // company / product / sales
CourseID *uint `gorm:"index" json:"course_id"`
Type string `gorm:"size:16;not null" json:"type"` // single / multiple / judge
Stem string `gorm:"type:text;not null" json:"stem"`
Options string `gorm:"type:text;not null" json:"options"` // JSON 数组:["A","B","C"]
Answer string `gorm:"type:text;not null" json:"answer"` // JSON 数组:single=[索引] multiple=[索引...] judge=[bool]
Explanation string `gorm:"type:text;default:''" json:"explanation"`
Status string `gorm:"size:16;not null;default:active;index" json:"status"` // active / inactive
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (Question) TableName() string { return "question" }
@@ -0,0 +1,38 @@
package model
import "time"
// Specialist 数字员工专员目录
type Specialist struct {
ID uint `gorm:"primaryKey" json:"id"`
Key string `gorm:"size:64;uniqueIndex;not null" json:"key"`
Label string `gorm:"size:128;not null" json:"label"`
Tier string `gorm:"size:16;not null;index" json:"tier"` // generic / industry
WorkerType string `gorm:"size:16;not null;default:dw;index" json:"worker_type"`
Route string `gorm:"size:128;not null" json:"route"`
Summary string `gorm:"type:text" json:"summary"`
WorkStatus string `gorm:"size:64;default:''" json:"work_status"`
RiskLabel string `gorm:"size:64;default:''" json:"risk_label"`
Color string `gorm:"size:16;default:''" json:"color"`
Stage string `gorm:"size:64;default:''" json:"stage"`
Progress int `gorm:"not null;default:0" json:"progress"`
MarketTag string `gorm:"size:32;not null;default:installed;index" json:"market_tag"` // 已安装 / 可升级 / 试用
Version string `gorm:"size:32;default:''" json:"version"`
ConnectorScope string `gorm:"type:text" json:"connector_scope"`
PermissionScope string `gorm:"type:text" json:"permission_scope"`
ResourceBindings string `gorm:"type:text" json:"resource_bindings"`
InfoSources string `gorm:"type:text" json:"info_sources"`
BaseSkills string `gorm:"type:text" json:"base_skills"`
AIAssistance string `gorm:"type:text" json:"ai_assistance"`
GeneratedSkills string `gorm:"type:text" json:"generated_skills"`
InputsRecordsJSON string `gorm:"column:source_records_json;type:text" json:"inputs_records_json"`
PermissionRecordsJSON string `gorm:"type:text" json:"permission_records_json"`
ActionRecordsJSON string `gorm:"type:text" json:"action_records_json"`
ResultRecordsJSON string `gorm:"type:text" json:"result_records_json"`
State string `gorm:"size:16;not null;default:active;index" json:"state"` // active / inactive
SortOrder int `gorm:"not null;default:0;index" json:"sort_order"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (Specialist) TableName() string { return "specialist" }
@@ -0,0 +1,16 @@
package model
import "time"
// StudyNote 学习笔记:员工在浏览公司介绍 / 产品 / 课程时记录的私人学习笔记。
type StudyNote struct {
ID uint `gorm:"primaryKey" json:"id"`
UserID uint `gorm:"not null;index" json:"user_id"`
ItemType string `gorm:"size:16;not null;index" json:"item_type"` // company / product / course
ItemID uint `gorm:"not null;index" json:"item_id"` // company 固定 0
Content string `gorm:"type:text;not null" json:"content"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (StudyNote) TableName() string { return "study_note" }
@@ -0,0 +1,14 @@
package model
import "time"
// SystemConfig 系统参数配置表
type SystemConfig struct {
ID uint `gorm:"primaryKey" json:"id"`
ConfigKey string `gorm:"size:64;uniqueIndex;not null" json:"config_key"`
ConfigValue string `gorm:"type:text;not null" json:"config_value"`
Description string `gorm:"size:256;default:''" json:"description"`
UpdatedAt time.Time `json:"updated_at"`
}
func (SystemConfig) TableName() string { return "system_config" }
@@ -0,0 +1,23 @@
package model
import "time"
// User 用户表
type User struct {
ID uint `gorm:"primaryKey" json:"id"`
Username string `gorm:"size:64;uniqueIndex;not null" json:"username"`
PasswordHash string `gorm:"size:256;not null" json:"-"`
FullName string `gorm:"size:64;not null" json:"full_name"`
Role string `gorm:"size:16;not null;default:employee;index" json:"role"` // employee / admin
Status string `gorm:"size:16;not null;default:active;index" json:"status"` // active / disabled
AiPoints int `gorm:"not null;default:100" json:"ai_points"` // 剩余 AI 算力点
LearningPoints int `gorm:"not null;default:0;index" json:"learning_points"` // 学习积分(游戏化成长值)
Department string `gorm:"size:64;default:''" json:"department"` // 部门
Position string `gorm:"size:64;default:''" json:"position"` // 岗位(文本,历史遗留)
PositionID *uint `gorm:"index" json:"position_id"` // 所属岗位,可空(历史用户/管理员可为空)
HireBatch string `gorm:"size:64;default:''" json:"hire_batch"` // 入职批次
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (User) TableName() string { return "user" }