Files
dvcp_v2_webapp/packages/party/AppPartyOrg/AppPartyOrganization.vue
2022-12-01 09:35:20 +08:00

608 lines
21 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<section class="AppPartyOrganization">
<ai-list v-if="hasPartyOrg">
<ai-title slot="title" title="党组织管理" isShowBottomBorder/>
<template slot="left">
<ai-tree-menu title="组织目录" @mouseleave.native="showContextmenu=false" searchPlaceholder="请输入党组织名称"
@search="v=>orgTreeRef.filter(v)">
<ai-party-tree :instance="instance" :root="user.info.organizationId"
:expand-on-click-node="false" highlight-current
ref="orgTree" default-first-option
:current-node-key="selectedOrg.id||user.info.organizationId"
:filter-node-method="(v,data)=>data.name.indexOf(v)>-1"
@node-contextmenu="handleContextmenu"
@node-click="handleNodeClick"/>
<ul class="contextmenu" v-if="showContextmenu" :style="contextmenuPos">
<li v-for="(op,i) in editOps" :key="i" @click="op.foo(op)">{{ op.label }}</li>
</ul>
<template #bottom>
<div class="bottomBar">
<span v-for="(op,i) in editOps" :key="i" class="iconfont" :class="op.icon" @click="op.foo(op)"
:title="op.label"/>
</div>
</template>
<!--编辑党组织-->
<ai-dialog :visible.sync="dialog" :title="currentEditOp.label" width="520px"
:close-on-click-modal="false" @close="orgForm={}" @onConfirm="submitOrg">
<el-form :model="orgForm" label-width="100px" :rules="rules" ref="orgForm" size="small">
<div class="tipInfo"><span class="iconfont iconModal_Warning"/> 添加党组织后请在党员管理中添加该组织的成员</div>
<el-form-item label="上级党组织" v-if="!!orgForm.parentName">
{{ orgForm.parentName }}
</el-form-item>
<el-form-item label="党组织名称" prop="name">
<el-input v-model="orgForm.name" placeholder="请输入..." clearable/>
</el-form-item>
<el-form-item label="组织级别" prop="partyType">
<ai-select placeholder="组织级别" v-model="orgForm.partyType" :selectList="dict.getDict('orgPartyType')"/>
</el-form-item>
<el-form-item label="组织类型" prop="orgType">
<ai-select placeholder="组织类型" v-model="orgForm.orgType" :selectList="dict.getDict('orgType')"/>
</el-form-item>
<el-form-item label="建立时间" prop="createTime">
<el-date-picker v-model="orgForm.createTime" type="date" placeholder="选择日期"
format="yyyy-MM-dd"
:value-format="'yyyy-MM-dd' + ' 00:00:00'"/>
</el-form-item>
</el-form>
</ai-dialog>
</ai-tree-menu>
</template>
<template v-if="!!selectedOrg.id" #content>
<ai-wrapper>
<el-row v-if="!!selectedOrg.name" align="middle" type="flex">
<span class="iconfont iconParent"/>
<div v-html="fullOrgName"/>
</el-row>
<ai-title title="总体概况" isShowBottomBorder/>
<ai-info-item label="建立时间">{{ selectedOrg.createTime|timeVal }}</ai-info-item>
<ai-info-item label="上级组织">{{ selectedOrg.parentName || "-" }}</ai-info-item>
<ai-title title="领导成员" isShowBottomBorder v-if="leaderList.length>0"/>
<div class="imgUl">
<li v-for="(item,index) in leaderList" :key="index">
<img v-if="item.avatarUrl" :src="item.avatarUrl.split(';')[0]" alt="图片" width="80px"
height="92px">
<el-row justify="center" align="middle" v-else>
<span class="iconfont iconProfile_Picture" style="font-size: 36px;color: #89b;"/>
<div style="font-size: 12px;color: #666;">暂无照片</div>
</el-row>
<p style="color: #333;">{{ item.name }}</p>
<p style="color: #999;">{{ dict.getLabel('partyPosition', item.partyPosition) }}</p>
</li>
</div>
<ai-title title="党员发展" isShowBottomBorder>
<template #rightBtn>
<el-button type="text" @click="memberDetailList(1)"
v-if="permissions('admin_syspartyorganization_detail')">党员详情
</el-button>
<!-- <el-button type="text" @click="memberDetailList(2)"-->
<!-- v-if="permissions('admin_syspartyorganization_detail')">发展党员详情-->
<!-- </el-button>-->
</template>
</ai-title>
<ai-info-item v-for="op in memberCounts" :key="op.prop">
<el-row slot="label" type="flex" align="middle" justify="end">
<div class="iconfont iconProlife"/>
<div v-html="op.label"/>
</el-row>
{{ op.v }}
</ai-info-item>
<ai-title title="基层党组织统计" isShowBottomBorder>
<template #rightBtn>
<el-button type="text" @click="exportExcel">导出</el-button>
</template>
</ai-title>
<el-table :data="organizationCounts" header-cell-class-name="table-header" border
show-summary size="small">
<el-table-column align="center" label="" prop="partyType">
<template slot-scope="{row}">
{{ dict.getLabel('orgPartyType', row.partyType) }}
</template>
</el-table-column>
<el-table-column align="center" label="基层组织数" prop="primary"></el-table-column>
<el-table-column align="center" label="机关单位" prop="governmentUnit"></el-table-column>
<el-table-column align="center" label="建制村/社区/队" prop="village"></el-table-column>
<el-table-column align="center" label="事业单位" prop="publicUnit"></el-table-column>
<el-table-column align="center" label="企业" prop="company"></el-table-column>
<el-table-column align="center" label="新经济社会组织" prop="social"></el-table-column>
</el-table>
</ai-wrapper>
<!--查看党员详情-->
<el-dialog title="党员列表" center :visible.sync="isCheckMember" width="60%" :close-on-click-modal="false">
<div style="overflow-y: auto;">
<el-table :data="tableData" header-cell-class-name="table-header" tooltip-effect="light"
row-class-name="table-row" cell-class-name="table-cell" max-height="500">
<el-table-column align="center" prop="name" label="姓名">
<template slot-scope="{row}">
{{ row.name || '-' }}
</template>
</el-table-column>
<el-table-column align="center" prop="sex" label="性别">
<template slot-scope="{row}">
{{ dict.getLabel('sex', row.sex) || '-' }}
</template>
</el-table-column>
<el-table-column align="center" prop="age" label="年龄">
<template slot-scope="{row}">
{{ row.age || '-' }}
</template>
</el-table-column>
<template v-if="detailType==1">
<el-table-column align="center" prop="partyStatus" label="党员状态">
<template slot-scope="{row}">
{{ dict.getLabel('partyStatus', row.partyStatus) || '-' }}
</template>
</el-table-column>
<el-table-column align="center" prop="joinPartyTime" label="入党日期">
<template slot-scope="{row}">
{{ row.joinPartyTime|timeVal }}
</template>
</el-table-column>
<el-table-column align="center" prop="partyPosition" label="党内职务">
<template slot-scope="{row}">
{{ dict.getLabel('partyPosition', row.partyPosition) || '-' }}
</template>
</el-table-column>
<el-table-column align="center" prop="flowStatus" label="流动状态">
<template slot-scope="{row}">
{{ dict.getLabel('flowStatus', row.flowStatus) || '-' }}
</template>
</el-table-column>
</template>
<template v-if="detailType==2">
<el-table-column prop="applyJoinPartyTime" label="入党申请时间">
<div slot-scope="{row}">
{{ row.applyJoinPartyTime|timeVal }}
</div>
</el-table-column>
<el-table-column prop="developStatus" label="发展状态">
<div slot-scope="{row}">
{{ dict.getLabel('developStatus', row.developStatus) || "-" }}
</div>
</el-table-column>
</template>
</el-table>
<div class="pagination">
<el-pagination background :current-page.sync="searchObj.current" :total="total"
layout="total,prev, pager, next,sizes, jumper"
@size-change="handleSizeChange"
:page-size.sync="searchObj.size"
:page-sizes="[10, 20, 50, 100,200]"
@current-change="handleChange"></el-pagination>
</div>
</div>
</el-dialog>
</template>
<ai-empty v-else slot="content">请选择党组织</ai-empty>
</ai-list>
<!--暂无党组织-->
<div v-else class="no-permission"
style="display: flex;flex-direction:column;align-items: center;justify-content: center;height: calc(100% - 148px);font-size: 14px;">
<div style="height: 170px;"></div>
<p>暂未分配党组织</p>
<p>请前往 <span style="color: #2771FF;">系统设置 - 账号管理 - 功能分配</span> 中进行设置</p>
</div>
</section>
</template>
<script>
import {mapState} from "vuex";
import dayjs from 'dayjs'
export default {
name: "AppPartyOrganization",
label: "党组织管理",
props: {
instance: Function,
dict: Object,
permissions: Function
},
data() {
return {
detailObj: {},
memberCount: {},
tableData: [],
total: 0,
searchObj: {
current: 1,
size: 10
},
isCheckMember: false,
detailType: 0,
selectedOrg: {},
orgForm: {},
showContextmenu: false,
dialog: false,
contextmenuPos: {},
currentEditOp: {},
info: {}
}
},
computed: {
...mapState(['user']),
hasPartyOrg() {
return Boolean(this.user.info.organizationId)
},
memberCounts() {
return [
{label: "正式党员", prop: "one"},
{label: "预备党员", prop: "five"},
{label: "发展对象", prop: "four"},
{label: "积极分子", prop: "three"},
{label: "申请入党", prop: "two"},
].map(e => ({...e, v: this.info.memberCount?.[e.prop] || 0}))
},
organizationCounts() {
return this.info.organizationCount || []
},
leaderList() {
return this.info?.leaderList?.filter(v => ['1', '2', '3', '4', '5'].includes(v.partyPosition)) || []
},
editOps() {
let initData = [
{
label: "编辑党组织", permit: "admin_syspartyorganization_edit", icon: "iconEdit",
foo: op => {
if (this.selectedOrg?.id) {
this.dialog = true
this.currentEditOp = op
this.orgForm = JSON.parse(JSON.stringify(this.selectedOrg))
} else {
this.$message.error('请选择党组织')
}
}
},
{
label: "新增下级党组织", permit: "admin_syspartyorganization_add", icon: "iconAdd_Subordinates",
foo: op => {
if (this.selectedOrg?.id) {
this.dialog = true
this.currentEditOp = op
this.orgForm.parentId = this.selectedOrg?.id
this.orgForm.parentName = this.selectedOrg?.name
} else {
this.$message.error('请选择党组织')
}
}
},
{
label: "新增同级党组织", permit: "admin_syspartyorganization_add", icon: "iconAdd_Peers",
foo: op => {
let parent = this.orgTreeRef.getNode(this.selectedOrg)?.parent?.data
if (parent) {
this.dialog = true
this.currentEditOp = op
this.orgForm.parentId = parent?.id
this.orgForm.parentName = parent?.name
} else {
this.$message.error("不能增加同级根组织!")
}
}
},
{
label: "删除党组织", permit: "admin_syspartyorganization_del", icon: "iconDelete",
foo: () => {
if (this.selectedOrg?.id) {
let {id} = this.selectedOrg
this.$confirm("确定需要删除该党组织吗?", {type: "error"}).then(() => {
this.instance.post('/app/partyOrganization/deletePartyOrganization', null, {
params: {id}
}).then(res => {
if (res?.code == 0) {
this.$message.success('删除成功');
this.orgTreeRef.remove(this.selectedOrg)
if (!!this.selectedOrg?.parentId) {
this.orgTreeRef.setCurrentKey(this.selectedOrg.parentId)
this.handleNodeClick(this.orgTreeRef.getCurrentNode())
} else {
this.selectedOrg = {}
}
}
})
})
} else {
this.$message.error('请选择党组织')
}
}
},
].map(e => ({
...e, foo: p => {
this.showContextmenu = false
e.foo(p)
}
}))
return initData.filter(e => this.permissions(e.permit))
},
rules() {
return {
name: [
{required: true, message: '请填写党组织名称', trigger: 'blur'}
],
partyType: [
{required: true, message: '请填写组织级别', trigger: 'change'}
],
orgType: [
{required: true, message: '请填写组织类别', trigger: 'change'}
],
createTime: [
{required: true, message: '请填写建立时间', trigger: 'blur'}
]
}
},
orgTreeRef() {
return this.$refs.orgTree?.$refs?.partyTree || {}
},
fullOrgName() {
let current = this.orgTreeRef.getNode(this.selectedOrg),
names = []
const getName = e => {
if (e.data?.name) {
names.push(e.data.name)
if (e.parent) {
getName(e.parent)
}
}
}
if (current) {
getName(current)
}
return names?.reverse()?.join(" / ")
}
},
filters: {
timeVal(val) {
if (val) {
return dayjs(val).format('YYYY-MM-DD');
} else {
return '-'
}
}
},
methods: {
// 查询党组织人员信息
getOrgInfo() {
let {id} = this.selectedOrg
return this.instance.post('/app/partyOrganization/detail', null, {
params: {id}
}).then(res => {
if (res?.data) {
this.info = res.data
}
})
},
// 党员详情
memberDetailList(index) {
this.detailType = index;
this.isCheckMember = true;
this.instance.post(index == 1 ? `/app/appparty/list` : `/app/apppartydevelop/list`, null, {
params: {
...this.searchObj,
partyOrgId: this.selectedOrg?.id
}
}).then((res) => {
this.tableData = res.data.records;
this.total = res.data.total;
})
},
handleSizeChange(val) {
this.searchObj.size = val;
this.memberDetailList(this.detailType);
},
handleChange(val) {
this.searchObj.current = val;
this.memberDetailList(this.detailType);
},
// 导出
exportExcel() {
this.instance.post('/app/partyOrganization/export', null, {
responseType: "blob",
params: {id: this.selectedOrg?.id}
}).then((res) => {
const link = document.createElement("a");
let blob = new Blob([res], {
type: "application/vnd.ms-excel"
});
link.style.display = "none";
link.href = URL.createObjectURL(blob);
let num = "";
for (let i = 0; i < 10; i++) {
num += Math.ceil(Math.random() * 10);
}
link.setAttribute("download", "党组织列表" + num + ".xls");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
},
handleContextmenu(e, data) {
this.handleNodeClick(data).then(() => {
if (e.which == 3) {
this.contextmenuPos = {top: (e.y + 16) + 'px', left: e.x + 'px'}
this.$nextTick(() => this.showContextmenu = true)
}
})
},
submitOrg() {
this.$refs.orgForm.validate(v => {
if (v) {
this.instance.post('/app/partyOrganization/updatePartyOrganization', this.orgForm).then(res => {
if (res?.data) {
this.dialog = false;
this.handleNodeClick(res.data)
if (this.orgForm.id) {
this.$message.success('修改成功')
let node = this.orgTreeRef.getNode(this.selectedOrg)
node.data = res.data
} else {
this.$message.success('添加成功')
this.orgTreeRef.append(res.data, res.data.parentId)
}
}
})
}
});
},
handleNodeClick(org) {
this.showContextmenu = false
if (org) {
this.selectedOrg = org
if (!this.selectedOrg?.parentName) {
let parent = this.orgTreeRef.getNode(this.selectedOrg)?.parent?.data
this.selectedOrg.parentName = parent?.name
}
return this.getOrgInfo()
}
}
},
created() {
if (this.hasPartyOrg) {
this.dict.load('orgType', 'orgPartyType', 'flowStatus', 'partyPosition', 'partyStatus', 'sex');
}
}
}
</script>
<style scoped lang="scss">
.AppPartyOrganization {
height: 100%;
.iconParent {
color: #8899BB;
margin-right: 8px;
}
:deep( .AiTreeMenu ){
.bottomBar {
width: 100%;
display: flex;
align-items: center;
justify-content: space-around;
height: 32px;
border-top: 1px solid #E5E5E5;
background: #fff;
.iconfont {
cursor: pointer;
&:hover {
color: #26f;
}
&.iconDelete:hover {
color: #f46;
}
}
.treePanel {
padding-bottom: 32px;
}
}
.contextmenu {
background: #fff;
border-radius: 2px;
font-size: 12px;
padding: 8px;
position: fixed;
z-index: 999;
li {
height: 28px;
line-height: 28px;
cursor: pointer;
text-indent: 8px;
}
li:hover {
background-color: #EFF6FF;
color: #5088FF;
}
}
.tipInfo {
height: 32px;
background: #FFF3E8;
border-radius: 4px;
color: #FF8822;
font-size: 12px;
border: 1px solid #f82;
display: flex;
align-items: center;
padding: 0 8px;
gap: 8px;
margin-bottom: 10px;
}
}
.el-form-item {
.el-date-editor {
width: 100%;
}
}
:deep( .ai-wrapper ){
.AiTitle {
width: 100%;
margin-bottom: 10px;
}
.iconProlife {
font-size: 14px;
margin-right: 4px;
}
.imgUl {
display: flex;
flex-wrap: wrap;
font-size: 14px;
text-align: center;
li {
padding: 0 16px 16px 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.el-row {
width: 80px;
background: #ddd;
padding: 16px 0;
}
}
.el-table {
flex: none;
border-left: 1px solid #D0D4DC;
border-top: 1px solid #D0D4DC;
}
}
:deep( .ai-list__content--right ){
margin-left: 1px;
.ai-list__content--right-wrapper {
position: relative;
// height: 100%;
.ai-empty {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
transform: translate(-50%, -50%);
.ai-empty__bg {
margin-top: 0;
}
}
}
}
:deep( .is-current>.el-tree-node__content){
width: 100%!important;
padding-right: 16px!important;
}
}
</style>