Эх сурвалжийг харах

feat(环评): 添加 360 环评持久化模型(任务 1/10)

wangkangyjy 1 өдөр өмнө
parent
commit
2f975416b3

+ 47 - 0
backend/src/main/java/com/emoon/okr/config/DatabaseMigrationRunner.java

@@ -411,6 +411,53 @@ public class DatabaseMigrationRunner implements CommandLineRunner {
                           )
                         """);
             }
+        }),
+
+        new DatabaseMigration(13, "add peer review workflow", context -> {
+            context.addColumnIfMissing("assessment_period", "peer_invitation_deadline", "TEXT");
+            context.addColumnIfMissing("assessment_period", "peer_review_deadline", "TEXT");
+            context.execute("""
+                    CREATE TABLE IF NOT EXISTS peer_review_request (
+                        id INTEGER PRIMARY KEY AUTOINCREMENT,
+                        period_id INTEGER NOT NULL,
+                        subject_user_id INTEGER NOT NULL,
+                        leader_id INTEGER NOT NULL,
+                        status VARCHAR(32) NOT NULL DEFAULT 'DRAFT',
+                        rejection_reason TEXT,
+                        submitted_at TEXT,
+                        approved_at TEXT,
+                        deleted INTEGER NOT NULL DEFAULT 0,
+                        created_at TEXT NOT NULL,
+                        updated_at TEXT NOT NULL
+                    )
+                    """);
+            context.execute("CREATE UNIQUE INDEX IF NOT EXISTS uk_peer_review_request_subject " +
+                    "ON peer_review_request(period_id, subject_user_id)");
+            context.execute("""
+                    CREATE TABLE IF NOT EXISTS peer_review_invitation (
+                        id INTEGER PRIMARY KEY AUTOINCREMENT,
+                        request_id INTEGER NOT NULL,
+                        reviewer_id INTEGER NOT NULL,
+                        reviewer_department_id_snapshot INTEGER,
+                        relation_type_snapshot VARCHAR(24) NOT NULL,
+                        status VARCHAR(24) NOT NULL DEFAULT 'PROPOSED',
+                        decline_reason TEXT,
+                        goal_contribution_score INTEGER,
+                        collaboration_score INTEGER,
+                        accountability_score INTEGER,
+                        strengths TEXT,
+                        improvement_suggestion TEXT,
+                        responded_at TEXT,
+                        submitted_at TEXT,
+                        deleted INTEGER NOT NULL DEFAULT 0,
+                        created_at TEXT NOT NULL,
+                        updated_at TEXT NOT NULL
+                    )
+                    """);
+            context.execute("CREATE UNIQUE INDEX IF NOT EXISTS uk_peer_review_invitation_reviewer " +
+                    "ON peer_review_invitation(request_id, reviewer_id)");
+            context.execute("CREATE INDEX IF NOT EXISTS idx_peer_review_invitation_reviewer " +
+                    "ON peer_review_invitation(reviewer_id, status)");
         }));
     }
 

+ 2 - 0
backend/src/main/java/com/emoon/okr/entity/AssessmentPeriod.java

@@ -27,6 +27,8 @@ public class AssessmentPeriod {
     private LocalDate selfReviewDueDate;
     private LocalDate managerReviewDueDate;
     private LocalDate confirmationDueDate;
+    private LocalDateTime peerInvitationDeadline;
+    private LocalDateTime peerReviewDeadline;
     private Long companyOwnerUserId;
 
     @TableField("status")

+ 37 - 0
backend/src/main/java/com/emoon/okr/entity/PeerReviewInvitation.java

@@ -0,0 +1,37 @@
+package com.emoon.okr.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+@TableName("peer_review_invitation")
+public class PeerReviewInvitation {
+    @TableId(type = IdType.AUTO)
+    private Long id;
+    private Long requestId;
+    private Long reviewerId;
+    private Long reviewerDepartmentIdSnapshot;
+    private String relationTypeSnapshot;
+    private String status;
+    private String declineReason;
+    private Integer goalContributionScore;
+    private Integer collaborationScore;
+    private Integer accountabilityScore;
+    private String strengths;
+    private String improvementSuggestion;
+    private LocalDateTime respondedAt;
+    private LocalDateTime submittedAt;
+    @TableLogic
+    private Integer deleted;
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createdAt;
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updatedAt;
+}

+ 31 - 0
backend/src/main/java/com/emoon/okr/entity/PeerReviewRequest.java

@@ -0,0 +1,31 @@
+package com.emoon.okr.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+@TableName("peer_review_request")
+public class PeerReviewRequest {
+    @TableId(type = IdType.AUTO)
+    private Long id;
+    private Long periodId;
+    private Long subjectUserId;
+    private Long leaderId;
+    private String status;
+    private String rejectionReason;
+    private LocalDateTime submittedAt;
+    private LocalDateTime approvedAt;
+    @TableLogic
+    private Integer deleted;
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createdAt;
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updatedAt;
+}

+ 9 - 0
backend/src/main/java/com/emoon/okr/mapper/PeerReviewInvitationMapper.java

@@ -0,0 +1,9 @@
+package com.emoon.okr.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.emoon.okr.entity.PeerReviewInvitation;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface PeerReviewInvitationMapper extends BaseMapper<PeerReviewInvitation> {
+}

+ 9 - 0
backend/src/main/java/com/emoon/okr/mapper/PeerReviewRequestMapper.java

@@ -0,0 +1,9 @@
+package com.emoon.okr.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.emoon.okr.entity.PeerReviewRequest;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface PeerReviewRequestMapper extends BaseMapper<PeerReviewRequest> {
+}

+ 42 - 0
backend/src/main/resources/schema.sql

@@ -39,6 +39,8 @@ CREATE TABLE IF NOT EXISTS assessment_period (
     self_review_due_date TEXT,
     manager_review_due_date TEXT,
     confirmation_due_date TEXT,
+    peer_invitation_deadline TEXT,
+    peer_review_deadline TEXT,
     company_owner_user_id INTEGER,
     status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
     created_by INTEGER,
@@ -311,3 +313,43 @@ CREATE TABLE IF NOT EXISTS performance_score_item (
 );
 
 CREATE INDEX IF NOT EXISTS idx_score_item_score ON performance_score_item(score_id, sort_order);
+
+CREATE TABLE IF NOT EXISTS peer_review_request (
+    id INTEGER PRIMARY KEY AUTOINCREMENT,
+    period_id INTEGER NOT NULL,
+    subject_user_id INTEGER NOT NULL,
+    leader_id INTEGER NOT NULL,
+    status VARCHAR(32) NOT NULL DEFAULT 'DRAFT',
+    rejection_reason TEXT,
+    submitted_at TEXT,
+    approved_at TEXT,
+    deleted INTEGER NOT NULL DEFAULT 0,
+    created_at TEXT NOT NULL,
+    updated_at TEXT NOT NULL
+);
+CREATE UNIQUE INDEX IF NOT EXISTS uk_peer_review_request_subject
+    ON peer_review_request(period_id, subject_user_id);
+
+CREATE TABLE IF NOT EXISTS peer_review_invitation (
+    id INTEGER PRIMARY KEY AUTOINCREMENT,
+    request_id INTEGER NOT NULL,
+    reviewer_id INTEGER NOT NULL,
+    reviewer_department_id_snapshot INTEGER,
+    relation_type_snapshot VARCHAR(24) NOT NULL,
+    status VARCHAR(24) NOT NULL DEFAULT 'PROPOSED',
+    decline_reason TEXT,
+    goal_contribution_score INTEGER,
+    collaboration_score INTEGER,
+    accountability_score INTEGER,
+    strengths TEXT,
+    improvement_suggestion TEXT,
+    responded_at TEXT,
+    submitted_at TEXT,
+    deleted INTEGER NOT NULL DEFAULT 0,
+    created_at TEXT NOT NULL,
+    updated_at TEXT NOT NULL
+);
+CREATE UNIQUE INDEX IF NOT EXISTS uk_peer_review_invitation_reviewer
+    ON peer_review_invitation(request_id, reviewer_id);
+CREATE INDEX IF NOT EXISTS idx_peer_review_invitation_reviewer
+    ON peer_review_invitation(reviewer_id, status);

+ 16 - 0
backend/src/test/java/com/emoon/okr/config/DatabaseMigrationRunnerTest.java

@@ -73,6 +73,22 @@ class DatabaseMigrationRunnerTest {
                 "SELECT COUNT(*) FROM schema_migration WHERE version = 5", Integer.class));
     }
 
+    @Test
+    void migrationAddsPeerReviewTablesAndDeadlines() {
+        createBaseTables();
+
+        DatabaseMigrationRunner runner = new DatabaseMigrationRunner(jdbcTemplate, transactionTemplate, backupService);
+        runner.run();
+        runner.run();
+
+        assertColumnExists(jdbcTemplate, "assessment_period", "peer_invitation_deadline");
+        assertColumnExists(jdbcTemplate, "assessment_period", "peer_review_deadline");
+        assertTableExists(jdbcTemplate, "peer_review_request");
+        assertTableExists(jdbcTemplate, "peer_review_invitation");
+        assertEquals(1, jdbcTemplate.queryForObject(
+                "SELECT COUNT(*) FROM schema_migration WHERE version = 13", Integer.class));
+    }
+
     @Test
     void migrationAddsPeriodDimensionSnapshotAndExplicitTemplateAssignments() {
         createBaseTables();