123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630 |
- <template>
- <span>
- <a-spin ref="scroll" :spinning="false" :class="$style.spin">
- <a-empty v-if="empty" />
- <a-dropdown
- v-else
- v-model="showMenu"
- :get-popup-container="() => this.$refs.scroll.$el"
- :trigger="['contextmenu']"
- :disabled="single"
- @visibleChange="menuVisibleChange"
- >
- <div>
- <a-tree
- ref="auditMattersTree"
- v-model="checkedKeys"
- :show-icon="true"
- :show-line="true"
- :check-strictly="true"
- :expanded-keys="expandedKeys"
- :default-expanded-keys="defaultTreeExpandedKeys"
- :checkable="checkable"
- :tree-data="treeData"
- :load-data="onLoadData"
- @click.native="treeClickNative"
- @select="treeSelect"
- @check="treeCheck"
- @rightClick="treeRightClick"
- @contextmenu.native.capture="treeRightClickNative"
- @expand="onExpand"
- >
- <!-- 如果已配置负责人,则展示用户图标 -->
- <template slot="showMatters" slot-scope="item">
- <a-icon type="file-ppt" @click="showMatters(item)" />
- </template>
- </a-tree>
- </div>
- <a-menu slot="overlay" @click="menuClick">
- <a-menu-item key="1" :disabled="!selectedNodeHasSelectableChild">
- <a-icon type="check" />选中下一级节点
- </a-menu-item>
- <a-menu-item key="2" :disabled="!selectedNodeHasSelectableChild">
- <a-icon type="close" />取消下一级节点
- </a-menu-item>
- </a-menu>
- </a-dropdown>
- </a-spin>
- </span>
- </template>
- <script>
- import cloneDeep from 'lodash.clonedeep'
- import { getUserInfo } from '@/common/store-mixin'
- import icTreeService from '../ic-tree-service'
- import components from './_import-components/iam-item-tree-import'
- // 判断是否已经选择
- function isChecked(selectedKeys, eventKey) {
- return selectedKeys.indexOf(eventKey) === -1
- }
- export default {
- name: 'IamItemTree',
- metaInfo: {
- title: 'IamItemTree',
- },
- components,
- props: {
- /**
- * <p>获取数据的回调,获取根节点时,parentId为undefined</p>
- * <pre>(parentId,parent) => childrenItems</pre>
- */
- loadTreeData: {
- type: Function,
- required: true,
- },
- // 默认选中节点
- selectedKeys: {
- type: Array,
- default: function() {
- return []
- },
- },
- // 是否显示复选框
- checkable: {
- type: Boolean,
- default: true,
- },
- // 是否可以拖拽
- draggable: {
- type: Boolean,
- default: false,
- },
- // 是否显示连线
- showLine: {
- type: Boolean,
- default: false,
- },
- // 根节点名称
- topNodeText: {
- type: String,
- default: '根节点',
- },
- // 地址树接口数据源
- treeparams: {
- type: Object,
- default: () => {
- return {}
- },
- },
- // 默认展开节点id
- defaultExpandedKeys: {
- type: Array,
- default: undefined,
- },
- // 是否显示隐藏按钮
- showPrimary: {
- type: Boolean,
- default: true,
- },
- // 地址树是否单选
- single: {
- type: Boolean,
- default: false,
- },
- refreshKey: {
- type: Number,
- default: 0,
- },
- treeDataType: {
- type: String,
- default: '',
- },
- types: {
- type: String,
- default: 'NK',
- },
- versionId: {
- type: String,
- default: '',
- },
- orgId: {
- type: String,
- default: '',
- },
- orgName: {
- type: String,
- default: '',
- },
- selecttype: {
- type: String,
- default: 'control',
- },
- optionValue: {
- type: String,
- default: 'id',
- },
- /**
- * @ignore
- */
- optionLabel: {
- type: String,
- default: 'name',
- },
- isAbandonment: {
- type: String,
- default: 'NO',
- },
- },
- data() {
- return {
- defaultTopNodeId: -1,
- treeData: [],
- checkedKeys: {
- checked: [],
- halfChecked: [],
- }, // 选中的节点数据
- dataList: [], // 数组dataList,搜索要用
- spinning: true,
- empty: false,
- icontype: 'left',
- fold: false,
- // replaceFields: {
- // title: 'text',
- // key: 'code',
- // },
- openId: [], // 已经打开过的id
- defaultTreeExpandedKeys: ['-1'],
- expandedKeys: ['-1'],
- defaultTopNodeText: '根节点',
- key: 0,
- newtree: [],
- depOptions: [], // 部门下拉框列表值
- edit: true, // 当前节点是否可编辑
- depvalue: [], // 选择的组织数据
- selectedNode: undefined,
- showMenu: false,
- setAllChecking: false,
- }
- },
- computed: {
- selectedNodeHasSelectableChild() {
- return this.selectedNode?.dataRef.children?.some((item) => !item.disabled)
- },
- },
- created() {
- this.initTreeData()
- },
- methods: {
- treeRightClickNative(evt) {
- // 右键如果没有点击到树节点,不触发右键菜单
- if (this.single) return
- if (evt.target.nodeName !== 'SPAN') evt.stopPropagation()
- },
- treeClickNative() {
- // 点击树的其他区域,隐藏菜单
- if (this.single) return
- this.hideContextMemu()
- },
- menuClick(menu) {
- this.selectedNode.dataRef.children?.forEach((item) => {
- if (!item.disabled) this.itemSelect(item.id + '', menu.key === '1')
- })
- this.hideContextMemu()
- },
- itemSelect(key, checked) {
- if (checked) {
- if (!this.checkedKeys.checked.includes(key)) {
- this.checkedKeys.checked.push(key)
- }
- } else {
- this.checkedKeys.checked.splice(this.checkedKeys.checked.indexOf(key), 1)
- }
- },
- hideContextMemu() {
- this.showMenu = false
- this.menuVisibleChange(false)
- },
- menuVisibleChange(visible) {
- if (!visible) this.selectedNode = undefined
- },
- treeRightClick({ node }) {
- // 记录当前点击的节点
- if (this.single) return
- this.selectedNode = node
- },
- // 选中当前节点下的所有节点
- checkAllNode(nodeinfo, checked) {
- if (nodeinfo.children) {
- nodeinfo.children.forEach((node) => {
- if (checked) {
- if (isChecked(this.checkedKeys.checked, node.id + '')) {
- this.checkedKeys.checked.push(node.id + '')
- }
- } else {
- if (this.checkedKeys.checked.indexOf(node.id + '') !== -1) {
- this.checkedKeys.checked.splice(this.checkedKeys.checked.indexOf(node.id + ''), 1)
- }
- }
- // 下级节点也要处理
- if (node.children) {
- this.checkAllNode(node, checked)
- }
- })
- }
- },
- /***
- * 选中复选框时的事件
- */
- treeCheck(allKeys, echecked) {
- // echecked.checkedNodes 选中的所有节点信息为数组 .data.props 获取详细信息
- // echecked.node.dataRef 当前选中的节点信息
- const params = {
- auditOrgId: parseInt(this.orgId),
- versionId: parseInt(this.versionId),
- isAbandonment: this.isAbandonment,
- }
- if (this.single) {
- this.checkedKeys.checked = []
- this.checkedKeys.checked = [echecked.node.dataRef.id + '']
- }
- // 勾选复选框,则直接获取下级数据
- if (this.checkedKeys.checked.includes(echecked.node.dataRef.id + '')) {
- // 如果是事项,则不取下级
- // if (echecked.node.dataRef.props.isEnd === '1') return
- this.$emit('checking', true)
- if (this.selecttype === 'cross') {
- icTreeService
- .getCategoryTree(echecked.node.dataRef.id, params, this.types)
- .then((res) => {
- res.data.forEach((item) => {
- item.title = item.text
- item.code = item.id.toString()
- if (item.props.isEnd === '0') {
- item.isLeaf = false
- item.cat = true
- } else {
- item.cat = false
- this.isendids.push(item.id.toString())
- }
- })
- this.onCheckedLoadData(echecked.node, res.data)
- })
- } else {
- icTreeService.getMeasureTree(echecked.node.dataRef.id, params, this.types).then((res) => {
- res.data.forEach((item) => {
- item.title = item.text
- item.code = item.id.toString()
- if (item.props.disabled) {
- item.isLeaf = false
- item.cat = true
- } else {
- item.cat = false
- }
- })
- this.onCheckedLoadData(echecked.node, res.data)
- })
- }
- }
- // 判断当前节点是否选中,选中的话,就把下级节点也一并选中,否则都去掉
- if (allKeys.checked.includes(echecked.node.dataRef.id + '')) {
- this.checkAllNode(echecked.node.dataRef, true)
- } else {
- this.checkAllNode(echecked.node.dataRef, false)
- }
- this.$emit('checkedKeys', echecked.node.dataRef, echecked.checkedNodes)
- },
- // 点击树
- treeSelect(selectedKeys, info) {
- this.defaultSelectedKeys = selectedKeys
- if (this.single) {
- this.checkedKeys = []
- this.checkedKeys = [info.node.dataRef.id + '']
- } else {
- if (isChecked(this.checkedKeys.checked, info.node.dataRef.id + '')) {
- this.checkedKeys.checked.push(info.node.dataRef.id + '')
- } else {
- this.checkedKeys.checked.splice(
- this.checkedKeys.checked.indexOf(info.node.dataRef.id + ''),
- 1
- )
- }
- this.checkedKeys.checked = [...new Set(this.checkedKeys.checked)]
- }
- // 判断当前节点是否选中,选中的话,就把下级节点也一并选中,否则都去掉
- if (this.checkedKeys.checked.includes(info.node.dataRef.id + '')) {
- this.checkAllNode(info.node.dataRef, true)
- } else {
- this.checkAllNode(info.node.dataRef, false)
- }
- this.$emit('treeSelect', [...selectedKeys, ...this.checkedKeys.checked], info)
- },
- transformData(data) {
- return data.map((d) => {
- const { children, checkable, selectable, isLeaf, ...rest } = d
- return {
- ...rest,
- checkable: checkable ?? true,
- selectable: selectable ?? false,
- isLeaf: isLeaf ?? true,
- key: d[this.optionValue],
- children: children && this.transformData(children),
- originalValue: rest,
- code: rest.code,
- }
- })
- },
- // 点击地址树展开时调用
- onLoadData(treeNode) {
- const params = {
- auditOrgId: parseInt(this.orgId),
- versionId: parseInt(this.versionId),
- isAbandonment: this.isAbandonment,
- }
- if (this.selecttype === 'cross') {
- if (treeNode.dataRef.children !== null && treeNode.dataRef.children.length > 0) {
- console.log('有子节点,不请求')
- return new Promise((resolve) => {
- resolve()
- })
- } else {
- return icTreeService
- .getCategoryTree(treeNode.dataRef.id, params, this.types)
- .then((res) => {
- res.data.forEach((item) => {
- item.title = item.text
- item.code = item.id.toString()
- if (item.props.isEnd === '0') {
- item.isLeaf = false
- item.cat = true
- } else {
- item.cat = false
- this.isendids.push(item.id.toString())
- }
- })
- treeNode.dataRef.children = this.transformData(res.data)
- this.treeData = [...this.treeData]
- })
- }
- } else {
- if (treeNode.dataRef.children !== null && treeNode.dataRef.children.length > 0) {
- console.log('有子节点,不请求')
- return new Promise((resolve) => {
- resolve()
- })
- } else {
- return icTreeService
- .getMeasureTree(treeNode.dataRef.id, params, this.types)
- .then((res) => {
- res.data.forEach((item) => {
- item.title = item.text
- item.code = item.id.toString()
- if (item.props.disabled) {
- item.isLeaf = false
- item.cat = true
- } else {
- item.cat = false
- }
- })
- treeNode.dataRef.children = this.transformData(res.data)
- this.treeData = [...this.treeData]
- })
- }
- }
- },
- // 点击地址树前复选框时候调用
- onCheckedLoadData(treeNode, children) {
- const id = parseInt(treeNode.dataRef.id)
- if (!this.openId.includes(id)) {
- this.openId.push(id)
- }
- if (children !== null) {
- treeNode.dataRef.children = [...children]
- }
- // 如果根节点是选中状态,则将下级节点也选中
- if (this.checkedKeys.checked.includes(id + '')) {
- this.transformCheckData(children)
- setTimeout(() => {
- this.$emit('checking', false)
- }, 1000)
- }
- this.treeData = this.transformData([...this.treeData])
- },
- transformCheckData(data) {
- data = data || []
- data.forEach((d) => {
- const checkid = this.checkedKeys.checked
- if (!checkid.includes(d.id + '')) {
- this.checkedKeys.checked.push(d.id + '')
- }
- const { children } = d
- this.transformCheckData(children)
- })
- },
- initTreeData(depId) {
- const params = {
- auditOrgId: parseInt(this.orgId),
- versionId: parseInt(this.versionId),
- }
- this.defaultTopNodeText = this.orgName
- icTreeService.getCategoryTree(this.defaultTopNodeId, params, this.types).then((res1) => {
- this.spinning = false
- res1.data.forEach((item) => {
- item.title = item.text
- item.code = item.id.toString()
- item.key = item.id.toString()
- item.cat = true
- item.isLeaf = false
- })
- const treeNode = [
- {
- id: this.defaultTopNodeId,
- text: this.defaultTopNodeText,
- code: this.defaultTopNodeId.toString(),
- isLeaf: false,
- props: {
- isroot: true,
- },
- title: this.defaultTopNodeText,
- children: res1.data,
- cat: true,
- },
- ]
- if (this.selecttype === 'cross') {
- treeNode.forEach((i) => {
- if (i.children) {
- i.children.forEach((c) => {
- if (c.props.isEnd === '0') {
- c.isLeaf = false
- c.cat = true
- } else {
- c.cat = false
- this.isendids.push(c.id.toString())
- }
- })
- }
- })
- }
- this.treeData = this.transformData(treeNode)
- this.expandedKeys = this.defaultTreeExpandedKeys
- this.$emit('checking', false)
- this.dataLoaded = true
- })
- },
- // 刷新树方法
- refreshTree() {
- this.key++
- },
- onExpand(expandedKeys) {
- // 用户点击展开时,取消自动展开效果
- this.expandedKeys = expandedKeys
- this.autoExpandParent = false
- },
- },
- }
- </script>
- <style module lang="scss">
- @use '@/common/design' as *;
- .depselect {
- width: 200px;
- }
- .spin {
- width: 100%;
- line-height: 30;
- }
- .ywlxtree {
- :global(.ant-tree-title) {
- display: inline-block;
- width: 100%;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- :global(.ant-input-search) {
- margin: 8px 0;
- overflow: hidden;
- }
- .active {
- color: $primary-color;
- }
- :global(.ant-select) {
- width: 100%;
- overflow: hidden;
- }
- }
- .treewrap {
- position: relative;
- display: flex;
- flex-direction: column;
- width: 20%;
- min-height: 100%;
- margin-right: $padding-lg;
- transition: width 0.2s;
- .fold {
- position: absolute;
- top: calc(50% - 30px);
- right: -15px;
- z-index: 2;
- width: 15px;
- height: 75px;
- padding: 0;
- border-radius: 0 10px 10px 0;
- }
- :global(.ant-tree) {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- :global(.ant-card-body) {
- background: $white;
- }
- }
- .collapse {
- width: 0;
- :global(.ant-card-body) {
- background: transparent;
- :global(.ant-empty) {
- display: none;
- }
- }
- }
- // 单选样式
- .single {
- :global .ant-tree-checkbox {
- .ant-tree-checkbox-inner {
- border-radius: 100px;
- &::after {
- position: absolute;
- top: 3px;
- left: 3px;
- display: table;
- width: 8px;
- height: 8px;
- content: ' ';
- background-color: $primary-color;
- border: 0;
- border-radius: 8px;
- opacity: 0;
- transition: all 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
- transform: scale(0);
- }
- }
- &.ant-tree-checkbox-checked {
- &::after {
- position: absolute;
- top: 16.67%;
- left: 0;
- width: 100%;
- height: 66.67%;
- content: '';
- border: 1px solid #1890ff;
- border-radius: 50%;
- animation: antRadioEffect 0.36s ease-in-out;
- animation-fill-mode: both;
- }
- .ant-tree-checkbox-inner {
- background-color: $white;
- &::after {
- opacity: 1;
- transition: all 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
- transform: scale(1);
- }
- }
- }
- }
- }
- </style>
|