feat: 提交校园智能助手后端工程源码(Spring Boot 2.7.18 + 平台 starter + JPA + Nacos)
build / build-push (push) Successful in 40s

- com.yunhai.agent,端口 8093,context-path /agent,制品 target/agent.jar;与 NoticeService 同构
- CAS 单点登录 + 三层角色权限(学生/教师/管理员/访客)+ 会话与工具调用审计落库
- DeepSeek 大模型编排 + 7 个业务模块工具(请假/公告/宿舍/活动/作业/资源库/教师发展)
- 浏览器代执行协议(服务端挂起 → 前端用登录态代调 → toolResult 续跑)+ 调用失败深链兜底
- 登出修复:服务端真正 session.invalidate() + 前端两步登出 + logout-guard
- 保留 projman 注入的 .gitea/workflows/build.yml 与 docker/Dockerfile;docker/application-prod.yml、run-app.sh 随工程入库
This commit is contained in:
lijing
2026-10-12 11:18:29 +08:00
parent 8589afd69a
commit 8303b857e9
58 changed files with 6883 additions and 2 deletions
@@ -0,0 +1,51 @@
package com.yunhai.agent.entity;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Index;
import javax.persistence.Lob;
import javax.persistence.Table;
/**
* 会话里的一条消息(system / user / assistant / tool),按 seq_no 保序。
*
* <p>assistant 消息可能携带工具调用请求,序列化进 {@link #toolCalls};
* tool 消息用于回填工具执行结果,关联 {@link #toolCallId}。
*/
@Entity
@Table(name = "agent_message", indexes = {
@Index(name = "idx_agent_msg_sid", columnList = "session_id,seq_no")
})
@Getter
@Setter
public class AgentMessage extends BaseEntity {
/** 所属会话 id */
@Column(name = "session_id", nullable = false, length = 64)
private String sessionId;
/** 会话内顺序(从 0 递增) */
@Column(name = "seq_no")
private Integer seqNo;
/** 角色:system / user / assistant / tool */
@Column(name = "role", length = 16)
private String role;
/** 正文(可能为空:assistant 只想调工具时) */
@Lob
@Column(name = "content", columnDefinition = "TEXT")
private String content;
/** assistant 的 tool_calls(JSON 数组字符串) */
@Lob
@Column(name = "tool_calls", columnDefinition = "TEXT")
private String toolCalls;
/** role=tool 时关联的调用 id */
@Column(name = "tool_call_id", length = 64)
private String toolCallId;
}
@@ -0,0 +1,50 @@
package com.yunhai.agent.entity;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Index;
import javax.persistence.Table;
import java.time.LocalDateTime;
/**
* 智能体会话:一个用户在「一段连续对话」里的上下文台账。
*
* <p>会话与 userId 绑定(跨用户复用同一 sessionId 会被拒绝并重建),承载多轮对话的归属与审计信息;
* 具体消息见 {@link AgentMessage}。
*/
@Entity
@Table(name = "agent_session", indexes = {
@Index(name = "idx_agent_session_sid", columnList = "session_id", unique = true),
@Index(name = "idx_agent_session_user", columnList = "user_id")
})
@Getter
@Setter
public class AgentSession extends BaseEntity {
/** 会话 id(前端持有并复用) */
@Column(name = "session_id", nullable = false, length = 64)
private String sessionId;
/** 归属用户 id */
@Column(name = "user_id")
private Integer userId;
/** 学校 id */
@Column(name = "sch_id")
private Integer schId;
/** 会话标题(取首条用户输入,便于列表展示) */
@Column(name = "title", length = 200)
private String title;
/** 角色快照(学生 / 教师 / 管理员),审计留痕用 */
@Column(name = "role_snapshot", length = 64)
private String roleSnapshot;
/** 最后访问时间(空闲过期依据) */
@Column(name = "last_access")
private LocalDateTime lastAccess;
}
@@ -0,0 +1,81 @@
package com.yunhai.agent.entity;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Index;
import javax.persistence.Lob;
import javax.persistence.Table;
/**
* 工具调用审计:每次对业务模块的真实调用留一条痕(含越权被拒的调用)。
*
* <p>用途:可追溯「谁、什么身份、在哪个会话、调了哪个模块的什么接口、传了什么、成没成、耗时多少」,
* 既是运维排障依据,也是「分学生、教师权限」的合规凭证。
*/
@Entity
@Table(name = "agent_tool_call_log", indexes = {
@Index(name = "idx_agent_log_sid", columnList = "session_id"),
@Index(name = "idx_agent_log_tool", columnList = "tool_name"),
@Index(name = "idx_agent_log_user", columnList = "user_id")
})
@Getter
@Setter
public class AgentToolCallLog extends BaseEntity {
/** 所属会话 id */
@Column(name = "session_id", length = 64)
private String sessionId;
/** 调用者用户 id */
@Column(name = "user_id")
private Integer userId;
/** 学校 id */
@Column(name = "sch_id")
private Integer schId;
/** 调用者角色(学生 / 教师 / 管理员) */
@Column(name = "role", length = 64)
private String role;
/** 业务模块标识 */
@Column(name = "module", length = 64)
private String module;
/** 工具名,如 leave.submit */
@Column(name = "tool_name", length = 128)
private String toolName;
/** 工具中文名 */
@Column(name = "tool_title", length = 128)
private String toolTitle;
/** 是否写操作 */
@Column(name = "is_write")
private Boolean write;
/** 调用参数(JSON) */
@Lob
@Column(name = "arguments", columnDefinition = "TEXT")
private String arguments;
/** 是否成功(越权拦截为 false) */
@Column(name = "success")
private Boolean success;
/** 失败原因 */
@Lob
@Column(name = "error", columnDefinition = "TEXT")
private String error;
/** 耗时(毫秒) */
@Column(name = "cost_ms")
private Long costMs;
/** 建议跳转路由 */
@Column(name = "landing_path", length = 128)
private String landingPath;
}
@@ -0,0 +1,46 @@
package com.yunhai.agent.entity;
import com.yunhai.agent.common.listener.AgentAuditListener;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 所有实体的公共基类:自增主键 + 创建人/时间 + 更新人/时间(由 {@link AgentAuditListener} 自动填充)。
*/
@MappedSuperclass
@Getter
@Setter
@EntityListeners(AgentAuditListener.class)
public abstract class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
/** 创建人登录账号 */
@Column(name = "create_by", updatable = false)
private String createBy;
/** 创建时间 */
@Column(name = "create_time", updatable = false)
private LocalDateTime createTime;
/** 更新人登录账号 */
@Column(name = "update_by")
private String updateBy;
/** 更新时间 */
@Column(name = "update_time")
private LocalDateTime updateTime;
}