This commit is contained in:
2026-08-25 13:50:47 +08:00
parent 33252a7225
commit 9503b5aa73
29 changed files with 1035 additions and 220 deletions
@@ -11,6 +11,8 @@ import com.budwk.app.flow.engine.event.ProcessPublisher;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.enums.*;
import com.budwk.app.sys.models.Sys_unit;
import com.budwk.app.sys.views.View_user;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
@@ -22,6 +24,7 @@ import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import java.util.List;
import java.util.Optional;
@IocBean
public class FlowCommonService {
@@ -61,11 +64,13 @@ public class FlowCommonService {
args.put(FlowConst.SUBMIT_TYPE, submitType);
Sys_unit sysUnit = dao.fetch(Sys_unit.class, Cnd.where("id", "=", SecurityUtil.getUnitId()));
// 设置办理人信息到表单参数
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "userName", SecurityUtil.getUserUsername());
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "loginName", SecurityUtil.getUserLoginname());
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "unitId", SecurityUtil.getUnitId());
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "unitName", SecurityUtil.getUnitId());
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "unitName", Optional.of(sysUnit).map(Sys_unit::getName).orElse(""));
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "unionId", SecurityUtil.getUnionId());
if (ObjectUtil.equals(submitType, ProcessSubmitTypeEnum.ROLLBACK.getCode())) {
@@ -4,7 +4,6 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RedisConstant;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.utils.PageUtil;
import com.budwk.app.sys.models.Sys_config;
import com.budwk.app.sys.services.SysConfigService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
@@ -139,17 +138,18 @@ public class SysConfController {
@At
@Ok("json:full")
@SaCheckPermission("sys.manager.conf")
public Object data(@Param("pageNumber") int pageNumber, @Param("pageSize") int pageSize, @Param("pageOrderName") String pageOrderName, @Param("pageOrderBy") String pageOrderBy) {
public Object data(@Param("pageNumber") int pageNumber,
@Param("pageSize") int pageSize,
@Param("pageOrderName") String pageOrderName,
@Param("pageOrderBy") String pageOrderBy,
@Param("configKey") String configKey) {
try {
ensureAppImageConfig("AppHomeImg", "PC首页轮播图");
ensureAppImageConfig("H5AppHomeImg", "移动端首页轮播图");
ensureAppImageConfig("AppFeaturedActivityImg", "精彩活动页顶部图片");
ensureAppImageConfig("AppFestivalBenefitImg", "节日福利页顶部图片");
Cnd cnd = Cnd.NEW();
if (Strings.isNotBlank(pageOrderName) && Strings.isNotBlank(pageOrderBy)) {
cnd.orderBy(pageOrderName, PageUtil.getOrder(pageOrderBy));
}
return Result.success().addData(sysConfigService.listPage(pageNumber, pageSize, cnd));
return Result.success().addData(sysConfigService.pageData(
pageNumber, pageSize, pageOrderName, pageOrderBy, configKey));
} catch (Exception e) {
return Result.error();
}
@@ -419,14 +419,13 @@ public class SysRoleController {
public Object user(@Param("roleId") String roleId, @Param("searchName") String searchName, @Param("searchKeyword") String searchKeyword,
@Param("pageNumber") int pageNumber, @Param("pageSize") int pageSize, @Param("pageOrderName") String pageOrderName, @Param("pageOrderBy") String pageOrderBy) {
try {
Sql sql = Sqls.create("SELECT a.*,c.name as unitname FROM sys_user a,sys_user_role b,sys_unit c WHERE a.unitid=c.id and a.id=b.userId and b.roleId=@roleId $s $o");
Sql sql = Sqls.create("SELECT a.*,c.name as unitname FROM sys_user a,sys_user_role b,sys_unit c WHERE a.unitid=c.id and a.id=b.userId and enable='1' and b.roleId=@roleId $s $o");
sql.params().set("roleId", roleId);
if (Strings.isNotBlank(searchName) && Strings.isNotBlank(searchKeyword)) {
sql.vars().set("s", " and a." + searchName + " like '%" + searchKeyword + "%'");
}
if (Strings.isNotBlank(pageOrderName) && Strings.isNotBlank(pageOrderBy)) {
sql.vars().set("o", " order by a." + pageOrderName + " " + PageUtil.getOrder(pageOrderBy));
}
return Result.success().addData(sysUserService.listPage(pageNumber, pageSize, sql));
} catch (Exception e) {
@@ -456,10 +456,16 @@ public class SysUnionController {
unionCadre.setIsJoin(true);
dao.insert(unionCadre);
// 去走工作流
// 校级管理员新增普通干部时直接授权,不生成无实际审核意义的流程数据。
boolean isAdmin = AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
if (isAdmin) {
sysUnionService.assignBranchUnionRole(userId, role.getId(), unionId, List.of());
return Result.success();
}
// 非校级管理员仍按原业务发起基层干部授权审核流程。
Dict args = Dict.create();
args.set("submit", isAdmin ? "admin" : "branch");
args.set("submit", "branch");
args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
args.set(FlowConst.FORM_DATA, unionCadre);
@@ -470,20 +476,12 @@ public class SysUnionController {
flowEngine.executeProcessTask(task.getId(), SecurityUtil.getUserId(), args);
}
if (isAdmin) {
// 如果是管理员,直接加角色
sysRoleService.clear("sys_user_role", Cnd.where("roleId", "=", role.getId()).and("userId", "=", userId).and("unionId", "=", unionId));
sysRoleService.insert("sys_user_role", Chain.make("roleId", role.getId()).add("userId", userId).add("unionId", unionId));
sysRoleService.clearCache();
sysUserService.clearCache();
}
return Result.success();
}
/**
* 发起二级党委书记授权审批。一个审批申请可关联当前分工会下的多个单位。
* 审核通过后由流程拦截器按单位写入角色,避免影响普通分工会角色的授权方式
* 新增二级党委书记授权。校级管理员直接按单位授权,其他用户发起审批,
* 审核通过后由流程拦截器按单位写入角色。
*
* @param userId 人员ID
* @param unionId 分工会ID
@@ -536,11 +534,18 @@ public class SysUnionController {
unionCadre.setIsJoin(true);
dao.insert(unionCadre);
boolean isAdmin = AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
if (isAdmin) {
// 校级管理员直接按所选单位授权,不创建 JCGHWY 流程实例和审核任务。
sysUnionService.assignBranchUnionRole(userId, role.getId(), unionId, distinctUnitIds);
return Result.success();
}
// 非校级管理员保留原审批流程,并将所选单位随表单传给审核通过拦截器。
JSONObject formData = JSONUtil.parseObj(unionCadre);
formData.set("unitIds", distinctUnitIds);
Dict args = Dict.create();
boolean isAdmin = AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
args.set("submit", isAdmin ? "admin" : "branch");
args.set("submit", "branch");
args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
args.set(FlowConst.FORM_DATA, formData.toString());
ProcessInstance instance = flowEngine.startProcessInstanceByKey("JCGHWY", unionCadre.getId(), SecurityUtil.getUserId(), args);
@@ -1,5 +1,6 @@
package com.budwk.app.sys.services;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.sys.models.Sys_config;
import com.budwk.app.base.service.BaseService;
@@ -16,4 +17,17 @@ public interface SysConfigService extends BaseService<Sys_config> {
List<Sys_config> getAllList();
Sys_config getValueByKey(String key);
/**
* 分页查询系统参数,支持按参数名模糊查询和安全排序。
*
* @param pageNumber 页码
* @param pageSize 每页条数
* @param pageOrderName 排序字段
* @param pageOrderBy 排序方向
* @param configKey 参数名关键字
* @return 系统参数分页数据
*/
Pagination<Sys_config> pageData(int pageNumber, int pageSize, String pageOrderName,
String pageOrderBy, String configKey);
}
@@ -3,5 +3,18 @@ package com.budwk.app.sys.services;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.sys.models.Sys_union;
import java.util.List;
public interface SysUnionService extends BaseService<Sys_union> {
/**
* 直接分配分工会干部角色。普通干部传空单位集合时按分工会写入一条角色关系;
* 二级党委书记传单位集合时按单位分别写入角色关系。
*
* @param userId 用户ID
* @param roleId 角色ID
* @param unionId 分工会ID
* @param unitIds 授权单位ID集合,普通干部角色传空集合
*/
void assignBranchUnionRole(String userId, String roleId, String unionId, List<String> unitIds);
}
@@ -1,15 +1,19 @@
package com.budwk.app.sys.services.impl;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.base.utils.PageUtil;
import com.budwk.app.sys.models.Sys_config;
import com.budwk.app.sys.services.SysConfigService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import java.util.List;
import java.util.Set;
/**
* Created by wizzer on 2016/12/23.
@@ -32,4 +36,32 @@ public class SysConfigServiceImpl extends BaseServiceImpl<Sys_config> implements
}
return sys_config;
}
/**
* 分页查询系统参数。参数名使用模糊匹配,排序字段限定在列表可展示字段内,
* 防止未经校验的前端字段直接进入排序 SQL。
*
* @param pageNumber 页码
* @param pageSize 每页条数
* @param pageOrderName 排序字段
* @param pageOrderBy 排序方向
* @param configKey 参数名关键字
* @return 系统参数分页数据
*/
@Override
@SuppressWarnings("unchecked")
public Pagination<Sys_config> pageData(int pageNumber, int pageSize, String pageOrderName,
String pageOrderBy, String configKey) {
Cnd cnd = Cnd.NEW();
if (Strings.isNotBlank(configKey)) {
cnd.where().andLike("configKey", configKey.trim());
}
Set<String> sortableColumns = Set.of("configKey", "configValue", "note");
if (sortableColumns.contains(pageOrderName) && Strings.isNotBlank(pageOrderBy)) {
cnd.orderBy(pageOrderName, PageUtil.getOrder(pageOrderBy));
} else {
cnd.asc("configKey");
}
return listPage(pageNumber, pageSize, cnd);
}
}
@@ -2,13 +2,65 @@ package com.budwk.app.sys.services.impl;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_union;
import com.budwk.app.sys.models.Sys_user_role;
import com.budwk.app.sys.services.SysRoleService;
import com.budwk.app.sys.services.SysUnionService;
import com.budwk.app.sys.services.SysUserService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import java.util.List;
@IocBean(args = {"refer:dao"})
public class SysUnionServiceImpl extends BaseServiceImpl<Sys_union> implements SysUnionService {
@Inject
private SysRoleService sysRoleService;
@Inject
private SysUserService sysUserService;
public SysUnionServiceImpl(Dao dao) {
super(dao);
}
/**
* 直接分配分工会干部角色,并在授权完成后统一清理权限缓存。
* 普通角色按分工会授权一次,包含单位的角色按每个单位分别授权。
*
* @param userId 用户ID
* @param roleId 角色ID
* @param unionId 分工会ID
* @param unitIds 授权单位ID集合,普通干部角色传空集合
*/
@Override
public void assignBranchUnionRole(String userId, String roleId, String unionId, List<String> unitIds) {
// 先清理同一用户在当前分工会下的相同角色,保证重新授权后不存在重复关系。
dao().clear(Sys_user_role.class, Cnd.where(Sys_user_role::getRoleId, "=", roleId)
.and(Sys_user_role::getUserId, "=", userId)
.and(Sys_user_role::getUnionId, "=", unionId));
if (unitIds == null || unitIds.isEmpty()) {
Sys_user_role userRole = new Sys_user_role();
userRole.setRoleId(roleId);
userRole.setUserId(userId);
userRole.setUnionId(unionId);
dao().insert(userRole);
} else {
// 二级党委书记按选中的单位分别生成角色关系,供后续单位级权限判断使用。
for (String unitId : unitIds) {
Sys_user_role userRole = new Sys_user_role();
userRole.setRoleId(roleId);
userRole.setUserId(userId);
userRole.setUnionId(unionId);
userRole.setUnitId(unitId);
dao().insert(userRole);
}
}
sysRoleService.clearCache();
sysUserService.clearCache();
}
}
@@ -14,6 +14,7 @@ import com.budwk.app.base.service.BaseService;
import com.budwk.app.base.utils.CommonDownloadUtil;
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 com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.vo.OutlayUnionIncomeExpenseVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -44,6 +45,8 @@ public class OutlayManageUnionIncomeExpenseController {
@Inject
private BaseService baseService;
@Inject
private OutlayManageUnionStatisticsService outlayManageUnionStatisticsService;
@At("")
@Ok("beetl:/platform/zhgh/dayofficework/outlay/outlayManage/union/incomeExpense/index.html")
@@ -60,6 +63,16 @@ public class OutlayManageUnionIncomeExpenseController {
return Result.success(pagination);
}
/**
* 查询当前筛选范围内全部分工会经费收支合计,不受分页参数影响。
*/
@At
@ApiOperation("查询经费收支合计")
@SaCheckPermission("outlay.outlayManage.union.incomeExpense")
public Result summary(Integer year, String unionId) {
return Result.success(outlayManageUnionStatisticsService.queryIncomeExpenseSummary(year, unionId));
}
@At
@Ok("void")
@ApiOperation("导出")
@@ -12,6 +12,7 @@ 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.model.OutlayUseDetail;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.OutlayUseDetailService;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.OutlayManageUnionStatisticsService;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.model.OutLayAllocateUnion;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -46,6 +47,8 @@ public class OutlayManageUnionUseDetailController {
private BaseService baseService;
@Inject
private OutlayUseDetailService outlayUseDetailService;
@Inject
private OutlayManageUnionStatisticsService outlayManageUnionStatisticsService;
@At("")
@Ok("beetl:/platform/zhgh/dayofficework/outlay/outlayManage/union/useDetail/index.html")
@@ -81,6 +84,16 @@ public class OutlayManageUnionUseDetailController {
return Result.success(pagination);
}
/**
* 查询当前筛选范围内全部分工会预算使用情况合计,不受分页参数影响。
*/
@At
@ApiOperation("查询预算使用情况合计")
@SaCheckPermission("outlay.outlayManage.union.useDetail")
public Result summary(Integer year, String unionId) {
return Result.success(outlayManageUnionStatisticsService.queryUseDetailSummary(year, unionId));
}
@At
@ApiOperation("某个分工会预算使用详情")
@@ -1,18 +1,54 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
/* 系统参数页面固定占满平台内容区,避免页面主体产生纵向滚动条。 */
#app .sys-conf-layout {
display: flex;
flex-direction: column;
min-height: 0;
height: calc(100vh - 82px);
overflow: hidden;
}
#app .sys-conf-query-card {
flex: 0 0 auto;
}
/* 列表卡片占用剩余空间,数据超出时仅由 Element 表格内部滚动。 */
#app .sys-conf-list-card {
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
}
#app .sys-conf-list-card > .el-card__body {
box-sizing: border-box;
display: flex;
flex-direction: column;
min-height: 0;
height: 100%;
overflow: hidden;
}
#app .sys-conf-list-card .ele-table-tool,
#app .sys-conf-list-card .el-pagination-container {
flex: 0 0 auto;
}
</style>
<div id="app" v-cloak>
<guava>
<el-card shadow="never">
<el-row type="flex" justify="end">
<el-button @click="openAdd" size="medium" type="primary">
<i class="ti-plus"></i>
添加配置项
</el-button>
</el-row>
<div class="sys-conf-layout">
<el-card class="sys-conf-query-card" shadow="never">
<search @search="doSearch">
<search-item label="参数名">
<el-input v-model="pageForm.configKey" clearable placeholder="请输入参数名"
@keyup.enter.native="doSearch"></el-input>
</search-item>
</search>
</el-card>
<el-card class="mt10" shadow="never">
<el-table :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%">
<el-card class="mt10 sys-conf-list-card" shadow="never">
<table-tool label="系统参数">
<el-button @click="openAdd" size="small" type="primary" icon="el-icon-plus">新增</el-button>
</table-tool>
<el-table v-loading="tableLoading" :data="tableData" :height="tableHeight"
@sort-change="pageOrder" header-align="center" ref="tableRef" style="width: 100%">
<el-table-column header-align="center" label="参数名" prop="configKey" sortable
width="200"></el-table-column>
<el-table-column :show-overflow-tooltip="true" header-align="center" label="参数值" prop="configValue"
@@ -40,6 +76,7 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</guava>
<el-dialog title="新增参数" :visible.sync="addDialogVisible" :close-on-click-modal="false" width="40%">
@@ -183,13 +220,18 @@ layout("/layouts/platform.html"){
return {
addDialogVisible: false,
editDialogVisible: false,
tableLoading: false,
tableHeight: 300,
tableResizeObserver: null,
pageRequestSequence: 0,
tableData: [],
pageForm: {
pageSize: 10,
pageNumber: 1,
pageOrderName: "",
pageOrderBy: "",
totalCount: 0
totalCount: 0,
configKey: ""
},
formData: {
configKey: "",
@@ -203,6 +245,10 @@ layout("/layouts/platform.html"){
}
},
methods: {
doSearch: function () {
this.pageForm.pageNumber = 1
this.pageData()
},
openAdd: function () {
this.addDialogVisible = true
this.formData = {} //打开新增窗口,表单先清空
@@ -317,24 +363,60 @@ layout("/layouts/platform.html"){
this.pageData()
},
pageData: function () {
//加载分页数据
// 查询期间清空旧页并显示加载状态,快速连续查询时仅接收最后一次响应。
var self = this
$.post(
base + "/platform/sys/conf/data",
self.pageForm,
function (data) {
if (data.code == 0) {
self.tableData = data.data.list
self.pageForm.totalCount = data.data.totalCount
} else {
self.$message({
message: data.msg,
type: "error"
})
var requestSequence = ++self.pageRequestSequence
self.tableData = []
self.tableLoading = true
$.post(base + "/platform/sys/conf/data", self.pageForm).then(function (data) {
if (requestSequence != self.pageRequestSequence) {
return
}
if (data.code == 0) {
self.tableData = data.data.list || []
self.pageForm.totalCount = data.data.totalCount || 0
self.updateTableHeight()
} else {
self.$message({
message: data.msg,
type: "error"
})
}
}).always(function () {
if (requestSequence == self.pageRequestSequence) {
self.tableLoading = false
}
})
},
updateTableHeight: function () {
var self = this
this.$nextTick(function () {
var cardBody = self.$el.querySelector(".sys-conf-list-card > .el-card__body")
if (!cardBody || cardBody.clientHeight <= 0) {
return
}
var getOuterHeight = function (element) {
if (!element) {
return 0
}
},
"json"
)
var style = window.getComputedStyle(element)
return element.offsetHeight
+ (parseFloat(style.marginTop) || 0)
+ (parseFloat(style.marginBottom) || 0)
}
var bodyStyle = window.getComputedStyle(cardBody)
var bodyPadding = (parseFloat(bodyStyle.paddingTop) || 0)
+ (parseFloat(bodyStyle.paddingBottom) || 0)
var tableTool = cardBody.querySelector(".ele-table-tool")
var pagination = cardBody.querySelector(".el-pagination-container")
var reservedHeight = bodyPadding + getOuterHeight(tableTool) + getOuterHeight(pagination)
self.tableHeight = Math.max(1, Math.floor(cardBody.clientHeight - reservedHeight))
self.$nextTick(function () {
if (self.$refs.tableRef) {
self.$refs.tableRef.doLayout()
}
})
})
},
dropdownCommand: function (command) {
//监听下拉框事件
@@ -392,6 +474,29 @@ layout("/layouts/platform.html"){
},
created: function () {
this.pageData()
},
mounted: function () {
var self = this
this.updateTableHeight()
if (window.ResizeObserver) {
this.tableResizeObserver = new ResizeObserver(function () {
self.updateTableHeight()
})
this.tableResizeObserver.observe(this.$el)
} else {
this.resizeHandler = function () {
self.updateTableHeight()
}
window.addEventListener("resize", this.resizeHandler)
}
},
beforeDestroy: function () {
if (this.tableResizeObserver) {
this.tableResizeObserver.disconnect()
}
if (this.resizeHandler) {
window.removeEventListener("resize", this.resizeHandler)
}
}
})
</script>
@@ -9,10 +9,124 @@ layout("/layouts/platform.html"){
padding: 1px 2px;
border-radius: 2px;
}
/* 关联用户弹窗固定占用可视区域,数据过多时仅表格内部滚动。 */
.role-user-dialog {
display: flex;
flex-direction: column;
height: 90vh;
margin-bottom: 0;
overflow: hidden;
}
.role-user-dialog .el-dialog__header {
flex: 0 0 auto;
padding: 22px 30px 18px;
border-bottom: 1px solid #ebeef5;
}
.role-user-dialog .el-dialog__title {
color: #1f2d3d;
font-size: 18px;
font-weight: 600;
}
.role-user-dialog .el-dialog__body {
flex: 1 1 auto;
min-height: 0;
padding: 8px 30px 12px;
overflow: hidden;
}
.role-user-dialog .el-dialog__footer {
flex: 0 0 auto;
padding: 14px 30px 18px;
border-top: 1px solid #ebeef5;
}
.role-user-layout {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
overflow: hidden;
}
.role-user-tip {
flex: 0 0 auto;
padding: 13px 16px;
color: #1677ff;
background: #f0f7ff;
border-radius: 4px;
}
.role-user-tip i {
margin-right: 8px;
}
.role-user-toolbar {
display: flex;
flex: 0 0 auto;
align-items: center;
gap: 12px;
margin: 16px 0;
}
.role-user-add-area,
.role-user-search-area {
display: flex;
align-items: center;
gap: 8px;
}
.role-user-remove-button {
margin-left: auto;
}
.role-user-table-wrap {
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
}
.role-user-pagination {
flex: 0 0 auto;
margin-top: 16px;
}
.role-user-status-dot {
display: inline-block;
width: 8px;
height: 8px;
margin-right: 7px;
border-radius: 50%;
}
.role-user-status-dot.is-success {
background: #21c77a;
}
.role-user-status-dot.is-danger {
background: #f56c6c;
}
/* 角色管理列表固定占满平台内容区,避免页面主体出现纵向滚动条。 */
#app .role-manage-page {
display: flex;
flex-direction: column;
height: calc(100vh - 82px);
min-height: 0;
overflow: hidden;
}
#app .role-manage-query-card {
flex: 0 0 auto;
}
#app .role-manage-list-card {
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
}
#app .role-manage-list-card > .el-card__body {
box-sizing: border-box;
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
overflow: hidden;
}
#app .role-manage-list-card .el-pagination-container {
flex: 0 0 auto;
}
</style>
<div id="app" v-cloak>
<el-card shadow="never">
<div class="role-manage-page">
<el-card class="role-manage-query-card" shadow="never">
<el-row type="flex" style="column-gap: 10px">
<el-select v-model="pageForm.moduleId" style="width: 180px" filterable clearable
placeholder="请选择所属模块">
@@ -61,9 +175,11 @@ layout("/layouts/platform.html"){
<!-- </el-button>-->
<!-- </div>-->
</el-card>
<el-card shadow="never" class="mt10">
<el-card shadow="never" class="mt10 role-manage-list-card">
<el-table
:data="tableData"
ref="roleTableRef"
:height="roleTableHeight"
@sort-change="pageOrder"
header-align="center"
:default-sort="{prop: 'serialNumber', order: 'ascending'}"
@@ -123,6 +239,7 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
<el-dialog append-to-body title="新建角色" :visible.sync="addDialogVisible" :close-on-click-modal="false"
width="70%">
@@ -274,71 +391,89 @@ layout("/layouts/platform.html"){
</span>
</el-dialog>
<el-dialog append-to-body :title="userDialogTitle" :visible.sync="userDialogVisible" :close-on-click-modal="false"
width="70%">
<div class="block mb10">
<el-select
size="small"
style="width: 60%"
class="span_n"
v-model="selUsers"
multiple
filterable
remote
default-first-option
reserve-keyword
:remote-method="remoteMethod"
:loading="loading"
placeholder="请输入用户名或姓名"
>
<el-option v-for="item in dbUsers" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
<el-button size="small" @click="userAddRole">将用户加入角色</el-button>
<div class="pull-right offscreen-right">
<el-button size="small" type="danger" @click="userDelRole">从角色中移除</el-button>
custom-class="role-user-dialog" top="5vh" width="82%" @opened="updateUserTableHeight">
<div class="role-user-layout">
<div class="role-user-toolbar">
<div class="role-user-add-area">
<el-select
size="small"
style="width: 360px"
v-model="selUsers"
multiple
filterable
remote
default-first-option
reserve-keyword
:remote-method="remoteMethod"
:loading="loading"
placeholder="请输入用户工号或姓名"
>
<el-option v-for="item in dbUsers" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
<el-button size="small" type="primary" plain icon="el-icon-circle-plus-outline"
@click="userAddRole">将用户加入角色</el-button>
</div>
<div class="role-user-search-area">
<el-input v-model="userForm.searchKeyword" clearable size="small" style="width: 280px"
placeholder="请输入查询内容" @clear="doUserSearch"
@keyup.enter.native="doUserSearch">
<el-select v-model="userForm.searchName" slot="prepend" style="width: 100px">
<el-option label="工号" value="loginname"></el-option>
<el-option label="姓名" value="username"></el-option>
</el-select>
</el-input>
<el-button size="small" type="primary" icon="el-icon-search" @click="doUserSearch">查询</el-button>
</div>
<el-button class="role-user-remove-button" size="small" type="danger" plain
icon="el-icon-delete" @click="userDelRole">从角色中移除</el-button>
</div>
<div class="role-user-table-wrap">
<el-table
ref="userTableRef"
:data="userTableData"
:height="userTableHeight"
@sort-change="userPageOrder"
size="small"
border
header-align="center"
style="width: 100%"
@selection-change="userSelectionChange"
>
<el-table-column type="selection" width="55" align="center"></el-table-column>
<el-table-column sortable prop="loginname" label="用户工号" header-align="center" align="center"></el-table-column>
<el-table-column prop="username" label="姓名" header-align="center" align="center"
:show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="unitname" label="所属单位" header-align="center" align="center"
:show-overflow-tooltip="true"></el-table-column>
<el-table-column sortable prop="disabled" label="账号状态" header-align="center" align="center"
:show-overflow-tooltip="true">
<template slot-scope="scope">
<span class="role-user-status-dot" :class="scope.row.disabled ? 'is-danger' : 'is-success'"></span>
<span>{{ scope.row.disabled ? '禁用' : '正常' }}</span>
</template>
</el-table-column>
<el-table-column sortable prop="useronline" label="在线状态" header-align="center" align="center"
:show-overflow-tooltip="true">
<template slot-scope="scope">
<span :class="scope.row.useronline ? 'text-success' : 'text-danger'">
{{ scope.row.useronline ? '在线' : '离线' }}
</span>
</template>
</el-table-column>
</el-table>
</div>
<el-pagination
class="role-user-pagination"
@size-change="userPageSizeChange"
@current-change="userPageNumberChange"
:current-page="userForm.pageNumber"
:page-sizes="[10, 20, 30, 50]"
:page-size="userForm.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="userForm.totalCount"
></el-pagination>
</div>
<el-table
:data="userTableData"
@sort-change="userPageOrder"
size="small"
header-align="center"
style="width: 100%"
@selection-change="userSelectionChange"
>
<el-table-column type="selection" width="35"></el-table-column>
<el-table-column sortable prop="loginname" label="用户名" header-align="center"></el-table-column>
<el-table-column prop="username" label="姓名" header-align="center"
:show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="unitname" label="所属单位" header-align="center" align="center"
:show-overflow-tooltip="true"></el-table-column>
<el-table-column sortable prop="disabled" label="帐号状态" header-align="center" align="center"
:show-overflow-tooltip="true">
<template slot-scope="scope">
<i v-if="scope.row.disabled" class="fa fa-circle text-danger ml5"></i>
<i v-if="!scope.row.disabled" class="fa fa-circle text-success ml5"></i>
</template>
</el-table-column>
<el-table-column sortable prop="useronline" label="在线状态" header-align="center" align="center"
:show-overflow-tooltip="true">
<template slot-scope="scope">
<i v-if="scope.row.useronline" class="text-success ml5">在线</i>
<i v-if="!scope.row.useronline" class="text-danger ml5">离线</i>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="userPageSizeChange"
@current-change="userPageNumberChange"
:current-page="userForm.pageNumber"
:page-sizes="[10, 20, 30, 50]"
:page-size="userForm.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="userForm.totalCount"
></el-pagination>
<span slot="footer" class="dialog-footer">
<el-button @click="userDialogVisible = false">关 闭</el-button>
</span>
</el-dialog>
<sort ref="sortRef" @refresh="doSearch"></sort>
@@ -388,6 +523,9 @@ layout("/layouts/platform.html"){
isLeaf: "leaf"
},
tableData: [],
roleTableHeight: 300,
roleTableResizeObserver: null,
roleTableResizeHandler: null,
moduleOptions: [],
options: [],
parentUnit: [],
@@ -447,6 +585,8 @@ layout("/layouts/platform.html"){
doCmsForm: {},
userForm: {
roleId: "",
searchName: "loginname",
searchKeyword: "",
pageNumber: 1,
pageSize: 10,
totalCount: 0,
@@ -454,6 +594,7 @@ layout("/layouts/platform.html"){
pageOrderBy: ""
},
userTableData: [],
userTableHeight: 360,
loading: false,
dbUsers: [], //分配用户
selUsers: [], //分配选中的用户
@@ -575,6 +716,31 @@ layout("/layouts/platform.html"){
this.pageForm.pageNumber = 1
this.pageData()
},
// 根据角色列表卡片的剩余空间设置表格高度,分页区域始终保持可见。
updateRoleTableHeight() {
this.$nextTick(() => {
const cardBody = this.$el.querySelector('.role-manage-list-card > .el-card__body')
if (!cardBody || cardBody.clientHeight <= 0) {
return
}
const pagination = cardBody.querySelector('.el-pagination-container')
const bodyStyle = window.getComputedStyle(cardBody)
const bodyPadding = (parseFloat(bodyStyle.paddingTop) || 0)
+ (parseFloat(bodyStyle.paddingBottom) || 0)
const paginationStyle = pagination ? window.getComputedStyle(pagination) : null
const paginationHeight = pagination
? pagination.offsetHeight
+ (parseFloat(paginationStyle.marginTop) || 0)
+ (parseFloat(paginationStyle.marginBottom) || 0)
: 0
this.roleTableHeight = Math.max(1, Math.floor(cardBody.clientHeight - bodyPadding - paginationHeight))
this.$nextTick(() => {
if (this.$refs.roleTableRef) {
this.$refs.roleTableRef.doLayout()
}
})
})
},
// 加载可选 PC 模块,创建、编辑和列表筛选共用同一数据源。
loadModuleOptions() {
this.$axios.post("/platform/sys/role/listModule").then((res) => {
@@ -624,6 +790,26 @@ layout("/layouts/platform.html"){
this.userForm.pageSize = val
this.doUserLoad()
},
// 查询当前角色已关联用户,查询时从第一页重新加载。
doUserSearch() {
this.userForm.pageNumber = 1
this.doUserLoad()
},
// 根据弹窗内表格容器的剩余空间计算高度,确保仅表格内部产生滚动条。
updateUserTableHeight() {
this.$nextTick(() => {
const tableWrap = document.querySelector('.role-user-dialog .role-user-table-wrap')
if (!tableWrap || tableWrap.clientHeight <= 0) {
return
}
this.userTableHeight = Math.max(180, Math.floor(tableWrap.clientHeight))
this.$nextTick(() => {
if (this.$refs.userTableRef) {
this.$refs.userTableRef.doLayout()
}
})
})
},
remoteMethod(query) {
if (query !== "") {
this.loading = true
@@ -763,6 +949,7 @@ layout("/layouts/platform.html"){
this.userDialogVisible = true
this.roleId = command.id
this.userForm.roleId = command.id
this.userForm.pageNumber = 1
this.doUserLoad()
}
if ("enable" === command.type || "disable" === command.type) {
@@ -903,6 +1090,31 @@ layout("/layouts/platform.html"){
this.loadModuleOptions()
this.pageData()
// await this.getMenuOptions()
},
mounted() {
this.updateRoleTableHeight()
window.addEventListener("resize", this.updateUserTableHeight)
const page = this.$el.querySelector('.role-manage-page')
if (window.ResizeObserver && page) {
this.roleTableResizeObserver = new ResizeObserver(() => {
this.updateRoleTableHeight()
})
this.roleTableResizeObserver.observe(page)
} else {
this.roleTableResizeHandler = () => {
this.updateRoleTableHeight()
}
window.addEventListener("resize", this.roleTableResizeHandler)
}
},
beforeDestroy() {
window.removeEventListener("resize", this.updateUserTableHeight)
if (this.roleTableResizeObserver) {
this.roleTableResizeObserver.disconnect()
}
if (this.roleTableResizeHandler) {
window.removeEventListener("resize", this.roleTableResizeHandler)
}
}
})
</script>
@@ -6,7 +6,7 @@ const branchUnionManage = {
<el-input placeholder="请输入分工会名称" clearable size="small" style="width: 300px" v-model="pageForm.searchKeyword"></el-input>
<el-button type="primary" class="ml5" size="small" icon="el-icon-search" @click="doSearch"></el-button>
<el-button @click="openAudit" icon="el-icon-s-check" type="primary" style="margin-left: auto" size="small">基层干部审核</el-button>
<el-button @click="openAudit" icon="el-icon-s-check" type="primary" style="margin-left: auto" size="small" v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN'])">基层干部审核</el-button>
<el-button @click="openAdd" icon="ti-plus" type="primary" size="small" v-if="$auth.hasPermission('sys.manager.union.add')">新建分工会</el-button>
</el-row>
</el-card>
@@ -1,12 +1,15 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<style>
<!--#include("../fixedListLayout.css"){}#-->
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="club-info-fixed-list-page">
<el-card class="club-info-fixed-query-card" shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
@@ -30,14 +33,14 @@ layout("/layouts/platform.html"){
</search>
</el-card>
<el-card class="mt10" shadow="never">
<el-card class="mt10 club-info-fixed-list-card" shadow="never">
<table-tool label="申请列表">
<el-radio-group v-model="pageForm.approval" size="small" @change="doSearch">
<el-radio-button :label="true">已审核</el-radio-button>
<el-radio-button :label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData">
<el-table :data="tableData" :height="tableHeight" ref="tableRef">
<el-table-column :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
<el-table-column label="社团名称" prop="clubName" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="申请人" prop="userName" sortable show-overflow-tooltip></el-table-column>
@@ -66,6 +69,7 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
<template #edit>
@@ -95,9 +99,10 @@ layout("/layouts/platform.html"){
<script nonce="${cspNonce!}">
<!--#include("../change/info.js"){}#-->
<!--#include("../fixedListLayout.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
mixins: [initTableMixins, CLUB_INFO_FIXED_LIST_MIXIN],
components: {
"info": clubManagerInfo,
},
@@ -1,12 +1,15 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<style>
<!--#include("../fixedListLayout.css"){}#-->
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="club-info-fixed-list-page">
<el-card class="club-info-fixed-query-card" shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
@@ -30,14 +33,14 @@ layout("/layouts/platform.html"){
</search>
</el-card>
<el-card class="mt10" shadow="never">
<el-card class="mt10 club-info-fixed-list-card" shadow="never">
<table-tool label="申请列表">
<el-button type="primary" size="small" @click="openAdd">
<i class="ti-plus"></i>
变更成员
</el-button>
</table-tool>
<el-table :data="tableData">
<el-table :data="tableData" :height="tableHeight" ref="tableRef">
<el-table-column :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
<el-table-column label="社团名称" prop="clubName" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="申请人" prop="userName" sortable show-overflow-tooltip></el-table-column>
@@ -64,6 +67,7 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
<template #edit_func>
@@ -106,13 +110,13 @@ layout("/layouts/platform.html"){
</el-select>
</el-form-item>
<el-form-item label="身份" prop="nowRoleCode">
<el-checkbox-group v-model="formData.nowRoleCode">
<el-checkbox-group v-model="formData.nowRoleCode" @change="handleRoleChange">
<el-checkbox label="CLUB_PRESIDENT">社团会长</el-checkbox>
<el-checkbox label="CLUB_VICE_PRESIDENT">社团副会长</el-checkbox>
<el-checkbox label="CLUB_SECRETARY">社团秘书长</el-checkbox>
<el-checkbox label="CLUB_VICE_SECRETARY">社团副秘书长</el-checkbox>
<el-checkbox label="CLUB_OPERATOR">社团操作员</el-checkbox>
<el-checkbox label="CLUB_MEMBER">社团会员</el-checkbox>
<el-checkbox label="CLUB_MEMBER" :disabled="memberRoleDisabled">社团会员</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form>
@@ -131,9 +135,10 @@ layout("/layouts/platform.html"){
<script nonce="${cspNonce!}">
<!--#include("info.js"){}#-->
<!--#include("../fixedListLayout.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
mixins: [initTableMixins, CLUB_INFO_FIXED_LIST_MIXIN],
components: {
"info": clubManagerInfo
},
@@ -155,6 +160,13 @@ layout("/layouts/platform.html"){
viewData: {},
}
},
computed: {
// 选择任意理事机构身份后,社团会员身份不可再选,避免互斥身份同时提交。
memberRoleDisabled() {
const roleCodes = Array.isArray(this.formData.nowRoleCode) ? this.formData.nowRoleCode : []
return roleCodes.some(roleCode => roleCode !== 'CLUB_MEMBER')
},
},
methods: {
clubChange(key) {
if(!key) {
@@ -169,10 +181,20 @@ layout("/layouts/platform.html"){
},
userChange(key) {
const user = this.userList.find(o => o.userId === key)
this.$set(this.formData, 'nowRoleCode', user?.roleCode)
const roleCodes = user && Array.isArray(user.roleCode) ? user.roleCode.slice() : []
this.$set(this.formData, 'nowRoleCode', roleCodes)
this.handleRoleChange(roleCodes)
this.$set(this.formData, 'changeUserId', key)
this.$set(this.formData, 'changeUserName', user?.userName)
},
// 身份发生变化时,只要存在非社团会员身份,就取消社团会员身份的选中状态。
handleRoleChange(roleCodes) {
const selectedRoleCodes = Array.isArray(roleCodes) ? roleCodes : []
const hasNonMemberRole = selectedRoleCodes.some(roleCode => roleCode !== 'CLUB_MEMBER')
if (hasNonMemberRole && selectedRoleCodes.includes('CLUB_MEMBER')) {
this.$set(this.formData, 'nowRoleCode', selectedRoleCodes.filter(roleCode => roleCode !== 'CLUB_MEMBER'))
}
},
openAdd() {
this.id = ''
this.taskId = ''
@@ -1,12 +1,15 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<style>
<!--#include("../fixedListLayout.css"){}#-->
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="club-info-fixed-list-page">
<el-card class="club-info-fixed-query-card" shadow="never">
<search @search="doSearch">
<search-item label="所属社团">
<el-select v-model="pageForm.clubId" placeholder="请选择社团" clearable filterable style="width: 100%">
@@ -25,9 +28,9 @@ layout("/layouts/platform.html"){
</search>
</el-card>
<el-card class="mt10" shadow="never">
<el-card class="mt10 club-info-fixed-list-card" shadow="never">
<table-tool label="退会人员列表"></table-tool>
<el-table :data="tableData">
<el-table :data="tableData" :height="tableHeight" ref="tableRef">
<el-table-column :index="indexMethod" label="序号" type="index" width="70"></el-table-column>
<el-table-column label="工号" prop="loginName" show-overflow-tooltip></el-table-column>
<el-table-column label="姓名" prop="userName" show-overflow-tooltip></el-table-column>
@@ -53,6 +56,7 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
<template #view>
@@ -63,9 +67,10 @@ layout("/layouts/platform.html"){
<script nonce="${cspNonce!}">
<!--#include("info.js"){}#-->
<!--#include("../fixedListLayout.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
mixins: [initTableMixins, CLUB_INFO_FIXED_LIST_MIXIN],
components: {
"info": clubExitInfo,
},
@@ -1,7 +1,7 @@
const CLUB_INFO_MANAGE_TEMPLATE = {
template: `
<div>
<el-card shadow="never">
<div class="club-manage-panel">
<el-card class="club-manage-query-card" shadow="never">
<search @search="doSearch">
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
@@ -15,7 +15,7 @@
</search>
</el-card>
<el-card shadow="never" class="mt10">
<el-card shadow="never" class="mt10 club-manage-list-card">
<table-tool label="会员信息">
<template v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])">
<el-button size="small" type="primary" icon="el-icon-download" @click="exportRegistrationDoc">导出登记表</el-button>
@@ -29,7 +29,8 @@
<el-radio-button label="1">理事机构</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" row-key="id" @sort-change='pageOrder'>
<el-table v-loading="tableLoading" :data="tableData" :height="tableHeight"
row-key="id" ref="tableRef" @sort-change='pageOrder'>
<el-table-column :index="indexMethod" label="序号" type="index" width="70"></el-table-column>
<el-table-column label="工号" prop="loginName" show-overflow-tooltip sortable></el-table-column>
<el-table-column label="姓名" prop="userName" show-overflow-tooltip sortable></el-table-column>
@@ -147,7 +148,7 @@
</el-dialog>
</div>
`,
mixins: [initTableMixins],
mixins: [initTableMixins, CLUB_FIXED_TABLE_MIXIN],
props: {
parentNode: {
type: Object,
@@ -339,20 +340,33 @@
})
},
async pageData() {
pageData() {
this.pageForm.clubId = this.parentNode.currentTreeData.id
const resp = await this.$axios.post("/platform/club/infoManage/manage/userPageData", this.pageForm)
if (resp.code === 0) {
this.tableData = resp.data.list
this.pageForm.totalCount = resp.data.totalCount
} else {
this.$message.warning(resp.msg)
}
// 切换树节点或分页时清空旧数据,避免新请求完成前显示上一社团的成员。
const requestSequence = ++this.pageRequestSequence
this.tableData = []
this.tableLoading = true
return this.$axios.post("/platform/club/infoManage/manage/userPageData", this.pageForm).then((resp) => {
if (requestSequence !== this.pageRequestSequence) {
return
}
if (resp.code === 0) {
this.tableData = resp.data.list || []
this.pageForm.totalCount = resp.data.totalCount || 0
this.updateFixedTableHeight()
} else {
this.$message.warning(resp.msg)
}
}).finally(() => {
if (requestSequence === this.pageRequestSequence) {
this.tableLoading = false
}
})
}
},
async created() {
created() {
this.$set(this.pageForm, "radioType", "3")
await this.pageData()
this.pageData()
}
}
@@ -1,16 +1,74 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<style>
/* 社团信息页面固定占满平台内容区,避免页面主体出现纵向滚动条。 */
#app .club-manage-layout {
height: calc(100vh - 82px);
min-height: 0;
overflow: hidden;
}
#app .club-tree-column,
#app .club-content-column {
height: 100%;
min-height: 0;
overflow: hidden;
}
#app .club-tree-card {
height: 100%;
}
#app .club-tree-card > .el-card__body {
box-sizing: border-box;
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
overflow: hidden;
}
#app .club-tree-scroll {
flex: 1 1 auto;
min-height: 0;
margin-top: 10px;
overflow: auto;
}
/* 右侧查询卡片固定,列表卡片占满剩余空间。 */
#app .club-manage-panel {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
overflow: hidden;
}
#app .club-manage-query-card {
flex: 0 0 auto;
}
#app .club-manage-list-card {
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
}
#app .club-manage-list-card > .el-card__body {
box-sizing: border-box;
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
overflow: hidden;
}
#app .club-manage-list-card .ele-table-tool,
#app .club-manage-list-card .el-pagination-container {
flex: 0 0 auto;
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-row type="flex" :gutter="10" style="height: calc(100vh - 126px)">
<el-col :span="4" style="height: 100%">
<el-card shadow="never" style="height: 100%" body-style="{ height: '100%' }">
<el-row class="club-manage-layout" type="flex" :gutter="10">
<el-col class="club-tree-column" :span="4">
<el-card class="club-tree-card" shadow="never">
<el-input placeholder="输入关键字进行查找" v-model="filterText" clearable></el-input>
<div style="max-height: calc(100vh - 200px); overflow-y: auto">
<div class="club-tree-scroll">
<el-tree
:data="treeData"
ref="treeRef"
@@ -32,7 +90,7 @@ layout("/layouts/platform.html"){
</div>
</el-card>
</el-col>
<el-col :span="20" style="height: 100%">
<el-col class="club-content-column" :span="20">
<template v-if="currentTreeNode==null || currentTreeNode.level===1">
<school-club-manage :parent-node="this"></school-club-manage>
</template>
@@ -57,6 +115,69 @@ layout("/layouts/platform.html"){
</div>
<script nonce="${cspNonce!}">
/* 右侧列表共享固定高度计算逻辑,工具栏和分页不参与数据滚动。 */
const CLUB_FIXED_TABLE_MIXIN = {
data() {
return {
tableHeight: 300,
tableResizeObserver: null,
pageRequestSequence: 0
}
},
methods: {
updateFixedTableHeight() {
this.$nextTick(() => {
const cardBody = this.$el.querySelector(".club-manage-list-card > .el-card__body")
if (!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)
this.tableHeight = Math.max(1, Math.floor(cardBody.clientHeight - reservedHeight))
this.$nextTick(() => {
if (this.$refs.tableRef) {
this.$refs.tableRef.doLayout()
}
})
})
}
},
mounted() {
this.updateFixedTableHeight()
if (window.ResizeObserver) {
this.tableResizeObserver = new ResizeObserver(() => {
this.updateFixedTableHeight()
})
this.tableResizeObserver.observe(this.$el)
} else {
this.resizeHandler = () => {
this.updateFixedTableHeight()
}
window.addEventListener("resize", this.resizeHandler)
}
},
beforeDestroy() {
if (this.tableResizeObserver) {
this.tableResizeObserver.disconnect()
}
if (this.resizeHandler) {
window.removeEventListener("resize", this.resizeHandler)
}
}
}
<!--#include("../../register/apply/clubRegisterForm.js"){}#-->
<!--#include("../../common/clubInfoComponent.js"){}#-->
<!--#include("../../common/clubRoleConstant.js"){}#-->
@@ -1,7 +1,7 @@
const SCHOOL_CLUB_MANAGE_TEMPLATE = {
template: `
<div>
<el-card shadow="never">
<div class="club-manage-panel">
<el-card class="club-manage-query-card" shadow="never">
<search @search="doSearch">
<search-item label="社团名称">
<el-input
@@ -19,13 +19,14 @@ const SCHOOL_CLUB_MANAGE_TEMPLATE = {
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<el-card shadow="never" class="mt10 club-manage-list-card">
<table-tool label="社团列表">
<template>
</template>
</table-tool>
<el-table :data="tableData" row-key="id">
<el-table v-loading="tableLoading" :data="tableData" :height="tableHeight"
row-key="id" ref="tableRef">
<el-table-column :index="indexMethod" label="序号" type="index" width="70"></el-table-column>
<el-table-column label="社团编码" sortable prop="clubCode"></el-table-column>
<el-table-column label="社团名称" prop="clubName" sortable></el-table-column>
@@ -69,7 +70,7 @@ const SCHOOL_CLUB_MANAGE_TEMPLATE = {
</el-card>
</div>
`,
mixins: [initTableMixins],
mixins: [initTableMixins, CLUB_FIXED_TABLE_MIXIN],
props: {
parentNode: {
type: Object,
@@ -118,17 +119,30 @@ const SCHOOL_CLUB_MANAGE_TEMPLATE = {
}
},
openImport() {},
async pageData() {
const resp = await this.$axios.post("/platform/club/infoManage/manage/pageData", this.pageForm)
if (resp.code === 0) {
this.tableData = resp.data.list
this.pageForm.totalCount = resp.data.totalCount
} else {
this.$message.warning(resp.msg)
}
pageData() {
// 查询期间清空旧页并显示加载状态,快速连续操作时只接收最后一次响应。
const requestSequence = ++this.pageRequestSequence
this.tableData = []
this.tableLoading = true
return this.$axios.post("/platform/club/infoManage/manage/pageData", this.pageForm).then((resp) => {
if (requestSequence !== this.pageRequestSequence) {
return
}
if (resp.code === 0) {
this.tableData = resp.data.list || []
this.pageForm.totalCount = resp.data.totalCount || 0
this.updateFixedTableHeight()
} else {
this.$message.warning(resp.msg)
}
}).finally(() => {
if (requestSequence === this.pageRequestSequence) {
this.tableLoading = false
}
})
}
},
async created() {
await this.pageData()
created() {
this.pageData()
}
}
@@ -2,6 +2,7 @@
layout("/layouts/platform.html"){
#-->
<style>
<!--#include("../fixedListLayout.css"){}#-->
.el-tooltip__popper {
line-height: 20px;
}
@@ -13,7 +14,8 @@ layout("/layouts/platform.html"){
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="club-info-fixed-list-page">
<el-card class="club-info-fixed-query-card" shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
@@ -54,13 +56,13 @@ layout("/layouts/platform.html"){
</search>
</el-card>
<el-card class="mt10" shadow="never">
<el-card class="mt10 club-info-fixed-list-card" shadow="never">
<table-tool label="缴费记录">
<el-button @click="batchOperatePay" size="small" type="primary">
批量设置
</el-button>
</table-tool>
<el-table :data="tableData" row-key="id" @selection-change="handleSelectionChange" ref="tableRef">
<el-table :data="tableData" :height="tableHeight" row-key="id" @selection-change="handleSelectionChange" ref="tableRef">
<el-table-column
:reserve-selection="true"
type="selection"
@@ -122,6 +124,7 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
<template #view>
@@ -156,9 +159,10 @@ layout("/layouts/platform.html"){
</div>
<script nonce="${cspNonce!}">
<!--#include("../fixedListLayout.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
mixins: [initTableMixins, CLUB_INFO_FIXED_LIST_MIXIN],
components: {
},
@@ -1,12 +1,15 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<style>
<!--#include("../fixedListLayout.css"){}#-->
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="club-info-fixed-list-page">
<el-card class="club-info-fixed-query-card" shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
@@ -30,14 +33,14 @@ layout("/layouts/platform.html"){
</search>
</el-card>
<el-card class="mt10" shadow="never">
<el-card class="mt10 club-info-fixed-list-card" shadow="never">
<table-tool label="申请列表">
<el-button type="primary" size="small" @click="openAdd">
<i class="ti-plus"></i>
上传报告
</el-button>
</table-tool>
<el-table :data="tableData">
<el-table :data="tableData" :height="tableHeight" ref="tableRef">
<el-table-column :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
<el-table-column label="社团名称" prop="clubName" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="申请人" prop="userName" sortable show-overflow-tooltip></el-table-column>
@@ -61,6 +64,7 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
<template #edit_func>
@@ -141,9 +145,10 @@ layout("/layouts/platform.html"){
<script nonce="${cspNonce!}">
<!--#include("info.js"){}#-->
<!--#include("../fixedListLayout.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
mixins: [initTableMixins, CLUB_INFO_FIXED_LIST_MIXIN],
components: {
"info": clubRefreshInfo,
},
@@ -1,12 +1,15 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<style>
<!--#include("../fixedListLayout.css"){}#-->
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="club-info-fixed-list-page">
<el-card class="club-info-fixed-query-card" shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
@@ -30,14 +33,14 @@ layout("/layouts/platform.html"){
</search>
</el-card>
<el-card class="mt10" shadow="never">
<el-card class="mt10 club-info-fixed-list-card" shadow="never">
<table-tool label="申请列表">
<el-button type="primary" size="small" @click="openAdd">
<i class="ti-plus"></i>
章程修订
</el-button>
</table-tool>
<el-table :data="tableData">
<el-table :data="tableData" :height="tableHeight" ref="tableRef">
<el-table-column :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
<el-table-column label="社团名称" prop="clubName" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="申请人" prop="userName" sortable show-overflow-tooltip></el-table-column>
@@ -61,6 +64,7 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
<template #edit_func>
@@ -99,9 +103,10 @@ layout("/layouts/platform.html"){
<script nonce="${cspNonce!}">
<!--#include("info.js"){}#-->
<!--#include("../fixedListLayout.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
mixins: [initTableMixins, CLUB_INFO_FIXED_LIST_MIXIN],
components: {
"info": clubRuleInfo,
},
@@ -1,12 +1,15 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<style>
<!--#include("../fixedListLayout.css"){}#-->
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="club-info-fixed-list-page">
<el-card class="club-info-fixed-query-card" shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
@@ -30,7 +33,7 @@ layout("/layouts/platform.html"){
</search>
</el-card>
<el-card class="mt10" shadow="never">
<el-card class="mt10 club-info-fixed-list-card" shadow="never">
<table-tool label="申请列表">
<el-button size="small" type="primary" @click="exportRefreshReportZip">导出换届报告Zip</el-button>
<el-radio-group v-model="pageForm.approval" size="small" @change="doSearch">
@@ -38,7 +41,7 @@ layout("/layouts/platform.html"){
<el-radio-button :label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData">
<el-table :data="tableData" :height="tableHeight" ref="tableRef">
<el-table-column :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
<el-table-column label="社团名称" prop="clubName" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="申请人" prop="userName" sortable show-overflow-tooltip></el-table-column>
@@ -64,6 +67,7 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
<template #edit>
@@ -93,9 +97,10 @@ layout("/layouts/platform.html"){
<script nonce="${cspNonce!}">
<!--#include("../refreshReport/info.js"){}#-->
<!--#include("../fixedListLayout.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
mixins: [initTableMixins, CLUB_INFO_FIXED_LIST_MIXIN],
components: {
"info": clubRefreshInfo,
},
@@ -1,12 +1,15 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<style>
<!--#include("../fixedListLayout.css"){}#-->
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="club-info-fixed-list-page">
<el-card class="club-info-fixed-query-card" shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
@@ -30,14 +33,14 @@ layout("/layouts/platform.html"){
</search>
</el-card>
<el-card class="mt10" shadow="never">
<el-card class="mt10 club-info-fixed-list-card" shadow="never">
<table-tool label="申请列表">
<el-radio-group v-model="pageForm.approval" size="small" @change="doSearch">
<el-radio-button :label="true">已审核</el-radio-button>
<el-radio-button :label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData">
<el-table :data="tableData" :height="tableHeight" ref="tableRef">
<el-table-column :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
<el-table-column label="社团名称" prop="clubName" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="申请人" prop="userName" sortable show-overflow-tooltip></el-table-column>
@@ -63,6 +66,7 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
<template #edit>
@@ -92,9 +96,10 @@ layout("/layouts/platform.html"){
<script nonce="${cspNonce!}">
<!--#include("../ruleUpdate/info.js"){}#-->
<!--#include("../fixedListLayout.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
mixins: [initTableMixins, CLUB_INFO_FIXED_LIST_MIXIN],
components: {
"info": clubRuleInfo,
},
@@ -1,11 +1,15 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
<!--#include("../fixedListLayout.css"){}#-->
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="outlay-union-fixed-list-page">
<el-card class="outlay-union-fixed-query-card" shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
@@ -38,7 +42,7 @@ layout("/layouts/platform.html"){
</search>
</el-card>
<el-card shadow="never" class="mt10">
<el-card class="outlay-union-fixed-list-card mt10" shadow="never">
<table-tool label="预算分配">
<el-button @click="showBatchAllocateDialog" size="small" type="primary" :loading="formLoading">一键分配
</el-button>
@@ -51,7 +55,7 @@ layout("/layouts/platform.html"){
<el-button @click="deleteAllocateRecord" size="small" type="danger" :loading="formLoading">重置分配记录
</el-button>
</table-tool>
<el-table :data="tableData" style="width: 100%" row-key="id"
<el-table ref="tableRef" :data="tableData" :height="tableHeight" style="width: 100%" row-key="id"
v-loading="tableLoading" :size="tableSize" class="vi-table">
<el-table-column type="index" :index="indexMethod" label="序号"
@@ -100,6 +104,7 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
<el-dialog title="一键分配所有工会额度" :visible.sync="batchAllocateDialogVisible" width="700px">
<el-form :model="batchAllocateForm" label-width="120px">
@@ -137,8 +142,8 @@ layout("/layouts/platform.html"){
<el-table-column type="index" label="序号" width="60"></el-table-column>
<el-table-column prop="unionCode" label="工会编码" min-width="120"></el-table-column>
<el-table-column prop="unionName" label="工会名称" min-width="160"></el-table-column>
<el-table-column prop="allocateMoney" label="分配额度" min-width="120"></el-table-column>
<el-table-column prop="errMsg" label="校验结果" min-width="180">
<el-table-column prop="allocateMoney" label="年初数" min-width="120"></el-table-column>
<el-table-column prop="errMsg" label="经费余额" min-width="180">
<template slot-scope="{row}">
<span class="text-danger" v-if="row.errMsg">{{row.errMsg}}</span>
<span class="text-success" v-else>通过</span>
@@ -193,10 +198,11 @@ layout("/layouts/platform.html"){
</div>
<script nonce="${cspNonce!}">
<!--#include("../fixedListLayout.js"){}#-->
new Vue({
el: '#app',
store,
mixins: [initTableMixins],
mixins: [initTableMixins, OUTLAY_UNION_FIXED_LIST_MIXIN],
dicts: ["OUTLAY_QUARTERLY"],
data() {
return {
@@ -208,8 +214,8 @@ layout("/layouts/platform.html"){
{prop: 'year', label: '年度'},
{prop: 'quarterly', label: '分配项目'},
{prop: 'unionName', label: '工会名称'},
{prop: 'allocateHeadMoney', label: '分配前额度'},
{prop: 'allocateMoney', label: '分配额度'},
{prop: 'allocateHeadMoney', label: '年初数'},
{prop: 'allocateMoney', label: '经费额度'},
],
periodList: [],
batchAllocateDialogVisible: false,
@@ -1,12 +1,16 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
<!--#include("../fixedListLayout.css"){}#-->
</style>
<div class="platform" id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="outlay-union-fixed-list-page">
<el-card class="outlay-union-fixed-query-card" shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
@@ -33,11 +37,11 @@ layout("/layouts/platform.html"){
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<el-card class="outlay-union-fixed-list-card mt10" shadow="never">
<table-tool label="经费收支使用情况表">
<el-button size="mini" type="primary" @click="doExport">导出</el-button>
</table-tool>
<el-table :data="tableData" style="width: 100%" row-key="unionId"
<el-table ref="tableRef" :data="tableData" :height="tableHeight" style="width: 100%" row-key="unionId"
v-loading="tableLoading" :size="tableSize" class="vi-table"
border>
<el-table-column
@@ -120,27 +124,95 @@ layout("/layouts/platform.html"){
</template>
</el-table-column>
</el-table>
<el-table
:data="[summaryData]"
:show-header="false"
v-loading="summaryLoading"
class="vi-table outlay-union-summary-table"
style="width: 100%">
<el-table-column
align="center"
header-align="center"
label="单位"
prop="unionName"
min-width="140">
<template v-slot>合计</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="年初数" prop="beginMoney" min-width="120">
<template v-slot="{row}">{{summaryValue('beginMoney', row)}}</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="1-4月会费" prop="feeJanApr" min-width="120">
<template v-slot="{row}">{{summaryValue('feeJanApr', row)}}</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="5-8月会费" prop="feeMayAug" min-width="120">
<template v-slot="{row}">{{summaryValue('feeMayAug', row)}}</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="9-12月会费" prop="feeSepDec" min-width="120">
<template v-slot="{row}">{{summaryValue('feeSepDec', row)}}</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="评优奖励" prop="awardMoney" min-width="120">
<template v-slot="{row}">{{summaryValue('awardMoney', row)}}</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="1-12月支出" prop="usedMoney" min-width="120">
<template v-slot="{row}">{{summaryValue('usedMoney', row)}}</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="经费余额" prop="remainMoney" min-width="120">
<template v-slot="{row}">{{summaryValue('remainMoney', row)}}</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("../fixedListLayout.js"){}#-->
const vue = new Vue({
el: '#app',
store,
mixins: [initTableMixins],
mixins: [initTableMixins, OUTLAY_UNION_FIXED_LIST_MIXIN],
data() {
return {
pageForm: {
year: this.$moment().format("YYYY"),
unionId: ""
},
unions: []
unions: [],
summaryData: {},
summaryLoading: false,
summaryLoaded: false
}
},
methods: {
doSearch() {
this.tableKey = new Date().getTime()
this.pageForm.pageNumber = 1
this.pageData()
this.querySummary()
},
querySummary() {
this.summaryLoaded = false
this.summaryLoading = true
this.$axios.post(loc() + "/summary", {
year: this.pageForm.year,
unionId: this.pageForm.unionId || ""
}).then((res) => {
if (res.code === 0) {
this.summaryData = res.data || {}
this.summaryLoaded = true
}
}).finally(() => {
this.summaryLoading = false
})
},
summaryValue(prop, row) {
if (!this.summaryLoaded) {
return ""
}
return this.formatMoney(row[prop])
},
formatMoney(value) {
return Number(value || 0).toFixed(2)
},
@@ -154,6 +226,7 @@ layout("/layouts/platform.html"){
this.unions = data
})
this.pageData()
this.querySummary()
}
})
</script>
@@ -2,13 +2,14 @@
layout("/layouts/platform.html"){
#-->
<style>
<!--#include("../fixedListLayout.css"){}#-->
</style>
<div class="platform" id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="outlay-union-fixed-list-page">
<el-card class="outlay-union-fixed-query-card" shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
@@ -34,7 +35,7 @@ layout("/layouts/platform.html"){
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<el-card class="outlay-union-fixed-list-card mt10" shadow="never">
<table-tool label="预算分配">
<template v-if="pageForm.year===$moment().format('YYYY')">
<el-button @click="issuedOutlay" size="small" type="primary" v-if="!isAllocation">年度分配
@@ -44,7 +45,7 @@ layout("/layouts/platform.html"){
</el-button>
</template>
</table-tool>
<el-table :data="tableData" style="width: 100%" row-key="id"
<el-table ref="tableRef" :data="tableData" :height="tableHeight" style="width: 100%" row-key="id"
v-loading="tableLoading" :size="tableSize" class="vi-table">
<el-table-column align="center" header-align="center" type="index"
@@ -95,15 +96,17 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("../fixedListLayout.js"){}#-->
const vue = new Vue({
el: '#app',
store,
mixins: [initTableMixins],
mixins: [initTableMixins, OUTLAY_UNION_FIXED_LIST_MIXIN],
data() {
return {
tableColumns: [
@@ -2,13 +2,14 @@
layout("/layouts/platform.html"){
#-->
<style>
<!--#include("../fixedListLayout.css"){}#-->
</style>
<div class="platform" id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="outlay-union-fixed-list-page">
<el-card class="outlay-union-fixed-query-card" shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
@@ -35,11 +36,11 @@ layout("/layouts/platform.html"){
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<el-card class="outlay-union-fixed-list-card mt10" shadow="never">
<table-tool label="预算使用情况">
</table-tool>
<el-table :data="tableData" style="width: 100%" row-key="id"
<el-table ref="tableRef" :data="tableData" :height="tableHeight" style="width: 100%" row-key="id"
v-loading="tableLoading" :size="tableSize" class="vi-table">
<el-table-column align="center" header-align="center" type="index"
@@ -71,8 +72,34 @@ layout("/layouts/platform.html"){
</template>
</el-table-column>
</el-table>
<el-table
:data="[summaryData]"
:show-header="false"
v-loading="summaryLoading"
class="vi-table outlay-union-summary-table"
style="width: 100%">
<el-table-column align="center" header-align="center" label="合计" width="80">
<template v-slot>合计</template>
</el-table-column>
<el-table-column
align="center"
header-align="center"
v-for="column in tableColumns"
:label="column.label"
:prop="column.prop"
:width="column.width"
min-width="50">
<template v-slot="{row}">
{{summaryValue(column.prop, row)}}
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="操作" width="250">
<template v-slot></template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
<template #view>
@@ -89,10 +116,11 @@ layout("/layouts/platform.html"){
<script nonce="${cspNonce!}">
<!--#include("detailInfo.js"){}#-->
<!--#include("quarterlyOutlayAllocate.js"){}#-->
<!--#include("../fixedListLayout.js"){}#-->
const vue = new Vue({
el: '#app',
store,
mixins: [initTableMixins],
mixins: [initTableMixins, OUTLAY_UNION_FIXED_LIST_MIXIN],
data() {
return {
tableColumns: [
@@ -106,7 +134,10 @@ layout("/layouts/platform.html"){
pageForm: {
year: this.$moment().format("YYYY")
},
unions: []
unions: [],
summaryData: {},
summaryLoading: false,
summaryLoaded: false
}
},
components: {
@@ -114,6 +145,39 @@ layout("/layouts/platform.html"){
"outlay-manage-union-quarterly-allocate": OUTLAY_MANAGE_UNION_QUARTERLY_ALLOCATE
},
methods: {
doSearch() {
this.tableKey = new Date().getTime()
this.pageForm.pageNumber = 1
this.pageData()
this.querySummary()
},
querySummary() {
this.summaryLoaded = false
this.summaryLoading = true
this.$axios.post(loc() + "/summary", {
year: this.pageForm.year,
unionId: this.pageForm.unionId || ""
}).then((res) => {
if (res.code === 0) {
this.summaryData = res.data || {}
this.summaryLoaded = true
}
}).finally(() => {
this.summaryLoading = false
})
},
summaryValue(prop, row) {
if (!this.summaryLoaded) {
return ""
}
if (["totalQuota", "usedQuota", "surplusQuota"].indexOf(prop) < 0) {
return ""
}
return this.formatMoney(row[prop])
},
formatMoney(value) {
return Number(value || 0).toFixed(2)
},
openAllocateView(row) {
this.$refs.guava.edit(() => {
this.$refs.quarterlyAllocate.open(row)
@@ -129,6 +193,7 @@ layout("/layouts/platform.html"){
async created() {
this.unions = await this.$businessTool.listUnion()
this.pageData()
this.querySummary()
}
})
</script>
@@ -13,8 +13,8 @@ let OUTLAY_MANAGE_UNION_QUARTERLY_ALLOCATE = {
:value="row.quarterly"></dict-tag>
</template>
</el-table-column>
<el-table-column label="分配前额度" prop="allocateHeadMoney"></el-table-column>
<el-table-column label="分配额度" prop="allocateMoney"></el-table-column>
<el-table-column label="年初数" prop="allocateHeadMoney"></el-table-column>
<el-table-column label="经费额度" prop="allocateMoney"></el-table-column>
</el-table>
</template>
</div>