change
This commit is contained in:
+31
@@ -0,0 +1,31 @@
|
||||
package com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
/**
|
||||
* 分工会预算统计服务。
|
||||
*
|
||||
* <p>统一封装分工会预算使用情况和经费收支情况的全量汇总查询,
|
||||
* 汇总口径与列表查询保持一致,不受分页参数影响。</p>
|
||||
*/
|
||||
public interface OutlayManageUnionStatisticsService extends BaseService {
|
||||
|
||||
/**
|
||||
* 查询分工会预算使用情况的全量合计。
|
||||
*
|
||||
* @param year 统计年度
|
||||
* @param unionId 分工会主键,管理员可为空查询全部
|
||||
* @return 包含 totalQuota、usedQuota、surplusQuota 的合计数据
|
||||
*/
|
||||
NutMap queryUseDetailSummary(Integer year, String unionId);
|
||||
|
||||
/**
|
||||
* 查询分工会经费收支使用情况的全量合计。
|
||||
*
|
||||
* @param year 统计年度
|
||||
* @param unionId 分工会主键,管理员可为空查询全部
|
||||
* @return 包含各项收入、支出和余额字段的合计数据
|
||||
*/
|
||||
NutMap queryIncomeExpenseSummary(Integer year, String unionId);
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.OutlayManageUnionStatisticsService;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 分工会预算统计服务实现。
|
||||
*
|
||||
* <p>汇总查询在数据库端完成,避免只汇总当前分页数据,
|
||||
* 同时复用列表的年度、分工会和权限过滤条件。</p>
|
||||
*/
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class OutlayManageUnionStatisticsServiceImpl extends BaseServiceImpl implements OutlayManageUnionStatisticsService {
|
||||
|
||||
public OutlayManageUnionStatisticsServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NutMap queryUseDetailSummary(Integer year, String unionId) {
|
||||
Cnd cnd = buildUnionManageCondition(year, unionId, false);
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
COALESCE(SUM(totalQuota), 0) AS totalQuota,
|
||||
COALESCE(SUM(usedQuota), 0) AS usedQuota,
|
||||
COALESCE(SUM(COALESCE(totalQuota, 0) - COALESCE(usedQuota, 0)), 0) AS surplusQuota
|
||||
FROM outlay_manage_union mu $condition
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
return executeMap(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NutMap queryIncomeExpenseSummary(Integer year, String unionId) {
|
||||
Cnd cnd = buildUnionManageCondition(year, unionId, true);
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
COALESCE(SUM(t.beginMoney), 0) AS beginMoney,
|
||||
COALESCE(SUM(t.feeJanApr), 0) AS feeJanApr,
|
||||
COALESCE(SUM(t.feeMayAug), 0) AS feeMayAug,
|
||||
COALESCE(SUM(t.feeSepDec), 0) AS feeSepDec,
|
||||
COALESCE(SUM(t.awardMoney), 0) AS awardMoney,
|
||||
COALESCE(SUM(t.usedMoney), 0) AS usedMoney,
|
||||
COALESCE(SUM(t.remainMoney), 0) AS remainMoney
|
||||
FROM (
|
||||
SELECT
|
||||
mu.unionId,
|
||||
COALESCE(SUM(CASE WHEN au.quarterly = 1 THEN au.allocateHeadMoney ELSE 0 END), 0) AS beginMoney,
|
||||
COALESCE(SUM(CASE WHEN au.quarterly = 1 THEN au.allocateMoney ELSE 0 END), 0) AS feeJanApr,
|
||||
COALESCE(SUM(CASE WHEN au.quarterly = 2 THEN au.allocateMoney ELSE 0 END), 0) AS feeMayAug,
|
||||
COALESCE(SUM(CASE WHEN au.quarterly = 3 THEN au.allocateMoney ELSE 0 END), 0) AS feeSepDec,
|
||||
COALESCE(SUM(CASE WHEN au.quarterly = 4 THEN au.allocateMoney ELSE 0 END), 0) AS awardMoney,
|
||||
COALESCE(mu.usedQuota, 0) AS usedMoney,
|
||||
COALESCE(mu.totalQuota, 0) - COALESCE(mu.usedQuota, 0) AS remainMoney
|
||||
FROM outlay_manage_union mu
|
||||
LEFT JOIN outlay_allocate_union au ON au.year = mu.year
|
||||
AND au.unionId = mu.unionId
|
||||
AND au.delFlag = 0
|
||||
LEFT JOIN sys_union su ON su.id = mu.unionId
|
||||
$condition
|
||||
GROUP BY mu.year, mu.unionId, mu.usedQuota, mu.totalQuota
|
||||
) t
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
return executeMap(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造两个列表共用的预算主表过滤条件,保证汇总和分页列表权限口径一致。
|
||||
*/
|
||||
private Cnd buildUnionManageCondition(Integer year, String unionId, boolean includeDelFlag) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (includeDelFlag) {
|
||||
cnd.and("mu.delFlag", "=", false);
|
||||
}
|
||||
cnd.and("mu.year", "=", year == null ? DateUtil.thisYear() : year);
|
||||
cnd.and("mu.totalQuota", "IS NOT", null);
|
||||
cnd.andEX("mu.unionId", "=", unionId);
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
cnd.and("mu.unionId", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
return cnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行单行统计查询,并在无数据时返回各字段为零的结果,方便前端直接展示。
|
||||
*/
|
||||
private NutMap executeMap(Sql sql) {
|
||||
sql.setCallback(Sqls.callback.map());
|
||||
dao().execute(sql);
|
||||
NutMap result = (NutMap) sql.getResult();
|
||||
return result == null ? NutMap.NEW() : result;
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package com.budwk.app.zhgh.democratic.teachercongress.delegation.constant;
|
||||
|
||||
/**
|
||||
* 代表团组成模式。
|
||||
*
|
||||
* <p>系统参数 {@code dbtzc} 为 {@code unit} 时按单位组成,
|
||||
* 为 {@code union} 时按分工会组成;空值或非法值统一兼容为单位模式。</p>
|
||||
*/
|
||||
public enum TeacherCongressDelegationCompositionMode {
|
||||
UNIT("unit", "单位"),
|
||||
UNION("union", "分工会");
|
||||
|
||||
private final String code;
|
||||
private final String label;
|
||||
|
||||
TeacherCongressDelegationCompositionMode(String code, String label) {
|
||||
this.code = code;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将系统参数转换为组成模式,非法配置按历史默认行为使用单位模式。
|
||||
*
|
||||
* @param value 系统参数值
|
||||
* @return 有效组成模式
|
||||
*/
|
||||
public static TeacherCongressDelegationCompositionMode from(String value) {
|
||||
if (UNION.code.equalsIgnoreCase(value)) {
|
||||
return UNION;
|
||||
}
|
||||
return UNIT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/* 社团信息维护列表页固定占满平台内容区,禁止页面主体产生纵向滚动条。 */
|
||||
#app .club-info-fixed-list-page {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100vh - 82px);
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#app .club-info-fixed-query-card {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
#app .club-info-fixed-list-card {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#app .club-info-fixed-list-card > .el-card__body {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#app .club-info-fixed-list-card .ele-table-tool,
|
||||
#app .club-info-fixed-list-card .el-pagination-container {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 社团信息维护列表页共用高度计算逻辑。
|
||||
* 查询卡片保持原始高度,列表表格占用工具栏与分页之外的全部剩余空间。
|
||||
*/
|
||||
const CLUB_INFO_FIXED_LIST_MIXIN = {
|
||||
data() {
|
||||
return {
|
||||
tableHeight: 300,
|
||||
clubInfoListResizeObserver: null,
|
||||
clubInfoListResizeHandler: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateClubInfoListTableHeight() {
|
||||
this.$nextTick(() => {
|
||||
const page = this.$el.querySelector('.club-info-fixed-list-page')
|
||||
const cardBody = this.$el.querySelector('.club-info-fixed-list-card > .el-card__body')
|
||||
if (!page || !cardBody || cardBody.clientHeight <= 0) {
|
||||
return
|
||||
}
|
||||
const getOuterHeight = element => {
|
||||
if (!element) {
|
||||
return 0
|
||||
}
|
||||
const style = window.getComputedStyle(element)
|
||||
return element.offsetHeight
|
||||
+ (parseFloat(style.marginTop) || 0)
|
||||
+ (parseFloat(style.marginBottom) || 0)
|
||||
}
|
||||
const bodyStyle = window.getComputedStyle(cardBody)
|
||||
const bodyPadding = (parseFloat(bodyStyle.paddingTop) || 0)
|
||||
+ (parseFloat(bodyStyle.paddingBottom) || 0)
|
||||
const tableTool = cardBody.querySelector('.ele-table-tool')
|
||||
const pagination = cardBody.querySelector('.el-pagination-container')
|
||||
const reservedHeight = bodyPadding + getOuterHeight(tableTool) + getOuterHeight(pagination)
|
||||
const nextHeight = Math.max(1, Math.floor(cardBody.clientHeight - reservedHeight))
|
||||
if (this.tableHeight !== nextHeight) {
|
||||
this.tableHeight = nextHeight
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.tableRef) {
|
||||
this.$refs.tableRef.doLayout()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.updateClubInfoListTableHeight()
|
||||
const page = this.$el.querySelector('.club-info-fixed-list-page')
|
||||
if (window.ResizeObserver && page) {
|
||||
this.clubInfoListResizeObserver = new ResizeObserver(() => {
|
||||
this.updateClubInfoListTableHeight()
|
||||
})
|
||||
this.clubInfoListResizeObserver.observe(page)
|
||||
} else {
|
||||
this.clubInfoListResizeHandler = () => {
|
||||
this.updateClubInfoListTableHeight()
|
||||
}
|
||||
window.addEventListener('resize', this.clubInfoListResizeHandler)
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.clubInfoListResizeObserver) {
|
||||
this.clubInfoListResizeObserver.disconnect()
|
||||
}
|
||||
if (this.clubInfoListResizeHandler) {
|
||||
window.removeEventListener('resize', this.clubInfoListResizeHandler)
|
||||
}
|
||||
},
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 分工会预算列表页统一布局:页面固定占满平台内容区,
|
||||
* 查询区和工具栏保持原高度,超出的数据仅在表格内部滚动。
|
||||
*/
|
||||
#app .outlay-union-fixed-list-page {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100vh - 82px);
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#app .outlay-union-fixed-query-card {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
#app .outlay-union-fixed-list-card {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#app .outlay-union-fixed-list-card > .el-card__body {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#app .outlay-union-fixed-list-card .ele-table-tool,
|
||||
#app .outlay-union-fixed-list-card .el-pagination-container,
|
||||
#app .outlay-union-fixed-list-card .outlay-union-summary-table {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
#app .outlay-union-fixed-list-card .outlay-union-summary-table {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#app .outlay-union-fixed-list-card .outlay-union-summary-table .el-table__body-wrapper {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
/* 合计行单独展示时不显示单元格网格线,避免与上方数据表格的边框重复。 */
|
||||
#app .outlay-union-fixed-list-card .outlay-union-summary-table,
|
||||
#app .outlay-union-fixed-list-card .outlay-union-summary-table::before,
|
||||
#app .outlay-union-fixed-list-card .outlay-union-summary-table::after,
|
||||
#app .outlay-union-fixed-list-card .outlay-union-summary-table .el-table__body,
|
||||
#app .outlay-union-fixed-list-card .outlay-union-summary-table .el-table__body tr,
|
||||
#app .outlay-union-fixed-list-card .outlay-union-summary-table .el-table__body td {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
/* 合计标签单元格保留完整边框,突出汇总行的起始位置。 */
|
||||
#app .outlay-union-fixed-list-card .outlay-union-summary-table .el-table__body td:first-child {
|
||||
border: 1px solid #ebeef5 !important;
|
||||
}
|
||||
|
||||
#app .outlay-union-fixed-list-card .outlay-union-fixed-table {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 分工会预算列表页统一高度逻辑:表格高度按列表卡片剩余空间动态计算,
|
||||
* 窗口尺寸或平台内容区变化时重新布局,保证分页始终可见。
|
||||
*/
|
||||
const OUTLAY_UNION_FIXED_LIST_MIXIN = {
|
||||
data() {
|
||||
return {
|
||||
tableHeight: 300,
|
||||
outlayUnionResizeObserver: null,
|
||||
outlayUnionResizeHandler: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateOutlayUnionTableHeight() {
|
||||
this.$nextTick(() => {
|
||||
const page = this.$el.querySelector('.outlay-union-fixed-list-page')
|
||||
const cardBody = this.$el.querySelector('.outlay-union-fixed-list-card > .el-card__body')
|
||||
if (!page || !cardBody || cardBody.clientHeight <= 0) {
|
||||
return
|
||||
}
|
||||
const getOuterHeight = (element) => {
|
||||
if (!element) {
|
||||
return 0
|
||||
}
|
||||
const style = window.getComputedStyle(element)
|
||||
return element.offsetHeight
|
||||
+ (parseFloat(style.marginTop) || 0)
|
||||
+ (parseFloat(style.marginBottom) || 0)
|
||||
}
|
||||
const bodyStyle = window.getComputedStyle(cardBody)
|
||||
const bodyPadding = (parseFloat(bodyStyle.paddingTop) || 0)
|
||||
+ (parseFloat(bodyStyle.paddingBottom) || 0)
|
||||
const tableTool = cardBody.querySelector('.ele-table-tool')
|
||||
const summaryTable = cardBody.querySelector('.outlay-union-summary-table')
|
||||
const pagination = cardBody.querySelector('.el-pagination-container')
|
||||
const reservedHeight = bodyPadding
|
||||
+ getOuterHeight(tableTool)
|
||||
+ getOuterHeight(summaryTable)
|
||||
+ getOuterHeight(pagination)
|
||||
const nextHeight = Math.max(1, Math.floor(cardBody.clientHeight - reservedHeight))
|
||||
if (this.tableHeight !== nextHeight) {
|
||||
this.tableHeight = nextHeight
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.tableRef) {
|
||||
this.$refs.tableRef.doLayout()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.updateOutlayUnionTableHeight()
|
||||
const page = this.$el.querySelector('.outlay-union-fixed-list-page')
|
||||
if (window.ResizeObserver && page) {
|
||||
this.outlayUnionResizeObserver = new ResizeObserver(() => {
|
||||
this.updateOutlayUnionTableHeight()
|
||||
})
|
||||
this.outlayUnionResizeObserver.observe(page)
|
||||
} else {
|
||||
this.outlayUnionResizeHandler = () => {
|
||||
this.updateOutlayUnionTableHeight()
|
||||
}
|
||||
window.addEventListener('resize', this.outlayUnionResizeHandler)
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.outlayUnionResizeObserver) {
|
||||
this.outlayUnionResizeObserver.disconnect()
|
||||
}
|
||||
if (this.outlayUnionResizeHandler) {
|
||||
window.removeEventListener('resize', this.outlayUnionResizeHandler)
|
||||
}
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user