This commit is contained in:
zhouhefeng
2026-06-02 08:17:07 +08:00
parent 268cbd6a49
commit 449428b762
3 changed files with 409 additions and 82 deletions
@@ -7,6 +7,8 @@ import com.alibaba.excel.EasyExcel;
import com.budwk.app.base.annotation.SLog; import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.page.Pagination; import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.sys.models.Sys_union;
import com.budwk.app.sys.models.Sys_union_cadre;
import com.budwk.app.zhgh.staffmanage.member.models.MemberHistory; import com.budwk.app.zhgh.staffmanage.member.models.MemberHistory;
import com.budwk.app.zhgh.staffmanage.member.param.pageform.MemberInfoPageForm; import com.budwk.app.zhgh.staffmanage.member.param.pageform.MemberInfoPageForm;
import com.budwk.app.zhgh.staffmanage.member.service.MemberInfoService; import com.budwk.app.zhgh.staffmanage.member.service.MemberInfoService;
@@ -14,6 +16,7 @@ import com.budwk.app.zhgh.staffmanage.member.vo.MemberImportVo;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd; import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql; import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop; import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
@@ -30,6 +33,7 @@ import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid; import javax.validation.Valid;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.stream.Collectors;
/** /**
* @version 1.0 * @version 1.0
@@ -72,6 +76,58 @@ public class MemberInfoGroupController {
return Result.success(pagination); return Result.success(pagination);
} }
@At
@SaCheckPermission("member.info.group")
public Result unionOverview(String unionId) {
Sys_union union = memberInfoService.dao().fetch(Sys_union.class, unionId);
if (union == null) {
return Result.success(NutMap.NEW());
}
int staffTotal = memberInfoService.count(Sqls.create("""
select count(1)
from vw_user u
where u.unionId = @unionId
and u.personType in (
select dict.code
from sys_dict dict
left join sys_dict parent on parent.id = dict.parentId
where parent.code = 'USER_PERSON_TYPE'
and dict.name = '教职工'
)
""")
.setParam("unionId", unionId));
int memberTotal = memberInfoService.count(Sqls.create("select count(1) from vw_user where unionId = @unionId and member = 1")
.setParam("unionId", unionId));
int maleTotal = memberInfoService.count(Sqls.create("select count(1) from vw_user where unionId = @unionId and member = 1 and (sex = '男' or sex = '男性')")
.setParam("unionId", unionId));
int femaleTotal = memberInfoService.count(Sqls.create("select count(1) from vw_user where unionId = @unionId and member = 1 and (sex = '女' or sex = '女性')")
.setParam("unionId", unionId));
java.util.List<Sys_union_cadre> chairmen = memberInfoService.dao().query(Sys_union_cadre.class,
Cnd.where("unionId", "=", unionId)
.and("roleCode", "=", "BRANCH_UNION_CHAIRMAN")
.and(Cnd.exps("isServing", "=", true).or("isServing", "is", null)));
String chairman = chairmen.stream()
.map(item -> item.getUserName() + "(" + item.getLoginName() + ")")
.collect(Collectors.joining(""));
String chairmanMobile = chairmen.stream()
.map(Sys_union_cadre::getMobile)
.filter(mobile -> mobile != null && !mobile.isBlank())
.collect(Collectors.joining(""));
return Result.success(NutMap.NEW()
.addv("unionName", union.getName())
.addv("unionCode", union.getUnionCode())
.addv("chairman", chairman)
.addv("telephone", union.getTelephone())
.addv("chairmanMobile", chairmanMobile)
.addv("memberTotal", memberTotal)
.addv("staffTotal", staffTotal)
.addv("maleTotal", maleTotal)
.addv("femaleTotal", femaleTotal));
}
@At @At
@SaCheckPermission("member.info.group") @SaCheckPermission("member.info.group")
@@ -20,7 +20,7 @@
<!-- <el-input placeholder="请输入内容" clearable v-model="pageForm.searchKeyword"></el-input>--> <!-- <el-input placeholder="请输入内容" clearable v-model="pageForm.searchKeyword"></el-input>-->
</search-item> </search-item>
<search-item label="所属工会"> <search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable filterable <el-select @change="handleUnionChange" @clear="handleUnionClear" clearable filterable
placeholder="请选择所属工会" style="width: 100%;" v-model="pageForm.unionId"> placeholder="请选择所属工会" style="width: 100%;" v-model="pageForm.unionId">
<el-option :key="item.id" :label="item.name" :value="item.id" <el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unions"></el-option> v-for="item in unions"></el-option>
@@ -94,6 +94,17 @@
pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys) pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
this.$emit('search', pageForm) this.$emit('search', pageForm)
}, },
handleUnionChange() {
this.flushUnits()
this.$emit("union-change", this.pageForm.unionId || "")
},
handleUnionClear() {
this.handleUnionChange()
},
setUnionFromTree(unionId) {
this.$set(this.pageForm, "unionId", unionId || "")
this.flushUnits()
},
async initData(){ async initData(){
if (this.$auth.hasRoleOr("SYSADMIN, SCHOOL_UNION_ADMIN, SCHOOL_UNION_MEMBER_ADMIN")) { if (this.$auth.hasRoleOr("SYSADMIN, SCHOOL_UNION_ADMIN, SCHOOL_UNION_MEMBER_ADMIN")) {
this.$businessTool.listUnion(this.pageForm.unionId).then((data) => { this.$businessTool.listUnion(this.pageForm.unionId).then((data) => {
@@ -4,11 +4,70 @@ layout("/layouts/platform.html"){
<div id="app" v-cloak> <div id="app" v-cloak>
<guava ref="guava"> <guava ref="guava">
<template> <template>
<el-card shadow="never"> <el-row type="flex" :gutter="20" style="height: calc(100vh - 126px)">
<common-query ref="commonQueryRef" @search="search"></common-query> <el-col :span="5">
<el-card shadow="never" style="height: 100%" :body-style="{ height: '100%' }">
<el-input placeholder="请输入关键字进行查找" v-model="filterText" clearable></el-input>
<div style="max-height: calc(100vh - 205px); overflow-y: auto; margin-top: 10px;">
<el-tree
:data="treeData"
ref="treeRef"
node-key="id"
:expand-on-click-node="false"
:props="{
children: 'children',
label: 'name'
}"
default-expand-all
:filter-node-method="filterNode"
highlight-current
@node-click="treeNodeClick"
>
<template slot-scope="{ node, data }">
<span class="el-tree-node__label">
<i class="el-icon-folder-opened" v-if="node.level===1"></i>
<i class="el-icon-folder" v-else></i>
{{node.label}}
</span>
</template>
</el-tree>
</div>
</el-card>
</el-col>
<el-col :span="19">
<el-card shadow="never" v-show="tabActive === 'memberList'">
<common-query ref="commonQueryRef" @search="search" @union-change="queryUnionChange"></common-query>
</el-card>
<el-card shadow="never" v-show="tabActive !== 'memberList' && currentUnionId">
<div style="display: flex; align-items: center; gap: 8px; font-size: 16px; font-weight: 600; color: #303133;">
<i class="el-icon-office-building"></i>
<span>{{ unionOverview.unionName || '-' }}</span>
<el-tag size="mini" type="primary">基层工会</el-tag>
</div>
<div style="margin-top: 10px; color: #606266; font-size: 13px;">
<span>负责人:{{ unionOverview.chairman || '-' }}</span>
<span style="margin: 0 12px; color: #dcdfe6;">|</span>
<span>联系电话:{{ unionOverview.telephone || unionOverview.chairmanMobile || '-' }}</span>
<span style="margin: 0 12px; color: #dcdfe6;">|</span>
<span>当前会员总数:{{ unionOverview.memberTotal || 0 }} 人</span>
</div>
<el-row :gutter="12" style="margin-top: 18px;">
<el-col :span="6" v-for="card in unionOverviewCards" :key="card.label">
<div style="background: #f5f9ff; border: 1px solid #e6f0ff; border-radius: 6px; padding: 18px 20px;">
<div style="font-size: 28px; line-height: 1; font-weight: 700; color: #0b72c9;">{{ card.value }}</div>
<div style="margin-top: 10px; color: #606266; font-size: 13px;">{{ card.label }}</div>
</div>
</el-col>
</el-row>
</el-card> </el-card>
<el-card shadow="never" class="mt10"> <el-card shadow="never" class="mt10">
<el-tabs v-model="tabActive" type="card" @tab-click="tabChange">
<el-tab-pane name="memberList">
<span slot="label">
<i class="el-icon-user"></i>
会员列表
</span>
<table-tool label="会员列表"> <table-tool label="会员列表">
<el-button type="primary" size="small" icon="el-icon-upload2" @click="openImport">导入会员</el-button> <el-button type="primary" size="small" icon="el-icon-upload2" @click="openImport">导入会员</el-button>
<el-button <el-button
@@ -85,7 +144,47 @@ layout("/layouts/platform.html"){
</el-table-column> </el-table-column>
</el-table> </el-table>
<!--#include("/layouts/pagination.html"){}#--> <!--#include("/layouts/pagination.html"){}#-->
</el-tab-pane>
<el-tab-pane name="branchUnionUserManage">
<span slot="label">
<i class="el-icon-school"></i>
分工会干部
</span>
<sys-union-branch-union-user-manage
v-if="currentUnionId"
ref="branchUnionUserManageRef"
:union_id="currentUnionId"
></sys-union-branch-union-user-manage>
<el-empty v-else description="请选择一个分工会"></el-empty>
</el-tab-pane>
<el-tab-pane name="branchUnionPartUnitManage">
<span slot="label">
<i class="el-icon-school"></i>
组成单位
</span>
<sys-union-branch-union-part-unit-manage
v-if="currentUnionId"
ref="branchUnionPartUnitManageRef"
:union_id="currentUnionId"
></sys-union-branch-union-part-unit-manage>
<el-empty v-else description="请选择一个分工会"></el-empty>
</el-tab-pane>
<el-tab-pane name="branchUnionGroup">
<span slot="label">
<i class="el-icon-school"></i>
工会小组
</span>
<sys-union-branch-union-group-manage
v-if="currentUnionId"
ref="branchUnionGroupRef"
:union_id="currentUnionId"
></sys-union-branch-union-group-manage>
<el-empty v-else description="请选择一个分工会"></el-empty>
</el-tab-pane>
</el-tabs>
</el-card> </el-card>
</el-col>
</el-row>
</template> </template>
<template #view> <template #view>
@@ -109,12 +208,21 @@ layout("/layouts/platform.html"){
<!--#include("archiveMember.js"){}#--> <!--#include("archiveMember.js"){}#-->
<!--#include("../common/commonQuery.js"){}#--> <!--#include("../common/commonQuery.js"){}#-->
<!--#include("../../common/info/memberInfo.js"){}#--> <!--#include("../../common/info/memberInfo.js"){}#-->
<!--#include("/platform/sys/union/branchUnionUserManage.js"){}#-->
<!--#include("/platform/sys/union/branchUnionPartUnitManage.js"){}#-->
<!--#include("/platform/sys/union/branchUnionGroupManage.js"){}#-->
new Vue({ new Vue({
el: "#app", el: "#app",
mixins: [initTableMixins], mixins: [initTableMixins],
data() { data() {
return { return {
filterText: null,
unionRootId: "member-union-root",
treeData: [],
currentTreeData: null,
tabActive: "memberList",
unionOverview: {},
pageForm: {}, pageForm: {},
tableColumns: [ tableColumns: [
{ prop: "loginname", label: "工号", width: 120, fixed: "left"}, { prop: "loginname", label: "工号", width: 120, fixed: "left"},
@@ -122,17 +230,17 @@ layout("/layouts/platform.html"){
{ prop: "sex", label: "性别", width: 120}, { prop: "sex", label: "性别", width: 120},
{ prop: "birthday", label: "出生年月", width: 120, sortable: true }, { prop: "birthday", label: "出生年月", width: 120, sortable: true },
{ prop: "nationality", label: "国籍", width: 120, sortable: true, checked: 0 }, { prop: "nationality", label: "国籍", width: 120, sortable: true, checked: 0 },
{ prop: "nation", label: "民族", width: 120, sortable: true}, // { prop: "nation", label: "民族", width: 120, sortable: true},
{ prop: "mobile", label: "联系电话", width: 120 }, { prop: "mobile", label: "联系电话", width: 120 },
{ prop: "political", label: "政治面貌", width: 120, sortable: true}, // { prop: "political", label: "政治面貌", width: 120, sortable: true},
{ prop: "userState", label: "在职状态", width: 120, sortable: true }, { prop: "userState", label: "在职状态", width: 120, sortable: true },
{ prop: "personType", label: "人员类型", width: 120, sortable: true, checked: 0 }, { prop: "personType", label: "人员类型", width: 120, sortable: true, checked: 0 },
// { prop: "preparedBy", label: "编制类别", width: 120, sortable: true }, // { prop: "preparedBy", label: "编制类别", width: 120, sortable: true },
{ prop: "postDoctoralJoinDate", label: "进站时间", sortable: true, checked: 0 }, { prop: "postDoctoralJoinDate", label: "进站时间", sortable: true, checked: 0 },
{ prop: "unionName", label: "所属工会", width: 120, sortable: true }, { prop: "unionName", label: "所属工会", width: 120, sortable: true },
{ prop: "unitName", label: "所属单位", width: 120, sortable: true }, { prop: "unitName", label: "所属单位", width: 120, sortable: true },
{ prop: "aidFundMemberUserType", label: "人员分类", width: 120, sortable: true }, // { prop: "aidFundMemberUserType", label: "人员分类", width: 120, sortable: true },
{ prop: "userAttribute", label: "人员属性", width: 120, sortable: true }, // { prop: "userAttribute", label: "人员属性", width: 120, sortable: true },
{ prop: "idCardType", label: "证件类型", width: 120, sortable: true, checked: 0 }, { prop: "idCardType", label: "证件类型", width: 120, sortable: true, checked: 0 },
{ prop: "idCard", label: "证件号码", width: 120, sortable: true, checked: 0 }, { prop: "idCard", label: "证件号码", width: 120, sortable: true, checked: 0 },
{ prop: "marriage", label: "婚姻状况", width: 120, sortable: true, checked: 0 }, { prop: "marriage", label: "婚姻状况", width: 120, sortable: true, checked: 0 },
@@ -154,11 +262,19 @@ layout("/layouts/platform.html"){
importDialog: false importDialog: false
} }
}, },
watch: {
filterText(val) {
this.$refs.treeRef.filter(val)
}
},
components: { components: {
"file-import": httpVueLoader("/components/plugins/sysImport/index.vue?v=" + new Date().getTime()), "file-import": httpVueLoader("/components/plugins/sysImport/index.vue?v=" + new Date().getTime()),
"archive-member": ARCHIVE_MEMBER, "archive-member": ARCHIVE_MEMBER,
"member-info": MEMBER_INFO, "member-info": MEMBER_INFO,
"common-query": COMMON_QUERY, "common-query": COMMON_QUERY,
"sys-union-branch-union-user-manage": branchUnionUserManage,
"sys-union-branch-union-part-unit-manage": branchUnionPartUnitManage,
"sys-union-branch-union-group-manage": branchUnionGroupManage,
}, },
methods: { methods: {
openImport() { openImport() {
@@ -188,6 +304,137 @@ layout("/layouts/platform.html"){
this.$refs.guava.view(() => { this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(userId) this.$refs.infoRef.onOpen(userId)
}) })
},
initDefaultView() {
this.tabActive = "memberList"
this.currentTreeData = null
this.unionOverview = {}
this.pageForm = {
...this.pageForm,
unionId: "",
unitId: null
}
},
treeNodeClick(data) {
const unionId = data && data.type === "union" ? data.id : ""
this.currentTreeData = data
if (this.$refs.commonQueryRef) {
this.$refs.commonQueryRef.setUnionFromTree(unionId)
this.$nextTick(() => {
if (this.tabActive === "memberList") {
this.$refs.commonQueryRef.doSearch()
} else {
this.loadUnionOverview()
this.refreshCurrentTab()
}
})
} else {
this.pageForm = {
...this.pageForm,
unionId,
unitId: null
}
if (this.tabActive === "memberList") {
this.pageData()
} else {
this.loadUnionOverview()
this.refreshCurrentTab()
}
}
},
queryUnionChange(unionId) {
const nodeKey = unionId || this.unionRootId
this.currentTreeData = this.findTreeNode(this.treeData, nodeKey)
this.setCurrentTreeNode(nodeKey)
this.$nextTick(() => {
if (this.tabActive !== "memberList") {
this.loadUnionOverview()
this.refreshCurrentTab()
}
})
},
filterNode(value, data) {
if (!value) return true
return data.name.indexOf(value) !== -1
},
findTreeNode(list, id) {
for (let i = 0; i < (list || []).length; i++) {
const item = list[i]
if (item.id === id) {
return item
}
const child = this.findTreeNode(item.children, id)
if (child) {
return child
}
}
return null
},
getTreeData() {
const hasAdmin = this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN", "SCHOOL_UNION_MEMBER_ADMIN"])
const unionId = hasAdmin ? null : this.$store.state.user.union.id
this.$businessTool.listUnion(unionId).then((data) => {
this.treeData = [{
id: this.unionRootId,
name: "工会委员会",
type: "root",
children: (data || []).map((item) => ({
id: item.id,
name: item.name,
type: "union"
}))
}]
this.$nextTick(() => {
this.currentTreeData = this.treeData[0]
this.setCurrentTreeNode(this.unionRootId)
if (this.tabActive !== "memberList") {
this.tabActive = "memberList"
}
})
})
},
setCurrentTreeNode(nodeKey) {
this.$nextTick(() => {
if (this.$refs.treeRef) {
this.$refs.treeRef.setCurrentKey(nodeKey)
}
})
},
tabChange(tab) {
this.$nextTick(() => {
if (tab.name === "memberList") {
if (this.$refs.commonQueryRef) {
this.$refs.commonQueryRef.doSearch()
} else {
this.pageData()
}
} else {
this.loadUnionOverview()
this.refreshCurrentTab(tab.name)
}
})
},
loadUnionOverview() {
if (!this.currentUnionId) {
this.unionOverview = {}
return
}
this.$axios.post(loc() + "/unionOverview", { unionId: this.currentUnionId }).then((data) => {
if (data.code === 0) {
this.unionOverview = data.data || {}
} else {
this.$message.error(data.msg)
}
})
},
refreshCurrentTab(tabName = this.tabActive) {
if (tabName === "memberList" || !this.currentUnionId) {
return
}
const ref = this.$refs[tabName + "Ref"]
if (ref && ref.doSearch) {
ref.doSearch()
}
}, },
search(pageForm) { search(pageForm) {
this.pageForm = { this.pageForm = {
@@ -227,10 +474,23 @@ layout("/layouts/platform.html"){
computed: { computed: {
showColumns() { showColumns() {
return this.tableColumns.filter(c => this.checkedFields.includes(c.prop)); return this.tableColumns.filter(c => this.checkedFields.includes(c.prop));
},
currentUnionId() {
return this.currentTreeData && this.currentTreeData.type === "union" ? this.currentTreeData.id : ""
},
unionOverviewCards() {
return [
{ label: "会员总数", value: this.unionOverview.memberTotal || 0 },
{ label: "教职工数", value: this.unionOverview.staffTotal || 0 },
{ label: "男性", value: this.unionOverview.maleTotal || 0 },
{ label: "女性", value: this.unionOverview.femaleTotal || 0 },
]
} }
}, },
created() { created() {
this.checkedFields = this.tableColumns.filter(c => c.checked !== 0).map(c => c.prop); this.checkedFields = this.tableColumns.filter(c => c.checked !== 0).map(c => c.prop);
this.initDefaultView()
this.getTreeData()
this.pageData() this.pageData()
} }
}) })