map/ui/dasadmin/src/views/backend/auth/org/index.vue
2024-10-22 14:04:02 +08:00

714 lines
24 KiB
Vue

<template>
<div class="institutionalManagement">
<el-dialog v-model="dialogVible" :title="dialogTitle" width="600">
<el-form :model="formModel" ref="formRef">
<template v-for="item in addFormItemList" :key="item.prop">
<el-form-item :prop="item.prop" :label="item.label" label-width="80" :rules="item.rules">
<template v-if="item.type === 'input'">
<el-input :disabled="formDisabled" v-model="formModel[item.prop]" :placeholder="item.placeholder"></el-input>
</template>
<template v-if="item.type === 'custom'">
<el-select
v-if="item.prop === 'province'"
:disabled="formDisabled"
v-model="formModel[item.prop]"
:placeholder="item.placeholder"
@change="changeProvince"
>
<el-option v-for="opt in provinceOptions" :key="opt.value" :label="opt.label" :value="opt.value"></el-option>
</el-select>
<el-select
v-if="item.prop === 'county'"
:disabled="formDisabled"
v-model="formModel[item.prop]"
:placeholder="item.placeholder"
@change="changeCounty"
>
<el-option v-for="opt in countyOptions" :key="opt.value" :label="opt.label" :value="opt.value"></el-option>
</el-select>
<el-select
v-if="item.prop === 'city'"
:disabled="formDisabled"
v-model="formModel[item.prop]"
:placeholder="item.placeholder"
>
<el-option v-for="opt in cityOptions" :key="opt.value" :label="opt.label" :value="opt.value"></el-option>
</el-select>
<el-tree-select
v-if="item.prop === 'parentOrgId'"
v-model="formModel[item.prop]"
:disabled="formDisabled"
lazy
:load="loadSelectTreeData"
check-strictly
value-key="id"
node-key="id"
:props="treeSelectReplaceProps"
:placeholder="item.placeholder"
></el-tree-select>
</template>
</el-form-item>
</template>
</el-form>
<template #footer>
<el-button @click="closeAddForm">取消</el-button>
<el-button type="primary" @click="submitAddForm" :disabled="formDisabled">提交</el-button>
</template>
</el-dialog>
<el-container class="defaultContainer">
<el-aside class="defaultAside">
<!-- <el-header class="treeHeader">
<el-input v-model="searchInputTreeValue" :placeholder="treeSearchInputPlaceholder" class="searchInput"></el-input>
</el-header> -->
<el-main class="treeMain">
<el-tree
class="treePart"
ref="treeRef"
:data="treeData"
lazy
highlight-current
:load="loadTreeData"
node-key="id"
:props="treeReplaceProps"
@node-click="treeNodeClick"
@node-contextmenu="rightClick"
></el-tree>
</el-main>
</el-aside>
<el-container class="defaultMainContainer">
<el-header class="defaultHeader">
<div class="searchPart">
<el-input v-model="searchTableInput" class="searchInput"></el-input>
<el-button @click="searchTable" type="primary" :icon="Search" class="defaultBtn">{{ t('management.search') }}</el-button>
</div>
<el-button type="primary" :icon="Plus" class="defaultBtn" @click="addInstitutional(false)">{{ t('management.add') }}</el-button>
</el-header>
<el-main class="defaultMain">
<el-table :data="tableData" class="tablePart">
<el-table-column
v-for="item in tableColumn"
:key="item.key"
:prop="item.prop"
:label="item.label"
:fixed="item.fixed"
:align="item.align ?? 'center'"
></el-table-column>
<el-table-column fixed="right" label="操作" min-width="80" align="center">
<template #default="scope">
<div class="tableOperate">
<a @click="editForm(scope.row)">编辑</a>
<a>|</a>
<el-popconfirm title="确定删除么?" @confirm="delForm(scope.row)">
<template #reference>
<a>删除</a>
</template>
</el-popconfirm>
</div>
</template>
</el-table-column>
</el-table>
<div class="mainFooter">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="currentPageSize"
:total="pageTotal"
:page-sizes="pagePagination"
background
:pager-count="7"
layout="prev, pager, next, jumper,sizes,total"
></el-pagination>
</div>
</el-main>
</el-container>
</el-container>
<ContextMenu v-model:visible="contextMenuVisible" :pos="contextMenuPos">
<template #default>
<div class="modelOperate">
<el-button @click="editForm(rightClickMenuData!, true)" :icon="Reading">查看</el-button>
<el-button @click="addInstitutional(true)" :icon="DocumentAdd">新增</el-button>
<el-button @click="editForm(rightClickMenuData!)" :icon="DocumentChecked">修改</el-button>
<el-popconfirm title="确认删除?" @confirm="delForm(rightClickMenuData!)">
<template #reference>
<el-button :icon="DocumentDelete" @click.stop>删除</el-button>
</template>
</el-popconfirm>
</div>
</template>
</ContextMenu>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, reactive, computed, nextTick } from 'vue'
import { Reading, DocumentAdd, DocumentChecked, DocumentDelete } from '@element-plus/icons-vue'
import {
ElContainer,
ElAside,
ElHeader,
ElMain,
ElInput,
ElButton,
ElTable,
ElTree,
ElDialog,
ElForm,
ElFormItem,
ElSelect,
ElOption,
ElPopconfirm,
ElMessage,
ElPagination,
} from 'element-plus'
import type { FormInstance, TreeInstance, TreeNode } from 'element-plus'
import type Node from 'element-plus/es/components/tree/src/model/node'
import { Plus, Search } from '@element-plus/icons-vue'
import {
getInstitutionalListReq,
addInstitutionalListReq,
changeInstitutionalListReq,
delInstitutionalListReq,
getInstitutionalTreeListReq,
} from '/@/api/backend/org/request'
import {
getDataType,
addDataEnum,
addDataType,
formItemListType,
addDataEnumKeyJointType,
tableColumnType,
changeDataType,
selectDataType,
getTreeDataReturnType,
allEnumType,
} from './type'
import ContextMenu from '/@/views/backend/auth/model/contextMenu.vue'
import { pcaTextArr } from 'element-china-area-data'
import { useAdminInfo } from '/@/stores/adminInfo'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const adminInfo = useAdminInfo()
// const treeSearchInputPlaceholder = '搜索机构'
// const searchInputTreeValue = ref<string>('')
const formRef = ref<FormInstance>()
const defaultFormModel = {
mrid: '',
name: '',
aliasName: '',
province: '',
city: '',
county: '',
address: '',
contactPhone: '',
remarks: '',
parentOrgId: null,
revision: 1,
}
const formModel = ref<addDataType | changeDataType>(JSON.parse(JSON.stringify(defaultFormModel)))
const provinceOptions: selectDataType[] = pcaTextArr
const countyOptions = ref<selectDataType[]>([])
const cityOptions = ref<selectDataType[]>([])
const changeProvince = (value: string) => {
const selectOptions = provinceOptions.find((item) => item.value === value)?.children
selectOptions && (countyOptions.value = selectOptions)
formModel.value.city = ''
formModel.value.county = ''
}
const changeCounty = (value: string) => {
const selectOptions = countyOptions.value.find((item) => item.value === value)?.children
selectOptions && (cityOptions.value = selectOptions)
formModel.value.city = ''
}
const phoneReg = /^1(3|4|5|7|8|9)\d{9}$/
const phoneRule = (rule: any, value: any, callback: any) => {
if (!value) {
callback(new Error('请输入手机号'))
} else if (!phoneReg.test(value)) {
callback(new Error('请输入正确的手机号'))
} else {
callback()
}
}
const addFormItemList: formItemListType<addDataEnumKeyJointType>[] = [
{
type: 'input',
prop: 'mrid',
label: addDataEnum['mrid'],
placeholder: `请输入${addDataEnum['mrid']}`,
rules: [{ required: true, message: `请输入${addDataEnum['mrid']}`, trigger: 'blur' }],
},
{
type: 'input',
prop: 'name',
label: addDataEnum['name'],
placeholder: `请输入${addDataEnum['name']}`,
rules: [{ required: true, message: `请输入${addDataEnum['name']}`, trigger: 'blur' }],
},
{
type: 'input',
prop: 'aliasName',
label: addDataEnum['aliasName'],
placeholder: `请输入${addDataEnum['aliasName']}`,
rules: [{ required: true, message: `请输入${addDataEnum['aliasName']}`, trigger: 'blur' }],
},
{
type: 'custom',
prop: 'province',
label: addDataEnum['province'],
placeholder: `请选择${addDataEnum['province']}`,
rules: [{ required: true, message: `请选择${addDataEnum['province']}`, trigger: 'blur' }],
},
{
type: 'custom',
prop: 'county',
label: addDataEnum['county'],
placeholder: `请选择${addDataEnum['county']}`,
rules: [{ required: true, message: '请输入机构名称', trigger: 'blur' }],
},
{
type: 'custom',
prop: 'city',
label: addDataEnum['city'],
placeholder: `请选择${addDataEnum['city']}`,
rules: [{ required: true, message: `请选择${addDataEnum['city']}`, trigger: 'blur' }],
},
{
type: 'input',
prop: 'address',
label: addDataEnum['address'],
placeholder: `请输入${addDataEnum['address']}`,
rules: [{ required: true, message: `请输入${addDataEnum['address']}`, trigger: 'blur' }],
},
{
type: 'input',
prop: 'contactPhone',
label: addDataEnum['contactPhone'],
placeholder: `请输入${addDataEnum['contactPhone']}`,
// rules: [{ required: true, validator: phoneRule, trigger: 'blur' }],
},
{
type: 'custom',
prop: 'parentOrgId',
label: addDataEnum['parentOrgId'],
placeholder: `请选择${addDataEnum['parentOrgId']}`,
// rules: [{ required: true, message: `请选择${addDataEnum['parentOrgId']}`, trigger: 'blur' }],
},
{
type: 'input',
prop: 'remarks',
label: addDataEnum['remarks'],
placeholder: `请输入${addDataEnum['remarks']}`,
// rules: [{ required: true, message: `请输入${addDataEnum['remarks']}`, trigger: 'blur' }],
},
]
const dialogTitle = ref('新增机构')
const dialogVible = ref(false)
const addInstitutional = (rightClick = false) => {
dialogTitle.value = '新增机构'
formModel.value = JSON.parse(JSON.stringify(defaultFormModel))
formRef.value && formRef.value.resetFields()
dialogVible.value = true
if (!rightClick) {
formModel.value.parentOrgId = clickTreeMenuData.value?.id!
}
formDisabled.value = false
}
const submitAddForm = () => {
console.log(formModel.value)
if (!formRef.value) return
formRef.value.validate((valid: boolean) => {
if (valid) {
if (dialogTitle.value === '新增机构') {
formModel.value.parentOrgId = formModel.value.parentOrgId ?? '0'
addInstitutionalListReq(formModel.value)
.then((res) => {
if (res.success) {
ElMessage.success('新增成功')
getInstitutionList({parentOrgId:rightClickMenuData.value?.parentOrgId})
dialogVible.value = false
refreshTreeData(formModel.value.parentOrgId)
} else {
ElMessage.error(res?.msg ?? '新增失败')
}
})
.catch((err) => {
ElMessage.error(err?.response?.data?.msg ?? '新增失败')
})
} else if (dialogTitle.value === '编辑机构') {
changeInstitutionalListReq(formModel.value as changeDataType)
.then((res) => {
if (res.success) {
ElMessage.success('编辑成功')
getInstitutionList({parentOrgId:rightClickMenuData.value?.parentOrgId})
dialogVible.value = false
refreshTreeData(rightClickMenuData.value!.parentOrgId).then(() => {
refreshTreeData(formModel.value.parentOrgId)
})
} else {
ElMessage.error(res?.msg ?? '编辑失败')
}
})
.catch((err) => {
ElMessage.error(err?.response?.data?.msg ?? '编辑失败')
})
}
}
})
}
const closeAddForm = () => {
dialogVible.value = false
}
const getInstitutionList = (data: getDataType = { name: null }) => {
getInstitutionalListReq(data).then((res) => {
pageTotal.value = res.total
console.log(res.rows);
originData.value = res.rows.map(item=>{
return {
...item,
parentOrgName:item.parentOrgName ? item.parentOrgName : '无'
}
})
})
}
const pagePagination = [ 10, 20, 30]
const currentPage = ref(1)
const currentPageSize = ref(pagePagination[1])
const pageTotal = ref(0)
const originData = ref<getTreeDataReturnType[]>()
const tableData = computed(() => {
const start = (currentPage.value - 1) * currentPageSize.value
const end = start + currentPageSize.value
return originData.value?.slice(start, end)
})
const tableColumn: tableColumnType<allEnumType>[] = [
{
key: 'mridColumn',
prop: 'mrid',
label: addDataEnum['mrid'],
},
{
key: 'nameColumn',
prop: 'name',
label: addDataEnum['name'],
},
{
key: 'aliasNameColumn',
prop: 'aliasName',
label: addDataEnum['aliasName'],
},
{
key: 'provinceColumn',
prop: 'province',
label: addDataEnum['province'],
},
{
key: 'cityColumn',
prop: 'city',
label: addDataEnum['city'],
},
{
key: 'countyColumn',
prop: 'county',
label: addDataEnum['county'],
},
{
key: 'addressColumn',
prop: 'address',
label: addDataEnum['address'],
},
{
key: 'contactPhoneColumn',
prop: 'contactPhone',
label: addDataEnum['contactPhone'],
},
{
key: 'remarksColumn',
prop: 'remarks',
label: addDataEnum['remarks'],
},
{
key: 'parentOrgNameColumn',
prop: 'parentOrgName',
label: addDataEnum['parentOrgName'],
},
]
const formDisabled = ref(false)
const editForm = (column: getTreeDataReturnType, onlyOpen = false) => {
formRef.value?.resetFields()
formModel.value = JSON.parse(JSON.stringify(column))
dialogTitle.value = '编辑机构'
dialogVible.value = true
formDisabled.value = onlyOpen
}
const delForm = (column: getTreeDataReturnType) => {
delInstitutionalListReq({ id: column.id })
.then((res) => {
if (res.success) {
ElMessage.success('删除成功')
getInstitutionList({parentOrgId:rightClickMenuData.value?.parentOrgId})
refreshTreeData(column.parentOrgId)
} else {
ElMessage.error(res?.msg ?? '删除失败')
}
})
.catch((err) => {
ElMessage.error(err?.response?.data?.msg ?? '删除失败')
})
}
const treeRef = ref<TreeInstance>()
const treeData = ref<getTreeDataReturnType[]>()
const treeReplaceProps = {
children: 'children',
label: 'name',
}
const treeSelectReplaceProps = {
label: 'name',
children: 'children',
isLeaf: 'isLeaf',
}
const loadTreeData = (node: Node, resolve: any) => {
if (node.level === 0) {
return
}
getTreeData(node.data.id)
.then((res) => {
if (!res.length) {
node.data.isLeaf = true
}
pageTotal.value = res.length
originData.value = [...res]
return resolve(res)
})
.catch((err) => {
console.log(err)
})
}
const loadSelectTreeData = (node: Node, resolve: any) => {
if (node.level === 0) {
return getTreeData(null)
.then((res) => {
if (!res.length) {
node.data.isLeaf = true
}
resolve([{ id: '0', name: '无', isLeaf: true }, ...res])
})
.catch((err) => {
console.log(err)
})
}
getTreeData(node.data.id)
.then((res) => {
if (!res.length) {
node.data.isLeaf = true
}
return resolve(res)
})
.catch((err) => {
console.log(err)
})
}
const getTreeData = (orgId: number | string | null) => {
return new Promise((resolve: (data: getTreeDataReturnType[]) => unknown) => {
getInstitutionalTreeListReq({ parentOrgId: orgId }).then((res) => {
if (res.data) {
resolve(res.data)
} else {
resolve([])
}
})
})
}
const initData = () => {
getTreeData(null)
.then((res) => {
console.log(res)
treeData.value = [...res]
console.log(treeData.value)
nextTick(() => {
treeRef.value?.setCurrentKey(res[0]?.id!, false)
clickTreeMenuData.value = res[0]
})
return
})
.then(() => {
return getTreeData(adminInfo.orgid)
})
.then((res) => {
pageTotal.value = res.length
originData.value = [...res]
})
}
const clickTreeMenuData = ref<getTreeDataReturnType>()
const refreshTreeData = (parentOrgId: string | number | null) => {
return new Promise((resolve) => {
const data = parentOrgId === 0 || parentOrgId === '0' ? null : parentOrgId
getTreeData(data).then((res) => {
if (data) {
treeRef.value?.updateKeyChildren(parentOrgId!, res)
} else {
treeData.value = [...res]
}
resolve(true)
})
})
}
const treeNodeClick = (nodeData: getTreeDataReturnType, node: Node) => {
if (node.childNodes.length || nodeData.isLeaf) {
getTreeData(nodeData.id).then((res) => {
pageTotal.value = res.length
originData.value = [...res]
})
}
clickTreeMenuData.value = nodeData
}
const rightClickMenuData = ref<getTreeDataReturnType>()
const rightClickNodeLevel = ref(0)
const contextMenuVisible = ref(false)
const contextMenuPos = reactive({
x: 0,
y: 0,
})
const rightClick = (event: any, data: getTreeDataReturnType, node: TreeNode) => {
contextMenuPos.x = event.pageX
contextMenuPos.y = event.pageY
contextMenuVisible.value = true
rightClickMenuData.value = data
rightClickNodeLevel.value = node.level!
}
const searchTableInput = ref('')
const searchTable = () => {
// if (searchTableInput.value === '') return
getInstitutionList({ name: searchTableInput.value, parentOrgId: clickTreeMenuData.value!.id! })
}
onMounted(() => {
initData()
})
</script>
<style lang="scss" scoped>
@mixin searchInput($value) {
margin-right: $value;
width: 220px;
height: 40px;
}
$defaultHeaderHeight: 60px;
$defaultMainHeight: calc(100% - 60px);
$paginationHeight: 32px;
.institutionalManagement {
width: 100%;
height: 100%;
// background-color: #fff;
.defaultContainer {
height: 100%;
.defaultAside {
width: 260px;
height: 100%;
border-right: 1px solid #eaebed;
// .treeHeader {
// display: flex;
// align-items: center;
// justify-content: center;
// height: $defaultHeaderHeight;
// .searchInput {
// @include searchInput(0);
// }
// }
.treeMain {
padding-top: 10px;
height: 100%;
.treePart {
height: 100%;
}
}
}
.defaultMainContainer {
height: 100%;
.defaultHeader {
display: flex;
justify-content: space-between;
align-items: center;
height: $defaultHeaderHeight;
.searchPart {
display: flex;
justify-content: space-between;
align-items: center;
}
.defaultBtn {
width: 88px;
height: 40px;
}
.searchInput {
@include searchInput(10px);
}
}
.defaultMain {
height: $defaultMainHeight;
.tablePart {
height: calc(100% - $paginationHeight);
}
.tableOperate {
display: flex;
justify-content: center;
align-items: center;
a {
margin: 5px;
color: #0064aa;
font-weight: 600;
&:hover {
cursor: pointer;
}
}
}
.mainFooter {
display: flex;
justify-content: right;
background-color: #fff;
}
}
}
}
.modelOperate {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
width: 80px;
height: 150px;
.el-button {
margin: 0;
}
}
}
.addOrgPopover {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
height: 70px;
.el-button {
margin: 0;
}
}
</style>