<template> <div class="design-tree-container"> <context-menu-container> <el-tree v-if="inited" ref="${ctrl.name}" class="design-tree" node-key="id" lazy :show-checkbox="!isSingleSelect" :check-on-click-node="!isSingleSelect" :default-expanded-keys="expandedKeys" :props="{ label: 'text', isLeaf: 'leaf', children: 'children' }" :load="load" :highlight-current="true" :expand-on-click-node="false" @check="onCheck" @current-change="selectionChange" :filter-node-method="filterNode" > <template slot-scope="{ node, data }"> <context-menu :contextMenuStyle="{width: '100%'}" :data="node" :renderContent="renderContextMenu"> <tooltip transfer style="width: 100%;" max-width="2000" placement="right"> <div class="tree-node" @dblclick="doDefaultAction(node)"> <span class="icon"> <i v-if=" data.iconcls && !Object.is(data.iconcls, '')" :class="data.iconcls"></i> <img v-else-if="data.icon && !Object.is(data.icon, '')" :src="data.icon" /> <icon v-else-if="isOutputIconDefault" type="ios-paper-outline"></icon> </span> <span class="text"> <span v-if="data.html" v-html="data.html"></span> <span v-else>{{ data.isUseLangRes ? $t(data.text) : data.text }}</span> </span> </div> <template slot="content"> <span v-if="data.html" v-html="data.html"></span> <span v-else>{{ data.isUseLangRes ? $t(data.text) : data.text }}</span> </template> </tooltip> </context-menu> </template> </el-tree> </context-menu-container> </div> </template> <#ibizinclude> ../@MACRO/CONTROL/CONTROL_HEADER-BASE.vue.ftl </#ibizinclude> /** * 获取多项数据 * * @returns {any[]} * @memberof ${srfclassname('${ctrl.codeName}')} */ public getDatas(): any[] { return [this.currentselectedNode]; } /** * 获取单项树 * * @returns {*} * @memberof ${srfclassname('${ctrl.codeName}')} */ public getData(): any { return this.currentselectedNode; } /** * 是否单选 * * @type {boolean} * @memberof ${srfclassname('${ctrl.codeName}')} */ @Prop({ default: true }) public isSingleSelect!: boolean; /** * 是否默认选中第一条数据 * * @type {boolean} * @memberof ${srfclassname('${ctrl.codeName}')} */ @Prop({ default: false }) public isSelectFirstDefault!: boolean; /** * 枝干节点是否可用(具有数据能力,可抛出) * * @type {string} * @memberof ${srfclassname('${ctrl.codeName}')} */ @Prop({default:true}) public isBranchAvailable!: boolean; /** * 显示处理提示 * * @type {boolean} * @memberof ${srfclassname('${ctrl.codeName}')} */ @Prop({ default: true }) public showBusyIndicator?: boolean; /** * 初始化完成 * * @type {boolean} * @memberof ${srfclassname('${ctrl.codeName}')} */ public inited: boolean = false; /** * 已选中数据集合 * * @type {*} * @memberof ${srfclassname('${ctrl.codeName}')} */ public selectedNodes: any = []; /** * 当前选中数据项 * * @type {*} * @memberof ${srfclassname('${ctrl.codeName}')} */ public currentselectedNode: any = {}; /** * 选中数据字符串 * * @type {string} * @memberof ${srfclassname('${ctrl.codeName}')} */ @Prop() public selectedData?: string; /** * 选中值变化 * * @param {*} newVal * @param {*} oldVal * @memberof ${srfclassname('${ctrl.codeName}')} */ @Watch('selectedData') public onValueChange(newVal: any, oldVal: any) { this.echoselectedNodes = newVal ? this.isSingleSelect ? JSON.parse(newVal)[0] : JSON.parse(newVal) : []; this.selectedNodes = []; if(this.echoselectedNodes.length > 0){ let AllnodesObj = (this.$refs.treeexpbar_tree as any).store.nodesMap; let AllnodesArray : any[] = []; for (const key in AllnodesObj) { if (AllnodesObj.hasOwnProperty(key)) { AllnodesArray.push(AllnodesObj[key].data); } } this.setDefaultSelection(AllnodesArray); } } /** * 回显选中数据集合 * * @type {*} * @memberof ${srfclassname('${ctrl.codeName}')} */ public echoselectedNodes:any[] = this.selectedData ? ( this.isSingleSelect ? [JSON.parse(this.selectedData)[0]] : JSON.parse(this.selectedData)) : []; /** * 部件行为--update * * @type {string} * @memberof ${srfclassname('${ctrl.codeName}')} */ @Prop() public updateAction!: string; /** * 部件行为--fetch * * @type {string} * @memberof ${srfclassname('${ctrl.codeName}')} */ @Prop() public fetchAction!: string; /** * 部件行为--remove * * @type {string} * @memberof ${srfclassname('${ctrl.codeName}')} */ @Prop() public removeAction!: string; /** * 部件行为--load * * @type {string} * @memberof ${srfclassname('${ctrl.codeName}')} */ @Prop() public loadAction!: string; /** * 部件行为--create * * @type {string} * @memberof ${srfclassname('${ctrl.codeName}')} */ @Prop() public createAction!: string; /** * 过滤属性 * * @type {string} * @memberof ${srfclassname('${ctrl.codeName}')} */ public srfnodefilter: string = ''; /** * 默认输出图标 * * @type {boolean} * @memberof ${srfclassname('${ctrl.codeName}')} */ public isOutputIconDefault: boolean = ${ctrl.isOutputIconDefault()?c}; <#-- /** * 树数据 * * @type {any[]} * @memberof ${srfclassname('${ctrl.codeName}')} */ @Provide() public nodes: any[] = []; --> /** * 数据展开主键 * * @type {string[]} * @memberof ${srfclassname('${ctrl.codeName}')} */ @Provide() public expandedKeys: string[] = []; /** * 选中数据变更事件 * * @public * @param {*} data * @param {*} data 当前节点对应传入对象 * @param {*} checkedState 树目前选中状态对象 * @memberof ${srfclassname('${ctrl.codeName}')} */ public onCheck(data: any, checkedState: any) { // 处理多选数据 if(!this.isSingleSelect){ let leafNodes = checkedState.checkedNodes.filter((item:any) => item.leaf); this.selectedNodes = JSON.parse(JSON.stringify(leafNodes)); this.$emit('selectionchange', this.selectedNodes); } } /** * 选中数据变更事件 * * @public * @param {*} data 节点对应传入对象 * @param {*} node 节点对应node对象 * @memberof ${srfclassname('${ctrl.codeName}')} */ public selectionChange(data: any, node: any) { // 禁用项处理 if (data.disabled){ node.isCurrent = false; return; } // 只处理最底层子节点 if(this.isBranchAvailable || data.leaf){ this.currentselectedNode = JSON.parse(JSON.stringify(data)); // 单选直接替换 if(this.isSingleSelect){ this.selectedNodes = [this.currentselectedNode]; this.$emit('selectionchange', this.selectedNodes); } // 多选用check方法 } } /** * Vue声明周期(处理组件的输入属性) * * @memberof ${srfclassname('${ctrl.codeName}')} */ public created() { this.afterCreated(); } /** * 执行created后的逻辑 * * @memberof ${srfclassname('${ctrl.codeName}')} */ public afterCreated(){ if (this.viewState) { this.viewStateEvent = this.viewState.subscribe(({ tag, action, data }) => { if (!Object.is(tag, this.name)) { return; } if (Object.is('load', action)) { this.inited = false; this.$nextTick(() => { this.inited = true; }); } if (Object.is('filter', action)) { this.srfnodefilter = data.srfnodefilter; this.refresh_all(); } if (Object.is('refresh_parent', action)) { this.refresh_parent(); } }); } } /** * 对树节点进行筛选操作 * @memberof OrderTree */ public filterNode(value:any, data:any) { if (!value) return true; return data.text.indexOf(value) !== -1; } /** * vue 生命周期 * * @memberof ${srfclassname('${ctrl.codeName}')} */ public destroyed() { this.afterDestroy(); } /** * 执行destroyed后的逻辑 * * @memberof ${srfclassname('${ctrl.codeName}')} */ public afterDestroy() { if (this.viewStateEvent) { this.viewStateEvent.unsubscribe(); } <#if destroyed_block??> ${destroyed_block} </#if> } /** * 刷新数据 * * @memberof ${srfclassname('${ctrl.codeName}')} */ public refresh_all(): void { this.inited = false; this.$nextTick(() => { this.inited = true; }); } /** * 刷新父节点 * * @memberof ${srfclassname('${ctrl.codeName}')} */ public refresh_parent(): void { if (Object.keys(this.currentselectedNode).length === 0) { return; } const tree: any = this.$refs.${ctrl.name}; const node: any = tree.getNode(this.currentselectedNode.id); if (!node || !node.parent) { return; } let curNode:any = {}; const { parent: _parent } = node; curNode = Util.deepObjectMerge(curNode,_parent); let tempContext:any = {}; if(curNode.data && curNode.data.srfappctx){ Object.assign(tempContext,curNode.data.srfappctx); }else{ Object.assign(tempContext,this.context); } const id: string = _parent.key ? _parent.key : '#'; const param: any = { srfnodeid: id }; this.refresh_node(tempContext,param, true); } /** * 数据加载 * * @param {*} node * @memberof ${srfclassname('${ctrl.codeName}')} */ public load(node: any = {}, resolve?: any) { if (node.data && node.data.children) { resolve(node.data.children); return; } const params: any = { srfnodeid: node.data && node.data.id ? node.data.id : "#", srfnodefilter: this.srfnodefilter }; let tempViewParams:any = JSON.parse(JSON.stringify(this.viewparams)); let curNode:any = {}; curNode = Util.deepObjectMerge(curNode,node); let tempContext:any = this.computecurNodeContext(curNode); if(curNode.data && curNode.data.srfparentdename){ Object.assign(tempContext,{srfparentdename:curNode.data.srfparentdename}); Object.assign(tempViewParams,{srfparentdename:curNode.data.srfparentdename}); } if(curNode.data && curNode.data.srfparentkey){ Object.assign(tempContext,{srfparentkey:curNode.data.srfparentkey}); Object.assign(tempViewParams,{srfparentkey:curNode.data.srfparentkey}); } Object.assign(params,{viewparams:tempViewParams}); this.service.getNodes(tempContext,params).then((response: any) => { if (!response || response.status !== 200) { this.$Notice.error({ title: "错误", desc: response.info }); resolve([]); return; } const _items = response.data; this.formatExpanded(_items); <#-- if (!node.level || node.level === 0) { this.nodes = [..._items]; } this.nodes = response.data; --> resolve([..._items]); let isRoot = Object.is(node.level,0); let isSelectedAll = node.checked; this.setDefaultSelection(_items, isRoot, isSelectedAll); this.$emit("load", _items); }).catch((response: any) => { resolve([]); if (response && response.status === 401) { return; } this.$Notice.error({ title: "错误", desc: response.info }); }); } /** * 计算当前节点的上下文 * * @param {*} curNode 当前节点 * @memberof ${srfclassname('${ctrl.codeName}')} */ public computecurNodeContext(curNode:any){ let tempContext:any = {}; if(curNode && curNode.data && curNode.data.srfappctx){ tempContext = JSON.parse(JSON.stringify(curNode.data.srfappctx)); }else{ tempContext = JSON.parse(JSON.stringify(this.context)); } return tempContext; } /** * 刷新功能 * * @param {any[]} args * @memberof ${srfclassname('${ctrl.codeName}')} */ public refresh(args: any[]): void { if (Object.keys(this.currentselectedNode).length === 0) { return; } const id: string = this.currentselectedNode.id; const param: any = { srfnodeid: id }; const tree: any = this.$refs.${ctrl.name}; const node: any = tree.getNode(id); if (!node) { return; } let curNode:any = {}; curNode = Util.deepObjectMerge(curNode,node); let tempContext:any; if(curNode.data && curNode.data.srfappctx){ Object.assign(tempContext,curNode.data.srfappctx); }else{ Object.assign(tempContext,this.context); } this.refresh_node(tempContext,param, false); } /** * 刷新节点 * * @public * @param {*} [curContext] 当前节点上下文 * @param {*} [arg={}] 当前节点附加参数 * @param {boolean} parentnode 是否是刷新父节点 * @memberof ${srfclassname('${ctrl.codeName}')} */ public refresh_node(curContext:any,arg: any = {}, parentnode: boolean): void { const { srfnodeid: id } = arg; Object.assign(arg,{viewparams:this.viewparams}); const get: Promise<any> = this.service.getNodes(JSON.parse(JSON.stringify(this.context)),arg); get.then((response: any) => { if (!response || response.status !== 200) { this.$Notice.error({ title: '错误', desc: response.info }); return; } const _items = [...response.data]; this.formatExpanded(_items); const tree: any = this.$refs.${ctrl.name}; tree.updateKeyChildren(id, _items); if (parentnode) { this.currentselectedNode = {}; } this.setDefaultSelection(_items); }).catch((response: any) => { if (response && response.status === 401) { return; } this.$Notice.error({ title: '错误', desc: response.info }); }); } /** * 默认展开节点 * * @public * @param {any[]} items * @returns {any[]} * @memberof ${srfclassname('${ctrl.codeName}')} */ public formatExpanded(items: any[]): any[] { const data: any[] = []; items.forEach((item) => { if (item.expanded || (item.children && item.children.length > 0)) { this.expandedKeys.push(item.id); } }); return data; } /** * 设置默认选中,回显数项,选中所有子节点 * * @param {any[]} items 当前节点所有子节点集合 * @param {boolean} isRoot 是否是加载根节点 * @param {boolean} isSelectedAll 是否选中所有子节点 * @memberof MainTree */ public setDefaultSelection(items: any[], isRoot: boolean = false, isSelectedAll: boolean = false): void { if(items.length == 0){ return; } let defaultData: any; // 导航中选中第一条配置的默认选中,没有选中第一条 if(this.isSelectFirstDefault){ if(this.isSingleSelect){ let index = items.findIndex((item: any) => item.selected); if(index === -1) { if(isRoot){ index = 0; }else{ return; } } defaultData = items[index]; this.setTreeNodeHighLight(defaultData); this.currentselectedNode = JSON.parse(JSON.stringify(defaultData)); if(this.isBranchAvailable || defaultData.leaf){ this.selectedNodes = [this.currentselectedNode]; this.$emit('selectionchange', this.selectedNodes); } } } // 已选数据的回显 if(this.echoselectedNodes && this.echoselectedNodes.length > 0){ let checkedNodes = items.filter((item:any)=>{ return this.echoselectedNodes.some((val:any)=> { if(Object.is(item.srfkey,val.srfkey) && Object.is(item.srfmajortext,val.srfmajortext)){ val.used = true; return true; } }); }); if(checkedNodes.length > 0){ this.echoselectedNodes = this.echoselectedNodes.filter((item:any)=> !item.used); // 父节点选中时,不需要执行这段,会选中所有子节点 if(!isSelectedAll){ if(this.isSingleSelect){ this.setTreeNodeHighLight(checkedNodes[0]); this.currentselectedNode = JSON.parse(JSON.stringify(checkedNodes[0])); this.selectedNodes = [this.currentselectedNode]; }else{ this.selectedNodes = this.selectedNodes.concat(checkedNodes); const tree: any = this.$refs.treeexpbar_tree; tree.setCheckedNodes(this.selectedNodes); } } } } // 父节点选中时,选中所有子节点 if(isSelectedAll){ let leafNodes = items.filter((item:any) => item.leaf); this.selectedNodes = this.selectedNodes.concat(leafNodes); this.$emit('selectionchange', this.selectedNodes); } } /** * 绘制右击菜单 * * @param {*} node * @returns * @memberof ${srfclassname('${ctrl.codeName}')} */ public renderContextMenu(node: any) { let content; if (node && node.data) { const data: any = JSON.parse(JSON.stringify(node.data)); this.currentselectedNode = { ...data }; const tags: string[] = data.id.split(';'); <#if ctrl.getPSControls()??> <#list ctrl.getPSControls() as childCtrl> <#if childCtrl.getControlType() == "CONTEXTMENU"> if (tags[0] === "${childCtrl.getOwner().getNodeType()}") { content = this.renderContextMenu${srfclassname(childCtrl.getOwner().getNodeType()?lower_case)}(); } </#if> </#list> </#if> } return content; } <#if ctrl.getPSControls()??> <#list ctrl.getPSControls() as childCtrl> <#if childCtrl.getControlType() == "CONTEXTMENU"> /** * 绘制${childCtrl.getOwner().getNodeType()}类型右键菜单 * * @param {*} node * @returns * @memberof ${srfclassname('${ctrl.codeName}')} */ public renderContextMenu${srfclassname(childCtrl.getOwner().getNodeType()?lower_case)}() { return ( <@ibizindent blank=12> ${P.getCtrlCode(childCtrl, 'CONTROL.html').code} </@ibizindent> ); } </#if> </#list> </#if> /** * 设置选中高亮 * * @param {*} data * @memberof ${srfclassname('${ctrl.codeName}')} */ public setTreeNodeHighLight(data: any): void { const tree: any = this.$refs.${ctrl.name}; tree.setCurrentKey(data.id); } /** * 执行默认界面行为 * * @param {*} node * @memberof AppView */ public doDefaultAction(node: any) { if (node && node.data) { const data: any = node.data; const tags: string[] = data.id.split(';'); <#if ctrl.getPSDETreeNodes()??> <#list ctrl.getPSDETreeNodes() as node> <#if node.getPSDEContextMenu()?? && node.getDefaultPSUIAction()??> <#assign contextMenu = node.getPSDEContextMenu()/> if (tags[0] === "${contextMenu.getOwner().getNodeType()}") { this.${contextMenu.name}_click({tag: '${node.getDefaultPSUIAction().name}'}); } </#if> </#list> </#if> } } <#ibizinclude> ../@MACRO/CONTROL/CONTROL_BOTTOM-BASE.vue.ftl </#ibizinclude> <#ibizinclude> ../@MACRO/CONTROL/CONTROL-BASE.style.ftl </#ibizinclude>