feat: 新增 site_submissions 审核表, 提交先进审核再写入sites
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
package com.par.core.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class SiteSubmissionDTO {
|
||||
private Long id;
|
||||
private String siteId;
|
||||
private Long submitterId;
|
||||
private List<String> names;
|
||||
private List<String> urls;
|
||||
private String notes;
|
||||
private String siteStatus; // 正常/关停/维护中/已迁移
|
||||
private String status; // pending/approved/rejected
|
||||
private Long reviewerId;
|
||||
private String reviewComment;
|
||||
private LocalDateTime reviewedAt;
|
||||
private LocalDateTime createdAt;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.par.core.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("site_submissions")
|
||||
public class SiteSubmission {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@TableField("site_id")
|
||||
private String siteId;
|
||||
|
||||
@TableField("submitter_id")
|
||||
private Long submitterId;
|
||||
|
||||
@TableField("raw_data")
|
||||
private String rawData;
|
||||
|
||||
@TableField("status")
|
||||
private String status; // pending / approved / rejected
|
||||
|
||||
@TableField("reviewer_id")
|
||||
private Long reviewerId;
|
||||
|
||||
@TableField("review_comment")
|
||||
private String reviewComment;
|
||||
|
||||
@TableField("reviewed_at")
|
||||
private LocalDateTime reviewedAt;
|
||||
|
||||
@TableField("site_record_id")
|
||||
private Long siteRecordId;
|
||||
|
||||
@TableField(value = "created_at", fill = FieldFill.INSERT)
|
||||
private LocalDateTime createdAt;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.par.core.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.par.core.entity.SiteSubmission;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface SiteSubmissionMapper extends BaseMapper<SiteSubmission> {
|
||||
|
||||
@Select("SELECT * FROM site_submissions WHERE status = #{status} ORDER BY created_at DESC")
|
||||
List<SiteSubmission> selectByStatus(@Param("status") String status);
|
||||
|
||||
@Select("SELECT * FROM site_submissions WHERE site_id = #{siteId} ORDER BY created_at DESC")
|
||||
List<SiteSubmission> selectBySiteId(@Param("siteId") String siteId);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.par.core.service;
|
||||
|
||||
import com.par.core.dto.SiteDTO;
|
||||
import com.par.core.dto.SiteSubmissionDTO;
|
||||
import com.par.core.entity.Site;
|
||||
|
||||
import java.util.List;
|
||||
@@ -32,9 +33,9 @@ public interface SiteService {
|
||||
String iconUrl, String siteType, Long submitterId);
|
||||
|
||||
/**
|
||||
* 提交站点信息反馈(状态、多名称、多地址、备注)
|
||||
* 提交站点信息反馈 → 写入 site_submissions 审核表
|
||||
*/
|
||||
Site updateSiteInfo(String siteId, String status, List<String> names,
|
||||
void submitSiteInfo(String siteId, String status, List<String> names,
|
||||
List<String> urls, String notes, Long submitterId);
|
||||
|
||||
/**
|
||||
@@ -46,12 +47,12 @@ public interface SiteService {
|
||||
/** 所有站点列表(管理员用) */
|
||||
List<Site> listAllSites();
|
||||
|
||||
/** 待审核站点列表 */
|
||||
List<Site> listPendingSites();
|
||||
/** 待审核提交列表 */
|
||||
List<SiteSubmissionDTO> listPendingSubmissions();
|
||||
|
||||
/** 审核通过 */
|
||||
void approveSite(Long id, Long reviewerId);
|
||||
/** 审核通过 → 写入 sites 表 */
|
||||
Site approveSubmission(Long submissionId, Long reviewerId);
|
||||
|
||||
/** 拒绝(删除) */
|
||||
void rejectSite(Long id);
|
||||
/** 拒绝提交 */
|
||||
void rejectSubmission(Long submissionId, Long reviewerId);
|
||||
}
|
||||
|
||||
@@ -4,17 +4,22 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.par.core.dto.SiteDTO;
|
||||
import com.par.core.dto.SiteSubmissionDTO;
|
||||
import com.par.core.entity.Site;
|
||||
import com.par.core.entity.SiteSubmission;
|
||||
import com.par.core.enums.SiteStatus;
|
||||
import com.par.core.enums.SiteType;
|
||||
import com.par.core.mapper.SiteMapper;
|
||||
import com.par.core.mapper.SiteSubmissionMapper;
|
||||
import com.par.core.service.SiteService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@@ -23,6 +28,7 @@ import java.util.stream.Collectors;
|
||||
public class SiteServiceImpl implements SiteService {
|
||||
|
||||
private final SiteMapper siteMapper;
|
||||
private final SiteSubmissionMapper submissionMapper;
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
// ==================== 工具方法 ====================
|
||||
@@ -118,34 +124,25 @@ public class SiteServiceImpl implements SiteService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Site updateSiteInfo(String siteId, String status, List<String> names,
|
||||
public void submitSiteInfo(String siteId, String status, List<String> names,
|
||||
List<String> urls, String notes, Long submitterId) {
|
||||
SiteStatus siteStatus = mapStatus(status);
|
||||
Map<String, Object> raw = new LinkedHashMap<>();
|
||||
raw.put("names", names != null ? names : List.of());
|
||||
raw.put("urls", urls != null ? urls : List.of());
|
||||
raw.put("notes", notes != null ? notes : "");
|
||||
raw.put("siteStatus", status != null ? status : "正常");
|
||||
|
||||
Site existing = siteMapper.selectBySiteId(siteId);
|
||||
if (existing != null) {
|
||||
if (names != null && !names.isEmpty()) existing.setNamesJson(toJsonArray(names));
|
||||
if (urls != null && !urls.isEmpty()) existing.setUrlsJson(toJsonArray(urls));
|
||||
if (notes != null && !notes.isBlank()) existing.setNotes(notes);
|
||||
existing.setStatus(siteStatus);
|
||||
existing.setSubmitterId(submitterId != null ? submitterId : existing.getSubmitterId());
|
||||
siteMapper.updateById(existing);
|
||||
log.info("站点信息反馈更新: siteId={} status={}", siteId, siteStatus.getValue());
|
||||
return existing;
|
||||
SiteSubmission sub = new SiteSubmission();
|
||||
sub.setSiteId(siteId);
|
||||
sub.setSubmitterId(submitterId);
|
||||
sub.setStatus("pending");
|
||||
try {
|
||||
sub.setRawData(objectMapper.writeValueAsString(raw));
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException("序列化提交数据失败", e);
|
||||
}
|
||||
|
||||
Site site = new Site();
|
||||
site.setSiteId(siteId);
|
||||
site.setNamesJson(toJsonArray(names != null && !names.isEmpty() ? names : List.of(siteId)));
|
||||
site.setUrlsJson(toJsonArray(urls != null && !urls.isEmpty() ? urls : List.of()));
|
||||
site.setNotes(notes);
|
||||
site.setSiteType(SiteType.UNKNOWN);
|
||||
site.setSchemaVersion("1.0.0");
|
||||
site.setStatus(SiteStatus.PENDING);
|
||||
site.setSubmitterId(submitterId);
|
||||
siteMapper.insert(site);
|
||||
log.info("站点信息反馈创建: siteId={} status=PENDING", siteId);
|
||||
return site;
|
||||
submissionMapper.insert(sub);
|
||||
log.info("站点信息提交审核: siteId={} submissionId={}", siteId, sub.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,32 +181,101 @@ public class SiteServiceImpl implements SiteService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Site> listPendingSites() {
|
||||
return siteMapper.selectList(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Site>()
|
||||
.eq(Site::getStatus, SiteStatus.PENDING)
|
||||
.eq(Site::getDeleted, 0));
|
||||
public List<SiteSubmissionDTO> listPendingSubmissions() {
|
||||
return submissionMapper.selectByStatus("pending").stream()
|
||||
.map(this::toSubmissionDTO).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void approveSite(Long id, Long reviewerId) {
|
||||
Site site = siteMapper.selectById(id);
|
||||
if (site != null) {
|
||||
site.setStatus(SiteStatus.ACTIVE);
|
||||
siteMapper.updateById(site);
|
||||
public Site approveSubmission(Long submissionId, Long reviewerId) {
|
||||
SiteSubmission sub = submissionMapper.selectById(submissionId);
|
||||
if (sub == null) throw new IllegalArgumentException("提交记录不存在");
|
||||
if (!"pending".equals(sub.getStatus())) throw new IllegalArgumentException("该提交已处理");
|
||||
|
||||
// 解析提交数据
|
||||
Map<String, Object> raw;
|
||||
try {
|
||||
raw = objectMapper.readValue(sub.getRawData(), new TypeReference<Map<String, Object>>() {});
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("解析提交数据失败", e);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> names = (List<String>) raw.getOrDefault("names", List.of());
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> urls = (List<String>) raw.getOrDefault("urls", List.of());
|
||||
String notes = (String) raw.getOrDefault("notes", "");
|
||||
|
||||
// 写入 sites 表
|
||||
Site existing = siteMapper.selectBySiteId(sub.getSiteId());
|
||||
Site site;
|
||||
if (existing != null) {
|
||||
existing.setNamesJson(toJsonArray(names));
|
||||
existing.setUrlsJson(toJsonArray(urls));
|
||||
if (notes != null && !notes.isBlank()) existing.setNotes(notes);
|
||||
existing.setStatus(SiteStatus.ACTIVE);
|
||||
siteMapper.updateById(existing);
|
||||
site = existing;
|
||||
} else {
|
||||
site = new Site();
|
||||
site.setSiteId(sub.getSiteId());
|
||||
site.setNamesJson(toJsonArray(names));
|
||||
site.setUrlsJson(toJsonArray(urls));
|
||||
site.setNotes(notes);
|
||||
site.setSiteType(SiteType.UNKNOWN);
|
||||
site.setSchemaVersion("1.0.0");
|
||||
site.setStatus(SiteStatus.ACTIVE);
|
||||
site.setSubmitterId(sub.getSubmitterId());
|
||||
siteMapper.insert(site);
|
||||
}
|
||||
|
||||
// 更新提交状态
|
||||
sub.setStatus("approved");
|
||||
sub.setReviewerId(reviewerId);
|
||||
sub.setReviewedAt(java.time.LocalDateTime.now());
|
||||
sub.setSiteRecordId(site.getId());
|
||||
submissionMapper.updateById(sub);
|
||||
log.info("站点审核通过: siteId={} submissionId={}", sub.getSiteId(), submissionId);
|
||||
return site;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rejectSite(Long id) {
|
||||
siteMapper.deleteById(id);
|
||||
public void rejectSubmission(Long submissionId, Long reviewerId) {
|
||||
SiteSubmission sub = submissionMapper.selectById(submissionId);
|
||||
if (sub == null) throw new IllegalArgumentException("提交记录不存在");
|
||||
if (!"pending".equals(sub.getStatus())) throw new IllegalArgumentException("该提交已处理");
|
||||
sub.setStatus("rejected");
|
||||
sub.setReviewerId(reviewerId);
|
||||
sub.setReviewedAt(java.time.LocalDateTime.now());
|
||||
submissionMapper.updateById(sub);
|
||||
log.info("站点审核拒绝: siteId={} submissionId={}", sub.getSiteId(), submissionId);
|
||||
}
|
||||
|
||||
private static SiteStatus mapStatus(String status) {
|
||||
if (status == null) return SiteStatus.ACTIVE;
|
||||
return switch (status) {
|
||||
case "关停", "已迁移" -> SiteStatus.DEPRECATED;
|
||||
default -> SiteStatus.ACTIVE;
|
||||
};
|
||||
private SiteSubmissionDTO toSubmissionDTO(SiteSubmission sub) {
|
||||
SiteSubmissionDTO dto = new SiteSubmissionDTO();
|
||||
dto.setId(sub.getId());
|
||||
dto.setSiteId(sub.getSiteId());
|
||||
dto.setSubmitterId(sub.getSubmitterId());
|
||||
dto.setStatus(sub.getStatus());
|
||||
dto.setReviewerId(sub.getReviewerId());
|
||||
dto.setReviewComment(sub.getReviewComment());
|
||||
dto.setReviewedAt(sub.getReviewedAt());
|
||||
dto.setCreatedAt(sub.getCreatedAt());
|
||||
|
||||
try {
|
||||
Map<String, Object> raw = objectMapper.readValue(sub.getRawData(), new TypeReference<Map<String, Object>>() {});
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> names = (List<String>) raw.getOrDefault("names", List.of());
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> urls = (List<String>) raw.getOrDefault("urls", List.of());
|
||||
dto.setNames(names);
|
||||
dto.setUrls(urls);
|
||||
dto.setNotes((String) raw.getOrDefault("notes", ""));
|
||||
dto.setSiteStatus((String) raw.getOrDefault("siteStatus", "正常"));
|
||||
} catch (Exception ignored) {
|
||||
dto.setNames(List.of());
|
||||
dto.setUrls(List.of());
|
||||
}
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
CREATE TABLE site_submissions (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
site_id VARCHAR(64) NOT NULL COMMENT '站点标识',
|
||||
submitter_id BIGINT UNSIGNED COMMENT '提交者账户ID',
|
||||
raw_data JSON NOT NULL COMMENT '原始提交数据 {names,urls,notes,site_status}',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT '审核状态: pending/approved/rejected',
|
||||
reviewer_id BIGINT UNSIGNED COMMENT '审核人ID',
|
||||
review_comment VARCHAR(500) COMMENT '审核备注',
|
||||
reviewed_at DATETIME COMMENT '审核时间',
|
||||
site_record_id BIGINT UNSIGNED COMMENT '审核通过后关联的 sites.id',
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_site_id (site_id),
|
||||
KEY idx_status (status),
|
||||
KEY idx_submitter (submitter_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='站点提交审核表';
|
||||
Reference in New Issue
Block a user