This commit is contained in:
2026-07-20 11:48:06 +08:00
parent 7119dc76a9
commit f379291e4f
409 changed files with 150227 additions and 8557 deletions
@@ -0,0 +1,20 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.gxmu.entity.ClassInfo;
import com.gxwebsoft.gxmu.param.ClassInfoParam;
import java.util.List;
/**
* 班级管理Service
*/
public interface ClassInfoService extends IService<ClassInfo> {
PageResult<ClassInfo> pageRel(ClassInfoParam param);
List<ClassInfo> listRel(ClassInfoParam param);
ClassInfo getByIdRel(Integer id, Integer tenantId);
}
@@ -0,0 +1,20 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.gxmu.entity.College;
import com.gxwebsoft.gxmu.param.CollegeParam;
import java.util.List;
/**
* 学院管理Service
*/
public interface CollegeService extends IService<College> {
PageResult<College> pageRel(CollegeParam param);
List<College> listRel(CollegeParam param);
College getByIdRel(Integer id, Integer tenantId);
}
@@ -0,0 +1,23 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.gxmu.entity.CrossSchoolActivityArticle;
import com.gxwebsoft.gxmu.param.CrossSchoolActivityArticleParam;
import java.util.List;
/**
* 跨校活动情报文章Service
*
* @author Codex
* @since 2026-07-04
*/
public interface CrossSchoolActivityArticleService extends IService<CrossSchoolActivityArticle> {
PageResult<CrossSchoolActivityArticle> pageRel(CrossSchoolActivityArticleParam param);
List<CrossSchoolActivityArticle> listRel(CrossSchoolActivityArticleParam param);
CrossSchoolActivityArticle getByIdRel(Integer id);
}
@@ -0,0 +1,17 @@
package com.gxwebsoft.gxmu.service;
/**
* 跨校活动情报抓取Service
*
* @author Codex
* @since 2026-07-04
*/
public interface CrossSchoolActivityCrawlerService {
/**
* 同步全部来源站点
*
* @return 写入/更新条数
*/
int syncAll();
}
@@ -0,0 +1,42 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.gxmu.entity.Declare;
import com.gxwebsoft.gxmu.param.DeclareParam;
import java.util.List;
/**
* 申报管理Service
*
* @author LX
* @since 2026-03-28 15:06:52
*/
public interface DeclareService extends IService<Declare> {
/**
* 分页关联查询
*
* @param param 查询参数
* @return PageResult<Declare>
*/
PageResult<Declare> pageRel(DeclareParam param);
/**
* 关联查询全部
*
* @param param 查询参数
* @return List<Declare>
*/
List<Declare> listRel(DeclareParam param);
/**
* 根据id查询
*
* @param id
* @return Declare
*/
Declare getByIdRel(Integer id);
}
@@ -0,0 +1,10 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.gxmu.entity.QmgcForm;
/**
* 青马工程培训班学员登记表Service
*/
public interface QmgcFormService extends IService<QmgcForm> {
}
@@ -0,0 +1,43 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.gxmu.entity.ReviewFlowConfig;
import com.gxwebsoft.gxmu.param.ReviewFlowConfigParam;
import java.util.List;
/**
* Service
*
* @author LX
* @since 2026-03-18 10:37:18
*/
public interface ReviewFlowConfigService extends IService<ReviewFlowConfig> {
/**
* 分页关联查询
*
* @param param 查询参数
* @return PageResult<ReviewFlowConfig>
*/
PageResult<ReviewFlowConfig> pageRel(ReviewFlowConfigParam param);
/**
* 关联查询全部
*
* @param param 查询参数
* @return List<ReviewFlowConfig>
*/
List<ReviewFlowConfig> listRel(ReviewFlowConfigParam param);
/**
* 根据id查询
*
* @param id
* @return ReviewFlowConfig
*/
ReviewFlowConfig getByIdRel(Integer id);
ReviewFlowConfig getByModule(String module);
}
@@ -0,0 +1,45 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.gxmu.entity.ReviewFlow;
import com.gxwebsoft.gxmu.param.ReviewFlowParam;
import java.util.List;
/**
* 审核流Service
*
* @author LX
* @since 2026-03-18 10:37:18
*/
public interface ReviewFlowService extends IService<ReviewFlow> {
/**
* 分页关联查询
*
* @param param 查询参数
* @return PageResult<ReviewFlow>
*/
PageResult<ReviewFlow> pageRel(ReviewFlowParam param);
/**
* 关联查询全部
*
* @param param 查询参数
* @return List<ReviewFlow>
*/
List<ReviewFlow> listRel(ReviewFlowParam param);
/**
* 根据id查询
*
* @param id
* @return ReviewFlow
*/
ReviewFlow getByIdRel(Integer id);
ReviewFlow getByTitle(String title);
List<ReviewFlow> listByTitle(String title);
}
@@ -0,0 +1,26 @@
package com.gxwebsoft.gxmu.service;
/**
* 审核流程发起服务
*
* @author LX
* @since 2026-03-18
*/
public interface ReviewFlowStarterService {
/**
* 发起模块的首个审核节点
*
* @param module 模块编码
* @param pk 业务主键
*/
void startReview(String module, Integer pk);
/**
* 当最新审核记录为拒绝时,重新生成第一条审核流
*
* @param module 模块编码
* @param pk 业务主键
*/
void restartReviewWhenLastRejected(String module, Integer pk);
}
@@ -0,0 +1,26 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.gxwebsoft.gxmu.entity.ReviewList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Function;
/**
* 审核记录回填服务
*
* @author LX
* @since 2026-03-18
*/
public interface ReviewListBindingService {
<T, E extends IPage<T>> E bindPage(E page, String module, Function<T, Integer> idGetter,
BiConsumer<T, List<ReviewList>> setter);
<T> List<T> bindList(List<T> list, String module, Function<T, Integer> idGetter,
BiConsumer<T, List<ReviewList>> setter);
<T> T bindOne(T entity, String module, Function<T, Integer> idGetter,
BiConsumer<T, List<ReviewList>> setter);
}
@@ -0,0 +1,51 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.gxmu.entity.ReviewList;
import com.gxwebsoft.gxmu.param.ReviewListParam;
import java.util.List;
/**
* 审核列表Service
*
* @author LX
* @since 2026-03-18 15:50:51
*/
public interface ReviewListService extends IService<ReviewList> {
/**
* 分页关联查询
*
* @param param 查询参数
* @return PageResult<ReviewList>
*/
PageResult<ReviewList> pageRel(ReviewListParam param);
/**
* 分页查询聚合后的审核列表
*
* @param param 查询参数
* @return PageResult<ReviewList>
*/
PageResult<ReviewList> pageGroupRel(ReviewListParam param);
/**
* 关联查询全部
*
* @param param 查询参数
* @return List<ReviewList>
*/
List<ReviewList> listRel(ReviewListParam param);
/**
* 根据id查询
*
* @param id
* @return ReviewList
*/
ReviewList getByIdRel(Integer id);
List<ReviewList> listByModuleNPK(String module, Integer pk);
}
@@ -0,0 +1,10 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.gxmu.entity.SjqnForm;
/**
* 十佳青年申报表Service
*/
public interface SjqnFormService extends IService<SjqnForm> {
}
@@ -0,0 +1,10 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.gxmu.entity.SjtbzbsjForm;
/**
* 十佳团支部书记申报表Service
*/
public interface SjtbzbsjFormService extends IService<SjtbzbsjForm> {
}
@@ -0,0 +1,17 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.gxmu.entity.TyglForm;
import com.gxwebsoft.gxmu.param.TyglGrowthArchivesUpdateParam;
import com.gxwebsoft.gxmu.param.TyglMemberRecordsUpdateParam;
/**
* 团员管理Service
*/
public interface TyglFormService extends IService<TyglForm> {
TyglForm getCurrentUserForm(Integer userId, Integer tenantId);
boolean updateMemberRecords(Integer id, TyglMemberRecordsUpdateParam param);
boolean updateGrowthArchives(Integer id, TyglGrowthArchivesUpdateParam param);
}
@@ -0,0 +1,36 @@
package com.gxwebsoft.gxmu.service;
/**
* 挑战杯项目/人才库爬虫Service
*
* @author Codex
* @since 2026-04-14
*/
public interface TzbProjectLibraryCrawlerService {
/**
* 抓取并同步项目库列表
*/
void syncProjectList();
/**
* 抓取并同步项目库列表
*
* @param maxRows 本次最多同步记录数
* @return 实际写入/更新记录数
*/
int syncProjectList(int maxRows);
/**
* 抓取并同步人才库列表
*/
void syncTalentList();
/**
* 抓取并同步人才库列表
*
* @param maxRows 本次最多同步记录数
* @return 实际写入/更新记录数
*/
int syncTalentList(int maxRows);
}
@@ -0,0 +1,41 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.gxmu.entity.TzbProjectListRecord;
import com.gxwebsoft.gxmu.param.TzbProjectListRecordParam;
import java.util.List;
/**
* 挑战杯项目库列表Service
*
* @author Codex
* @since 2026-04-14
*/
public interface TzbProjectListRecordService extends IService<TzbProjectListRecord> {
/**
* 分页查询
*
* @param param 查询参数
* @return 分页结果
*/
PageResult<TzbProjectListRecord> pageRel(TzbProjectListRecordParam param);
/**
* 查询列表
*
* @param param 查询参数
* @return 列表数据
*/
List<TzbProjectListRecord> listRel(TzbProjectListRecordParam param);
/**
* 根据ID查询
*
* @param id 主键ID
* @return 列表记录
*/
TzbProjectListRecord getByIdRel(Integer id);
}
@@ -0,0 +1,41 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.gxmu.entity.TzbTalentListRecord;
import com.gxwebsoft.gxmu.param.TzbTalentListRecordParam;
import java.util.List;
/**
* 挑战杯人才库列表Service
*
* @author Codex
* @since 2026-04-14
*/
public interface TzbTalentListRecordService extends IService<TzbTalentListRecord> {
/**
* 分页查询
*
* @param param 查询参数
* @return 分页结果
*/
PageResult<TzbTalentListRecord> pageRel(TzbTalentListRecordParam param);
/**
* 查询列表
*
* @param param 查询参数
* @return 列表数据
*/
List<TzbTalentListRecord> listRel(TzbTalentListRecordParam param);
/**
* 根据ID查询
*
* @param id 主键ID
* @return 列表记录
*/
TzbTalentListRecord getByIdRel(Integer id);
}
@@ -0,0 +1,12 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.gxmu.entity.TzbcyForm;
import com.gxwebsoft.gxmu.model.TzbcyStatisticsResult;
/**
* 挑战杯创业计划竞赛申报表Service
*/
public interface TzbcyFormService extends IService<TzbcyForm> {
TzbcyStatisticsResult getStatistics(Integer year);
}
@@ -0,0 +1,31 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.FileRecord;
import com.gxwebsoft.gxmu.entity.TzbcyMaterial;
import com.gxwebsoft.gxmu.param.TzbcyMaterialParam;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
* 挑战杯申报材料Service
*/
public interface TzbcyMaterialService extends IService<TzbcyMaterial> {
PageResult<TzbcyMaterial> pageRel(TzbcyMaterialParam param);
List<TzbcyMaterial> listRel(TzbcyMaterialParam param);
TzbcyMaterial getByIdRel(Integer id);
boolean saveMaterial(TzbcyMaterial material, FileRecord fileRecord, Integer loginUserId, Integer tenantId);
boolean updateMaterial(TzbcyMaterial material, FileRecord fileRecord);
boolean audit(Integer id, Integer status, String rejectReason, Integer auditUserId);
FileRecord exportZip(TzbcyMaterialParam param, String uploadPath, String requestURL, Integer loginUserId)
throws IOException;
}
@@ -0,0 +1,7 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.gxmu.entity.WorkLedger;
public interface WorkLedgerService extends IService<WorkLedger> {
}
@@ -0,0 +1,10 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.gxmu.entity.WshqtwForm;
/**
* 五四红旗团委申报表Service
*/
public interface WshqtwFormService extends IService<WshqtwForm> {
}
@@ -0,0 +1,10 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.gxmu.entity.WshqtzbForm;
/**
* 五四红旗团支部申报表Service
*/
public interface WshqtzbFormService extends IService<WshqtzbForm> {
}
@@ -0,0 +1,12 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.gxmu.entity.WxxzxForm;
import com.gxwebsoft.gxmu.param.WxxzxMaterialUpdateParam;
/**
* 未来学术之星课题申报表Service
*/
public interface WxxzxFormService extends IService<WxxzxForm> {
boolean updateMaterials(Integer id, WxxzxMaterialUpdateParam param);
}
@@ -0,0 +1,10 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.gxmu.entity.YxgqtdgbForm;
/**
* 优秀共青团干部申报表Service
*/
public interface YxgqtdgbFormService extends IService<YxgqtdgbForm> {
}
@@ -0,0 +1,10 @@
package com.gxwebsoft.gxmu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.gxmu.entity.YxgqtyForm;
/**
* 优秀共青团员申报表Service
*/
public interface YxgqtyFormService extends IService<YxgqtyForm> {
}
@@ -0,0 +1,103 @@
package com.gxwebsoft.gxmu.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.Organization;
import com.gxwebsoft.common.system.service.OrganizationService;
import com.gxwebsoft.gxmu.entity.ClassInfo;
import com.gxwebsoft.gxmu.mapper.ClassInfoMapper;
import com.gxwebsoft.gxmu.param.ClassInfoParam;
import com.gxwebsoft.gxmu.service.ClassInfoService;
import com.gxwebsoft.gxmu.util.GxmuQueryHelper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 班级管理Service实现
*/
@Service
public class ClassInfoServiceImpl extends ServiceImpl<ClassInfoMapper, ClassInfo> implements ClassInfoService {
@Resource
private OrganizationService organizationService;
@Override
public PageResult<ClassInfo> pageRel(ClassInfoParam param) {
PageParam<ClassInfo, ClassInfoParam> page = new PageParam<>(param);
page.setDefaultOrder("sort_number asc, id desc");
QueryWrapper<ClassInfo> wrapper = buildWrapper(page, param);
IPage<ClassInfo> result = baseMapper.selectPage(page, wrapper);
bindCollegeName(result.getRecords(), param == null ? null : param.getTenantId());
return new PageResult<>(result.getRecords(), result.getTotal());
}
@Override
public List<ClassInfo> listRel(ClassInfoParam param) {
PageParam<ClassInfo, ClassInfoParam> page = new PageParam<>(param);
page.setDefaultOrder("sort_number asc, id desc");
QueryWrapper<ClassInfo> wrapper = buildWrapper(page, param);
List<ClassInfo> list = baseMapper.selectList(wrapper);
list = page.sortRecords(list);
bindCollegeName(list, param == null ? null : param.getTenantId());
return list;
}
@Override
public ClassInfo getByIdRel(Integer id, Integer tenantId) {
ClassInfo classInfo = baseMapper.selectOne(new LambdaQueryWrapper<ClassInfo>()
.eq(ClassInfo::getId, id)
.eq(ClassInfo::getTenantId, tenantId));
if (classInfo != null) {
Organization organization = organizationService.getOne(new LambdaQueryWrapper<Organization>()
.eq(Organization::getOrganizationId, classInfo.getCollegeId())
.eq(tenantId != null, Organization::getTenantId, tenantId));
if (organization != null) {
classInfo.setCollegeName(organization.getOrganizationName());
}
}
return classInfo;
}
private QueryWrapper<ClassInfo> buildWrapper(PageParam<ClassInfo, ClassInfoParam> page, ClassInfoParam param) {
QueryWrapper<ClassInfo> wrapper = page.getWrapper("keywords");
if (param != null && param.getTenantId() != null) {
wrapper.eq("tenant_id", param.getTenantId());
}
if (param == null || param.getDeleted() == null) {
wrapper.eq("deleted", 0);
}
if (param != null) {
GxmuQueryHelper.applyKeywords(wrapper, param.getKeywords(), "class_name", "class_code", "counselor_name");
}
return page.getOrderWrapper(wrapper);
}
private void bindCollegeName(List<ClassInfo> list, Integer tenantId) {
if (CollUtil.isEmpty(list)) {
return;
}
Set<Integer> collegeIds = list.stream()
.map(ClassInfo::getCollegeId)
.filter(id -> id != null)
.collect(Collectors.toSet());
if (CollUtil.isEmpty(collegeIds)) {
return;
}
List<Organization> organizationList = organizationService.list(new LambdaQueryWrapper<Organization>()
.in(Organization::getOrganizationId, collegeIds)
.eq(tenantId != null, Organization::getTenantId, tenantId));
Map<Integer, String> collegeMap = organizationList.stream()
.collect(Collectors.toMap(Organization::getOrganizationId, Organization::getOrganizationName, (a, b) -> a));
list.forEach(item -> item.setCollegeName(collegeMap.get(item.getCollegeId())));
}
}
@@ -0,0 +1,79 @@
package com.gxwebsoft.gxmu.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.gxmu.entity.College;
import com.gxwebsoft.gxmu.mapper.CollegeMapper;
import com.gxwebsoft.gxmu.param.CollegeParam;
import com.gxwebsoft.gxmu.service.CollegeService;
import com.gxwebsoft.gxmu.util.GxmuQueryHelper;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 学院管理Service实现
*/
@Service
public class CollegeServiceImpl extends ServiceImpl<CollegeMapper, College> implements CollegeService {
@Override
public PageResult<College> pageRel(CollegeParam param) {
PageParam<College, CollegeParam> page = new PageParam<>(param);
page.setDefaultOrder("sort_number asc, id desc");
QueryWrapper<College> wrapper = buildWrapper(page, param);
IPage<College> result = baseMapper.selectPage(page, wrapper);
bindClassCount(result.getRecords(), param == null ? null : param.getTenantId());
return new PageResult<>(result.getRecords(), result.getTotal());
}
@Override
public List<College> listRel(CollegeParam param) {
PageParam<College, CollegeParam> page = new PageParam<>(param);
page.setDefaultOrder("sort_number asc, id desc");
QueryWrapper<College> wrapper = buildWrapper(page, param);
List<College> list = baseMapper.selectList(wrapper);
list = page.sortRecords(list);
bindClassCount(list, param == null ? null : param.getTenantId());
return list;
}
@Override
public College getByIdRel(Integer id, Integer tenantId) {
College college = baseMapper.selectOne(new LambdaQueryWrapper<College>()
.eq(College::getId, id)
.eq(College::getTenantId, tenantId));
if (college != null) {
college.setClassCount(0);
}
return college;
}
private QueryWrapper<College> buildWrapper(PageParam<College, CollegeParam> page, CollegeParam param) {
QueryWrapper<College> wrapper = page.getWrapper("keywords");
if (param != null && param.getTenantId() != null) {
wrapper.eq("tenant_id", param.getTenantId());
}
if (param == null || param.getDeleted() == null) {
wrapper.eq("deleted", 0);
}
if (param != null) {
GxmuQueryHelper.applyKeywords(wrapper, param.getKeywords(), "college_name", "college_code", "short_name");
}
return page.getOrderWrapper(wrapper);
}
private void bindClassCount(List<College> list, Integer tenantId) {
if (CollUtil.isEmpty(list)) {
return;
}
for (College college : list) {
college.setClassCount(0);
}
}
}
@@ -0,0 +1,70 @@
package com.gxwebsoft.gxmu.service.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.gxmu.entity.CrossSchoolActivityArticle;
import com.gxwebsoft.gxmu.mapper.CrossSchoolActivityArticleMapper;
import com.gxwebsoft.gxmu.param.CrossSchoolActivityArticleParam;
import com.gxwebsoft.gxmu.service.CrossSchoolActivityArticleService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 跨校活动情报文章Service实现
*
* @author Codex
* @since 2026-07-04
*/
@Service
public class CrossSchoolActivityArticleServiceImpl
extends ServiceImpl<CrossSchoolActivityArticleMapper, CrossSchoolActivityArticle>
implements CrossSchoolActivityArticleService {
@Override
public PageResult<CrossSchoolActivityArticle> pageRel(CrossSchoolActivityArticleParam param) {
PageParam<CrossSchoolActivityArticle, CrossSchoolActivityArticleParam> page = new PageParam<>(param);
page.setDefaultOrder("publish_time desc, id desc");
QueryWrapper<CrossSchoolActivityArticle> wrapper = buildWrapper(page, param);
IPage<CrossSchoolActivityArticle> result = baseMapper.selectPage(page, wrapper);
return new PageResult<>(result.getRecords(), result.getTotal());
}
@Override
public List<CrossSchoolActivityArticle> listRel(CrossSchoolActivityArticleParam param) {
PageParam<CrossSchoolActivityArticle, CrossSchoolActivityArticleParam> page = new PageParam<>(param);
page.setDefaultOrder("publish_time desc, id desc");
QueryWrapper<CrossSchoolActivityArticle> wrapper = buildWrapper(page, param);
List<CrossSchoolActivityArticle> list = baseMapper.selectList(wrapper);
return page.sortRecords(list);
}
@Override
public CrossSchoolActivityArticle getByIdRel(Integer id) {
return baseMapper.selectById(id);
}
private QueryWrapper<CrossSchoolActivityArticle> buildWrapper(
PageParam<CrossSchoolActivityArticle, CrossSchoolActivityArticleParam> page,
CrossSchoolActivityArticleParam param
) {
QueryWrapper<CrossSchoolActivityArticle> wrapper = page.getWrapper();
if (param == null || param.getDeleted() == null) {
wrapper.eq("deleted", 0);
}
if (param != null && StrUtil.isNotBlank(param.getKeywords())) {
wrapper.and(q -> q.like("title", param.getKeywords())
.or()
.like("school_name", param.getKeywords())
.or()
.like("summary", param.getKeywords())
.or()
.like("tags", param.getKeywords()));
}
return page.getOrderWrapper(wrapper);
}
}
@@ -0,0 +1,450 @@
package com.gxwebsoft.gxmu.service.impl;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.gxwebsoft.gxmu.entity.CrossSchoolActivityArticle;
import com.gxwebsoft.gxmu.mapper.CrossSchoolActivityArticleMapper;
import com.gxwebsoft.gxmu.service.CrossSchoolActivityCrawlerService;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 跨校活动情报抓取Service实现
*
* @author Codex
* @since 2026-07-04
*/
@Service
public class CrossSchoolActivityCrawlerServiceImpl implements CrossSchoolActivityCrawlerService {
private static final Logger logger = LoggerFactory.getLogger(CrossSchoolActivityCrawlerServiceImpl.class);
private static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
+ "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36";
private static final Pattern FULL_DATE_PATTERN = Pattern.compile("(20\\d{2})[-/年.](\\d{1,2})[-/月.](\\d{1,2})");
private static final int MAX_ARTICLES_PER_RUN_LIMIT = 100;
private static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd")
.optionalStart()
.appendPattern(" HH:mm")
.optionalEnd()
.toFormatter(Locale.CHINA);
@Resource
private CrossSchoolActivityArticleMapper crossSchoolActivityArticleMapper;
@Value("${gxmu.cross-school-crawler.timeout-ms:15000}")
private int timeoutMs;
@Value("${gxmu.cross-school-crawler.max-retries:2}")
private int maxRetries;
@Value("${gxmu.cross-school-crawler.max-articles-per-site:12}")
private int maxArticlesPerSite;
@Value("${gxmu.cross-school-crawler.max-articles-per-run:100}")
private int maxArticlesPerRun;
@Override
public int syncAll() {
LocalDateTime syncTime = LocalDateTime.now();
int runLimit = resolveRunLimit();
int totalRows = 0;
for (SiteConfig site : buildSites()) {
if (totalRows >= runLimit) {
logger.info("跨校活动情报同步达到本轮上限 {} 条,停止继续抓取", runLimit);
break;
}
try {
List<CrossSchoolActivityArticle> articles = crawlSite(site, syncTime, runLimit - totalRows);
if (!CollectionUtils.isEmpty(articles)) {
crossSchoolActivityArticleMapper.batchUpsert(articles);
totalRows += articles.size();
}
logger.info("跨校活动情报同步来源完成:{},{} 条", site.schoolName, articles.size());
} catch (Exception e) {
logger.error("跨校活动情报同步来源失败:" + site.schoolName, e);
}
}
logger.info("跨校活动情报同步完成,共写入/更新 {} 条", totalRows);
return totalRows;
}
private List<CrossSchoolActivityArticle> crawlSite(SiteConfig site, LocalDateTime syncTime, int remainingLimit) {
int siteLimit = Math.min(Math.max(maxArticlesPerSite, 1), Math.max(remainingLimit, 0));
if (siteLimit <= 0) {
return new ArrayList<CrossSchoolActivityArticle>();
}
Document document = fetchDocument(site.listUrl);
Elements links = document.select(site.linkSelector);
Map<String, CrossSchoolActivityArticle> articleMap = new LinkedHashMap<String, CrossSchoolActivityArticle>();
for (Element link : links) {
if (articleMap.size() >= siteLimit) {
break;
}
String detailUrl = link.attr("abs:href");
if (StrUtil.isBlank(detailUrl) || articleMap.containsKey(detailUrl)) {
continue;
}
Element item = findContainer(link);
String title = firstNotBlank(link.attr("title"), selectText(item, ".title"), selectText(item, "h5"), link.text());
title = cleanTitle(title);
if (StrUtil.isBlank(title) || title.length() < 4) {
continue;
}
CrossSchoolActivityArticle article = new CrossSchoolActivityArticle();
article.setSourceKey(md5(detailUrl));
article.setTitle(title);
article.setSchoolName(site.schoolName);
article.setSourceName(site.sourceName);
article.setDetailUrl(detailUrl);
article.setSourceUrl(site.listUrl);
article.setSummary(truncate(firstNotBlank(selectText(item, ".abstract"), selectText(item, ".intro"), selectText(item, ".news_text"), selectText(item, "p")), 360));
article.setCoverImage(firstImage(item));
article.setPublishTime(parsePublishTime(item, title));
article.setLastSyncTime(syncTime);
enrichFromDetail(article);
enrichAnalysis(article);
LocalDateTime now = LocalDateTime.now();
article.setCreateTime(now);
article.setUpdateTime(now);
article.setDeleted(0);
articleMap.put(detailUrl, article);
}
return new ArrayList<CrossSchoolActivityArticle>(articleMap.values());
}
private int resolveRunLimit() {
return Math.min(Math.max(maxArticlesPerRun, 1), MAX_ARTICLES_PER_RUN_LIMIT);
}
private void enrichFromDetail(CrossSchoolActivityArticle article) {
try {
Document detail = fetchDocument(article.getDetailUrl());
String metaTitle = metaContent(detail, "ArticleTitle");
if (StrUtil.isNotBlank(metaTitle)) {
article.setTitle(cleanTitle(metaTitle));
}
String metaDate = firstNotBlank(metaContent(detail, "PubDate"), textAfter(detail.text(), "发布时间:"), textAfter(detail.text(), "日期:"));
LocalDateTime publishTime = parsePublishTime(metaDate);
if (publishTime != null) {
article.setPublishTime(publishTime);
}
String metaSource = firstNotBlank(metaContent(detail, "ContentSource"), textAfter(detail.text(), "来源:"));
if (StrUtil.isNotBlank(metaSource)) {
article.setSourceName(cleanSource(metaSource));
}
String contentText = firstNotBlank(
selectText(detail, ".v_news_content"),
selectText(detail, "[data-power-area=content] .conTxt"),
selectText(detail, ".conTxt"),
selectText(detail, ".news_text"),
selectText(detail, ".content")
);
article.setContentText(truncate(contentText, 4000));
String description = firstNotBlank(metaContent(detail, "Description"), contentText);
if (StrUtil.isBlank(article.getSummary())) {
article.setSummary(truncate(description, 360));
}
String cover = firstNotBlank(metaContent(detail, "Image"), firstImage(detail.selectFirst(".v_news_content, [data-power-area=content], .conTxt, .content")));
if (StrUtil.isBlank(article.getCoverImage())) {
article.setCoverImage(cover);
}
} catch (Exception e) {
logger.warn("跨校活动情报详情补充失败:{}", article.getDetailUrl());
}
}
private void enrichAnalysis(CrossSchoolActivityArticle article) {
String text = firstNotBlank(article.getTitle(), "") + " " + firstNotBlank(article.getSummary(), "");
String category = "校园要闻";
if (containsAny(text, "竞赛", "比赛", "挑战杯", "创新创业", "科创", "大赛", "项目", "一等奖", "二等奖", "冠军")) {
category = "科创竞赛";
} else if (containsAny(text, "实践", "志愿", "服务", "调研", "社会实践", "走访", "慰问")) {
category = "实践活动";
} else if (containsAny(text, "诵读", "歌", "体育", "运动", "文化", "艺术", "读书", "沙龙", "毕业典礼")) {
category = "文体活动";
} else if (containsAny(text, "团委", "青年", "学生", "党课", "培训", "座谈会", "交流")) {
category = "品牌活动";
}
article.setCategory(category);
LocalDate publishDate = article.getPublishTime() == null ? null : article.getPublishTime().toLocalDate();
long days = publishDate == null ? 99 : ChronoUnit.DAYS.between(publishDate, LocalDate.now());
boolean highSignal = containsAny(text, "全国", "一等奖", "冠军", "表彰", "揭牌", "成立", "重要讲话", "高质量");
if (days <= 3 && highSignal) {
article.setHeatLevel("高热");
} else if (days <= 7 || containsAny(text, "交流", "调研", "座谈", "培训", "比赛")) {
article.setHeatLevel("跟进");
} else {
article.setHeatLevel("观察");
}
Set<String> tags = new LinkedHashSet<String>();
tags.add(article.getSchoolName().replace("大学", ""));
tags.add(category);
addTagIfMatch(tags, text, "交流", "校际交流");
addTagIfMatch(tags, text, "竞赛", "赛事");
addTagIfMatch(tags, text, "比赛", "赛事");
addTagIfMatch(tags, text, "实践", "实践育人");
addTagIfMatch(tags, text, "培训", "培训");
addTagIfMatch(tags, text, "青年", "青年工作");
addTagIfMatch(tags, text, "学生", "学生参与");
article.setTags(JSON.toJSONString(tags));
article.setHighlight(resolveHighlight(category));
if (StrUtil.isBlank(article.getSummary())) {
article.setSummary("来源站点暂未提供摘要,可点击原文查看完整内容。");
}
}
private List<SiteConfig> buildSites() {
return Arrays.asList(
new SiteConfig("广西大学", "新闻中心", "https://news.gxu.edu.cn/", "a[href*='info/1002/']"),
new SiteConfig("广西师范大学", "师大要闻", "https://news.gxnu.edu.cn/1334/list.htm", "a[href*='/c1334a']"),
new SiteConfig("桂林医科大学", "桂医要闻", "https://www.glmu.edu.cn/xyzy/gyyw.htm", "a[href*='/info/1057/']"),
new SiteConfig("广西中医药大学", "学校要闻", "https://www.gxtcmu.edu.cn/xwzx/xyxw/xxyw", "a.tit[href*='/xwzx/xyxw/xxyw/content_']"),
new SiteConfig("桂林电子科技大学", "桂电要闻", "https://www.guet.edu.cn/gdyw_6356/list.htm", ".news_title a[href*='/c6356a']"),
new SiteConfig("桂林理工大学", "桂工要闻", "https://www.glut.edu.cn/ggyw.htm", ".list_box_riqi a[href*='info/1073/']")
);
}
private Document fetchDocument(String pageUrl) {
RuntimeException lastException = null;
int retryTimes = Math.max(maxRetries, 1);
for (int attempt = 1; attempt <= retryTimes; attempt++) {
try {
String body = HttpRequest.get(pageUrl)
.timeout(timeoutMs)
.header(Header.USER_AGENT, DEFAULT_USER_AGENT)
.header(Header.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
.execute()
.body();
return Jsoup.parse(body, pageUrl);
} catch (Exception e) {
lastException = new RuntimeException("抓取页面失败: " + pageUrl, e);
logger.warn("抓取跨校活动页面失败,第 {}/{} 次:{}", attempt, retryTimes, pageUrl);
}
}
throw lastException;
}
private Element findContainer(Element link) {
Element current = link;
for (int i = 0; i < 5 && current != null; i++) {
if ("li".equalsIgnoreCase(current.tagName()) || current.hasClass("news") || current.hasClass("con")) {
return current;
}
current = current.parent();
}
return link.parent() == null ? link : link.parent();
}
private LocalDateTime parsePublishTime(Element item, String title) {
String y = selectText(item, ".y");
String m = selectText(item, ".m");
if (StrUtil.isNotBlank(y) && StrUtil.isNotBlank(m)) {
LocalDateTime time = parsePublishTime(y.trim() + "-" + m.trim());
if (time != null) {
return time;
}
}
String d1 = selectText(item, ".d1");
String d2 = selectText(item, ".d2");
String d3 = selectText(item, ".d3");
if (StrUtil.isNotBlank(d1) && StrUtil.isNotBlank(d2) && StrUtil.isNotBlank(d3)) {
LocalDateTime time = parsePublishTime(d3.trim() + "-" + d2.replace(".", "").trim() + "-" + d1.trim());
if (time != null) {
return time;
}
}
return parsePublishTime(firstNotBlank(selectText(item, ".news_date"), selectText(item, ".date"), item.text(), title));
}
private LocalDateTime parsePublishTime(String text) {
if (StrUtil.isBlank(text)) {
return null;
}
Matcher matcher = FULL_DATE_PATTERN.matcher(text);
if (!matcher.find()) {
return null;
}
String date = matcher.group(1) + "-" + pad2(matcher.group(2)) + "-" + pad2(matcher.group(3));
try {
return LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();
} catch (Exception ignored) {
try {
return LocalDateTime.parse(date, DATE_TIME_FORMATTER);
} catch (Exception e) {
return null;
}
}
}
private String metaContent(Document document, String name) {
Element element = document.selectFirst("meta[name=" + name + "]");
return element == null ? null : normalizeText(element.attr("content"));
}
private String textAfter(String text, String marker) {
if (StrUtil.isBlank(text) || !text.contains(marker)) {
return null;
}
String value = text.substring(text.indexOf(marker) + marker.length());
int end = Math.min(value.length(), 32);
return normalizeText(value.substring(0, end));
}
private String selectText(Element element, String selector) {
if (element == null || StrUtil.isBlank(selector)) {
return null;
}
Element selected = element.selectFirst(selector);
return selected == null ? null : normalizeText(selected.text());
}
private String firstImage(Element element) {
if (element == null) {
return null;
}
Element image = element.selectFirst("img[src]");
return image == null ? null : image.attr("abs:src");
}
private String firstNotBlank(String... values) {
if (values == null) {
return null;
}
for (String value : values) {
if (StrUtil.isNotBlank(value)) {
return normalizeText(value);
}
}
return null;
}
private String cleanTitle(String title) {
if (StrUtil.isBlank(title)) {
return title;
}
return normalizeText(title).replaceAll("(20\\d{2}[-/.年]\\d{1,2}[-/.月]\\d{1,2}日?)$", "");
}
private String cleanSource(String source) {
if (StrUtil.isBlank(source)) {
return source;
}
return normalizeText(source).replace("发布时间", "").replace("日期", "").replace("点击数", "");
}
private String normalizeText(String text) {
if (text == null) {
return null;
}
return text.replace('\u00A0', ' ').replaceAll("\\s+", " ").trim();
}
private String truncate(String value, int maxLength) {
if (StrUtil.isBlank(value)) {
return value;
}
String text = normalizeText(value);
return text.length() <= maxLength ? text : text.substring(0, maxLength) + "...";
}
private boolean containsAny(String text, String... keywords) {
if (StrUtil.isBlank(text)) {
return false;
}
for (String keyword : keywords) {
if (text.contains(keyword)) {
return true;
}
}
return false;
}
private void addTagIfMatch(Set<String> tags, String text, String keyword, String tag) {
if (text.contains(keyword)) {
tags.add(tag);
}
}
private String resolveHighlight(String category) {
if ("科创竞赛".equals(category)) {
return "赛事成果 + 经验沉淀";
}
if ("实践活动".equals(category)) {
return "现场行动 + 后续报道";
}
if ("文体活动".equals(category)) {
return "主题内容 + 参与扩散";
}
if ("品牌活动".equals(category)) {
return "议题设计 + 组织联动";
}
return "选题跟踪 + 案例复盘";
}
private String pad2(String value) {
return value.length() == 1 ? "0" + value : value;
}
private String md5(String text) {
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] bytes = digest.digest(text.getBytes(StandardCharsets.UTF_8));
StringBuilder builder = new StringBuilder();
for (byte item : bytes) {
builder.append(String.format("%02x", item & 0xff));
}
return builder.toString();
} catch (Exception e) {
return String.valueOf(text.hashCode());
}
}
private static class SiteConfig {
private final String schoolName;
private final String sourceName;
private final String listUrl;
private final String linkSelector;
private SiteConfig(String schoolName, String sourceName, String listUrl, String linkSelector) {
this.schoolName = schoolName;
this.sourceName = sourceName;
this.listUrl = listUrl;
this.linkSelector = linkSelector;
}
}
}
@@ -0,0 +1,47 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.gxmu.mapper.DeclareMapper;
import com.gxwebsoft.gxmu.service.DeclareService;
import com.gxwebsoft.gxmu.entity.Declare;
import com.gxwebsoft.gxmu.param.DeclareParam;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 申报管理Service实现
*
* @author LX
* @since 2026-03-28 15:06:52
*/
@Service
public class DeclareServiceImpl extends ServiceImpl<DeclareMapper, Declare> implements DeclareService {
@Override
public PageResult<Declare> pageRel(DeclareParam param) {
PageParam<Declare, DeclareParam> page = new PageParam<>(param);
page.setDefaultOrder("create_time desc");
List<Declare> list = baseMapper.selectPageRel(page, param);
return new PageResult<>(list, page.getTotal());
}
@Override
public List<Declare> listRel(DeclareParam param) {
List<Declare> list = baseMapper.selectListRel(param);
// 排序
PageParam<Declare, DeclareParam> page = new PageParam<>();
page.setDefaultOrder("create_time desc");
return page.sortRecords(list);
}
@Override
public Declare getByIdRel(Integer id) {
DeclareParam param = new DeclareParam();
param.setId(id);
return param.getOne(baseMapper.selectListRel(param));
}
}
@@ -0,0 +1,41 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.gxmu.entity.QmgcForm;
import com.gxwebsoft.gxmu.mapper.QmgcFormMapper;
import com.gxwebsoft.gxmu.service.QmgcFormService;
import com.gxwebsoft.gxmu.service.ReviewListBindingService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
/**
* 青马工程培训班学员登记表Service实现
*/
@Service
public class QmgcFormServiceImpl extends ServiceImpl<QmgcFormMapper, QmgcForm> implements QmgcFormService {
@Resource
private ReviewListBindingService reviewListBindingService;
@Override
public <E extends IPage<QmgcForm>> E page(E page, Wrapper<QmgcForm> queryWrapper) {
return reviewListBindingService.bindPage(super.page(page, queryWrapper), "gxmu_qmgc_form",
QmgcForm::getId, QmgcForm::setReviewList);
}
@Override
public List<QmgcForm> list(Wrapper<QmgcForm> queryWrapper) {
return reviewListBindingService.bindList(super.list(queryWrapper), "gxmu_qmgc_form",
QmgcForm::getId, QmgcForm::setReviewList);
}
@Override
public QmgcForm getById(Serializable id) {
return reviewListBindingService.bindOne(super.getById(id), "gxmu_qmgc_form",
QmgcForm::getId, QmgcForm::setReviewList);
}
}
@@ -0,0 +1,120 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.gxmu.entity.ReviewFlow;
import com.gxwebsoft.gxmu.mapper.ReviewFlowConfigMapper;
import com.gxwebsoft.gxmu.service.ReviewFlowService;
import com.gxwebsoft.gxmu.service.ReviewFlowConfigService;
import com.gxwebsoft.gxmu.entity.ReviewFlowConfig;
import com.gxwebsoft.gxmu.param.ReviewFlowConfigParam;
import com.gxwebsoft.common.system.entity.Organization;
import com.gxwebsoft.common.system.service.OrganizationService;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Service实现
*
* @author LX
* @since 2026-03-18 10:37:18
*/
@Service
public class ReviewFlowConfigServiceImpl extends ServiceImpl<ReviewFlowConfigMapper, ReviewFlowConfig> implements ReviewFlowConfigService {
private static final Map<String, String> MODULE_NAME_MAP;
static {
Map<String, String> moduleNameMap = new LinkedHashMap<>();
moduleNameMap.put("cms_manuscript", "稿件");
moduleNameMap.put("gxmu_sjqn", "十佳青年岗位能手");
moduleNameMap.put("gxmu_sjtbzbsj", "十佳团支部书记");
moduleNameMap.put("gxmu_wshqtw", "五四红旗团委");
moduleNameMap.put("gxmu_wshqtzb", "五四红旗团支部");
moduleNameMap.put("gxmu_yxgqtdgb", "优秀共青团干部");
moduleNameMap.put("gxmu_yxgqty", "优秀共青团员");
moduleNameMap.put("gxmu_tzbcy_form", "挑战杯");
moduleNameMap.put("gxmu_qmgc_form", "青马工程");
moduleNameMap.put("gxmu_wxxzx_project", "未来学术之星");
MODULE_NAME_MAP = Collections.unmodifiableMap(moduleNameMap);
}
@Resource
private ReviewFlowService reviewFlowService;
@Resource
private OrganizationService organizationService;
@Override
public PageResult<ReviewFlowConfig> pageRel(ReviewFlowConfigParam param) {
PageParam<ReviewFlowConfig, ReviewFlowConfigParam> page = new PageParam<>(param);
page.setDefaultOrder("create_time desc");
List<ReviewFlowConfig> list = baseMapper.selectPageRel(page, param);
fillReviewFlowConfigNames(list);
return new PageResult<>(list, page.getTotal());
}
@Override
public List<ReviewFlowConfig> listRel(ReviewFlowConfigParam param) {
List<ReviewFlowConfig> list = baseMapper.selectListRel(param);
fillReviewFlowConfigNames(list);
// 排序
PageParam<ReviewFlowConfig, ReviewFlowConfigParam> page = new PageParam<>();
page.setDefaultOrder("create_time desc");
return page.sortRecords(list);
}
@Override
public ReviewFlowConfig getByIdRel(Integer id) {
ReviewFlowConfigParam param = new ReviewFlowConfigParam();
param.setId(id);
return param.getOne(baseMapper.selectListRel(param));
}
@Override
public ReviewFlowConfig getByModule(String module) {
return getOne(
new LambdaQueryWrapper<ReviewFlowConfig>()
.eq(ReviewFlowConfig::getModule, module)
.last("limit 1")
);
}
private void fillReviewFlowConfigNames(List<ReviewFlowConfig> list) {
if (list == null || list.isEmpty()) {
return;
}
Set<Integer> organizationIds = list.stream()
.map(ReviewFlowConfig::getOrganizationId)
.filter(organizationId -> organizationId != null)
.collect(Collectors.toSet());
Map<Integer, String> organizationNameMap = new HashMap<>();
if (!organizationIds.isEmpty()) {
organizationNameMap = organizationService.listByIds(organizationIds).stream()
.collect(Collectors.toMap(Organization::getOrganizationId, Organization::getOrganizationName, (left, right) -> left));
}
Set<Integer> flowIds = list.stream()
.map(ReviewFlowConfig::getFlowId)
.filter(flowId -> flowId != null)
.collect(Collectors.toSet());
Map<Integer, String> flowNameMap = new HashMap<>();
if (!flowIds.isEmpty()) {
flowNameMap = reviewFlowService.listByIds(flowIds).stream()
.collect(Collectors.toMap(ReviewFlow::getId, ReviewFlow::getTitle, (left, right) -> left));
}
for (ReviewFlowConfig item : list) {
item.setFlowName(flowNameMap.get(item.getFlowId()));
item.setModuleName(MODULE_NAME_MAP.get(item.getModule()));
item.setOrganizationName(organizationNameMap.get(item.getOrganizationId()));
}
}
}
@@ -0,0 +1,94 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.system.entity.Organization;
import com.gxwebsoft.common.system.service.OrganizationService;
import com.gxwebsoft.common.system.service.UserService;
import com.gxwebsoft.gxmu.mapper.ReviewFlowMapper;
import com.gxwebsoft.gxmu.service.ReviewFlowService;
import com.gxwebsoft.gxmu.entity.ReviewFlow;
import com.gxwebsoft.gxmu.param.ReviewFlowParam;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 审核流Service实现
*
* @author LX
* @since 2026-03-18 10:37:18
*/
@Service
public class ReviewFlowServiceImpl extends ServiceImpl<ReviewFlowMapper, ReviewFlow> implements ReviewFlowService {
@Resource
private OrganizationService organizationService;
@Resource
private UserService userService;
@Override
public PageResult<ReviewFlow> pageRel(ReviewFlowParam param) {
PageParam<ReviewFlow, ReviewFlowParam> page = new PageParam<>(param);
page.setDefaultOrder("create_time desc");
List<ReviewFlow> list = baseMapper.selectPageRel(page, param);
if (param.getWithGroup() != null && param.getWithGroup()) {
for (ReviewFlow reviewFlow : list) {
List<ReviewFlow> flows = list(
new LambdaQueryWrapper<ReviewFlow>()
.eq(ReviewFlow::getTitle, reviewFlow.getTitle())
.orderByAsc(ReviewFlow::getLevel)
);
if (!flows.isEmpty()) {
for (ReviewFlow flow : flows) {
Organization organization = organizationService.getById(flow.getOrganizationId());
if (organization != null) {
flow.setOrganizationName(organization.getOrganizationName());
}
if (flow.getReviewUserId() != null)
flow.setReviewUser(userService.getById(flow.getReviewUserId()));
}
}
reviewFlow.setFlows(flows);
}
}
return new PageResult<>(list, page.getTotal());
}
@Override
public List<ReviewFlow> listRel(ReviewFlowParam param) {
List<ReviewFlow> list = baseMapper.selectListRel(param);
// 排序
PageParam<ReviewFlow, ReviewFlowParam> page = new PageParam<>();
page.setDefaultOrder("create_time desc");
return page.sortRecords(list);
}
@Override
public ReviewFlow getByIdRel(Integer id) {
ReviewFlowParam param = new ReviewFlowParam();
param.setId(id);
return param.getOne(baseMapper.selectListRel(param));
}
@Override
public ReviewFlow getByTitle(String title) {
return getOne(
new LambdaQueryWrapper<ReviewFlow>()
.eq(ReviewFlow::getTitle, title)
.last("limit 1")
);
}
@Override
public List<ReviewFlow> listByTitle(String title) {
return list(
new LambdaQueryWrapper<ReviewFlow>()
.eq(ReviewFlow::getTitle, title)
.orderByAsc(ReviewFlow::getLevel)
);
}
}
@@ -0,0 +1,101 @@
package com.gxwebsoft.gxmu.service.impl;
import com.gxwebsoft.gxmu.entity.ReviewFlow;
import com.gxwebsoft.gxmu.entity.ReviewFlowConfig;
import com.gxwebsoft.gxmu.entity.ReviewList;
import com.gxwebsoft.gxmu.service.ReviewFlowConfigService;
import com.gxwebsoft.gxmu.service.ReviewFlowService;
import com.gxwebsoft.gxmu.service.ReviewFlowStarterService;
import com.gxwebsoft.gxmu.service.ReviewListService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
/**
* 审核流程发起服务实现
*
* @author LX
* @since 2026-03-18
*/
@Service
public class ReviewFlowStarterServiceImpl implements ReviewFlowStarterService {
@Resource
private ReviewFlowConfigService reviewFlowConfigService;
@Resource
private ReviewFlowService reviewFlowService;
@Resource
private ReviewListService reviewListService;
@Override
public void startReview(String module, Integer pk) {
if (module == null || pk == null) {
return;
}
List<ReviewList> reviewLists = reviewListService.listByModuleNPK(module, pk);
if (reviewLists != null && !reviewLists.isEmpty()) {
return;
}
ReviewFlowConfig reviewFlowConfig = reviewFlowConfigService.getByModule(module);
if (reviewFlowConfig == null || reviewFlowConfig.getFlowId() == null) {
return;
}
ReviewFlow firstOne = getFirstFlow(reviewFlowConfig);
if (firstOne == null) {
return;
}
saveFirstReviewNode(module, pk, firstOne);
}
@Override
public void restartReviewWhenLastRejected(String module, Integer pk) {
if (module == null || pk == null) {
return;
}
List<ReviewList> reviewLists = reviewListService.listByModuleNPK(module, pk);
if (reviewLists == null || reviewLists.isEmpty()) {
return;
}
ReviewList latestReview = reviewLists.stream()
.max(Comparator
.comparing(ReviewList::getCreateTime,
Comparator.nullsLast(LocalDateTime::compareTo))
.thenComparing(ReviewList::getId, Comparator.nullsLast(Integer::compareTo)))
.orElse(null);
if (latestReview == null || latestReview.getStatus() == null || latestReview.getStatus() != 2) {
return;
}
ReviewFlowConfig reviewFlowConfig = reviewFlowConfigService.getByModule(module);
if (reviewFlowConfig == null || reviewFlowConfig.getFlowId() == null) {
return;
}
ReviewFlow firstOne = getFirstFlow(reviewFlowConfig);
if (firstOne == null) {
return;
}
saveFirstReviewNode(module, pk, firstOne);
}
private ReviewFlow getFirstFlow(ReviewFlowConfig reviewFlowConfig) {
ReviewFlow reviewFlow = reviewFlowService.getById(reviewFlowConfig.getFlowId());
if (reviewFlow == null) {
return null;
}
List<ReviewFlow> reviewFlowList = reviewFlowService.listByTitle(reviewFlow.getTitle());
if (reviewFlowList == null || reviewFlowList.isEmpty()) {
return null;
}
return reviewFlowList.get(0);
}
private void saveFirstReviewNode(String module, Integer pk, ReviewFlow firstOne) {
ReviewList reviewList = new ReviewList();
reviewList.setPk(pk);
reviewList.setModule(module);
reviewList.setUserId(firstOne.getReviewUserId());
reviewList.setSortNumber(0);
reviewListService.save(reviewList);
}
}
@@ -0,0 +1,58 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.gxwebsoft.gxmu.entity.ReviewList;
import com.gxwebsoft.gxmu.service.ReviewListBindingService;
import com.gxwebsoft.gxmu.service.ReviewListService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Function;
/**
* 审核记录回填服务实现
*
* @author LX
* @since 2026-03-18
*/
@Service
public class ReviewListBindingServiceImpl implements ReviewListBindingService {
@Resource
private ReviewListService reviewListService;
@Override
public <T, E extends IPage<T>> E bindPage(E page, String module, Function<T, Integer> idGetter,
BiConsumer<T, List<ReviewList>> setter) {
if (page == null) {
return null;
}
bindList(page.getRecords(), module, idGetter, setter);
return page;
}
@Override
public <T> List<T> bindList(List<T> list, String module, Function<T, Integer> idGetter,
BiConsumer<T, List<ReviewList>> setter) {
if (list == null || list.isEmpty()) {
return list;
}
for (T item : list) {
Integer pk = idGetter.apply(item);
setter.accept(item, reviewListService.listByModuleNPK(module, pk));
}
return list;
}
@Override
public <T> T bindOne(T entity, String module, Function<T, Integer> idGetter,
BiConsumer<T, List<ReviewList>> setter) {
if (entity == null) {
return null;
}
Integer pk = idGetter.apply(entity);
setter.accept(entity, reviewListService.listByModuleNPK(module, pk));
return entity;
}
}
@@ -0,0 +1,116 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.system.service.UserService;
import com.gxwebsoft.gxmu.mapper.ReviewListMapper;
import com.gxwebsoft.gxmu.service.ReviewListService;
import com.gxwebsoft.gxmu.entity.ReviewList;
import com.gxwebsoft.gxmu.param.ReviewListParam;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* 审核列表Service实现
*
* @author LX
* @since 2026-03-18 15:50:51
*/
@Service
public class ReviewListServiceImpl extends ServiceImpl<ReviewListMapper, ReviewList> implements ReviewListService {
private static final Map<String, String> MODULE_NAME_MAP;
static {
Map<String, String> moduleNameMap = new LinkedHashMap<>();
moduleNameMap.put("cms_manuscript", "稿件");
moduleNameMap.put("gxmu_sjqn", "十佳青年岗位能手");
moduleNameMap.put("gxmu_sjtbzbsj", "十佳团支部书记");
moduleNameMap.put("gxmu_wshqtw", "五四红旗团委");
moduleNameMap.put("gxmu_wshqtzb", "五四红旗团支部");
moduleNameMap.put("gxmu_yxgqtdgb", "优秀共青团干部");
moduleNameMap.put("gxmu_yxgqty", "优秀共青团员");
moduleNameMap.put("gxmu_tzbcy_form", "挑战杯");
moduleNameMap.put("gxmu_qmgc_form", "青马工程");
moduleNameMap.put("gxmu_wxxzx_project", "未来学术之星");
MODULE_NAME_MAP = Collections.unmodifiableMap(moduleNameMap);
}
@Resource
private UserService userService;
@Override
public PageResult<ReviewList> pageRel(ReviewListParam param) {
PageParam<ReviewList, ReviewListParam> page = new PageParam<>(param);
page.setDefaultOrder("sort_number asc, create_time desc, id desc");
List<ReviewList> list = baseMapper.selectPageRel(page, param);
fillUsers(list);
fillModuleNames(list);
return new PageResult<>(list, page.getTotal());
}
@Override
public PageResult<ReviewList> pageGroupRel(ReviewListParam param) {
PageParam<ReviewList, ReviewListParam> page = new PageParam<>(param);
page.setDefaultOrder("create_time desc, id desc");
List<ReviewList> list = baseMapper.selectPageGroupRel(page, param);
fillUsers(list);
fillModuleNames(list);
return new PageResult<>(list, page.getTotal());
}
private void fillUsers(List<ReviewList> list) {
if (list == null || list.isEmpty()) {
return;
}
for (ReviewList reviewList : list) {
if (reviewList.getUserId() != null) {
reviewList.setUser(userService.getById(reviewList.getUserId()));
}
}
}
@Override
public List<ReviewList> listRel(ReviewListParam param) {
List<ReviewList> list = baseMapper.selectListRel(param);
fillModuleNames(list);
// 排序
PageParam<ReviewList, ReviewListParam> page = new PageParam<>();
page.setDefaultOrder("sort_number asc, create_time desc, id desc");
fillUsers(list);
return page.sortRecords(list);
}
@Override
public ReviewList getByIdRel(Integer id) {
ReviewListParam param = new ReviewListParam();
param.setId(id);
return param.getOne(baseMapper.selectListRel(param));
}
private void fillModuleNames(List<ReviewList> list) {
if (list == null || list.isEmpty()) {
return;
}
for (ReviewList item : list) {
item.setModuleName(MODULE_NAME_MAP.get(item.getModule()));
}
}
@Override
public List<ReviewList> listByModuleNPK(String module, Integer pk){
return list(
new LambdaQueryWrapper<ReviewList>()
.eq(ReviewList::getModule, module)
.eq(ReviewList::getPk, pk)
.orderByAsc(ReviewList::getSortNumber)
);
}
}
@@ -0,0 +1,41 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.gxmu.entity.SjqnForm;
import com.gxwebsoft.gxmu.mapper.SjqnFormMapper;
import com.gxwebsoft.gxmu.service.ReviewListBindingService;
import com.gxwebsoft.gxmu.service.SjqnFormService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
/**
* 十佳青年申报表Service实现
*/
@Service
public class SjqnFormServiceImpl extends ServiceImpl<SjqnFormMapper, SjqnForm> implements SjqnFormService {
@Resource
private ReviewListBindingService reviewListBindingService;
@Override
public <E extends IPage<SjqnForm>> E page(E page, Wrapper<SjqnForm> queryWrapper) {
return reviewListBindingService.bindPage(super.page(page, queryWrapper), "gxmu_sjqn",
SjqnForm::getId, SjqnForm::setReviewList);
}
@Override
public List<SjqnForm> list(Wrapper<SjqnForm> queryWrapper) {
return reviewListBindingService.bindList(super.list(queryWrapper), "gxmu_sjqn",
SjqnForm::getId, SjqnForm::setReviewList);
}
@Override
public SjqnForm getById(Serializable id) {
return reviewListBindingService.bindOne(super.getById(id), "gxmu_sjqn",
SjqnForm::getId, SjqnForm::setReviewList);
}
}
@@ -0,0 +1,41 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.gxmu.entity.SjtbzbsjForm;
import com.gxwebsoft.gxmu.mapper.SjtbzbsjFormMapper;
import com.gxwebsoft.gxmu.service.ReviewListBindingService;
import com.gxwebsoft.gxmu.service.SjtbzbsjFormService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
/**
* 十佳团支部书记申报表Service实现
*/
@Service
public class SjtbzbsjFormServiceImpl extends ServiceImpl<SjtbzbsjFormMapper, SjtbzbsjForm> implements SjtbzbsjFormService {
@Resource
private ReviewListBindingService reviewListBindingService;
@Override
public <E extends IPage<SjtbzbsjForm>> E page(E page, Wrapper<SjtbzbsjForm> queryWrapper) {
return reviewListBindingService.bindPage(super.page(page, queryWrapper), "gxmu_sjtbzbsj",
SjtbzbsjForm::getId, SjtbzbsjForm::setReviewList);
}
@Override
public List<SjtbzbsjForm> list(Wrapper<SjtbzbsjForm> queryWrapper) {
return reviewListBindingService.bindList(super.list(queryWrapper), "gxmu_sjtbzbsj",
SjtbzbsjForm::getId, SjtbzbsjForm::setReviewList);
}
@Override
public SjtbzbsjForm getById(Serializable id) {
return reviewListBindingService.bindOne(super.getById(id), "gxmu_sjtbzbsj",
SjtbzbsjForm::getId, SjtbzbsjForm::setReviewList);
}
}
@@ -0,0 +1,85 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.gxmu.entity.TyglForm;
import com.gxwebsoft.gxmu.mapper.TyglFormMapper;
import com.gxwebsoft.gxmu.param.TyglGrowthArchivesUpdateParam;
import com.gxwebsoft.gxmu.param.TyglMemberRecordsUpdateParam;
import com.gxwebsoft.gxmu.service.ReviewListBindingService;
import com.gxwebsoft.gxmu.service.TyglFormService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
/**
* 团员管理Service实现
*/
@Service
public class TyglFormServiceImpl extends ServiceImpl<TyglFormMapper, TyglForm>
implements TyglFormService {
@Resource
private ReviewListBindingService reviewListBindingService;
@Override
public <E extends IPage<TyglForm>> E page(E page, Wrapper<TyglForm> queryWrapper) {
return reviewListBindingService.bindPage(super.page(page, queryWrapper), "gxmu_tygl_form",
TyglForm::getId, TyglForm::setReviewList);
}
@Override
public List<TyglForm> list(Wrapper<TyglForm> queryWrapper) {
return reviewListBindingService.bindList(super.list(queryWrapper), "gxmu_tygl_form",
TyglForm::getId, TyglForm::setReviewList);
}
@Override
public TyglForm getById(Serializable id) {
return reviewListBindingService.bindOne(super.getById(id), "gxmu_tygl_form",
TyglForm::getId, TyglForm::setReviewList);
}
@Override
public TyglForm getCurrentUserForm(Integer userId, Integer tenantId) {
if (userId == null || tenantId == null) {
return null;
}
LambdaQueryWrapper<TyglForm> queryWrapper = new LambdaQueryWrapper<TyglForm>()
.eq(TyglForm::getUserId, userId)
.eq(TyglForm::getTenantId, tenantId)
.orderByDesc(TyglForm::getUpdateTime)
.orderByDesc(TyglForm::getId)
.last("limit 1");
return reviewListBindingService.bindOne(super.getOne(queryWrapper, false), "gxmu_tygl_form",
TyglForm::getId, TyglForm::setReviewList);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateMemberRecords(Integer id, TyglMemberRecordsUpdateParam param) {
if (id == null || param == null) {
return false;
}
TyglForm entity = new TyglForm();
entity.setId(id);
entity.setMemberRecords(param.getMemberRecords());
return super.updateById(entity);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateGrowthArchives(Integer id, TyglGrowthArchivesUpdateParam param) {
if (id == null || param == null) {
return false;
}
TyglForm entity = new TyglForm();
entity.setId(id);
entity.setGrowthArchives(param.getGrowthArchives());
return super.updateById(entity);
}
}
@@ -0,0 +1,341 @@
package com.gxwebsoft.gxmu.service.impl;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import com.gxwebsoft.gxmu.entity.TzbProjectListRecord;
import com.gxwebsoft.gxmu.entity.TzbTalentListRecord;
import com.gxwebsoft.gxmu.mapper.TzbProjectListRecordMapper;
import com.gxwebsoft.gxmu.mapper.TzbTalentListRecordMapper;
import com.gxwebsoft.gxmu.service.TzbProjectLibraryCrawlerService;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 挑战杯项目/人才库爬虫Service实现
*
* @author Codex
* @since 2026-04-14
*/
@Service
public class TzbProjectLibraryCrawlerServiceImpl implements TzbProjectLibraryCrawlerService {
private static final Logger logger = LoggerFactory.getLogger(TzbProjectLibraryCrawlerServiceImpl.class);
private static final String BASE_HOST = "https://xmk.tiaozhanbei.net";
private static final Pattern PAGE_PATTERN = Pattern.compile("[?&]page=(\\d+)");
private static final Pattern DETAIL_ID_PATTERN = Pattern.compile("/project/(\\d+)/");
private static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
+ "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36";
private static final int MAX_RECORDS_PER_RUN_LIMIT = 100;
@Resource
private TzbProjectListRecordMapper tzbProjectListRecordMapper;
@Resource
private TzbTalentListRecordMapper tzbTalentListRecordMapper;
@Value("${gxmu.tzb-crawler.project-list-url:https://xmk.tiaozhanbei.net/project/list/project/}")
private String projectListUrl;
@Value("${gxmu.tzb-crawler.talent-list-url:https://xmk.tiaozhanbei.net/project/list/talent/}")
private String talentListUrl;
@Value("${gxmu.tzb-crawler.timeout-ms:15000}")
private int timeoutMs;
@Value("${gxmu.tzb-crawler.max-retries:3}")
private int maxRetries;
@Value("${gxmu.tzb-crawler.max-pages:0}")
private int maxPages;
@Value("${gxmu.tzb-crawler.log-page-interval:100}")
private int logPageInterval;
@Override
public void syncProjectList() {
syncProjectList(Integer.MAX_VALUE);
}
@Override
public int syncProjectList(int maxRows) {
LocalDateTime syncTime = LocalDateTime.now();
int runLimit = resolveRunLimit(maxRows);
int totalRows = 0;
int totalPages = 1;
for (int pageNo = 1; pageNo <= totalPages; pageNo++) {
if (totalRows >= runLimit) {
logger.info("挑战杯项目库同步达到本次上限 {} 条,停止继续抓取", runLimit);
break;
}
String pageUrl = buildPageUrl(projectListUrl, pageNo);
Document document = fetchDocument(pageUrl);
if (pageNo == 1) {
totalPages = resolveTargetPages(document);
logger.info("挑战杯项目库开始同步,共 {} 页", totalPages);
}
List<TzbProjectListRecord> records = parseProjectRows(document, pageUrl, pageNo, syncTime, runLimit - totalRows);
if (CollectionUtils.isEmpty(records)) {
logger.warn("挑战杯项目库第 {} 页未解析到数据,提前结束", pageNo);
break;
}
tzbProjectListRecordMapper.batchUpsert(records);
totalRows += records.size();
logPageProgress("项目库", pageNo, totalPages, records.size(), totalRows);
}
logger.info("挑战杯项目库同步完成,共写入/更新 {} 条记录", totalRows);
return totalRows;
}
@Override
public void syncTalentList() {
syncTalentList(Integer.MAX_VALUE);
}
@Override
public int syncTalentList(int maxRows) {
LocalDateTime syncTime = LocalDateTime.now();
int runLimit = resolveRunLimit(maxRows);
int totalRows = 0;
int totalPages = 1;
for (int pageNo = 1; pageNo <= totalPages; pageNo++) {
if (totalRows >= runLimit) {
logger.info("挑战杯人才库同步达到本次上限 {} 条,停止继续抓取", runLimit);
break;
}
String pageUrl = buildPageUrl(talentListUrl, pageNo);
Document document = fetchDocument(pageUrl);
if (pageNo == 1) {
totalPages = resolveTargetPages(document);
logger.info("挑战杯人才库开始同步,共 {} 页", totalPages);
}
List<TzbTalentListRecord> records = parseTalentRows(document, pageUrl, pageNo, syncTime, runLimit - totalRows);
if (CollectionUtils.isEmpty(records)) {
logger.warn("挑战杯人才库第 {} 页未解析到数据,提前结束", pageNo);
break;
}
tzbTalentListRecordMapper.batchUpsert(records);
totalRows += records.size();
logPageProgress("人才库", pageNo, totalPages, records.size(), totalRows);
}
logger.info("挑战杯人才库同步完成,共写入/更新 {} 条记录", totalRows);
return totalRows;
}
private void logPageProgress(String typeName, int pageNo, int totalPages, int pageRows, int totalRows) {
if (pageNo == 1 || pageNo == totalPages || (logPageInterval > 0 && pageNo % logPageInterval == 0)) {
logger.info("挑战杯{}同步进度:第 {}/{} 页,本页 {} 条,累计 {} 条", typeName, pageNo, totalPages, pageRows, totalRows);
}
}
private int resolveTargetPages(Document document) {
int resolvedPages = resolveTotalPages(document);
if (maxPages > 0) {
return Math.min(resolvedPages, maxPages);
}
return resolvedPages;
}
private int resolveTotalPages(Document document) {
int maxPage = 1;
Elements links = document.select("nav[aria-label=pagination] a[href*=\"page=\"]");
for (Element link : links) {
int pageNo = extractPageNumber(link.attr("href"));
if (pageNo > maxPage) {
maxPage = pageNo;
}
}
return maxPage;
}
private int resolveRunLimit(int maxRows) {
return Math.min(Math.max(maxRows, 1), MAX_RECORDS_PER_RUN_LIMIT);
}
private List<TzbProjectListRecord> parseProjectRows(Document document, String pageUrl, int pageNo, LocalDateTime syncTime, int remainingLimit) {
List<TzbProjectListRecord> records = new ArrayList<TzbProjectListRecord>();
int rowLimit = Math.max(remainingLimit, 0);
if (rowLimit <= 0) {
return records;
}
Elements rows = document.select("table tbody tr");
for (Element row : rows) {
if (records.size() >= rowLimit) {
break;
}
Elements cells = row.select("td");
if (cells.size() < 7) {
continue;
}
String detailUrl = getDetailUrl(row);
Long sourceId = extractSourceId(detailUrl);
if (sourceId == null) {
continue;
}
LocalDateTime now = LocalDateTime.now();
TzbProjectListRecord record = new TzbProjectListRecord();
record.setSourceId(sourceId);
record.setProjectName(normalizeText(cells.get(0).select("div").text()));
record.setSchoolName(normalizeText(cells.get(1).text()));
record.setAwardName(normalizeText(cells.get(2).text()));
record.setMatchYear(parseInteger(normalizeText(cells.get(3).text())));
record.setMatchTerm(normalizeText(cells.get(4).text()));
record.setMatchLevel(normalizeText(cells.get(5).text()));
record.setCoverImage(row.select("td:eq(0) img").attr("abs:src"));
record.setDetailUrl(detailUrl);
record.setSourceUrl(pageUrl);
record.setPageNo(pageNo);
record.setLastSyncTime(syncTime);
record.setCreateTime(now);
record.setUpdateTime(now);
record.setDeleted(0);
records.add(record);
}
return records;
}
private List<TzbTalentListRecord> parseTalentRows(Document document, String pageUrl, int pageNo, LocalDateTime syncTime, int remainingLimit) {
List<TzbTalentListRecord> records = new ArrayList<TzbTalentListRecord>();
int rowLimit = Math.max(remainingLimit, 0);
if (rowLimit <= 0) {
return records;
}
Elements rows = document.select("table tbody tr");
for (Element row : rows) {
if (records.size() >= rowLimit) {
break;
}
Elements cells = row.select("td");
if (cells.size() < 8) {
continue;
}
String detailUrl = getDetailUrl(row);
Long sourceId = extractSourceId(detailUrl);
if (sourceId == null) {
continue;
}
LocalDateTime now = LocalDateTime.now();
TzbTalentListRecord record = new TzbTalentListRecord();
record.setSourceId(sourceId);
record.setPersonName(normalizeText(cells.get(0).select("div").text()));
record.setSchoolName(normalizeText(cells.get(1).text()));
record.setTalentType(normalizeText(cells.get(2).text()));
record.setProjectName(normalizeText(cells.get(3).text()));
record.setAwardName(normalizeText(cells.get(4).text()));
record.setMatchTerm(normalizeText(cells.get(5).text()));
record.setMatchLevel(normalizeText(cells.get(6).text()));
record.setCoverImage(row.select("td:eq(0) img").attr("abs:src"));
record.setDetailUrl(detailUrl);
record.setSourceUrl(pageUrl);
record.setPageNo(pageNo);
record.setLastSyncTime(syncTime);
record.setCreateTime(now);
record.setUpdateTime(now);
record.setDeleted(0);
records.add(record);
}
return records;
}
private Document fetchDocument(String pageUrl) {
RuntimeException lastException = null;
int retryTimes = Math.max(maxRetries, 1);
for (int attempt = 1; attempt <= retryTimes; attempt++) {
try {
String body = HttpRequest.get(pageUrl)
.timeout(timeoutMs)
.header(Header.USER_AGENT, DEFAULT_USER_AGENT)
.header(Header.REFERER, BASE_HOST + "/project/")
.execute()
.body();
return Jsoup.parse(body, BASE_HOST);
} catch (Exception e) {
lastException = new RuntimeException("抓取页面失败: " + pageUrl + ",第 " + attempt + " 次重试失败", e);
logger.warn("抓取页面失败,第 {}/{} 次:{}", attempt, retryTimes, pageUrl);
}
}
throw lastException;
}
private String buildPageUrl(String baseUrl, int pageNo) {
if (pageNo <= 1) {
return baseUrl;
}
return baseUrl + (baseUrl.contains("?") ? "&" : "?") + "page=" + pageNo;
}
private String getDetailUrl(Element row) {
Element link = row.select("a[href]").last();
if (link == null) {
return null;
}
return link.attr("abs:href");
}
private int extractPageNumber(String href) {
if (StrUtil.isBlank(href)) {
return 0;
}
Matcher matcher = PAGE_PATTERN.matcher(href);
if (matcher.find()) {
return parseInteger(matcher.group(1), 0);
}
return 0;
}
private Long extractSourceId(String detailUrl) {
if (StrUtil.isBlank(detailUrl)) {
return null;
}
Matcher matcher = DETAIL_ID_PATTERN.matcher(detailUrl);
if (matcher.find()) {
try {
return Long.valueOf(matcher.group(1));
} catch (NumberFormatException e) {
logger.warn("解析详情ID失败:{}", detailUrl);
}
}
return null;
}
private Integer parseInteger(String value) {
return parseInteger(value, null);
}
private Integer parseInteger(String value, Integer defaultValue) {
if (StrUtil.isBlank(value)) {
return defaultValue;
}
try {
return Integer.valueOf(value);
} catch (NumberFormatException e) {
return defaultValue;
}
}
private String normalizeText(String value) {
if (value == null) {
return null;
}
return value.replace('\u00A0', ' ').replaceAll("\\s+", " ").trim();
}
}
@@ -0,0 +1,69 @@
package com.gxwebsoft.gxmu.service.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.gxmu.entity.TzbProjectListRecord;
import com.gxwebsoft.gxmu.mapper.TzbProjectListRecordMapper;
import com.gxwebsoft.gxmu.param.TzbProjectListRecordParam;
import com.gxwebsoft.gxmu.service.TzbProjectListRecordService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 挑战杯项目库列表Service实现
*
* @author Codex
* @since 2026-04-14
*/
@Service
public class TzbProjectListRecordServiceImpl extends ServiceImpl<TzbProjectListRecordMapper, TzbProjectListRecord>
implements TzbProjectListRecordService {
@Override
public PageResult<TzbProjectListRecord> pageRel(TzbProjectListRecordParam param) {
PageParam<TzbProjectListRecord, TzbProjectListRecordParam> page = new PageParam<>(param);
page.setDefaultOrder("source_id desc");
QueryWrapper<TzbProjectListRecord> wrapper = buildWrapper(page, param);
IPage<TzbProjectListRecord> result = baseMapper.selectPage(page, wrapper);
return new PageResult<>(result.getRecords(), result.getTotal());
}
@Override
public List<TzbProjectListRecord> listRel(TzbProjectListRecordParam param) {
PageParam<TzbProjectListRecord, TzbProjectListRecordParam> page = new PageParam<>(param);
page.setDefaultOrder("source_id desc");
QueryWrapper<TzbProjectListRecord> wrapper = buildWrapper(page, param);
List<TzbProjectListRecord> list = baseMapper.selectList(wrapper);
return page.sortRecords(list);
}
@Override
public TzbProjectListRecord getByIdRel(Integer id) {
return baseMapper.selectById(id);
}
private QueryWrapper<TzbProjectListRecord> buildWrapper(
PageParam<TzbProjectListRecord, TzbProjectListRecordParam> page,
TzbProjectListRecordParam param
) {
QueryWrapper<TzbProjectListRecord> wrapper = page.getWrapper();
if (param == null || param.getDeleted() == null) {
wrapper.eq("deleted", 0);
}
if (param != null && StrUtil.isNotBlank(param.getKeywords())) {
wrapper.and(q -> q.like("project_name", param.getKeywords())
.or()
.like("school_name", param.getKeywords())
.or()
.like("award_name", param.getKeywords())
.or()
.like("match_term", param.getKeywords()));
}
return page.getOrderWrapper(wrapper);
}
}
@@ -0,0 +1,71 @@
package com.gxwebsoft.gxmu.service.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.gxmu.entity.TzbTalentListRecord;
import com.gxwebsoft.gxmu.mapper.TzbTalentListRecordMapper;
import com.gxwebsoft.gxmu.param.TzbTalentListRecordParam;
import com.gxwebsoft.gxmu.service.TzbTalentListRecordService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 挑战杯人才库列表Service实现
*
* @author Codex
* @since 2026-04-14
*/
@Service
public class TzbTalentListRecordServiceImpl extends ServiceImpl<TzbTalentListRecordMapper, TzbTalentListRecord>
implements TzbTalentListRecordService {
@Override
public PageResult<TzbTalentListRecord> pageRel(TzbTalentListRecordParam param) {
PageParam<TzbTalentListRecord, TzbTalentListRecordParam> page = new PageParam<>(param);
page.setDefaultOrder("source_id desc");
QueryWrapper<TzbTalentListRecord> wrapper = buildWrapper(page, param);
IPage<TzbTalentListRecord> result = baseMapper.selectPage(page, wrapper);
return new PageResult<>(result.getRecords(), result.getTotal());
}
@Override
public List<TzbTalentListRecord> listRel(TzbTalentListRecordParam param) {
PageParam<TzbTalentListRecord, TzbTalentListRecordParam> page = new PageParam<>(param);
page.setDefaultOrder("source_id desc");
QueryWrapper<TzbTalentListRecord> wrapper = buildWrapper(page, param);
List<TzbTalentListRecord> list = baseMapper.selectList(wrapper);
return page.sortRecords(list);
}
@Override
public TzbTalentListRecord getByIdRel(Integer id) {
return baseMapper.selectById(id);
}
private QueryWrapper<TzbTalentListRecord> buildWrapper(
PageParam<TzbTalentListRecord, TzbTalentListRecordParam> page,
TzbTalentListRecordParam param
) {
QueryWrapper<TzbTalentListRecord> wrapper = page.getWrapper();
if (param == null || param.getDeleted() == null) {
wrapper.eq("deleted", 0);
}
if (param != null && StrUtil.isNotBlank(param.getKeywords())) {
wrapper.and(q -> q.like("person_name", param.getKeywords())
.or()
.like("school_name", param.getKeywords())
.or()
.like("project_name", param.getKeywords())
.or()
.like("award_name", param.getKeywords())
.or()
.like("talent_type", param.getKeywords()));
}
return page.getOrderWrapper(wrapper);
}
}
@@ -0,0 +1,262 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.gxmu.entity.ReviewList;
import com.gxwebsoft.gxmu.entity.TzbcyForm;
import com.gxwebsoft.gxmu.mapper.TzbcyFormMapper;
import com.gxwebsoft.gxmu.model.TzbcyStatisticsResult;
import com.gxwebsoft.gxmu.service.ReviewListBindingService;
import com.gxwebsoft.gxmu.service.TzbcyFormService;
import com.gxwebsoft.gxmu.util.TzbcyFormItemNormalizer;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 挑战杯创业计划竞赛申报表Service实现
*/
@Service
public class TzbcyFormServiceImpl extends ServiceImpl<TzbcyFormMapper, TzbcyForm> implements TzbcyFormService {
@Resource
private ReviewListBindingService reviewListBindingService;
@Override
public <E extends IPage<TzbcyForm>> E page(E page, Wrapper<TzbcyForm> queryWrapper) {
E result = reviewListBindingService.bindPage(super.page(page, queryWrapper), "gxmu_tzbcy_form",
TzbcyForm::getId, TzbcyForm::setReviewList);
normalizeForms(result.getRecords());
return result;
}
@Override
public List<TzbcyForm> list(Wrapper<TzbcyForm> queryWrapper) {
List<TzbcyForm> result = reviewListBindingService.bindList(super.list(queryWrapper), "gxmu_tzbcy_form",
TzbcyForm::getId, TzbcyForm::setReviewList);
normalizeForms(result);
return result;
}
@Override
public TzbcyForm getById(Serializable id) {
TzbcyForm result = reviewListBindingService.bindOne(super.getById(id), "gxmu_tzbcy_form",
TzbcyForm::getId, TzbcyForm::setReviewList);
normalizeForm(result);
return result;
}
@Override
public TzbcyStatisticsResult getStatistics(Integer year) {
List<TzbcyForm> allForms = list(new LambdaQueryWrapper<TzbcyForm>()
.orderByDesc(TzbcyForm::getYear)
.orderByDesc(TzbcyForm::getId));
List<TzbcyForm> filteredForms = allForms.stream()
.filter(item -> year == null || year.equals(item.getYear()))
.collect(Collectors.toList());
TzbcyStatisticsResult result = new TzbcyStatisticsResult();
result.setYear(year);
result.setAvailableYears(allForms.stream()
.map(TzbcyForm::getYear)
.filter(item -> item != null)
.distinct()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList()));
result.setAwardCountDescription("当前按“审核通过作品数”统计获奖数量。");
TzbcyStatisticsResult.Summary summary = new TzbcyStatisticsResult.Summary();
summary.setDeclarationCount(filteredForms.size());
summary.setParticipantCount(countDistinctParticipants(filteredForms));
summary.setAdvisorCount(countDistinctAdvisors(filteredForms));
summary.setAwardCount((int) filteredForms.stream().filter(this::isAwardedForm).count());
summary.setSchoolCount((int) filteredForms.stream()
.map(TzbcyForm::getSchoolName)
.filter(this::hasText)
.map(String::trim)
.distinct()
.count());
result.setSummary(summary);
result.setYearDistribution(buildDistribution(allForms, new LabelExtractor() {
@Override
public String extract(TzbcyForm form) {
return form.getYear() == null ? "未填年份" : String.valueOf(form.getYear());
}
}, false, 0));
result.setTypeDistribution(buildDistribution(filteredForms, new LabelExtractor() {
@Override
public String extract(TzbcyForm form) {
return form.getProjectType();
}
}, true, 0));
result.setGroupDistribution(buildDistribution(filteredForms, new LabelExtractor() {
@Override
public String extract(TzbcyForm form) {
return form.getProjectGroup();
}
}, true, 0));
result.setSchoolDistribution(buildDistribution(filteredForms, new LabelExtractor() {
@Override
public String extract(TzbcyForm form) {
return form.getSchoolName();
}
}, true, 10));
return result;
}
private int countDistinctParticipants(List<TzbcyForm> forms) {
Set<String> participants = new LinkedHashSet<>();
for (TzbcyForm form : forms) {
if (form.getTeamMembers() == null) {
continue;
}
for (TzbcyForm.TeamMember member : form.getTeamMembers()) {
String key = buildPersonKey(member == null ? null : member.getName(),
member == null ? null : member.getPhone());
if (key != null) {
participants.add(key);
}
}
}
return participants.size();
}
private int countDistinctAdvisors(List<TzbcyForm> forms) {
Set<String> advisors = new LinkedHashSet<>();
for (TzbcyForm form : forms) {
if (form.getAdvisors() == null) {
continue;
}
for (TzbcyForm.Advisor advisor : form.getAdvisors()) {
String key = buildPersonKey(advisor == null ? null : advisor.getName(),
advisor == null ? null : advisor.getPhone());
if (key != null) {
advisors.add(key);
}
}
}
return advisors.size();
}
private boolean isAwardedForm(TzbcyForm form) {
if (form == null || form.getReviewList() == null || form.getReviewList().isEmpty()) {
return false;
}
List<ReviewList> reviewList = form.getReviewList();
ReviewList latest = reviewList.get(reviewList.size() - 1);
return latest != null && latest.getStatus() != null && latest.getStatus() == 1;
}
private String buildPersonKey(String name, String phone) {
String normalizedName = normalizeText(name);
String normalizedPhone = normalizeText(phone);
if (normalizedName == null && normalizedPhone == null) {
return null;
}
if (normalizedName != null && normalizedPhone != null) {
return normalizedName + "#" + normalizedPhone;
}
return normalizedName != null ? normalizedName : normalizedPhone;
}
private String normalizeText(String value) {
if (!hasText(value)) {
return null;
}
return value.trim();
}
private boolean hasText(String value) {
return value != null && !value.trim().isEmpty();
}
private List<TzbcyStatisticsResult.StatisticItem> buildDistribution(List<TzbcyForm> forms,
LabelExtractor extractor,
boolean sortByValueDesc,
int limit) {
if (forms == null || forms.isEmpty()) {
return new ArrayList<>();
}
Map<String, Integer> countMap = new LinkedHashMap<>();
for (TzbcyForm form : forms) {
String label = normalizeText(extractor.extract(form));
if (label == null) {
label = "未填写";
}
countMap.put(label, countMap.getOrDefault(label, 0) + 1);
}
List<TzbcyStatisticsResult.StatisticItem> list = countMap.entrySet().stream()
.map(item -> new TzbcyStatisticsResult.StatisticItem(item.getKey(), item.getValue()))
.collect(Collectors.toList());
if (sortByValueDesc) {
list.sort(Comparator
.comparing(TzbcyStatisticsResult.StatisticItem::getValue, Comparator.reverseOrder())
.thenComparing(TzbcyStatisticsResult.StatisticItem::getLabel, Comparator.nullsLast(String::compareTo)));
} else {
list.sort(new Comparator<TzbcyStatisticsResult.StatisticItem>() {
@Override
public int compare(TzbcyStatisticsResult.StatisticItem left, TzbcyStatisticsResult.StatisticItem right) {
Integer leftYear = parseYear(left.getLabel());
Integer rightYear = parseYear(right.getLabel());
if (leftYear != null && rightYear != null) {
return leftYear.compareTo(rightYear);
}
if (leftYear != null) {
return -1;
}
if (rightYear != null) {
return 1;
}
String leftLabel = left.getLabel() == null ? "" : left.getLabel();
String rightLabel = right.getLabel() == null ? "" : right.getLabel();
return leftLabel.compareTo(rightLabel);
}
});
}
if (limit > 0 && list.size() > limit) {
return new ArrayList<>(list.subList(0, limit));
}
return list;
}
private Integer parseYear(String value) {
if (!hasText(value)) {
return null;
}
try {
return Integer.parseInt(value.trim());
} catch (NumberFormatException e) {
return null;
}
}
private void normalizeForms(List<TzbcyForm> forms) {
if (forms == null || forms.isEmpty()) {
return;
}
for (TzbcyForm form : forms) {
normalizeForm(form);
}
}
private void normalizeForm(TzbcyForm form) {
TzbcyFormItemNormalizer.normalize(form);
}
private interface LabelExtractor {
String extract(TzbcyForm form);
}
}
@@ -0,0 +1,319 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.config.ConfigProperties;
import com.gxwebsoft.common.core.exception.BusinessException;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.FileRecord;
import com.gxwebsoft.common.system.service.FileRecordService;
import com.gxwebsoft.gxmu.entity.TzbcyForm;
import com.gxwebsoft.gxmu.entity.TzbcyMaterial;
import com.gxwebsoft.gxmu.mapper.TzbcyMaterialMapper;
import com.gxwebsoft.gxmu.param.TzbcyMaterialParam;
import com.gxwebsoft.gxmu.service.TzbcyFormService;
import com.gxwebsoft.gxmu.service.TzbcyMaterialService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 挑战杯申报材料Service实现
*/
@Service
public class TzbcyMaterialServiceImpl extends ServiceImpl<TzbcyMaterialMapper, TzbcyMaterial>
implements TzbcyMaterialService {
@Resource
private TzbcyFormService tzbcyFormService;
@Resource
private FileRecordService fileRecordService;
@Resource
private ConfigProperties config;
@Override
public PageResult<TzbcyMaterial> pageRel(TzbcyMaterialParam param) {
PageParam<TzbcyMaterial, TzbcyMaterialParam> page = new PageParam<>(param);
page.setDefaultOrder("id desc");
List<TzbcyMaterial> list = baseMapper.selectPageRel(page, param);
normalizeFileUrls(list);
return new PageResult<>(list, page.getTotal());
}
@Override
public List<TzbcyMaterial> listRel(TzbcyMaterialParam param) {
List<TzbcyMaterial> list = baseMapper.selectListRel(param);
normalizeFileUrls(list);
return list;
}
@Override
public TzbcyMaterial getByIdRel(Integer id) {
TzbcyMaterialParam param = new TzbcyMaterialParam();
param.setId(id);
List<TzbcyMaterial> list = baseMapper.selectListRel(param);
normalizeFileUrls(list);
return list == null || list.isEmpty() ? null : list.get(0);
}
@Override
public boolean saveMaterial(TzbcyMaterial material, FileRecord fileRecord, Integer loginUserId, Integer tenantId) {
validateEditablePayload(material, fileRecord);
TzbcyForm form = tzbcyFormService.getById(material.getFormId());
if (form == null) {
throw new BusinessException("申报记录不存在");
}
fillFileInfo(material, fileRecord);
material.setStatus(0);
material.setRejectReason(null);
material.setAuditUserId(null);
material.setAuditTime(null);
material.setUserId(loginUserId != null ? loginUserId : form.getUserId());
material.setTenantId(tenantId);
return save(material);
}
@Override
public boolean updateMaterial(TzbcyMaterial material, FileRecord fileRecord) {
validateEditablePayload(material, fileRecord);
TzbcyMaterial old = getById(material.getId());
if (old == null) {
throw new BusinessException("材料不存在");
}
if (Integer.valueOf(1).equals(old.getStatus())) {
throw new BusinessException("材料已审核通过,不能再编辑");
}
material.setFormId(old.getFormId());
fillFileInfo(material, fileRecord);
material.setStatus(0);
material.setRejectReason(null);
material.setAuditUserId(null);
material.setAuditTime(null);
material.setUserId(old.getUserId());
material.setTenantId(old.getTenantId());
return updateById(material);
}
@Override
public boolean audit(Integer id, Integer status, String rejectReason, Integer auditUserId) {
if (!Integer.valueOf(1).equals(status) && !Integer.valueOf(2).equals(status)) {
throw new BusinessException("审核状态不正确");
}
TzbcyMaterial old = getById(id);
if (old == null) {
throw new BusinessException("材料不存在");
}
TzbcyMaterial update = new TzbcyMaterial();
update.setId(id);
update.setStatus(status);
update.setRejectReason(Integer.valueOf(2).equals(status) ? rejectReason : null);
update.setAuditUserId(auditUserId);
update.setAuditTime(LocalDateTime.now());
return updateById(update);
}
@Override
public FileRecord exportZip(TzbcyMaterialParam param, String uploadPath, String requestURL, Integer loginUserId)
throws IOException {
List<TzbcyMaterial> materials = listRel(param);
if (materials == null || materials.isEmpty()) {
throw new BusinessException("暂无可导出的材料");
}
String relativePath = "file/zip/挑战杯材料_" + System.currentTimeMillis() + ".zip";
File targetFile = new File(uploadPath + relativePath);
File parentFile = targetFile.getParentFile();
if (parentFile != null && !parentFile.exists()) {
parentFile.mkdirs();
}
Set<String> entryNames = new LinkedHashSet<>();
int count = 0;
try (FileOutputStream outputStream = new FileOutputStream(targetFile);
ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
byte[] buffer = new byte[8192];
for (TzbcyMaterial material : materials) {
File sourceFile = resolveSourceFile(material, uploadPath);
if (sourceFile == null || !sourceFile.exists() || !sourceFile.isFile()) {
continue;
}
String entryName = buildEntryName(material, entryNames);
zipOutputStream.putNextEntry(new ZipEntry(entryName));
try (FileInputStream inputStream = new FileInputStream(sourceFile)) {
int len;
while ((len = inputStream.read(buffer)) != -1) {
zipOutputStream.write(buffer, 0, len);
}
}
zipOutputStream.closeEntry();
count++;
}
zipOutputStream.finish();
}
if (count == 0) {
targetFile.delete();
throw new BusinessException("暂无可导出的实体文件");
}
FileRecord result = new FileRecord();
result.setCreateUserId(loginUserId);
result.setName(targetFile.getName());
result.setPath(targetFile.getAbsolutePath());
result.setLength(targetFile.length());
result.setContentType("application/zip");
result.setUrl(trimEnd(requestURL) + "/" + relativePath);
result.setDownloadUrl(result.getUrl());
fileRecordService.save(result);
return result;
}
private void validateEditablePayload(TzbcyMaterial material, FileRecord fileRecord) {
if (material == null || material.getFormId() == null && material.getId() == null) {
throw new BusinessException("材料参数不完整");
}
if (!hasText(material.getMaterialType())) {
throw new BusinessException("请输入材料类型");
}
if (fileRecord == null || fileRecord.getId() == null) {
throw new BusinessException("请上传材料文件");
}
}
private void fillFileInfo(TzbcyMaterial material, FileRecord fileRecord) {
material.setFileId(fileRecord.getId());
material.setFileName(fileRecord.getName());
material.setFilePath(fileRecord.getPath());
material.setFileUrl(resolveFileUrl(fileRecord.getPath()));
material.setDownloadUrl(resolveDownloadUrl(fileRecord.getPath()));
material.setFileSize(fileRecord.getLength());
material.setContentType(fileRecord.getContentType());
}
private void normalizeFileUrls(List<TzbcyMaterial> materials) {
if (materials == null || materials.isEmpty()) {
return;
}
for (TzbcyMaterial material : materials) {
if (material == null) {
continue;
}
String path = material.getFilePath();
if (!hasText(path) && material.getFileId() != null) {
FileRecord fileRecord = fileRecordService.getById(material.getFileId());
path = fileRecord == null ? null : fileRecord.getPath();
if (fileRecord != null && !hasText(material.getFileName())) {
material.setFileName(fileRecord.getName());
}
}
if (!hasText(material.getFileUrl())) {
material.setFileUrl(resolveFileUrl(path));
}
if (!hasText(material.getDownloadUrl())) {
material.setDownloadUrl(resolveDownloadUrl(path));
}
}
}
private String resolveFileUrl(String path) {
if (!hasText(path)) {
return null;
}
return (trimEnd(config.getFileServer()) + "/api/file/" + normalizeUrlPath(path))
.replace("file//", "file/");
}
private String resolveDownloadUrl(String path) {
if (!hasText(path)) {
return null;
}
return trimEnd(config.getFileServer()) + "/download" + ensureLeadingSlash(path);
}
private File resolveSourceFile(TzbcyMaterial material, String uploadPath) {
FileRecord fileRecord = material.getFileId() == null ? null : fileRecordService.getById(material.getFileId());
String path = fileRecord != null && hasText(fileRecord.getPath()) ? fileRecord.getPath() : material.getFilePath();
if (!hasText(path)) {
return null;
}
File file = new File(path);
if (file.isAbsolute()) {
return file;
}
String normalized = path.startsWith("/") ? path.substring(1) : path;
if (normalized.startsWith("file/")) {
normalized = normalized.substring("file/".length());
}
return new File(uploadPath + "file/", normalized);
}
private String buildEntryName(TzbcyMaterial material, Set<String> entryNames) {
String folder = safeName(material.getMaterialType(), "未分类");
String project = safeName(material.getProjectName(), "项目");
String leader = safeName(material.getLeader(), "负责人");
String fileName = safeName(material.getFileName(), "材料");
String baseName = folder + "/" + project + "_" + leader + "_" + fileName;
String entryName = baseName;
int index = 1;
while (entryNames.contains(entryName)) {
entryName = appendIndex(baseName, index++);
}
entryNames.add(entryName);
return entryName;
}
private String appendIndex(String name, int index) {
int slashIndex = name.lastIndexOf('/');
int dotIndex = name.lastIndexOf('.');
if (dotIndex > slashIndex) {
return name.substring(0, dotIndex) + "_" + index + name.substring(dotIndex);
}
return name + "_" + index;
}
private String safeName(String value, String fallback) {
String text = hasText(value) ? value.trim() : fallback;
text = text.replaceAll("[\\\\/:*?\"<>|]", "_");
return text.length() > 80 ? text.substring(0, 80) : text;
}
private boolean hasText(String value) {
return value != null && !value.trim().isEmpty();
}
private String trimEnd(String value) {
if (value == null) {
return "";
}
while (value.endsWith("/")) {
value = value.substring(0, value.length() - 1);
}
return value;
}
private String normalizeUrlPath(String path) {
String normalized = ensureLeadingSlash(path);
if (normalized == null) {
return "";
}
return normalized.startsWith("/") ? normalized.substring(1) : normalized;
}
private String ensureLeadingSlash(String path) {
if (!hasText(path)) {
return null;
}
return path.startsWith("/") ? path : "/" + path;
}
}
@@ -0,0 +1,12 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.gxmu.entity.WorkLedger;
import com.gxwebsoft.gxmu.mapper.WorkLedgerMapper;
import com.gxwebsoft.gxmu.service.WorkLedgerService;
import org.springframework.stereotype.Service;
@Service
public class WorkLedgerServiceImpl extends ServiceImpl<WorkLedgerMapper, WorkLedger>
implements WorkLedgerService {
}
@@ -0,0 +1,41 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.gxmu.entity.WshqtwForm;
import com.gxwebsoft.gxmu.mapper.WshqtwFormMapper;
import com.gxwebsoft.gxmu.service.ReviewListBindingService;
import com.gxwebsoft.gxmu.service.WshqtwFormService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
/**
* 五四红旗团委申报表Service实现
*/
@Service
public class WshqtwFormServiceImpl extends ServiceImpl<WshqtwFormMapper, WshqtwForm> implements WshqtwFormService {
@Resource
private ReviewListBindingService reviewListBindingService;
@Override
public <E extends IPage<WshqtwForm>> E page(E page, Wrapper<WshqtwForm> queryWrapper) {
return reviewListBindingService.bindPage(super.page(page, queryWrapper), "gxmu_wshqtw",
WshqtwForm::getId, WshqtwForm::setReviewList);
}
@Override
public List<WshqtwForm> list(Wrapper<WshqtwForm> queryWrapper) {
return reviewListBindingService.bindList(super.list(queryWrapper), "gxmu_wshqtw",
WshqtwForm::getId, WshqtwForm::setReviewList);
}
@Override
public WshqtwForm getById(Serializable id) {
return reviewListBindingService.bindOne(super.getById(id), "gxmu_wshqtw",
WshqtwForm::getId, WshqtwForm::setReviewList);
}
}
@@ -0,0 +1,41 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.gxmu.entity.WshqtzbForm;
import com.gxwebsoft.gxmu.mapper.WshqtzbFormMapper;
import com.gxwebsoft.gxmu.service.ReviewListBindingService;
import com.gxwebsoft.gxmu.service.WshqtzbFormService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
/**
* 五四红旗团支部申报表Service实现
*/
@Service
public class WshqtzbFormServiceImpl extends ServiceImpl<WshqtzbFormMapper, WshqtzbForm> implements WshqtzbFormService {
@Resource
private ReviewListBindingService reviewListBindingService;
@Override
public <E extends IPage<WshqtzbForm>> E page(E page, Wrapper<WshqtzbForm> queryWrapper) {
return reviewListBindingService.bindPage(super.page(page, queryWrapper), "gxmu_wshqtzb",
WshqtzbForm::getId, WshqtzbForm::setReviewList);
}
@Override
public List<WshqtzbForm> list(Wrapper<WshqtzbForm> queryWrapper) {
return reviewListBindingService.bindList(super.list(queryWrapper), "gxmu_wshqtzb",
WshqtzbForm::getId, WshqtzbForm::setReviewList);
}
@Override
public WshqtzbForm getById(Serializable id) {
return reviewListBindingService.bindOne(super.getById(id), "gxmu_wshqtzb",
WshqtzbForm::getId, WshqtzbForm::setReviewList);
}
}
@@ -0,0 +1,349 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.gxmu.entity.WxxzxApplicant;
import com.gxwebsoft.gxmu.entity.WxxzxArchiveRecord;
import com.gxwebsoft.gxmu.entity.WxxzxBudgetItem;
import com.gxwebsoft.gxmu.entity.WxxzxForm;
import com.gxwebsoft.gxmu.entity.WxxzxGuidanceTeacher;
import com.gxwebsoft.gxmu.entity.WxxzxReviewMemberEntity;
import com.gxwebsoft.gxmu.mapper.WxxzxApplicantMapper;
import com.gxwebsoft.gxmu.mapper.WxxzxArchiveRecordMapper;
import com.gxwebsoft.gxmu.mapper.WxxzxBudgetItemMapper;
import com.gxwebsoft.gxmu.mapper.WxxzxFormMapper;
import com.gxwebsoft.gxmu.mapper.WxxzxGuidanceTeacherMapper;
import com.gxwebsoft.gxmu.mapper.WxxzxReviewMemberEntityMapper;
import com.gxwebsoft.gxmu.param.WxxzxMaterialUpdateParam;
import com.gxwebsoft.gxmu.service.ReviewListBindingService;
import com.gxwebsoft.gxmu.service.WxxzxFormService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* 未来学术之星课题申报表Service实现
*/
@Service
public class WxxzxFormServiceImpl extends ServiceImpl<WxxzxFormMapper, WxxzxForm> implements WxxzxFormService {
@Resource
private WxxzxGuidanceTeacherMapper guidanceTeacherMapper;
@Resource
private WxxzxApplicantMapper applicantMapper;
@Resource
private WxxzxArchiveRecordMapper archiveRecordMapper;
@Resource
private WxxzxBudgetItemMapper budgetItemMapper;
@Resource
private WxxzxReviewMemberEntityMapper reviewMemberEntityMapper;
@Resource
private ReviewListBindingService reviewListBindingService;
@Override
public <E extends IPage<WxxzxForm>> E page(E page, Wrapper<WxxzxForm> queryWrapper) {
return reviewListBindingService.bindPage(super.page(page, queryWrapper), "gxmu_wxxzx_project",
WxxzxForm::getId, WxxzxForm::setReviewList);
}
@Override
public List<WxxzxForm> list(Wrapper<WxxzxForm> queryWrapper) {
return reviewListBindingService.bindList(super.list(queryWrapper), "gxmu_wxxzx_project",
WxxzxForm::getId, WxxzxForm::setReviewList);
}
@Override
public WxxzxForm getById(Serializable id) {
WxxzxForm form = super.getById(id);
if (form == null) {
return null;
}
fillChildren(form);
return reviewListBindingService.bindOne(form, "gxmu_wxxzx_project",
WxxzxForm::getId, WxxzxForm::setReviewList);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean save(WxxzxForm entity) {
boolean saved = super.save(entity);
if (!saved) {
return false;
}
saveChildren(entity);
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateById(WxxzxForm entity) {
boolean updated = super.updateById(entity);
if (!updated) {
return false;
}
removeChildren(entity.getId());
saveChildren(entity);
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateMaterials(Integer id, WxxzxMaterialUpdateParam param) {
if (id == null || param == null) {
return false;
}
WxxzxForm entity = new WxxzxForm();
entity.setId(id);
entity.setFundingBudgetFile(param.getFundingBudgetFile());
entity.setFundingAllocationFile(param.getFundingAllocationFile());
entity.setMidtermRemark(param.getMidtermRemark());
entity.setMidtermMaterials(param.getMidtermMaterials());
entity.setFinalRemark(param.getFinalRemark());
entity.setFinalMaterials(param.getFinalMaterials());
entity.setArchiveAwards(param.getArchiveAwards());
entity.setArchiveProofs(param.getArchiveProofs());
boolean updated = super.updateById(entity);
if (!updated) {
return false;
}
WxxzxForm current = super.getById(id);
replaceArchiveRecords(id, param.getArchiveRecords(), current);
return true;
}
private void fillChildren(WxxzxForm form) {
Integer projectId = form.getId();
form.setGuidanceTeachers(guidanceTeacherMapper.selectList(
new LambdaQueryWrapper<WxxzxGuidanceTeacher>()
.eq(WxxzxGuidanceTeacher::getProjectId, projectId)
.orderByAsc(WxxzxGuidanceTeacher::getTeacherOrder)
).stream().map(this::toGuidanceTeacher).collect(Collectors.toList()));
form.setApplicants(applicantMapper.selectList(
new LambdaQueryWrapper<WxxzxApplicant>()
.eq(WxxzxApplicant::getProjectId, projectId)
.orderByAsc(WxxzxApplicant::getApplicantOrder)
).stream().map(this::toApplicant).collect(Collectors.toList()));
form.setBudgets(budgetItemMapper.selectList(
new LambdaQueryWrapper<WxxzxBudgetItem>()
.eq(WxxzxBudgetItem::getProjectId, projectId)
.orderByAsc(WxxzxBudgetItem::getBudgetOrder)
).stream().map(this::toBudget).collect(Collectors.toList()));
form.setReviewMembers(reviewMemberEntityMapper.selectList(
new LambdaQueryWrapper<WxxzxReviewMemberEntity>()
.eq(WxxzxReviewMemberEntity::getProjectId, projectId)
.orderByAsc(WxxzxReviewMemberEntity::getMemberOrder)
).stream().map(this::toReviewMember).collect(Collectors.toList()));
form.setArchiveRecords(archiveRecordMapper.selectList(
new LambdaQueryWrapper<WxxzxArchiveRecord>()
.eq(WxxzxArchiveRecord::getProjectId, projectId)
.orderByAsc(WxxzxArchiveRecord::getArchiveOrder)
).stream().map(this::toArchiveRecord).collect(Collectors.toList()));
}
private void saveChildren(WxxzxForm form) {
if (form.getId() == null) {
return;
}
Long userId = form.getUserId() == null ? null : form.getUserId().longValue();
Long tenantId = form.getTenantId() == null ? null : form.getTenantId().longValue();
List<WxxzxForm.GuidanceTeacher> guidanceTeachers = filterItems(
form.getGuidanceTeachers(),
item -> hasText(item.getName()) || hasText(item.getGender()) || hasText(item.getTitle())
|| hasText(item.getDept()) || hasText(item.getSign())
);
for (int i = 0; i < guidanceTeachers.size(); i++) {
WxxzxForm.GuidanceTeacher item = guidanceTeachers.get(i);
WxxzxGuidanceTeacher entity = new WxxzxGuidanceTeacher();
entity.setProjectId(form.getId());
entity.setTeacherOrder(i + 1);
entity.setName(item.getName());
entity.setGender(item.getGender());
entity.setJobTitle(item.getTitle());
entity.setDepartmentName(item.getDept());
entity.setSignName(item.getSign());
entity.setYear(form.getYear());
entity.setUserId(userId);
entity.setTenantId(tenantId);
guidanceTeacherMapper.insert(entity);
}
List<WxxzxForm.Applicant> applicants = filterItems(
form.getApplicants(),
item -> hasText(item.getName()) || hasText(item.getGrade()) || hasText(item.getClassName())
|| hasText(item.getGender()) || hasText(item.getMajor()) || hasText(item.getRole())
);
for (int i = 0; i < applicants.size(); i++) {
WxxzxForm.Applicant item = applicants.get(i);
WxxzxApplicant entity = new WxxzxApplicant();
entity.setProjectId(form.getId());
entity.setApplicantOrder(i + 1);
entity.setName(item.getName());
entity.setGrade(item.getGrade());
entity.setClassName(item.getClassName());
entity.setGender(item.getGender());
entity.setMajor(item.getMajor());
entity.setRoleDesc(item.getRole());
entity.setYear(form.getYear());
entity.setUserId(userId);
entity.setTenantId(tenantId);
applicantMapper.insert(entity);
}
List<WxxzxForm.Budget> budgets = filterItems(
form.getBudgets(),
item -> hasText(item.getItem()) || hasText(item.getAmount()) || hasText(item.getReason())
);
for (int i = 0; i < budgets.size(); i++) {
WxxzxForm.Budget item = budgets.get(i);
WxxzxBudgetItem entity = new WxxzxBudgetItem();
entity.setProjectId(form.getId());
entity.setBudgetOrder(i + 1);
entity.setExpenseItem(item.getItem());
entity.setAmount(item.getAmount());
entity.setReason(item.getReason());
entity.setYear(form.getYear());
entity.setUserId(userId);
entity.setTenantId(tenantId);
budgetItemMapper.insert(entity);
}
List<WxxzxForm.ReviewMember> reviewMembers = filterItems(
form.getReviewMembers(),
item -> hasText(item.getName()) || hasText(item.getGender()) || hasText(item.getNation())
|| hasText(item.getPolitics()) || hasText(item.getBirthMonth()) || hasText(item.getTitle())
|| hasText(item.getDuty()) || hasText(item.getDepartment()) || hasText(item.getRemark())
);
for (int i = 0; i < reviewMembers.size(); i++) {
WxxzxForm.ReviewMember item = reviewMembers.get(i);
WxxzxReviewMemberEntity entity = new WxxzxReviewMemberEntity();
entity.setProjectId(form.getId());
entity.setMemberOrder(i + 1);
entity.setName(item.getName());
entity.setGender(item.getGender());
entity.setNation(item.getNation());
entity.setPolitics(item.getPolitics());
entity.setBirthMonth(item.getBirthMonth());
entity.setJobTitle(item.getTitle());
entity.setDuty(item.getDuty());
entity.setDepartmentName(item.getDepartment());
entity.setRemark(item.getRemark());
entity.setYear(form.getYear());
entity.setUserId(userId);
entity.setTenantId(tenantId);
reviewMemberEntityMapper.insert(entity);
}
}
private void removeChildren(Integer projectId) {
guidanceTeacherMapper.delete(new LambdaQueryWrapper<WxxzxGuidanceTeacher>()
.eq(WxxzxGuidanceTeacher::getProjectId, projectId));
applicantMapper.delete(new LambdaQueryWrapper<WxxzxApplicant>()
.eq(WxxzxApplicant::getProjectId, projectId));
budgetItemMapper.delete(new LambdaQueryWrapper<WxxzxBudgetItem>()
.eq(WxxzxBudgetItem::getProjectId, projectId));
reviewMemberEntityMapper.delete(new LambdaQueryWrapper<WxxzxReviewMemberEntity>()
.eq(WxxzxReviewMemberEntity::getProjectId, projectId));
archiveRecordMapper.delete(new LambdaQueryWrapper<WxxzxArchiveRecord>()
.eq(WxxzxArchiveRecord::getProjectId, projectId));
}
private WxxzxForm.GuidanceTeacher toGuidanceTeacher(WxxzxGuidanceTeacher entity) {
WxxzxForm.GuidanceTeacher item = new WxxzxForm.GuidanceTeacher();
item.setName(entity.getName());
item.setGender(entity.getGender());
item.setTitle(entity.getJobTitle());
item.setDept(entity.getDepartmentName());
item.setSign(entity.getSignName());
return item;
}
private WxxzxForm.Applicant toApplicant(WxxzxApplicant entity) {
WxxzxForm.Applicant item = new WxxzxForm.Applicant();
item.setName(entity.getName());
item.setGrade(entity.getGrade());
item.setClassName(entity.getClassName());
item.setGender(entity.getGender());
item.setMajor(entity.getMajor());
item.setRole(entity.getRoleDesc());
return item;
}
private WxxzxForm.Budget toBudget(WxxzxBudgetItem entity) {
WxxzxForm.Budget item = new WxxzxForm.Budget();
item.setItem(entity.getExpenseItem());
item.setAmount(entity.getAmount());
item.setReason(entity.getReason());
return item;
}
private WxxzxForm.ReviewMember toReviewMember(WxxzxReviewMemberEntity entity) {
WxxzxForm.ReviewMember item = new WxxzxForm.ReviewMember();
item.setName(entity.getName());
item.setGender(entity.getGender());
item.setNation(entity.getNation());
item.setPolitics(entity.getPolitics());
item.setBirthMonth(entity.getBirthMonth());
item.setTitle(entity.getJobTitle());
item.setDuty(entity.getDuty());
item.setDepartment(entity.getDepartmentName());
item.setRemark(entity.getRemark());
return item;
}
private WxxzxForm.ArchiveRecord toArchiveRecord(WxxzxArchiveRecord entity) {
WxxzxForm.ArchiveRecord item = new WxxzxForm.ArchiveRecord();
item.setId(entity.getId());
item.setAwardName(entity.getAwardName());
item.setAwardTime(entity.getAwardTime());
item.setRemark(entity.getRemark());
item.setProofFile(entity.getProofFile());
return item;
}
private void replaceArchiveRecords(Integer projectId, List<WxxzxForm.ArchiveRecord> archiveRecords,
WxxzxForm current) {
archiveRecordMapper.delete(new LambdaQueryWrapper<WxxzxArchiveRecord>()
.eq(WxxzxArchiveRecord::getProjectId, projectId));
List<WxxzxForm.ArchiveRecord> records = filterItems(
archiveRecords,
item -> hasText(item.getAwardName()) || hasText(item.getAwardTime())
|| hasText(item.getRemark()) || hasText(item.getProofFile())
);
for (int i = 0; i < records.size(); i++) {
WxxzxForm.ArchiveRecord item = records.get(i);
WxxzxArchiveRecord entity = new WxxzxArchiveRecord();
entity.setProjectId(projectId);
entity.setArchiveOrder(i + 1);
entity.setAwardName(item.getAwardName());
entity.setAwardTime(item.getAwardTime());
entity.setRemark(item.getRemark());
entity.setProofFile(item.getProofFile());
if (current != null) {
entity.setYear(current.getYear());
entity.setUserId(current.getUserId() == null ? null : current.getUserId().longValue());
entity.setTenantId(current.getTenantId() == null ? null : current.getTenantId().longValue());
}
archiveRecordMapper.insert(entity);
}
}
private <T> List<T> filterItems(List<T> items, Predicate<T> predicate) {
if (items == null || items.isEmpty()) {
return new ArrayList<>();
}
return items.stream().filter(Objects::nonNull).filter(predicate).collect(Collectors.toList());
}
private boolean hasText(String value) {
return value != null && !value.trim().isEmpty();
}
}
@@ -0,0 +1,41 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.gxmu.entity.YxgqtdgbForm;
import com.gxwebsoft.gxmu.mapper.YxgqtdgbFormMapper;
import com.gxwebsoft.gxmu.service.ReviewListBindingService;
import com.gxwebsoft.gxmu.service.YxgqtdgbFormService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
/**
* 优秀共青团干部申报表Service实现
*/
@Service
public class YxgqtdgbFormServiceImpl extends ServiceImpl<YxgqtdgbFormMapper, YxgqtdgbForm> implements YxgqtdgbFormService {
@Resource
private ReviewListBindingService reviewListBindingService;
@Override
public <E extends IPage<YxgqtdgbForm>> E page(E page, Wrapper<YxgqtdgbForm> queryWrapper) {
return reviewListBindingService.bindPage(super.page(page, queryWrapper), "gxmu_yxgqtdgb",
YxgqtdgbForm::getId, YxgqtdgbForm::setReviewList);
}
@Override
public List<YxgqtdgbForm> list(Wrapper<YxgqtdgbForm> queryWrapper) {
return reviewListBindingService.bindList(super.list(queryWrapper), "gxmu_yxgqtdgb",
YxgqtdgbForm::getId, YxgqtdgbForm::setReviewList);
}
@Override
public YxgqtdgbForm getById(Serializable id) {
return reviewListBindingService.bindOne(super.getById(id), "gxmu_yxgqtdgb",
YxgqtdgbForm::getId, YxgqtdgbForm::setReviewList);
}
}
@@ -0,0 +1,41 @@
package com.gxwebsoft.gxmu.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.gxmu.entity.YxgqtyForm;
import com.gxwebsoft.gxmu.mapper.YxgqtyFormMapper;
import com.gxwebsoft.gxmu.service.ReviewListBindingService;
import com.gxwebsoft.gxmu.service.YxgqtyFormService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
/**
* 优秀共青团员申报表Service实现
*/
@Service
public class YxgqtyFormServiceImpl extends ServiceImpl<YxgqtyFormMapper, YxgqtyForm> implements YxgqtyFormService {
@Resource
private ReviewListBindingService reviewListBindingService;
@Override
public <E extends IPage<YxgqtyForm>> E page(E page, Wrapper<YxgqtyForm> queryWrapper) {
return reviewListBindingService.bindPage(super.page(page, queryWrapper), "gxmu_yxgqty",
YxgqtyForm::getId, YxgqtyForm::setReviewList);
}
@Override
public List<YxgqtyForm> list(Wrapper<YxgqtyForm> queryWrapper) {
return reviewListBindingService.bindList(super.list(queryWrapper), "gxmu_yxgqty",
YxgqtyForm::getId, YxgqtyForm::setReviewList);
}
@Override
public YxgqtyForm getById(Serializable id) {
return reviewListBindingService.bindOne(super.getById(id), "gxmu_yxgqty",
YxgqtyForm::getId, YxgqtyForm::setReviewList);
}
}