This commit is contained in:
@jyuhsin
2026-04-22 19:05:31 +08:00
16 changed files with 545 additions and 199 deletions
@@ -133,6 +133,9 @@ public class ClubExamineApplyController {
.and("year", "=", year)
.desc("year")
);
if (club == null) {
return Result.success(0f);
}
Number number = ObjectUtil.defaultIfNull(club.getTotalQuota(), 0);
return Result.success(number.floatValue());
}
@@ -154,7 +157,6 @@ public class ClubExamineApplyController {
}
@At
@SaCheckPermission("club.examine")
public Result info(String id) {
if(StrUtil.isBlank(id)) {
return Result.error("id信息为空,请核查");
@@ -1,17 +1,29 @@
package com.budwk.app.zhgh.club.controller.examine;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.club.param.ClubUserPageForm;
import com.budwk.app.zhgh.club.service.SysClubExamineService;
import com.budwk.app.zhgh.club.vo.ClubExamineVo;
import com.budwk.app.zhgh.club.vo.ClubExaminePageVo;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.apache.poi.ss.usermodel.Workbook;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName ClubExamineSchoolLeaderAuditController
@@ -39,4 +51,49 @@ public class ClubExamineSchoolLeaderAuditController {
Pagination<ClubExaminePageVo> pagination = sysClubExamineService.schoolLeaderAuditPageData(pageForm);
return Result.success(pagination);
}
@At
@Ok("void")
@SaCheckPermission("club.examine.schoolLeaderAudit")
public void doExportPlan(String id, HttpServletResponse response) {
ClubExamineVo examineVo = sysClubExamineService.findOne(id);
if (Lang.isEmpty(examineVo)) {
return;
}
// 导出下一年度活动计划,字段顺序与查看页列表保持一致。
List<NutMap> exportData = sysClubExamineService.getPlanExportData(id);
List<ExcelExportEntity> entityList = new ArrayList<>();
entityList.add(new ExcelExportEntity("活动主题/赛事名称", "activityName", 40));
entityList.add(new ExcelExportEntity("活动/赛事主办单位", "activityUnit", 40));
entityList.add(new ExcelExportEntity("活动地点", "activityAddress", 40));
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, exportData);
CommonDownloadUtil.download(examineVo.getClubName() + "下一年度活动计划.xlsx", workbook, response);
}
@At
@Ok("void")
@SaCheckPermission("club.examine.schoolLeaderAudit")
public void doExportActivity(String id, HttpServletResponse response) {
ClubExamineVo examineVo = sysClubExamineService.findOne(id);
if (Lang.isEmpty(examineVo)) {
return;
}
// 导出本年度活动开展情况,字段与年审填报表格列保持一致。
List<NutMap> exportData = sysClubExamineService.getYearActivityExportData(id);
List<ExcelExportEntity> entityList = new ArrayList<>();
entityList.add(new ExcelExportEntity("活动时间", "activityTime", 20));
entityList.add(new ExcelExportEntity("活动主题/赛事名称", "activityName", 40));
entityList.add(new ExcelExportEntity("活动/赛事主办单位", "activityUnit", 40));
entityList.add(new ExcelExportEntity("活动地点", "activityAddress", 40));
entityList.add(new ExcelExportEntity("参加人数", "joinNum", 20));
entityList.add(new ExcelExportEntity("获奖情况", "prize", 30));
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, exportData);
CommonDownloadUtil.download(examineVo.getClubName() + "本年度活动开展情况.xlsx", workbook, response);
}
}
@@ -30,4 +30,20 @@ public interface SysClubExamineService extends BaseService<SysClubExamineRegiste
Pagination<ClubExaminePageVo> schoolLeaderAuditPageData(@Valid ClubUserPageForm pageForm);
ClubExamineVo findOne(@Valid String id);
/**
* 查询本年度活动开展情况导出数据。
*
* @param id 年审主键
* @return 导出行数据
*/
List<NutMap> getYearActivityExportData(@Valid String id);
/**
* 查询下一年度活动计划导出数据。
*
* @param id 年审主键
* @return 导出行数据
*/
List<NutMap> getPlanExportData(@Valid String id);
}
@@ -1,6 +1,7 @@
package com.budwk.app.zhgh.club.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.budwk.app.base.constant.RoleConstant;
@@ -308,7 +309,7 @@ public class SysClubExamineServiceImpl extends BaseServiceImpl<SysClubExamineReg
""");
// 构建基础分页查询条件
buildPageBaseCondition(cnd, pageForm, "info");
cnd.and("info.userId", "=", SecurityUtil.getUserId());
// cnd.and("info.userId", "=", SecurityUtil.getUserId());
cnd.groupBy("info.id");
// cnd.desc("registerDate");
cnd.asc("sc.foundTime");
@@ -367,6 +368,41 @@ public class SysClubExamineServiceImpl extends BaseServiceImpl<SysClubExamineReg
return clubExamineVo;
}
@Override
public List<NutMap> getYearActivityExportData(String id) {
ClubExamineVo examineVo = this.findOne(id);
if (Lang.isEmpty(examineVo) || Lang.isEmpty(examineVo.getYearActivityList())) {
return new ArrayList<>();
}
// 导出字段与前端表格字段保持一致,避免控制层再做字段转换。
return examineVo.getYearActivityList().stream()
.map(item -> Dict.create()
.set("activityTime", item.getStr("activityTime"))
.set("activityName", item.getStr("activityName"))
.set("activityUnit", item.getStr("activityUnit"))
.set("activityAddress", item.getStr("activityAddress"))
.set("joinNum", item.getStr("joinNum"))
.set("prize", item.getStr("prize")))
.map(NutMap::new)
.collect(Collectors.toList());
}
@Override
public List<NutMap> getPlanExportData(String id) {
ClubExamineVo examineVo = this.findOne(id);
if (Lang.isEmpty(examineVo) || Lang.isEmpty(examineVo.getPlans())) {
return new ArrayList<>();
}
// 下年度活动计划导出只保留页面已有的三个业务字段。
return examineVo.getPlans().stream()
.map(item -> Dict.create()
.set("activityName", item.getStr("activityName"))
.set("activityUnit", item.getStr("activityUnit"))
.set("activityAddress", item.getStr("activityAddress")))
.map(NutMap::new)
.collect(Collectors.toList());
}
/**
* 生成审核分页通用SQL
* @param pageForm 分页查询参数
@@ -0,0 +1,47 @@
package com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.model.OutLayAllocateUnion;
import java.math.BigDecimal;
/**
* 分工会季度额度分配服务。
*
* <p>该服务统一处理季度额度的分配、批量分配和重置回滚,
* 保证季度记录与年度预算表金额始终同步。</p>
*
* @author zhf
*/
public interface OutlayManageUnionAllocateService extends BaseService<OutLayAllocateUnion> {
/**
* 修改单个分工会的季度分配金额。
*
* @param id outlay_allocate_union 表主键,用于定位当前编辑的季度分配记录
* @param allocateMoney 本次要设置的季度分配金额,传入的是最终金额,不是增量金额
* @return Result 成功时返回 success;失败时返回错误信息,前端据此提示用户
*/
Result doEdit(String id, BigDecimal allocateMoney);
/**
* 批量设置某一季度所有分工会的分配金额。
*
* @param allocateMoney 本次批量设置的季度分配金额,所有命中的分工会都会写入该金额
* @param quarterly 要操作的季度,例如 1/2/3/4
* @param year 要操作的年份,用于筛选对应季度的有效分配记录
* @return Result 成功时返回 success;失败时返回错误信息
*/
Result doBatchAllocate(BigDecimal allocateMoney, Integer quarterly, Integer year);
/**
* 重置当前季度的分配记录。
*
* <p>重置时会先回滚 outlay_manage_union.totalQuota
* 再将当前季度的 outlay_allocate_union 记录标记删除。</p>
*
* @return Result 成功时返回 success;失败时返回错误信息
*/
Result deleteAllocateRecord();
}
@@ -0,0 +1,167 @@
package com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.impl;
import cn.hutool.core.date.DateUtil;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_union;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.OutlayManageUnionAllocateService;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.model.OutLayAllocateUnion;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.model.OutlayManageUnion;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import java.math.BigDecimal;
import java.util.List;
/**
* 分工会季度额度分配实现。
*
* @author zhf
*/
@IocBean(args = {"refer:dao"})
public class OutlayManageUnionAllocateServiceImpl extends BaseServiceImpl<OutLayAllocateUnion> implements OutlayManageUnionAllocateService {
public OutlayManageUnionAllocateServiceImpl(Dao dao) {
super(dao);
}
@Override
public Result doEdit(String id, BigDecimal allocateMoney) {
OutLayAllocateUnion allocateUnion = fetch(id);
if (Lang.isEmpty(allocateUnion)) {
return Result.error("分配记录不存在!");
}
int currentQuarter = getCurrentQuarter();
if (allocateUnion.getQuarterly() < currentQuarter) {
return Result.error("当前是第【" + currentQuarter + "季度】无法修改【第" + allocateUnion.getQuarterly() + "季度】的额度!");
}
applyAllocateMoney(allocateUnion, allocateMoney);
return Result.success();
}
@Override
public Result doBatchAllocate(BigDecimal allocateMoney, Integer quarterly, Integer year) {
List<OutLayAllocateUnion> allocateUnionList = dao().query(OutLayAllocateUnion.class,
Cnd.where(OutLayAllocateUnion::getQuarterly, "=", quarterly)
.and(OutLayAllocateUnion::getYear, "=", year)
.and(OutLayAllocateUnion::getDelFlag, "=", false));
if (allocateUnionList == null || allocateUnionList.isEmpty()) {
return Result.error("当前季度没有分配记录!");
}
for (OutLayAllocateUnion allocateUnion : allocateUnionList) {
applyAllocateMoney(allocateUnion, allocateMoney);
}
return Result.success();
}
@Override
public Result deleteAllocateRecord() {
int currentQuarter = getCurrentQuarter();
List<OutLayAllocateUnion> allocateUnionList = dao().query(OutLayAllocateUnion.class,
Cnd.where(OutLayAllocateUnion::getQuarterly, "=", currentQuarter)
.and(OutLayAllocateUnion::getYear, "=", DateUtil.thisYear())
.and(OutLayAllocateUnion::getDelFlag, "=", false));
if (allocateUnionList == null || allocateUnionList.isEmpty()) {
return Result.error("当前季度还未分配,无法重置!");
}
for (OutLayAllocateUnion allocateUnion : allocateUnionList) {
rollbackAllocateMoney(allocateUnion);
}
dao().update(OutLayAllocateUnion.class, Chain.make("delFlag", true),
Cnd.where(OutLayAllocateUnion::getQuarterly, "=", currentQuarter)
.and(OutLayAllocateUnion::getYear, "=", DateUtil.thisYear())
.and(OutLayAllocateUnion::getDelFlag, "=", false));
return Result.success();
}
/**
* 按“先回退旧额度,再写入新额度”的方式同步季度记录和年度预算表。
*
* @param allocateUnion 当前季度分配记录,包含分工会、年份、旧分配额度等上下文
* @param newAllocateMoney 本次最终要保存的季度分配金额
*/
private void applyAllocateMoney(OutLayAllocateUnion allocateUnion, BigDecimal newAllocateMoney) {
BigDecimal oldAllocateMoney = defaultValue(allocateUnion.getAllocateMoney());
OutlayManageUnion manageUnion = dao().fetch(OutlayManageUnion.class,
Cnd.where(OutlayManageUnion::getUnionId, "=", allocateUnion.getUnionId())
.and(OutlayManageUnion::getYear, "=", DateUtil.thisYear()));
if (Lang.isEmpty(manageUnion)) {
manageUnion = buildManageUnion(allocateUnion, newAllocateMoney);
insert(manageUnion);
} else {
// 当前 totalQuota 里已经包含了旧季度额度,因此要先减旧值,再加新值,避免重复累加。
BigDecimal newTotalQuota = defaultValue(manageUnion.getTotalQuota())
.subtract(oldAllocateMoney)
.add(newAllocateMoney);
dao().update(OutlayManageUnion.class, Chain.make("totalQuota", newTotalQuota),
Cnd.where(OutlayManageUnion::getId, "=", manageUnion.getId()));
}
dao().update(OutLayAllocateUnion.class, Chain.make("allocateMoney", newAllocateMoney),
Cnd.where(OutLayAllocateUnion::getId, "=", allocateUnion.getId()));
}
/**
* 回滚当前季度已分配到年度预算表中的金额。
*
* @param allocateUnion 当前季度分配记录,allocateMoney 表示本次需要从年度额度中扣回的金额
*/
private void rollbackAllocateMoney(OutLayAllocateUnion allocateUnion) {
OutlayManageUnion manageUnion = dao().fetch(OutlayManageUnion.class,
Cnd.where(OutlayManageUnion::getUnionId, "=", allocateUnion.getUnionId())
.and(OutlayManageUnion::getYear, "=", DateUtil.thisYear()));
if (Lang.isEmpty(manageUnion)) {
return;
}
BigDecimal newTotalQuota = defaultValue(manageUnion.getTotalQuota())
.subtract(defaultValue(allocateUnion.getAllocateMoney()));
dao().update(OutlayManageUnion.class, Chain.make("totalQuota", newTotalQuota),
Cnd.where(OutlayManageUnion::getId, "=", manageUnion.getId()));
}
/**
* 当前年份预算表不存在时,按“分配前额度 + 本次分配额度”创建年度预算记录。
*
* @param allocateUnion 当前季度分配记录,allocateHeadMoney 表示生成记录时的剩余额度快照
* @param allocateMoney 本次要设置的季度分配额度
* @return OutlayManageUnion 新建的年度预算实体
*/
private OutlayManageUnion buildManageUnion(OutLayAllocateUnion allocateUnion, BigDecimal allocateMoney) {
Sys_union union = dao().fetch(Sys_union.class, allocateUnion.getUnionId());
OutlayManageUnion manageUnion = new OutlayManageUnion();
manageUnion.setYear(DateUtil.thisYear());
manageUnion.setUnionId(allocateUnion.getUnionId());
manageUnion.setTotalQuota(defaultValue(allocateUnion.getAllocateHeadMoney()).add(allocateMoney));
manageUnion.setUsedQuota(BigDecimal.ZERO);
if (Lang.isNotEmpty(union)) {
manageUnion.setUnionName(union.getName());
manageUnion.setUnionCode(union.getUnionCode());
}
return manageUnion;
}
/**
* 统一处理空金额,避免金额运算时出现空指针。
*
* @param value 可能为空的金额字段
* @return BigDecimal 非空金额;为空时返回 0
*/
private BigDecimal defaultValue(BigDecimal value) {
return value == null ? BigDecimal.ZERO : value;
}
/**
* 计算当前自然季度。
*
* @return int 当前季度,取值范围 1-4
*/
private int getCurrentQuarter() {
return DateUtil.month(DateUtil.date()) / 3 + 1;
}
}
@@ -9,13 +9,13 @@ import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.sys.models.Sys_union;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.OutlayManageUnionAllocateService;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.model.OutLayAllocateUnion;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.model.OutlayManageUnion;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
@@ -45,6 +45,8 @@ public class OutlayManageUnionAllocateController {
@Inject
private BaseService baseService;
@Inject
private OutlayManageUnionAllocateService outlayManageUnionAllocateService;
@At("")
@Ok("beetl:/platform/zhgh/dayofficework/outlay/outlayManage/union/allocate/index.html")
@@ -88,59 +90,7 @@ public class OutlayManageUnionAllocateController {
if (StrUtil.isEmpty(allocateMoney) || StrUtil.isEmpty(id)) {
return Result.error("参数错误!");
}
OutLayAllocateUnion allocateUnion = baseService.dao().fetch(OutLayAllocateUnion.class, id);
int quarter = DateUtil.month(DateUtil.date()) / 3 + 1;
if (allocateUnion.getQuarterly() < quarter) {
return Result.error("当前是第【" + quarter + "季度】无法修改【第" + allocateUnion.getQuarterly() + "季度】的额度!");
}
baseService.dao().update(OutLayAllocateUnion.class, Chain.make("allocateMoney", allocateMoney),
Cnd.where(OutLayAllocateUnion::getId, "=", id));
//找出今年工会的预算表
OutlayManageUnion newOutlayManageUnion = baseService.dao().fetch(OutlayManageUnion.class,
Cnd.where(OutlayManageUnion::getUnionId, "=", allocateUnion.getUnionId())
.and(OutlayManageUnion::getYear, "=", DateUtil.thisYear()));
if (allocateUnion.getQuarterly() == 1) {
//如果是第一季度,添加年度预算表
Sys_union union = baseService.dao().fetch(Sys_union.class, allocateUnion.getUnionId());
//找出去年剩余的钱
OutlayManageUnion oldOutlayManageUnion = baseService.dao().fetch(OutlayManageUnion.class,
Cnd.where(OutlayManageUnion::getUnionId, "=", allocateUnion.getUnionId())
.and(OutlayManageUnion::getYear, "=", DateUtil.thisYear() - 1));
BigDecimal newTotalQuota = Lang.isNotEmpty(oldOutlayManageUnion) ? oldOutlayManageUnion.getTotalQuota().subtract(oldOutlayManageUnion.getUsedQuota()) : new BigDecimal(allocateMoney);
if (Lang.isNotEmpty(newOutlayManageUnion)) {
//如果有今年的预算,代表第一季度已经分配过一次,现在修改
newOutlayManageUnion.setTotalQuota(newTotalQuota);
baseService.update(newOutlayManageUnion);
} else {
OutlayManageUnion manageUnion = new OutlayManageUnion();
manageUnion.setYear(DateUtil.thisYear());
manageUnion.setUnionId(union.getId());
manageUnion.setUnionName(union.getName());
manageUnion.setUnionCode(union.getUnionCode());
//找出去年剩余多少钱,
if (Lang.isNotEmpty(oldOutlayManageUnion)) {
BigDecimal surplusMoney = oldOutlayManageUnion.getTotalQuota().subtract(oldOutlayManageUnion.getUsedQuota());
//去年剩余的钱加上当年的分配金额
manageUnion.setTotalQuota(surplusMoney.add(new BigDecimal(allocateMoney)));
} else {
manageUnion.setTotalQuota(new BigDecimal(allocateMoney));
}
manageUnion.setUsedQuota(BigDecimal.ZERO);
baseService.insert(manageUnion);
}
} else {
baseService.dao().update(OutlayManageUnion.class,
Chain.make("totalQuota", newOutlayManageUnion.getTotalQuota().add(new BigDecimal(allocateMoney))),
Cnd.where(OutlayManageUnion::getId, "=", newOutlayManageUnion.getId()));
}
return Result.success();
return outlayManageUnionAllocateService.doEdit(id, new BigDecimal(allocateMoney));
}
@At
@@ -151,79 +101,20 @@ public class OutlayManageUnionAllocateController {
public Result doBatchAllocate(@Param("allocateMoney") BigDecimal allocateMoney,
@Param("quarterly") Integer quarterly,
@Param("year") Integer year) {
List<OutLayAllocateUnion> allocateUnionList = baseService.dao().query(OutLayAllocateUnion.class,
Cnd.where(OutLayAllocateUnion::getQuarterly, "=", quarterly)
.and(OutLayAllocateUnion::getYear, "=", year)
.and(OutLayAllocateUnion::getDelFlag, "=", 0));
if (allocateUnionList == null || allocateUnionList.isEmpty()) {
return Result.error("当前季度没有分配记录!");
if (allocateMoney == null || quarterly == null || year == null) {
return Result.error("参数错误!");
}
for (OutLayAllocateUnion allocateUnion : allocateUnionList) {
baseService.dao().update(OutLayAllocateUnion.class,
Chain.make("allocateMoney", allocateMoney),
Cnd.where(OutLayAllocateUnion::getId, "=", allocateUnion.getId()));
OutlayManageUnion newOutlayManageUnion = baseService.dao().fetch(OutlayManageUnion.class,
Cnd.where(OutlayManageUnion::getUnionId, "=", allocateUnion.getUnionId())
.and(OutlayManageUnion::getYear, "=", DateUtil.thisYear()));
if (allocateUnion.getQuarterly() == 1) {
Sys_union union = baseService.dao().fetch(Sys_union.class, allocateUnion.getUnionId());
OutlayManageUnion oldOutlayManageUnion = baseService.dao().fetch(OutlayManageUnion.class,
Cnd.where(OutlayManageUnion::getUnionId, "=", allocateUnion.getUnionId())
.and(OutlayManageUnion::getYear, "=", DateUtil.thisYear() - 1));
BigDecimal newTotalQuota = Lang.isNotEmpty(oldOutlayManageUnion)
? oldOutlayManageUnion.getTotalQuota().subtract(oldOutlayManageUnion.getUsedQuota())
: allocateMoney;
if (Lang.isNotEmpty(newOutlayManageUnion)) {
newOutlayManageUnion.setTotalQuota(newTotalQuota);
baseService.update(newOutlayManageUnion);
} else {
OutlayManageUnion manageUnion = new OutlayManageUnion();
manageUnion.setYear(DateUtil.thisYear());
manageUnion.setUnionId(union.getId());
manageUnion.setUnionName(union.getName());
manageUnion.setUnionCode(union.getUnionCode());
if (Lang.isNotEmpty(oldOutlayManageUnion)) {
BigDecimal surplusMoney = oldOutlayManageUnion.getTotalQuota().subtract(oldOutlayManageUnion.getUsedQuota());
manageUnion.setTotalQuota(surplusMoney.add(allocateMoney));
} else {
manageUnion.setTotalQuota(allocateMoney);
}
manageUnion.setUsedQuota(BigDecimal.ZERO);
baseService.insert(manageUnion);
}
} else {
baseService.dao().update(OutlayManageUnion.class,
Chain.make("totalQuota", newOutlayManageUnion.getTotalQuota().add(allocateMoney)),
Cnd.where(OutlayManageUnion::getId, "=", newOutlayManageUnion.getId()));
}
}
return Result.success();
return outlayManageUnionAllocateService.doBatchAllocate(allocateMoney, quarterly, year);
}
@At
@ApiOperation("重置预算季度记录")
@Aop(TransAop.READ_COMMITTED)
@SLog(tag = "分工会预算-季度预算分配", msg = "重置预算季度记录")
@SaCheckPermission("outlay.outlayManage.union.allocate")
public Result deleteAllocateRecord() {
int quarter = DateUtil.month(DateUtil.date()) / 3 + 1;
// 查询当前季度
int count = baseService.dao().count(OutLayAllocateUnion.class, Cnd.where(OutLayAllocateUnion::getQuarterly, "=", quarter)
.and(OutLayAllocateUnion::getYear, "=", DateUtil.thisYear()));
if (count == 0) {
return Result.error("当前季度还未分配,无法重置!");
}
baseService.dao().update(OutLayAllocateUnion.class, Chain.make("delFlag", 1),
Cnd.where(OutLayAllocateUnion::getQuarterly, "=", quarter)
.and(OutLayAllocateUnion::getYear, "=", DateUtil.thisYear()));
return Result.success();
return outlayManageUnionAllocateService.deleteAllocateRecord();
}
@At
@@ -59,7 +59,7 @@ public class AIdFundPayRecordController {
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/medicalMutualAid/aidFund/paexportYearPayRecordyRecord/index.html")
@Ok("beetl:/platform/zhgh/staffbenefit/medicalMutualAid/aidFund/payRecord/index.html")
@SaCheckPermission("medicalMutualAid.aidFund.payRecord")
public void index() {
}
@@ -22,8 +22,9 @@ layout("/layouts/platform.html"){
width: 80px;
}
/* 财务明细表格高度 */
.finance-table {
.finance-table >>> .el-table__body-wrapper {
max-height: 600px;
overflow-y: auto !important;
}
/* 统计表格高度 */
.stat-table {
@@ -725,7 +726,12 @@ layout("/layouts/platform.html"){
},
// 计算年度结余
calcSurplus(row) {
const total = (row.lastYearSurplus || 0) + (row.income || 0) + (row.allocate || 0) + (row.support || 0) - (row.totalExpend || 0);
const lastYearSurplusVal = this.lastYearSurplus !== null ? this.lastYearSurplus : (row.lastYearSurplus || 0);
const income = row.income || 0;
const allocate = row.allocate || 0;
const support = row.support || 0;
const totalExpend = row.totalExpend || 0;
const total = Number(lastYearSurplusVal) + Number(income) + Number(allocate) + Number(support) - Number(totalExpend);
return this.formatNumber(total);
},
// 表单校验通用方法
@@ -783,13 +789,43 @@ layout("/layouts/platform.html"){
this.formData = data;
// 初始化财务数据
this.financeData.incomeCensus = data.incomeCensus || [{ lastYearSurplus: 0, income: 0, allocate: 0, support: 0, totalExpend: 0, surplus: 0 }];
this.financeData.incomeDetailed = data.detailedList || [];
// 从统计数据中提取去年年度结余
if (this.financeData.incomeCensus && this.financeData.incomeCensus.length > 0) {
this.lastYearSurplus = this.financeData.incomeCensus[0].lastYearSurplus || 0;
}
if (data.detailedList && data.detailedList.length > 0) {
this.financeData.incomeDetailed = this.sortIncomeDetailed(data.detailedList);
} else {
this.financeData.incomeDetailed = [];
}
// 初始化成员数据
await this.fetchClubUserNum(data.clubId);
await this.fetchMemberList(data.clubId);
// 检查是否已登记
await this.checkIsRegistered();
},
sortIncomeDetailed(list) {
const defaultContents = [new Date().getFullYear() - 1 + "年度结余", "会费收入", "校工会拨款"];
const defaultItems = [];
const customItems = [];
list.forEach(item => {
if (item.content && defaultContents.includes(item.content)) {
defaultItems.push(item);
} else {
customItems.push(item);
}
});
// 按默认顺序排列前三条
const sortedDefaults = defaultContents.map(content =>
defaultItems.find(item => item.content === content)
).filter(item => item !== undefined);
return [...sortedDefaults, ...customItems];
},
// 获取社团成员数量
async fetchClubUserNum(clubId) {
const resp = await this.$axios.post("/platform/club/examine/apply/getClubUserNum", {
@@ -830,6 +866,11 @@ layout("/layouts/platform.html"){
year: this.formData.year
});
this.lastYearSurplus = resp.data || 0;
// 同步更新到统计表格
if (this.financeData.incomeCensus && this.financeData.incomeCensus.length > 0) {
this.financeData.incomeCensus[0].lastYearSurplus = this.lastYearSurplus;
}
},
// 获取上年度社团数据
async fetchLastClubData() {
@@ -897,22 +938,25 @@ layout("/layouts/platform.html"){
},
// 删除财务明细项
deleteFinanceItem(row, index) {
// 扣除对应统计金额
this.financeData.incomeCensus[0].income = (this.financeData.incomeCensus[0].income || 0) - (Number(row.income) || 0);
this.financeData.incomeCensus[0].support = (this.financeData.incomeCensus[0].support || 0) - (Number(row.income) || 0);
this.financeData.incomeCensus[0].totalExpend = (this.financeData.incomeCensus[0].totalExpend || 0) - (Number(row.expend) || 0);
// 根据收支类型扣除对应统计金额
const income = Number(row.income) || 0;
const expend = Number(row.expend) || 0;
if (row.incomeType === "会费收入") {
this.financeData.incomeCensus[0].income = (this.financeData.incomeCensus[0].income || 0) - income;
} else if (row.incomeType === "校工会拨款") {
this.financeData.incomeCensus[0].allocate = (this.financeData.incomeCensus[0].allocate || 0) - income;
} else if (row.incomeType === "社会赞助") {
this.financeData.incomeCensus[0].support = (this.financeData.incomeCensus[0].support || 0) - income;
} else if (row.incomeType === "支出") {
this.financeData.incomeCensus[0].totalExpend = (this.financeData.incomeCensus[0].totalExpend || 0) - expend;
}
// 删除明细项
this.financeData.incomeDetailed.splice(index, 1);
// 清空统计数据
if (this.financeData.incomeDetailed.length === 0) {
this.financeData.incomeCensus = [{
income: this.dueIncome,
allocate: this.unionAllocate,
support: 0,
totalExpend: 0,
surplus: 0
}];
}
// 重新计算统计数据,确保准确性
this.recalculateCensus();
},
// 收支类型变化处理
handleIncomeTypeChange(row) {
@@ -933,27 +977,31 @@ layout("/layouts/platform.html"){
// 年初余额输入处理
handleQcMoneyInput(row) {
this.lastYearSurplus = Number(row.qcMoney) || 0;
// 同步更新到统计表格
if (this.financeData.incomeCensus && this.financeData.incomeCensus.length > 0) {
this.financeData.incomeCensus[0].lastYearSurplus = this.lastYearSurplus;
}
// 更新后强制重新计算统计数据
this.$forceUpdate();
},
// 收入输入处理
handleIncomeInput(row) {
// 计算总收入
let totalIncome = 0;
this.financeData.incomeDetailed.forEach(item => {
totalIncome += Number(item.income) || 0;
});
this.financeData.incomeCensus[0].income = totalIncome;
// 按类型更新对应统计
if (row.incomeType === "社会赞助") this.calcSupportTotal();
if (row.incomeType === "校工会拨款") this.calcAllocateTotal();
if (row.incomeType === "会费收入") this.calcDueIncomeTotal();
if (row.incomeType === "社会赞助") {
this.calcSupportTotal();
} else if (row.incomeType === "校工会拨款") {
this.calcAllocateTotal();
} else if (row.incomeType === "会费收入") {
this.calcDueIncomeTotal();
}
// 重新计算所有统计数据,确保一致性
this.recalculateCensus();
},
// 支出输入处理
handleExpendInput: function() {
let totalExpend = 0;
this.financeData.incomeDetailed.forEach(item => {
totalExpend += Number(item.expend) || 0;
});
this.financeData.incomeCensus[0].totalExpend = totalExpend;
this.calcExpendTotal();
// 重新计算所有统计数据,确保一致性
this.recalculateCensus();
},
// 计算校工会拨款合计
calcAllocateTotal() {
@@ -984,6 +1032,43 @@ layout("/layouts/platform.html"){
.reduce((sum, item) => sum + (Number(item.expend) || 0), 0);
this.financeData.incomeCensus[0].totalExpend = total;
},
// 重新计算所有统计数据
recalculateCensus() {
// 计算会费收入总额
const dueIncomeTotal = this.financeData.incomeDetailed
.filter(item => item.incomeType === "会费收入")
.reduce((sum, item) => sum + (Number(item.income) || 0), 0);
// 计算校工会拨款总额
const allocateTotal = this.financeData.incomeDetailed
.filter(item => item.incomeType === "校工会拨款")
.reduce((sum, item) => sum + (Number(item.income) || 0), 0);
// 计算社会赞助总额
const supportTotal = this.financeData.incomeDetailed
.filter(item => item.incomeType === "社会赞助")
.reduce((sum, item) => sum + (Number(item.income) || 0), 0);
// 计算总支出
const totalExpend = this.financeData.incomeDetailed
.filter(item => item.incomeType === "支出")
.reduce((sum, item) => sum + (Number(item.expend) || 0), 0);
// 更新统计数据
this.financeData.incomeCensus[0].income = dueIncomeTotal;
this.financeData.incomeCensus[0].allocate = allocateTotal;
this.financeData.incomeCensus[0].support = supportTotal;
this.financeData.incomeCensus[0].totalExpend = totalExpend;
// 确保去年年度结余不丢失
this.financeData.incomeCensus[0].lastYearSurplus = this.lastYearSurplus;
// 同步更新全局变量
this.dueIncome = dueIncomeTotal;
this.unionAllocate = allocateTotal;
// 强制更新视图,确保年度结余重新计算
this.$forceUpdate();
},
/************************ 事件处理方法 ************************/
// 年度变化处理
@@ -73,6 +73,10 @@ layout("/layouts/platform.html"){
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
<el-form-item label="电子签名" prop="tf_userSign"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<pc-signature v-model="formData.tf_userSign"></pc-signature>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
@@ -124,22 +128,27 @@ layout("/layouts/platform.html"){
})
},
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
this.$refs.formRef.validate((valid) => {
if (!valid) {
return
}
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
@@ -50,11 +50,13 @@ layout("/layouts/platform.html"){
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="300">
<el-table-column label="操作" width="420">
<template v-slot="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @click="onAudit(row)" size="mini" type="primary">审核</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回</el-button>
<el-button @click="doExportPlan(row)" size="mini" type="primary">导出活动计划</el-button>
<el-button @click="doExportActivity(row)" size="mini" type="primary">导出活动开展情况</el-button>
</template>
</el-table-column>
</el-table>
@@ -73,6 +75,10 @@ layout("/layouts/platform.html"){
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
<el-form-item label="电子签名" prop="tf_userSign"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<pc-signature v-model="formData.tf_userSign"></pc-signature>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
@@ -124,22 +130,27 @@ layout("/layouts/platform.html"){
})
},
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
this.$refs.formRef.validate((valid) => {
if (!valid) {
return
}
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
@@ -157,6 +168,12 @@ layout("/layouts/platform.html"){
})
})
},
doExportPlan(row) {
this.$downLoad("/platform/club/examine/schoolLeaderAudit/doExportPlan", { id: row.id })
},
doExportActivity(row) {
this.$downLoad("/platform/club/examine/schoolLeaderAudit/doExportActivity", { id: row.id })
},
async pageData() {
let form = clone(this.pageForm)
if (form.isAudit === null) {
@@ -20,8 +20,8 @@ layout("/layouts/platform.html"){
<el-descriptions-item label="性别">
<el-form-item prop="sex">
<el-radio-group v-model="formData.sex" size="small">
<el-radio border label="男"></el-radio>
<el-radio border label="女"></el-radio>
<el-radio border label="男"></el-radio>
<el-radio border label="女"></el-radio>
</el-radio-group>
</el-form-item>
</el-descriptions-item>
@@ -229,7 +229,7 @@ layout("/layouts/platform.html"){
<!-- </el-descriptions-item>-->
</el-descriptions>
</el-form>
<el-row type="flex" justify="end" class="mt20">
<el-row v-if="showActionButtons" type="flex" justify="end" class="mt20">
<el-button type="primary" plain @click="onSave">保存</el-button>
<el-button type="primary" @click="onSubmit" v-if="!taskId">提交</el-button>
<el-button type="primary" @click="onFinishTask" v-else>提交</el-button>
@@ -247,6 +247,8 @@ layout("/layouts/platform.html"){
id: GetQueryString("bizId"),
taskId: GetQueryString("taskId"),
units: [],
// 当前登录人已是会员时,不显示保存和提交按钮。
showActionButtons: true,
formData: {
families: []
},
@@ -396,6 +398,8 @@ layout("/layouts/platform.html"){
} else {
user = this.$store.state.user
}
// 页面按钮是否展示,以当前登录人的会员状态为准。
this.showActionButtons = !(user && user.member)
if (this.id) {
const res = await this.$axios.post("/platform/member/apply/submit/findApplyById", { id: this.id })
@@ -32,8 +32,11 @@ layout("/layouts/platform.html"){
code="USER_PERSON_TYPE"></dict-select>
</search-item>
<search-item label="变更类型">
<dict-select v-model="pageForm.changeType" placeholder="变更类型" @change="doSearch"
code="MEMBER_CHANGE_TYPE"></dict-select>
<el-select v-model="pageForm.changeType" placeholder="变更类型" @change="doSearch"
clearable filterable style="width: 100%">
<el-option :key="item.code" :label="item.changeTypeName" :value="item.code"
v-for="item in changeTypeData"></el-option>
</el-select>
</search-item>
<search-item label="人员分类">
<dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch"
@@ -27,8 +27,11 @@ layout("/layouts/platform.html"){
<el-descriptions-item label="民族">
<el-form-item prop="nation">
<dict-select style="width: 100%" placeholder="请选择民族" v-model="formData.nation"
:disabled="allowFields('nation')" code="USER_NATION"></dict-select>
<el-select style="width: 100%" placeholder="请选择民族" v-model="formData.nation"
:disabled="allowFields('nation')" clearable filterable>
<el-option v-for="item in nationOptions" :key="item.code" :label="item.name"
:value="item.code"></el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="出生日期">
@@ -292,6 +295,8 @@ layout("/layouts/platform.html"){
taskId: GetQueryString("taskId"),
units: [],
unions: [],
// 民族下拉需要保留原字典顺序,仅在存在“汉族”时将其置顶。
nationOptions: [],
// 允许变更的字段
allowChangeFields: [],
formData: {
@@ -434,6 +439,16 @@ layout("/layouts/platform.html"){
allowFields(prop) {
return !this.allowChangeFields.map(v => v.code).includes(prop)
},
// 民族字典按页面要求处理排序,如果存在“汉族”则优先显示在第一位。
async initNationOptions() {
const nationOptions = await this.$businessTool.getDictOptions("USER_NATION")
const hanIndex = nationOptions.findIndex(item => item && item.name === "汉族")
if (hanIndex > 0) {
const hanNation = nationOptions.splice(hanIndex, 1)[0]
nationOptions.unshift(hanNation)
}
this.nationOptions = nationOptions
},
// 初始化表单数据
async init(userId){
if (userId) {
@@ -451,6 +466,7 @@ layout("/layouts/platform.html"){
} else {
this.units = await this.$businessTool.listUnit(this.user.union.id)
}
await this.initNationOptions()
},
// 获取根据userId获取用户信息
async getUserById(userId){
@@ -46,14 +46,6 @@ layout("/layouts/platform.html"){
<search-item label="教职工类别">
<dict-select v-model="pageForm.personType" placeholder="请选择教职工类别" @change="doSearch" code="USER_PERSON_TYPE"></dict-select>
</search-item>
<search-item label="编制类别">
<dict-select
v-model="pageForm.preparedBy"
placeholder="请选择编制类别"
@change="doSearch"
code="USER_PREPARED_BY_TYPE"
></dict-select>
</search-item>
<search-item label="人员分类">
<dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch" code="AIDFUND_MEMBER_USER_TYPE"></dict-select>
</search-item>
@@ -288,7 +288,7 @@ layout("/layouts/platform_h5.html"){
</div>
</van-checkbox>
</van-cell-group>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<div v-if="showActionButtons" style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button block type="primary" @click.submit="onSave">保存</van-button>
<van-button v-if="!taskId" block type="primary" @click.submit="onSubmit">提交</van-button>
<van-button v-else block type="primary" @click.submit="onFinishTask">提交</van-button>
@@ -304,6 +304,8 @@ layout("/layouts/platform_h5.html"){
return {
id: GetQueryString("bizId"),
taskId: GetQueryString("taskId"),
// 当前登录人已是会员时,不显示保存和提交按钮。
showActionButtons: true,
formData: {
families: []
},
@@ -446,6 +448,8 @@ layout("/layouts/platform_h5.html"){
} else {
user = this.$store.state.user
}
// 页面按钮是否展示,以当前登录人的会员状态为准。
this.showActionButtons = !(user && user.member)
if (this.id) {
const res = await this.$axios.post("/platform/member/apply/submit/findApplyById", { id: this.id })