Merge remote-tracking branch 'origin/main'

This commit is contained in:
2026-08-26 13:55:59 +08:00
168 changed files with 26590 additions and 5518 deletions
@@ -87,6 +87,9 @@ public class FamilyActivityApplyController {
Cnd cnd = Cnd.NEW();
cnd.andEX("id", "=", id);
cnd.andEX("`year`", "=", year);
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
cnd.and("activityName", "like", "%" + pageForm.getSearchKeyword().trim() + "%");
}
//查询报名中
if (activityType == 2) {
cnd.and(new Static("now() < activitySignUpEndTime"));
@@ -117,6 +120,7 @@ public class FamilyActivityApplyController {
@Param(value = "courseTypeId") String courseTypeId,
@Param(value = "activityId") String activityId,
@Param(value = "assortTypes") String[] assortTypes,
@Param(value = "searchKeyword") String searchKeyword,
@Param(value = "dataType") String dataType) {
FamilyActivity activity = dao.fetch(FamilyActivity.class, activityId);
Sql sql = Sqls.create("""
@@ -131,6 +135,9 @@ public class FamilyActivityApplyController {
Cnd cnd = Cnd.NEW();
cnd.andEX("type.id", "=", courseTypeId);
cnd.and("tsuc.activityId", "=", activityId);
if (StrUtil.isNotBlank(searchKeyword)) {
cnd.and("tsuc.courseName", "like", "%" + searchKeyword.trim() + "%");
}
if(Lang.isNotEmpty(assortTypes)) {
cnd.and("tsuc.assort", "in", assortTypes);
}
@@ -64,8 +64,8 @@ public class H5ActivitySportsApplyUserController {
@At
@SaCheckPermission("h5.activity.sports.applyUser")
public Result activityData(Integer year, Integer isActivity, Integer applyStatus) {
return Result.success(activitySportsApplyUserService.activityData(year, isActivity, applyStatus));
public Result activityData(Integer year, Integer isActivity, Integer applyStatus, String searchKeyword) {
return Result.success(activitySportsApplyUserService.activityData(year, isActivity, applyStatus, searchKeyword));
}
@@ -18,6 +18,7 @@ public class ActivitySportsApplyUserPageParam extends PageForm {
private String applyType;
private String isAudit;
private String groupName;
private String searchKeyword;
private String activityId;
private String eventId;
private String year;
@@ -19,6 +19,17 @@ public interface ActivitySportsApplyUserService extends BaseService<ActivityScho
Pagination activityData(Integer year, Integer isActivity,Integer applyStatus);
/**
* 根据年份、活动状态、报名状态和活动名称查询体育活动。
*
* @param year 活动年份
* @param isActivity 活动状态
* @param applyStatus 当前用户报名状态
* @param searchKeyword 活动名称模糊查询关键词
* @return 体育活动分页数据
*/
Pagination activityData(Integer year, Integer isActivity, Integer applyStatus, String searchKeyword);
List<NutMap> getEvents(String activityId);
Object getUnionCoachLeaderHead(String activityId,String unionId);
@@ -122,6 +122,9 @@ public class ActivitySportsApplyUserServiceImpl extends BaseServiceImpl<Activity
cnd.and(new Static("(SELECT COUNT(1) FROM activity_school_apply WHERE eventId = ase.eventId AND activityId = ase.activityId AND userId='%s')%s0".formatted(SecurityUtil.getUserId(), (pageParam.getIsAudit().equals("true") ? ">" : "="))));
}
cnd.and("ase.activityId", "=", pageParam.getActivityId());
if (StrUtil.isNotBlank(pageParam.getSearchKeyword())) {
cnd.and("eve.allName", "like", "%" + pageParam.getSearchKeyword().trim() + "%");
}
cnd.andEX("ase.eventId", "=", pageParam.getEventId());
cnd.andEX("YEAR(school.applyStartTime)", "=", pageParam.getYear());
@@ -144,6 +147,20 @@ public class ActivitySportsApplyUserServiceImpl extends BaseServiceImpl<Activity
@Override
public Pagination activityData(Integer year, Integer isActivity, Integer applyStatus) {
return activityData(year, isActivity, applyStatus, null);
}
/**
* 根据筛选条件及活动名称查询当前用户可见的体育活动。
*
* @param year 活动年份
* @param isActivity 活动状态
* @param applyStatus 当前用户报名状态
* @param searchKeyword 活动名称模糊查询关键词
* @return 体育活动分页数据
*/
@Override
public Pagination activityData(Integer year, Integer isActivity, Integer applyStatus, String searchKeyword) {
Sql sql = Sqls.create("""
SELECT
@@ -183,6 +200,10 @@ public class ActivitySportsApplyUserServiceImpl extends BaseServiceImpl<Activity
cnd.and("school.isSave", "!=", true);
if (Lang.isNotEmpty(searchKeyword)) {
cnd.and("school.NAME", "like", "%" + searchKeyword.trim() + "%");
}
//查询报名中
if (isActivity == 2) {
cnd.and(new Static("now() >applyStartTime and now() < applyEndTime"));
@@ -93,6 +93,9 @@ public class TrainSignUpApplyController {
Cnd cnd = Cnd.NEW();
cnd.andEX("id", "=", id);
cnd.andEX("`year`", "=", year);
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
cnd.and(Cnd.likeEX("activityName", pageForm.getSearchKeyword()));
}
//查询报名中
if (activityType == 2) {
cnd.and(new Static("now() < activitySignUpEndTime"));
@@ -123,6 +126,7 @@ public class TrainSignUpApplyController {
@Param(value = "courseTypeId") String courseTypeId,
@Param(value = "activityId") String activityId,
@Param(value = "assortTypes") String[] assortTypes,
@Param(value = "searchKeyword") String searchKeyword,
@Param(value = "dataType") String dataType) {
Sql sql = Sqls.create("""
SELECT
@@ -156,6 +160,9 @@ public class TrainSignUpApplyController {
Cnd cnd = Cnd.NEW();
cnd.andEX("type.id", "=", courseTypeId);
cnd.and("tsuc.activityId", "=", activityId);
if (StrUtil.isNotBlank(searchKeyword)) {
cnd.and("tsuc.courseName", "like", "%" + searchKeyword.trim() + "%");
}
if (Lang.isNotEmpty(assortTypes)) {
cnd.and("tsuc.assort", "in", assortTypes);
@@ -1,6 +1,7 @@
package com.budwk.app.zhgh.democratic.proposal.controller.transact;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaMode;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.ExportTableColumns;
@@ -55,8 +56,17 @@ public class ProposalCaseCheckController {
public void index() {
}
/**
* 打开提案委员会审查手机端列表页。
*/
@At("/h5")
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/caseCheck/index.html")
@SaCheckPermission("h5.proposal.caseCheck")
public void h5Index() {
}
@At
@SaCheckPermission("proposal.caseCheck")
@SaCheckPermission(value = {"proposal.caseCheck", "h5.proposal.caseCheck"}, mode = SaMode.OR)
@ApiOperation("分页列表")
public Result pageData(@Valid ProposalSearchParam pageForm, boolean approval) {
Sql sql = Sqls.create("""
@@ -129,7 +139,7 @@ public class ProposalCaseCheckController {
}
@At
@SaCheckPermission("proposal.caseCheck")
@SaCheckPermission(value = {"proposal.caseCheck", "h5.proposal.caseCheck"}, mode = SaMode.OR)
@ApiOperation("查询当前提案承办单位")
public Result listReplyUnits(String proposalId) {
return Result.success(proposalCaseCheckService.listReplyUnits(proposalId));
@@ -49,7 +49,6 @@ public class ProposalCommissionerController {
public void h5Index() {
}
@At
@SaCheckPermission("proposal.commissioner")
public Result pageData(@Valid ProposalSearchParam pageForm, boolean approval) {
@@ -64,7 +64,6 @@ public class ProposalDelegationController {
public void h5Index() {
}
@At
@SaCheckPermission("proposal.delegation")
@ApiOperation("分页列表")
@@ -52,7 +52,6 @@ public class ProposalFeedbackEvaluationController {
public void h5Index() {
}
@At
@SaCheckPermission("proposal.feedbackEvaluation")
@ApiOperation("分页列表")
@@ -52,6 +52,11 @@ public class ProposalPreAuditController {
public void index() {
}
@At("/h5")
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/preAudit/index.html")
@SaCheckPermission("proposal.preAudit")
public void h5Index() {
}
@At
@SaCheckPermission("proposal.preAudit")
@@ -74,7 +74,6 @@ public class ProposalSchoolLeaderApprovalController {
public void h5Index() {
}
@At
@SaCheckPermission("proposal.schoolLeaderApproval")
@ApiOperation("分页列表")
@@ -84,7 +84,7 @@ public class LearningCourseDisplayController {
/**
* 查询课程展示列表。
* pageForm 传分页页码和每页条数;keyword、courseTypeId、recommendFlag 分别用于关键词、分类和推荐标识筛选;
* sortType 支持 default(综合排序)和 view_count(观看次数倒序)。返回值为 Pagination,list 中包含课程基础字段、课节数、总时长观看次数。
* sortType 支持 default(综合排序)和 view_count(观看次数倒序)。返回值为 Pagination,list 中包含课程基础字段、课节数、总时长观看次数和当前用户学习进度
*/
public Result pageData(PageForm pageForm, String keyword, String courseTypeId, String recommendFlag, String sortType) {
Cnd cnd = Cnd.where("c.status", "=", "published");
@@ -112,6 +112,9 @@ public class LearningCourseDisplayController {
SELECT c.id, c.courseName, c.courseIntro, c.startTime, c.endTime, c.openType, c.cover,
c.recommendFlags, c.courseTypeId, c.lecturerName, c.sortNum,
COALESCE(c.viewCount, 0) AS viewCount, t.typeName AS courseTypeName,
COALESCE((SELECT ROUND(AVG(IFNULL(sr.progressPercent, 0)))
FROM learning_study_record sr
WHERE sr.courseId = c.id AND sr.userId = @userId), 0) AS progressPercent,
(SELECT COUNT(1) FROM learning_outline_resource r
WHERE r.courseId = c.id AND r.status = 'enabled') AS resourceCount,
COALESCE((SELECT SUM(r.durationSeconds) FROM learning_outline_resource r
@@ -122,6 +125,7 @@ public class LearningCourseDisplayController {
ORDER BY $orderBy
""");
listSql.setCondition(cnd);
listSql.params().set("userId", SecurityUtil.getUserId());
// 排序字段由固定选项映射,禁止将前端参数直接拼接进SQL。
listSql.setVar("orderBy", "view_count".equals(sortType)
? "COALESCE(c.viewCount, 0) DESC, c.sortNum ASC, c.createdAt DESC"
@@ -0,0 +1,101 @@
package com.budwk.app.zhgh.spread.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.spread.models.SpreadCategory;
import com.budwk.app.zhgh.spread.service.SpreadCategoryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
@IocBean
@Ok("json:full")
@Api("风采墙-栏目管理")
@At("/platform/spread/category")
public class SpreadCategoryController {
@Inject
private SpreadCategoryService categoryService;
@At("")
@Ok("beetl:/platform/zhgh/spread/category/index.html")
@SaCheckPermission("spread.category")
public void index() {
}
@At
@ApiOperation("栏目列表")
@SaCheckPermission("spread.category")
public Result listData() {
return Result.success(categoryService.listCategories(false));
}
@At
@ApiOperation("栏目树")
@SaCheckPermission("spread.category")
public Result treeData() {
return Result.success(categoryService.categoryTree(false));
}
@At
@ApiOperation("新增栏目")
@SaCheckPermission("spread.category")
@SLog(tag = "风采墙-栏目管理", msg = "新增栏目:${args[0].name}")
@Aop(TransAop.READ_COMMITTED)
public Result doAdd(SpreadCategory category) {
try {
categoryService.saveCategory(category);
return Result.success();
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@At
@ApiOperation("编辑栏目")
@SaCheckPermission("spread.category")
@SLog(tag = "风采墙-栏目管理", msg = "编辑栏目:${args[0].id}")
@Aop(TransAop.READ_COMMITTED)
public Result doEdit(SpreadCategory category) {
try {
categoryService.updateCategory(category);
return Result.success();
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@At
@ApiOperation("删除栏目")
@SaCheckPermission("spread.category")
@SLog(tag = "风采墙-栏目管理", msg = "删除栏目:${args[0]}")
@Aop(TransAop.READ_COMMITTED)
public Result doDelete(String id) {
try {
categoryService.deleteCategory(id);
return Result.success();
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@At
@ApiOperation("设置栏目显示状态")
@SaCheckPermission("spread.category")
@SLog(tag = "风采墙-栏目管理", msg = "栏目:${args[0]},显示状态:${args[1]}")
@Aop(TransAop.READ_COMMITTED)
public Result doVisible(String id, Integer visible) {
try {
categoryService.setVisible(id, visible);
return Result.success();
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
}
@@ -0,0 +1,88 @@
package com.budwk.app.zhgh.spread.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.spread.models.SpreadContent;
import com.budwk.app.zhgh.spread.service.SpreadCategoryService;
import com.budwk.app.zhgh.spread.service.SpreadContentService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
@IocBean
@Ok("json:full")
@Api("风采墙-内容发布")
@At("/platform/spread/creation")
public class SpreadCreationController {
@Inject
private SpreadCategoryService categoryService;
@Inject
private SpreadContentService contentService;
@At("")
@Ok("beetl:/platform/zhgh/spread/creation/index.html")
@SaCheckPermission("spread.creation")
public void index() {
}
@At
@ApiOperation("可选栏目树")
@SaCheckPermission("spread.creation")
public Result categoryTree() {
return Result.success(categoryService.categoryTree(true));
}
@At
@ApiOperation("当前登录人员可选择的工会")
@SaCheckPermission("spread.creation")
public Result unionOptions() {
return Result.success(contentService.selectableUnions());
}
@At
@ApiOperation("内容详情")
@SaCheckPermission("spread.creation")
public Result detailData(String id) {
try {
return Result.success(contentService.getContent(id));
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@At
@ApiOperation("新增内容")
@SaCheckPermission("spread.creation")
@SLog(tag = "风采墙-内容发布", msg = "新增内容:${args[0].title}")
@Aop(TransAop.READ_COMMITTED)
public Result doAdd(SpreadContent content) {
try {
contentService.saveContent(content);
return Result.success();
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@At
@ApiOperation("编辑内容")
@SaCheckPermission("spread.creation")
@SLog(tag = "风采墙-内容发布", msg = "编辑内容:${args[0].id}")
@Aop(TransAop.READ_COMMITTED)
public Result doEdit(SpreadContent content) {
try {
contentService.updateContent(content);
return Result.success();
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
}
@@ -0,0 +1,76 @@
package com.budwk.app.zhgh.spread.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.spread.service.SpreadCategoryService;
import com.budwk.app.zhgh.spread.service.SpreadContentService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
@IocBean
@Ok("json:full")
@Api("风采墙-展示")
@At("/platform/spread/display")
public class SpreadDisplayController {
@Inject
private SpreadCategoryService categoryService;
@Inject
private SpreadContentService contentService;
@At("")
@Ok("beetl:/platform/zhgh/spread/display/index.html")
@SaCheckPermission("spread.display")
public void index() {
}
@At
@ApiOperation("可见栏目树")
@SaCheckPermission("spread.display")
public Result categoryTree() {
return Result.success(categoryService.categoryTree(true));
}
@At
@ApiOperation("已发布内容分页")
@SaCheckPermission("spread.display")
public Result pageData(PageForm pageForm, String categoryId) {
return Result.success(contentService.pagePublished(pageForm, categoryId));
}
@At
@ApiOperation("内容详情")
@SaCheckPermission("spread.display")
public Result detailData(String id) {
try {
return Result.success(contentService.getContent(id));
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@At
@ApiOperation("轮播内容")
@SaCheckPermission("spread.display")
public Result sliderData() {
return Result.success(contentService.sliderContent());
}
@At
@ApiOperation("增加浏览量")
@SaCheckPermission("spread.display")
public Result addView(String id) {
try {
contentService.addViewCount(id);
return Result.success();
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
}
@@ -0,0 +1,78 @@
package com.budwk.app.zhgh.spread.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.spread.param.SpreadContentQuery;
import com.budwk.app.zhgh.spread.service.SpreadCategoryService;
import com.budwk.app.zhgh.spread.service.SpreadContentService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
@IocBean
@Ok("json:full")
@Api("风采墙-内容管理")
@At("/platform/spread/manage")
public class SpreadManageController {
@Inject
private SpreadCategoryService categoryService;
@Inject
private SpreadContentService contentService;
@At("")
@Ok("beetl:/platform/zhgh/spread/manage/index.html")
@SaCheckPermission("spread.manage")
public void index() {
}
@At
@ApiOperation("内容分页")
@SaCheckPermission("spread.manage")
public Result pageData(PageForm pageForm, SpreadContentQuery query) {
return Result.success(contentService.pageContent(pageForm, query));
}
@At
@ApiOperation("栏目树")
@SaCheckPermission("spread.manage")
public Result categoryTree() {
return Result.success(categoryService.categoryTree(false));
}
@At
@ApiOperation("删除内容")
@SaCheckPermission("spread.manage")
@SLog(tag = "风采墙-内容管理", msg = "删除内容:${args[0]}")
@Aop(TransAop.READ_COMMITTED)
public Result doDelete(String id) {
try {
contentService.deleteContent(id);
return Result.success();
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
@At
@ApiOperation("发布或撤回内容")
@SaCheckPermission("spread.manage")
@SLog(tag = "风采墙-内容管理", msg = "内容:${args[0]},发布状态:${args[1]}")
@Aop(TransAop.READ_COMMITTED)
public Result doPublish(String id, Integer status) {
try {
contentService.publishContent(id, status);
return Result.success();
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
}
@@ -0,0 +1,60 @@
package com.budwk.app.zhgh.spread.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.spread.param.SpreadStatisticsQuery;
import com.budwk.app.zhgh.spread.service.SpreadCategoryService;
import com.budwk.app.zhgh.spread.service.SpreadStatisticsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
@IocBean
@Ok("json:full")
@Api("风采墙-统计分析")
@At("/platform/spread/statistics")
public class SpreadStatisticsController {
@Inject
private SpreadCategoryService categoryService;
@Inject
private SpreadStatisticsService statisticsService;
@At("")
@Ok("beetl:/platform/zhgh/spread/statistics/index.html")
@SaCheckPermission("spread.statistics")
public void index() {
}
@At
@ApiOperation("栏目树")
@SaCheckPermission("spread.statistics")
public Result categoryTree() {
return Result.success(categoryService.categoryTree(false));
}
@At
@ApiOperation("统计卡片")
@SaCheckPermission("spread.statistics")
public Result summary(SpreadStatisticsQuery query) {
return Result.success(statisticsService.summary(query));
}
@At
@ApiOperation("浏览量前十")
@SaCheckPermission("spread.statistics")
public Result top10(SpreadStatisticsQuery query) {
return Result.success(statisticsService.top10(query));
}
@At
@ApiOperation("栏目统计")
@SaCheckPermission("spread.statistics")
public Result categoryData(SpreadStatisticsQuery query) {
return Result.success(statisticsService.categoryStatistics(query));
}
}
@@ -0,0 +1,112 @@
package com.budwk.app.zhgh.spread.h5controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.spread.service.SpreadCategoryService;
import com.budwk.app.zhgh.spread.service.SpreadContentService;
import io.swagger.annotations.ApiOperation;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
/**
* 风采墙 H5 展示控制器,提供栏目、列表和内容详情预览。
*/
@IocBean
@Ok("json:full")
@At("/platform/h5/spread")
public class H5SpreadDisplayController {
@Inject
private SpreadCategoryService categoryService;
@Inject
private SpreadContentService contentService;
/**
* 打开风采墙 H5 预览页面。
*/
@At("")
@Ok("beetl:/platform/zhghh5/spread/display/index.html")
@SaCheckLogin
public void index() {
}
/**
* 打开工会动态 H5 详情页面。
*/
@At("/detail")
@Ok("beetl:/platform/zhghh5/spread/display/detail.html")
@SaCheckLogin
public void detail() {
}
/**
* 查询 H5 端可见栏目树。
*
* @return 按层级组织的可见栏目
*/
@At
@SaCheckLogin
@ApiOperation("H5可见栏目树")
public Result categoryTree() {
return Result.success(categoryService.categoryTree(true));
}
/**
* 查询指定栏目及其子栏目的已发布内容。
*
* @param pageForm 分页参数
* @param categoryId 栏目 ID
* @param title 标题模糊查询条件
* @param sortType 排序方式
* @param publishDays 发布时间范围天数
* @param contentFlag 内容属性筛选
* @return 已发布内容分页数据
*/
@At
@SaCheckLogin
@ApiOperation("H5已发布内容分页")
public Result pageData(PageForm pageForm, String categoryId, String title,
String sortType, Integer publishDays, String contentFlag) {
return Result.success(contentService.pagePublished(pageForm, categoryId, title,
sortType, publishDays, contentFlag));
}
/**
* 查询 H5 内容详情。
*
* @param id 内容 ID
* @return 内容详情
*/
@At
@SaCheckLogin
@ApiOperation("H5内容详情")
public Result detailData(String id) {
try {
return Result.success(contentService.getContent(id));
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
/**
* 登记 H5 内容浏览量。
*
* @param id 内容 ID
* @return 操作结果
*/
@At
@SaCheckLogin
@ApiOperation("H5增加浏览量")
public Result addView(String id) {
try {
contentService.addViewCount(id);
return Result.success();
} catch (RuntimeException e) {
return Result.error(e.getMessage());
}
}
}
@@ -0,0 +1,55 @@
package com.budwk.app.zhgh.spread.models;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.ColDefine;
import org.nutz.dao.entity.annotation.ColType;
import org.nutz.dao.entity.annotation.Column;
import org.nutz.dao.entity.annotation.Comment;
import org.nutz.dao.entity.annotation.Name;
import org.nutz.dao.entity.annotation.Table;
import org.nutz.dao.interceptor.annotation.PrevInsert;
@Data
@Table("spread_category")
@EqualsAndHashCode(callSuper = true)
public class SpreadCategory extends BaseModel {
@Column
@Name
@Comment("ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
@PrevInsert(uu32 = true)
private String id;
@Column
@Comment("父栏目ID0表示顶级栏目")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String parentId;
@Column
@Comment("栏目名称")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String name;
@Column
@Comment("栏目编码")
@ColDefine(type = ColType.VARCHAR, width = 50)
private String code;
@Column
@Comment("排序")
@ColDefine(type = ColType.INT)
private Integer sortOrder;
@Column
@Comment("是否可见")
@ColDefine(type = ColType.INT)
private Integer visible;
@Column
@Comment("是否参与轮播")
@ColDefine(type = ColType.INT)
private Integer slider;
}
@@ -0,0 +1,109 @@
package com.budwk.app.zhgh.spread.models;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.ColDefine;
import org.nutz.dao.entity.annotation.ColType;
import org.nutz.dao.entity.annotation.Column;
import org.nutz.dao.entity.annotation.Comment;
import org.nutz.dao.entity.annotation.Name;
import org.nutz.dao.entity.annotation.Table;
import org.nutz.dao.interceptor.annotation.PrevInsert;
@Data
@Table("spread_content")
@EqualsAndHashCode(callSuper = true)
public class SpreadContent extends BaseModel {
@Column
@Name
@Comment("ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
@PrevInsert(uu32 = true)
private String id;
@Column
@Comment("栏目ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String categoryId;
@Column
@Comment("栏目名称")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String categoryName;
@Column
@Comment("所属工会ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String unionId;
@Column
@Comment("所属工会名称")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String unionName;
@Column
@Comment("标题")
@ColDefine(type = ColType.VARCHAR, width = 300)
private String title;
@Column
@Comment("副标题")
@ColDefine(type = ColType.VARCHAR, width = 255)
private String subTitle;
@Column
@Comment("摘要")
@ColDefine(type = ColType.VARCHAR, width = 1000)
private String summary;
@Column
@Comment("正文")
@ColDefine(customType = "longtext")
private String contentBody;
@Column
@Comment("封面图")
@ColDefine(type = ColType.VARCHAR, width = 1000)
private String thumbUrl;
@Column
@Comment("轮播图片")
@ColDefine(customType = "longtext")
private String sliderImages;
@Column
@Comment("是否置顶")
@ColDefine(type = ColType.INT)
private Integer isTop;
@Column
@Comment("是否推荐")
@ColDefine(type = ColType.INT)
private Integer isRecommend;
@Column
@Comment("是否头条")
@ColDefine(type = ColType.INT)
private Integer isHeadline;
@Column
@Comment("浏览量")
@ColDefine(type = ColType.INT)
private Integer viewCount;
@Column
@Comment("排序")
@ColDefine(type = ColType.INT)
private Integer sortOrder;
@Column
@Comment("是否发布")
@ColDefine(type = ColType.INT)
private Integer isPublished;
@Column
@Comment("发布时间")
private Long publishedAt;
}
@@ -0,0 +1,12 @@
package com.budwk.app.zhgh.spread.param;
import lombok.Data;
@Data
public class SpreadContentQuery {
private String categoryId;
private String title;
private Integer isPublished;
private String beginTime;
private String endTime;
}
@@ -0,0 +1,11 @@
package com.budwk.app.zhgh.spread.param;
import lombok.Data;
@Data
public class SpreadStatisticsQuery {
private String categoryId;
private Integer isPublished;
private String beginTime;
private String endTime;
}
@@ -0,0 +1,22 @@
package com.budwk.app.zhgh.spread.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.spread.models.SpreadCategory;
import org.nutz.lang.util.NutMap;
import java.util.List;
public interface SpreadCategoryService extends BaseService<SpreadCategory> {
List<SpreadCategory> listCategories(boolean visibleOnly);
List<NutMap> categoryTree(boolean visibleOnly);
void saveCategory(SpreadCategory category);
void updateCategory(SpreadCategory category);
void deleteCategory(String id);
void setVisible(String id, Integer visible);
}
@@ -0,0 +1,61 @@
package com.budwk.app.zhgh.spread.service;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.spread.models.SpreadContent;
import com.budwk.app.zhgh.spread.param.SpreadContentQuery;
import com.budwk.app.sys.models.Sys_union;
import org.nutz.lang.util.NutMap;
import java.util.List;
public interface SpreadContentService extends BaseService<SpreadContent> {
Pagination<NutMap> pageContent(PageForm pageForm, SpreadContentQuery query);
Pagination<NutMap> pagePublished(PageForm pageForm, String categoryId);
/**
* 分页查询指定栏目中标题匹配的已发布内容。
*
* @param pageForm 分页参数
* @param categoryId 栏目 ID,查询时包含该栏目的直接子栏目
* @param title 标题模糊查询条件
* @return 已发布内容分页数据
*/
Pagination<NutMap> pagePublished(PageForm pageForm, String categoryId, String title);
/**
* 按 H5 筛选条件分页查询已发布内容。
*
* @param pageForm 分页参数
* @param categoryId 栏目 ID,查询时包含该栏目的直接子栏目
* @param title 标题模糊查询条件
* @param sortType 排序方式:comprehensive、latest、views
* @param publishDays 发布时间范围天数,空或 0 表示不限
* @param contentFlag 内容属性:all、recommend、headline、top
* @return 已发布内容分页数据
*/
Pagination<NutMap> pagePublished(PageForm pageForm, String categoryId, String title,
String sortType, Integer publishDays, String contentFlag);
SpreadContent getContent(String id);
void saveContent(SpreadContent content);
void updateContent(SpreadContent content);
void deleteContent(String id);
void publishContent(String id, Integer status);
void addViewCount(String id);
List<NutMap> sliderContent();
/**
* 查询当前登录人员可选择的工会。
*/
List<Sys_union> selectableUnions();
}
@@ -0,0 +1,15 @@
package com.budwk.app.zhgh.spread.service;
import com.budwk.app.zhgh.spread.param.SpreadStatisticsQuery;
import org.nutz.lang.util.NutMap;
import java.util.List;
public interface SpreadStatisticsService {
NutMap summary(SpreadStatisticsQuery query);
List<NutMap> top10(SpreadStatisticsQuery query);
List<NutMap> categoryStatistics(SpreadStatisticsQuery query);
}
@@ -0,0 +1,183 @@
package com.budwk.app.zhgh.spread.service.impl;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.zhgh.spread.models.SpreadCategory;
import com.budwk.app.zhgh.spread.models.SpreadContent;
import com.budwk.app.zhgh.spread.service.SpreadCategoryService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@IocBean(args = {"refer:dao"})
public class SpreadCategoryServiceImpl extends BaseServiceImpl<SpreadCategory> implements SpreadCategoryService {
public SpreadCategoryServiceImpl(Dao dao) {
super(dao);
}
@Override
public List<SpreadCategory> listCategories(boolean visibleOnly) {
Cnd cnd = Cnd.where("delFlag", "=", false);
if (visibleOnly) {
cnd.and("visible", "=", 1);
}
cnd.asc("sortOrder").asc("createdAt");
return query(cnd);
}
@Override
public List<NutMap> categoryTree(boolean visibleOnly) {
List<SpreadCategory> categories = listCategories(visibleOnly);
Map<String, NutMap> nodeMap = new LinkedHashMap<>();
Map<String, List<NutMap>> childrenMap = new LinkedHashMap<>();
for (SpreadCategory category : categories) {
List<NutMap> children = new ArrayList<>();
nodeMap.put(category.getId(), NutMap.NEW()
.addv("id", category.getId())
.addv("parentId", category.getParentId())
.addv("name", category.getName())
.addv("code", category.getCode())
.addv("sortOrder", category.getSortOrder())
.addv("visible", category.getVisible())
.addv("slider", category.getSlider())
.addv("children", children));
childrenMap.put(category.getId(), children);
}
List<NutMap> roots = new ArrayList<>();
for (NutMap node : nodeMap.values()) {
String parentId = node.getString("parentId");
if ("0".equals(parentId) || !nodeMap.containsKey(parentId)) {
roots.add(node);
} else {
// 直接向节点持有的原始集合追加,避免 NutMap 类型转换后子节点没有写回。
childrenMap.get(parentId).add(node);
}
}
// 叶子栏目不返回空 children,避免级联选择器误判为仍有下一级。
nodeMap.forEach((id, node) -> {
if (childrenMap.get(id).isEmpty()) {
node.remove("children");
}
});
return roots;
}
@Override
public void saveCategory(SpreadCategory category) {
validateCategory(category, null);
applyDefaults(category);
insert(category);
syncParentSlider(category);
}
@Override
public void updateCategory(SpreadCategory category) {
if (category == null || StrUtil.isBlank(category.getId())) {
throw new RuntimeException("请选择要编辑的栏目");
}
SpreadCategory dbCategory = fetch(category.getId());
if (dbCategory == null || Boolean.TRUE.equals(dbCategory.getDelFlag())) {
throw new RuntimeException("栏目不存在");
}
validateCategory(category, category.getId());
if (!dbCategory.getParentId().equals(category.getParentId())
&& count(Cnd.where("parentId", "=", category.getId()).and("delFlag", "=", false)) > 0) {
throw new RuntimeException("该栏目下存在子栏目,不能移动");
}
applyDefaults(category);
updateIgnoreNull(category);
syncParentSlider(category);
if ("0".equals(category.getParentId()) && Integer.valueOf(0).equals(category.getSlider())) {
SpreadCategory child = new SpreadCategory();
child.setSlider(0);
dao().update(SpreadCategory.class, org.nutz.dao.Chain.make("slider", 0),
Cnd.where("parentId", "=", category.getId()).and("delFlag", "=", false));
}
}
@Override
public void deleteCategory(String id) {
if (StrUtil.isBlank(id)) {
throw new RuntimeException("请选择要删除的栏目");
}
List<SpreadCategory> children = query(Cnd.where("parentId", "=", id).and("delFlag", "=", false));
List<String> ids = new ArrayList<>();
ids.add(id);
children.forEach(item -> ids.add(item.getId()));
if (dao().count(SpreadContent.class,
Cnd.where("categoryId", "in", ids).and("delFlag", "=", false)) > 0) {
throw new RuntimeException("栏目下存在内容,请先删除相关内容");
}
dao().clear(SpreadCategory.class, Cnd.where("id", "in", ids));
}
@Override
public void setVisible(String id, Integer visible) {
if (StrUtil.isBlank(id) || (visible == null || (visible != 0 && visible != 1))) {
throw new RuntimeException("栏目或显示状态不正确");
}
dao().update(SpreadCategory.class, org.nutz.dao.Chain.make("visible", visible),
Cnd.where("id", "=", id).and("delFlag", "=", false));
if (visible == 0) {
dao().update(SpreadCategory.class, org.nutz.dao.Chain.make("visible", 0),
Cnd.where("parentId", "=", id).and("delFlag", "=", false));
}
}
private void validateCategory(SpreadCategory category, String excludeId) {
if (category == null || StrUtil.isBlank(category.getName())) {
throw new RuntimeException("栏目名称不能为空");
}
category.setName(category.getName().trim());
// 参考模块不要求用户维护栏目编码,空值统一保存为 NULL。
category.setCode(StrUtil.isBlank(category.getCode()) ? null : category.getCode().trim());
category.setParentId(StrUtil.blankToDefault(category.getParentId(), "0"));
if (category.getId() != null && category.getId().equals(category.getParentId())) {
throw new RuntimeException("上级栏目不能选择自身");
}
if (!"0".equals(category.getParentId())) {
SpreadCategory parent = fetch(category.getParentId());
if (parent == null || Boolean.TRUE.equals(parent.getDelFlag())) {
throw new RuntimeException("上级栏目不存在");
}
if (!"0".equals(parent.getParentId())) {
throw new RuntimeException("风采墙栏目最多支持两级");
}
}
Cnd nameCnd = Cnd.where("name", "=", category.getName())
.and("parentId", "=", category.getParentId())
.and("delFlag", "=", false);
if (StrUtil.isNotBlank(excludeId)) {
nameCnd.and("id", "!=", excludeId);
}
if (count(nameCnd) > 0) {
throw new RuntimeException("同级栏目名称已存在");
}
}
private void applyDefaults(SpreadCategory category) {
if (category.getSortOrder() == null) {
category.setSortOrder(255);
}
if (category.getVisible() == null) {
category.setVisible(1);
}
if (category.getSlider() == null) {
category.setSlider(0);
}
}
private void syncParentSlider(SpreadCategory category) {
if (!"0".equals(category.getParentId()) && Integer.valueOf(1).equals(category.getSlider())) {
dao().update(SpreadCategory.class, org.nutz.dao.Chain.make("slider", 1),
Cnd.where("id", "=", category.getParentId()).and("delFlag", "=", false));
}
}
}
@@ -0,0 +1,377 @@
package com.budwk.app.zhgh.spread.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_union;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.spread.models.SpreadCategory;
import com.budwk.app.zhgh.spread.models.SpreadContent;
import com.budwk.app.zhgh.spread.param.SpreadContentQuery;
import com.budwk.app.zhgh.spread.service.SpreadContentService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@IocBean(args = {"refer:dao"})
public class SpreadContentServiceImpl extends BaseServiceImpl<SpreadContent> implements SpreadContentService {
public SpreadContentServiceImpl(Dao dao) {
super(dao);
}
@Override
public Pagination<NutMap> pageContent(PageForm pageForm, SpreadContentQuery query) {
Cnd cnd = buildCondition(query);
Sql countSql = Sqls.create("""
SELECT COUNT(1)
FROM spread_content c
$condition
""");
countSql.setCondition(cnd);
countSql.setCallback(Sqls.callback.integer());
dao().execute(countSql);
Sql listSql = Sqls.create("""
SELECT c.*
FROM spread_content c
$condition
ORDER BY c.isTop DESC, c.sortOrder ASC, c.createdAt DESC
""");
listSql.setCondition(cnd);
listSql.setPager(dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize()));
listSql.setCallback(Sqls.callback.maps());
dao().execute(listSql);
return new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(),
countSql.getInt(), listSql.getList(NutMap.class));
}
@Override
public Pagination<NutMap> pagePublished(PageForm pageForm, String categoryId) {
return pagePublished(pageForm, categoryId, null, null, null, null);
}
/**
* 分页查询指定栏目中标题匹配的已发布内容。
*
* @param pageForm 分页参数
* @param categoryId 栏目 ID,查询时包含该栏目的直接子栏目
* @param title 标题模糊查询条件
* @return 已发布内容分页数据
*/
@Override
public Pagination<NutMap> pagePublished(PageForm pageForm, String categoryId, String title) {
return pagePublished(pageForm, categoryId, title, null, null, null);
}
/**
* 按 H5 筛选条件分页查询已发布内容。
*
* @param pageForm 分页参数
* @param categoryId 栏目 ID,查询时包含该栏目的直接子栏目
* @param title 标题模糊查询条件
* @param sortType 排序方式
* @param publishDays 发布时间范围天数
* @param contentFlag 内容属性筛选
* @return 已发布内容分页数据
*/
@Override
public Pagination<NutMap> pagePublished(PageForm pageForm, String categoryId, String title,
String sortType, Integer publishDays, String contentFlag) {
SpreadContentQuery query = new SpreadContentQuery();
query.setCategoryId(categoryId);
query.setTitle(title);
query.setIsPublished(1);
Cnd cnd = buildCondition(query);
if (publishDays != null && publishDays > 0) {
cnd.and("c.publishedAt", ">=", System.currentTimeMillis() - publishDays * 24L * 60L * 60L * 1000L);
}
if ("recommend".equals(contentFlag)) {
cnd.and("c.isRecommend", "=", 1);
} else if ("headline".equals(contentFlag)) {
cnd.and("c.isHeadline", "=", 1);
} else if ("top".equals(contentFlag)) {
cnd.and("c.isTop", "=", 1);
}
Sql countSql = Sqls.create("SELECT COUNT(1) FROM spread_content c $condition");
countSql.setCondition(cnd);
countSql.setCallback(Sqls.callback.integer());
dao().execute(countSql);
String orderBy = resolvePublishedOrder(sortType);
Sql listSql = Sqls.create("""
SELECT c.*,
CASE WHEN child.parentId = '0' OR parent.id IS NULL THEN child.name ELSE parent.name END AS parentCategoryName,
CASE WHEN child.parentId = '0' OR parent.id IS NULL THEN NULL ELSE child.name END AS childCategoryName
FROM spread_content c
LEFT JOIN spread_category child ON child.id = c.categoryId AND child.delFlag = 0
LEFT JOIN spread_category parent ON parent.id = child.parentId AND parent.delFlag = 0
$condition
ORDER BY
""" + orderBy);
listSql.setCondition(cnd);
listSql.setPager(dao().createPager(pageForm.getPageNumber(), pageForm.getPageSize()));
listSql.setCallback(Sqls.callback.maps());
dao().execute(listSql);
return new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(),
countSql.getInt(), listSql.getList(NutMap.class));
}
/**
* 将前端排序标识转换为固定 SQL 排序片段,避免客户端直接控制排序字段。
*/
private String resolvePublishedOrder(String sortType) {
if ("latest".equals(sortType)) {
return "c.publishedAt DESC, c.createdAt DESC";
}
if ("views".equals(sortType)) {
return "c.viewCount DESC, c.publishedAt DESC, c.createdAt DESC";
}
return "c.isTop DESC, c.publishedAt DESC, c.sortOrder ASC, c.createdAt DESC";
}
@Override
public SpreadContent getContent(String id) {
if (StrUtil.isBlank(id)) {
throw new RuntimeException("请选择内容");
}
SpreadContent content = fetch(Cnd.where("id", "=", id).and("delFlag", "=", false));
if (content == null) {
throw new RuntimeException("内容不存在");
}
return content;
}
@Override
public void saveContent(SpreadContent content) {
validateContent(content);
applyDefaults(content);
if (Integer.valueOf(1).equals(content.getIsPublished())) {
content.setPublishedAt(System.currentTimeMillis());
}
insert(content);
}
@Override
public void updateContent(SpreadContent content) {
if (content == null || StrUtil.isBlank(content.getId())) {
throw new RuntimeException("请选择要编辑的内容");
}
SpreadContent dbContent = getContent(content.getId());
validateContent(content);
applyDefaults(content);
if (Integer.valueOf(1).equals(content.getIsPublished()) && !Integer.valueOf(1).equals(dbContent.getIsPublished())) {
content.setPublishedAt(System.currentTimeMillis());
}
updateIgnoreNull(content);
}
@Override
public void deleteContent(String id) {
getContent(id);
dao().clear(SpreadContent.class, Cnd.where("id", "=", id));
}
@Override
public void publishContent(String id, Integer status) {
getContent(id);
if (status == null || (status != 0 && status != 1)) {
throw new RuntimeException("发布状态不正确");
}
org.nutz.dao.Chain chain = org.nutz.dao.Chain.make("isPublished", status);
if (status == 1) {
chain.add("publishedAt", System.currentTimeMillis());
}
dao().update(SpreadContent.class, chain, Cnd.where("id", "=", id).and("delFlag", "=", false));
}
@Override
public void addViewCount(String id) {
getContent(id);
Sql sql = Sqls.create("""
UPDATE spread_content
SET viewCount = IFNULL(viewCount, 0) + 1,
updatedAt = @updatedAt
WHERE id = @id AND delFlag = 0
""");
sql.params().set("id", id);
sql.params().set("updatedAt", System.currentTimeMillis());
dao().execute(sql);
}
@Override
public List<NutMap> sliderContent() {
Sql sql = Sqls.create("""
SELECT c.id, c.title, c.summary, c.thumbUrl, c.sliderImages, c.categoryId, c.categoryName, c.unionId, c.unionName
FROM spread_content c
INNER JOIN spread_category child ON child.id = c.categoryId
LEFT JOIN spread_category parent ON parent.id = child.parentId
WHERE c.delFlag = 0
AND c.isPublished = 1
AND child.delFlag = 0
AND child.visible = 1
AND child.slider = 1
AND (child.parentId = '0' OR (parent.delFlag = 0 AND parent.visible = 1 AND parent.slider = 1))
ORDER BY c.isTop DESC, c.publishedAt DESC, c.createdAt DESC
LIMIT 10
""");
sql.setCallback(Sqls.callback.maps());
dao().execute(sql);
return sql.getList(NutMap.class);
}
@Override
public List<Sys_union> selectableUnions() {
Cnd cnd = Cnd.NEW();
if (!canSelectAllUnions()) {
String currentUnionId = SecurityUtil.getUnionId();
if (StrUtil.isBlank(currentUnionId)) {
return Collections.emptyList();
}
cnd.and("id", "=", currentUnionId);
}
cnd.asc("unionCode");
return dao().query(Sys_union.class, cnd);
}
/**
* 校工会管理员和系统管理员可选择全部工会,其他人员只能选择登录人员自己的分工会。
*/
private boolean canSelectAllUnions() {
return AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
}
/**
* 校验工会是否存在且在当前登录人员的可选择范围内。
*/
private Sys_union requireSelectableUnion(String unionId) {
if (StrUtil.isBlank(unionId)) {
throw new RuntimeException("请选择所属工会");
}
Sys_union union = dao().fetch(Sys_union.class, unionId);
if (union == null) {
throw new RuntimeException("所属工会不存在");
}
if (!canSelectAllUnions() && !unionId.equals(SecurityUtil.getUnionId())) {
throw new RuntimeException("无权选择该所属工会");
}
return union;
}
/**
* 校验并规范每张轮播图的标题,轮播图统一继承内容所属工会。
*/
private void validateSliderImages(SpreadContent content) {
if (StrUtil.isBlank(content.getSliderImages())) {
return;
}
JSONArray sliderArray;
try {
sliderArray = JSONUtil.parseArray(content.getSliderImages());
} catch (RuntimeException e) {
throw new RuntimeException("轮播图片数据格式不正确");
}
JSONArray normalizedArray = new JSONArray();
for (int i = 0; i < sliderArray.size(); i++) {
Object rawItem = sliderArray.get(i);
if (!(rawItem instanceof JSONObject)) {
throw new RuntimeException("请完善第" + (i + 1) + "张轮播图标题");
}
JSONObject item = (JSONObject) rawItem;
if (StrUtil.isBlank(item.getStr("src"))) {
throw new RuntimeException("" + (i + 1) + "张轮播图地址不能为空");
}
if (StrUtil.isBlank(item.getStr("title"))) {
throw new RuntimeException("请输入第" + (i + 1) + "张轮播图标题");
}
JSONObject normalizedItem = new JSONObject();
normalizedItem.set("src", item.getStr("src"));
normalizedItem.set("title", item.getStr("title").trim());
normalizedArray.add(normalizedItem);
}
content.setSliderImages(JSONUtil.toJsonStr(normalizedArray));
}
private Cnd buildCondition(SpreadContentQuery query) {
Cnd cnd = Cnd.where("c.delFlag", "=", false);
if (query == null) {
return cnd;
}
if (StrUtil.isNotBlank(query.getCategoryId())) {
List<String> categoryIds = new ArrayList<>();
categoryIds.add(query.getCategoryId());
List<SpreadCategory> children = dao().query(SpreadCategory.class,
Cnd.where("parentId", "=", query.getCategoryId()).and("delFlag", "=", false));
children.forEach(item -> categoryIds.add(item.getId()));
cnd.and("c.categoryId", "in", categoryIds);
}
cnd.and(Cnd.likeEX("c.title", query.getTitle()));
cnd.andEX("c.isPublished", "=", query.getIsPublished());
if (StrUtil.isNotBlank(query.getBeginTime())) {
cnd.and("c.createdAt", ">=", DateUtil.parse(query.getBeginTime()).getTime());
}
if (StrUtil.isNotBlank(query.getEndTime())) {
cnd.and("c.createdAt", "<=", DateUtil.parse(query.getEndTime()).getTime());
}
return cnd;
}
private void validateContent(SpreadContent content) {
if (content == null || StrUtil.isBlank(content.getCategoryId())) {
throw new RuntimeException("请选择栏目");
}
SpreadCategory category = dao().fetch(SpreadCategory.class,
Cnd.where("id", "=", content.getCategoryId()).and("delFlag", "=", false));
if (category == null) {
throw new RuntimeException("栏目不存在");
}
if (dao().count(SpreadCategory.class,
Cnd.where("parentId", "=", category.getId()).and("delFlag", "=", false)) > 0) {
throw new RuntimeException("内容只能发布到末级栏目");
}
Sys_union union = requireSelectableUnion(content.getUnionId());
if (StrUtil.isBlank(content.getTitle())) {
throw new RuntimeException("标题不能为空");
}
content.setTitle(content.getTitle().trim());
content.setCategoryName(category.getName());
content.setUnionName(union.getName());
validateSliderImages(content);
}
private void applyDefaults(SpreadContent content) {
if (content.getIsTop() == null) {
content.setIsTop(0);
}
if (content.getIsRecommend() == null) {
content.setIsRecommend(0);
}
if (content.getIsHeadline() == null) {
content.setIsHeadline(0);
}
if (content.getViewCount() == null) {
content.setViewCount(0);
}
if (content.getSortOrder() == null) {
content.setSortOrder(255);
}
if (content.getIsPublished() == null) {
content.setIsPublished(0);
}
}
}
@@ -0,0 +1,115 @@
package com.budwk.app.zhgh.spread.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.zhgh.spread.param.SpreadStatisticsQuery;
import com.budwk.app.zhgh.spread.service.SpreadStatisticsService;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import java.util.List;
@IocBean
public class SpreadStatisticsServiceImpl implements SpreadStatisticsService {
@Inject
private Dao dao;
@Override
public NutMap summary(SpreadStatisticsQuery query) {
String condition = buildContentCondition(query, "c");
Sql sql = Sqls.create("""
SELECT
(SELECT COUNT(1) FROM spread_category cg WHERE cg.delFlag = 0) AS categoryCount,
COUNT(1) AS contentCount,
IFNULL(SUM(CASE WHEN c.isPublished = 1 THEN 1 ELSE 0 END), 0) AS publishedCount,
IFNULL(SUM(c.viewCount), 0) AS viewCount,
IFNULL(ROUND(AVG(c.viewCount)), 0) AS avgViewCount
FROM spread_content c
WHERE c.delFlag = 0
$condition
""");
sql.setVar("condition", condition);
setParams(sql, query);
sql.setCallback(Sqls.callback.map());
dao.execute(sql);
NutMap result = sql.getObject(NutMap.class);
return result == null ? NutMap.NEW() : result;
}
@Override
public List<NutMap> top10(SpreadStatisticsQuery query) {
Sql sql = Sqls.create("""
SELECT c.id, c.title, c.summary, c.categoryName, c.unionId, c.unionName, c.viewCount, c.isPublished, c.publishedAt
FROM spread_content c
WHERE c.delFlag = 0
AND c.isPublished = 1
$condition
ORDER BY c.viewCount DESC, c.updatedAt DESC
LIMIT 10
""");
sql.setVar("condition", buildContentCondition(query, "c"));
setParams(sql, query);
sql.setCallback(Sqls.callback.maps());
dao.execute(sql);
return sql.getList(NutMap.class);
}
@Override
public List<NutMap> categoryStatistics(SpreadStatisticsQuery query) {
Sql sql = Sqls.create("""
SELECT c.categoryId, c.categoryName, COUNT(1) AS contentCount,
IFNULL(SUM(c.viewCount), 0) AS viewCount
FROM spread_content c
WHERE c.delFlag = 0
AND c.isPublished = 1
$condition
GROUP BY c.categoryId, c.categoryName
ORDER BY viewCount DESC, contentCount DESC
""");
sql.setVar("condition", buildContentCondition(query, "c"));
setParams(sql, query);
sql.setCallback(Sqls.callback.maps());
dao.execute(sql);
return sql.getList(NutMap.class);
}
private String buildContentCondition(SpreadStatisticsQuery query, String alias) {
if (query == null) {
return "";
}
StringBuilder condition = new StringBuilder();
if (StrUtil.isNotBlank(query.getCategoryId())) {
condition.append(" AND ").append(alias)
.append(".categoryId IN (SELECT id FROM spread_category WHERE id = @categoryId OR parentId = @categoryId)");
}
if (query.getIsPublished() != null) {
condition.append(" AND ").append(alias).append(".isPublished = @isPublished");
}
if (StrUtil.isNotBlank(query.getBeginTime())) {
condition.append(" AND ").append(alias).append(".createdAt >= @beginAt");
}
if (StrUtil.isNotBlank(query.getEndTime())) {
condition.append(" AND ").append(alias).append(".createdAt <= @endAt");
}
return condition.toString();
}
private void setParams(Sql sql, SpreadStatisticsQuery query) {
if (query == null) {
return;
}
sql.params().set("categoryId", query.getCategoryId());
sql.params().set("isPublished", query.getIsPublished());
if (StrUtil.isNotBlank(query.getBeginTime())) {
sql.params().set("beginAt", DateUtil.parse(query.getBeginTime()).getTime());
}
if (StrUtil.isNotBlank(query.getEndTime())) {
sql.params().set("endAt", DateUtil.parse(query.getEndTime()).getTime());
}
}
}
@@ -48,7 +48,8 @@ public class WelfareMineController {
@At
@SaCheckPermission("welfare.mine")
public Result pageData(PageForm pageForm,
Integer year) {
Integer year,
String name) {
Sql sql = Sqls.create("""
SELECT
wp.*,
@@ -57,13 +58,14 @@ public class WelfareMineController {
WHEN wus.selectUserId IS NOT NULL THEN
1 ELSE 0
END AS isChoose,
GROUP_CONCAT(DISTINCT wuso.optionName ,'',wus.selectNum,'份)') AS gist_list,
wus.receiveAddress,
GROUP_CONCAT(DISTINCT wuso.optionName ,'',wus.selectNum,'份)') AS gist_list,
MAX(wus.selectTime) AS selectTime,
wus.receiveAddress,
wl.userId
FROM
welfare_list wl
LEFT JOIN welfare_project wp ON wp.id = wl.projectId
LEFT JOIN welfare_project_user_selection wus ON wl.projectId = wus.welfareId
INNER JOIN welfare_project_user_selection wus ON wl.projectId = wus.welfareId
AND wus.selectUserId = @selectUserId
LEFT JOIN welfare_project_subject_option wuso ON wus.selectOptionId = wuso.id
$condition
@@ -73,6 +75,9 @@ public class WelfareMineController {
cnd.and("wp.isDisabled", "=", 0);
cnd.andEX("YEAR(wp.choiceTimeStart)", "=", year);
cnd.andEX("wl.userId", "=", SecurityUtil.getUserId());
if (StrUtil.isNotBlank(name)) {
cnd.and("wp.name", "like", "%" + name.trim() + "%");
}
cnd.desc("wp.choiceTimeStart");
cnd.groupBy("wl.id");
sql.setCondition(cnd);
@@ -1,6 +1,7 @@
package com.budwk.app.zhgh.welfare.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
@@ -47,7 +48,7 @@ public class WelfareUserSelectController {
@At
@SaCheckPermission("welfare.user.select")
@ApiOperation("获取用户选择列表分页")
public Result pageData(PageForm pageForm, Integer year) {
public Result pageData(PageForm pageForm, Integer year, String name) {
Sql sql = Sqls.create("""
SELECT
wp.*,
@@ -71,6 +72,9 @@ public class WelfareUserSelectController {
cnd.and("wp.provideMode", "in", "2,3");
cnd.andEX("YEAR(wp.choiceTimeStart)", "in", year);
cnd.and("wp.isDisabled", "=", 0);
if (StrUtil.isNotBlank(name)) {
cnd.and("wp.name", "like", "%" + name.trim() + "%");
}
cnd.groupBy("wp.id");
cnd.desc("wp.choiceTimeStart");
sql.setCondition(cnd);