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.page.Pagination;
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.param.pageform.MemberInfoPageForm;
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 org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
@@ -30,6 +33,7 @@ import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.stream.Collectors;
/**
* @version 1.0
@@ -72,6 +76,58 @@ public class MemberInfoGroupController {
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
@SaCheckPermission("member.info.group")
@@ -20,7 +20,7 @@
<!-- <el-input placeholder="请输入内容" clearable v-model="pageForm.searchKeyword"></el-input>-->
</search-item>
<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">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
@@ -94,6 +94,17 @@
pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
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(){
if (this.$auth.hasRoleOr("SYSADMIN, SCHOOL_UNION_ADMIN, SCHOOL_UNION_MEMBER_ADMIN")) {
this.$businessTool.listUnion(this.pageForm.unionId).then((data) => {
@@ -4,88 +4,187 @@ layout("/layouts/platform.html"){
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<common-query ref="commonQueryRef" @search="search"></common-query>
</el-card>
<el-row type="flex" :gutter="20" style="height: calc(100vh - 126px)">
<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 shadow="never" class="mt10">
<table-tool label="会员列表">
<el-button type="primary" size="small" icon="el-icon-upload2" @click="openImport">导入会员</el-button>
<el-button
type="primary"
v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN'])"
size="small"
icon="el-icon-time"
@click="openArchive"
>
备份历史会员
</el-button>
<el-button type="primary" size="small" icon="el-icon-download" @click="exportMember">会员档案导出</el-button>
<el-popover
placement="bottom"
trigger="click"
width="200">
<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="会员列表">
<el-button type="primary" size="small" icon="el-icon-upload2" @click="openImport">导入会员</el-button>
<el-button
type="primary"
v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN'])"
size="small"
icon="el-icon-time"
@click="openArchive"
>
备份历史会员
</el-button>
<el-button type="primary" size="small" icon="el-icon-download" @click="exportMember">会员档案导出</el-button>
<el-popover
placement="bottom"
trigger="click"
width="200">
<div style="padding:4px 0;border-bottom:1px solid #eee;">
<el-button size="mini" @click="checkAll">全选</el-button>
<!-- <el-button size="mini" @click="invertCheck">反选</el-button>-->
</div>
<div style="padding:4px 0;border-bottom:1px solid #eee;">
<el-button size="mini" @click="checkAll">全选</el-button>
<!-- <el-button size="mini" @click="invertCheck">反选</el-button>-->
</div>
<div style="max-height:40vh;overflow-y:auto;padding:6px 0;">
<el-checkbox-group v-model="checkedFields">
<el-checkbox
v-for="f in tableColumns"
:key="f.prop"
:label="f.prop"
style="display:block;margin:6px 0;">
{{ f.label }}
</el-checkbox>
</el-checkbox-group>
</div>
<div style="max-height:40vh;overflow-y:auto;padding:6px 0;">
<el-checkbox-group v-model="checkedFields">
<el-checkbox
v-for="f in tableColumns"
:key="f.prop"
:label="f.prop"
style="display:block;margin:6px 0;">
{{ f.label }}
</el-checkbox>
</el-checkbox-group>
</div>
<el-button
slot="reference"
type="text"
icon="el-icon-s-operation"
size="small"
style="margin-left:12px;">
列设置
</el-button>
</el-popover>
</table-tool>
<el-button
slot="reference"
type="text"
icon="el-icon-s-operation"
size="small"
style="margin-left:12px;">
列设置
</el-button>
</el-popover>
</table-tool>
<el-table :data="tableData" style="width: 100%" row-key="id" @sort-change="pageOrder" :size="tableSize" class="vi-table">
<el-table-column
align="center"
header-align="center"
type="index"
fixed="left"
:index="indexMethod"
label="序号"
width="80px"
></el-table-column>
<el-table-column
show-overflow-tooltip
align="center"
header-align="center"
v-for="column in tableColumns"
v-if="checkedFields.includes(column.prop)"
:label="column.label"
:fixed="column.fixed"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
min-width="50"
></el-table-column>
<el-table :data="tableData" style="width: 100%" row-key="id" @sort-change="pageOrder" :size="tableSize" class="vi-table">
<el-table-column
align="center"
header-align="center"
type="index"
fixed="left"
:index="indexMethod"
label="序号"
width="80px"
></el-table-column>
<el-table-column
show-overflow-tooltip
align="center"
header-align="center"
v-for="column in tableColumns"
v-if="checkedFields.includes(column.prop)"
:label="column.label"
:fixed="column.fixed"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
min-width="50"
></el-table-column>
<el-table-column prop="userOnline" align="center" header-align="center" label="操作" fixed="right" width="100px">
<template scope="scope">
<el-button size="mini" type="primary" @click="openView(scope.row.id)">查看</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-table-column prop="userOnline" align="center" header-align="center" label="操作" fixed="right" width="100px">
<template scope="scope">
<el-button size="mini" type="primary" @click="openView(scope.row.id)">查看</el-button>
</template>
</el-table-column>
</el-table>
<!--#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-col>
</el-row>
</template>
<template #view>
@@ -109,12 +208,21 @@ layout("/layouts/platform.html"){
<!--#include("archiveMember.js"){}#-->
<!--#include("../common/commonQuery.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({
el: "#app",
mixins: [initTableMixins],
data() {
return {
filterText: null,
unionRootId: "member-union-root",
treeData: [],
currentTreeData: null,
tabActive: "memberList",
unionOverview: {},
pageForm: {},
tableColumns: [
{ prop: "loginname", label: "工号", width: 120, fixed: "left"},
@@ -122,17 +230,17 @@ layout("/layouts/platform.html"){
{ prop: "sex", label: "性别", width: 120},
{ prop: "birthday", label: "出生年月", width: 120, sortable: true },
{ 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: "political", label: "政治面貌", width: 120, sortable: true},
// { prop: "political", label: "政治面貌", width: 120, sortable: true},
{ prop: "userState", label: "在职状态", width: 120, sortable: true },
{ prop: "personType", label: "人员类型", width: 120, sortable: true, checked: 0 },
// { prop: "preparedBy", label: "编制类别", width: 120, sortable: true },
{ prop: "postDoctoralJoinDate", label: "进站时间", sortable: true, checked: 0 },
{ prop: "unionName", label: "所属工会", width: 120, sortable: true },
{ prop: "unitName", label: "所属单位", width: 120, sortable: true },
{ prop: "aidFundMemberUserType", label: "人员分类", width: 120, sortable: true },
{ prop: "userAttribute", label: "人员属性", width: 120, sortable: true },
// { prop: "aidFundMemberUserType", label: "人员分类", width: 120, sortable: true },
// { prop: "userAttribute", label: "人员属性", width: 120, sortable: true },
{ prop: "idCardType", 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 },
@@ -154,11 +262,19 @@ layout("/layouts/platform.html"){
importDialog: false
}
},
watch: {
filterText(val) {
this.$refs.treeRef.filter(val)
}
},
components: {
"file-import": httpVueLoader("/components/plugins/sysImport/index.vue?v=" + new Date().getTime()),
"archive-member": ARCHIVE_MEMBER,
"member-info": MEMBER_INFO,
"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: {
openImport() {
@@ -188,6 +304,137 @@ layout("/layouts/platform.html"){
this.$refs.guava.view(() => {
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) {
this.pageForm = {
@@ -227,10 +474,23 @@ layout("/layouts/platform.html"){
computed: {
showColumns() {
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() {
this.checkedFields = this.tableColumns.filter(c => c.checked !== 0).map(c => c.prop);
this.initDefaultView()
this.getTreeData()
this.pageData()
}
})