提交 a278cdd1 编写于 作者: Mosher's avatar Mosher

update:更新

1、新增树节点上下文菜单支持
2、树部件部分标识调整
3、增加刷新父与刷新全部预置界面行为
上级 fceaed54
{
name: "{{item.name}}",
caption: "{{item.caption}}",
showCaption: {{item.showCaption}},
tooltip: "{{item.tooltip}}",
nodeOwner: "{{owner}}",
{{#if item.psUIAction}}
{{#item.psUIAction}}
actionTarget: "{{actionTarget}}",
uIActionType: "{{uIActionType}}",
uIActionTag: "{{uIActionTag}}",
uIActionMode: "{{uIActionMode}}",
noPrivDisplayMode: "{{noPrivDisplayMode}}",
dataAccessAction: "{{dataAccessAction}}",
visible: true,
disabled: false,
{{/item.psUIAction}}
{{/if}}
{{#if (and item.showIcon item.psSysImage item.psSysImage.cssClass)}}
cssClass: "{{item.psSysImage.cssClass}}",
{{/if}}
{{#eq item.itemType "ITEMS"}}
{{#if item.psDEContextMenuItems}}
items: [
{{#each item.psDEContextMenuItems as | childItem |}}
{{#neq item.itemType "SEPERATOR"}}
{{> @macro/front-end/widgets/tree-detail/tree-node-context-menu-item.hbs item=childItem owner=owner}}
{{/neq}}
{{/each}}
]
{{/if}}
{{/eq}}
},
<script setup lang="ts">
import { IContext, IParam } from "@core";
interface IProps {
// 应用上下文
context?: IContext;
// 视图参数
viewParams?: IParam;
// 菜单项
menu: any;
}
// 输入参数
const props = defineProps<IProps>();
</script>
<template>
<template v-if="menu.items && menu.items.length">
<a-sub-menu v-if="menu.visible" :key="menu.name" :disabled="menu.disabled">
<template #icon v-if="menu.cssClass">
<i :class="menu.cssClass"/>
</template>
<template #title v-if="menu.showCaption">
<span>{{menu.caption}}</span>
</template>
<AppTreeContextMenuItem
v-for="(item, index) in menu.items"
:key="index"
:context="context"
:viewParams="viewParams"
:menu="item"
/>
</a-sub-menu>
</template>
<template v-else>
<a-menu-item v-if="menu.visible" :key="menu.name" :disabled="menu.disabled">
<i v-if="menu.cssClass" :class="['context-menu-item__icon', menu.cssClass]"/>
<span v-if="menu.showCaption" class="context-menu-item__text">{{menu.caption}}</span>
</a-menu-item>
</template>
</template>
\ No newline at end of file
...@@ -71,6 +71,12 @@ export class AppSysAction { ...@@ -71,6 +71,12 @@ export class AppSysAction {
case 'Refresh': case 'Refresh':
this.refresh(params); this.refresh(params);
break; break;
case 'RefreshParent':
this.refreshParent(params);
break;
case 'RefreshAll':
this.refreshAll(params);
break;
case 'Exit': case 'Exit':
this.exit(params); this.exit(params);
break; break;
...@@ -278,6 +284,38 @@ export class AppSysAction { ...@@ -278,6 +284,38 @@ export class AppSysAction {
} }
} }
/**
* 刷新父
*
* @static
* @param {IUIActionParams} params
* @memberof AppSysAction
*/
public static refreshParent(params: IUIActionParams) {
const { actionEnvironment } = params;
if (actionEnvironment.xDataControl && hasFunction(actionEnvironment.xDataControl, 'refresh')) {
actionEnvironment.xDataControl.refresh({});
} else if (isExist(actionEnvironment.refresh)) {
actionEnvironment.refresh({ target: 'parent' });
}
}
/**
* 刷新全部
*
* @static
* @param {IUIActionParams} params
* @memberof AppSysAction
*/
public static refreshAll(params: IUIActionParams) {
const { actionEnvironment } = params;
if (actionEnvironment.xDataControl && hasFunction(actionEnvironment.xDataControl, 'refresh')) {
actionEnvironment.xDataControl.refresh({});
} else if (isExist(actionEnvironment.refresh)) {
actionEnvironment.refresh({ target: 'all' });
}
}
/** /**
* 关闭 * 关闭
* *
......
...@@ -15,6 +15,13 @@ export interface TreeControlState extends MDControlState { ...@@ -15,6 +15,13 @@ export interface TreeControlState extends MDControlState {
*/ */
currentSelectedNode: IParam; currentSelectedNode: IParam;
/**
* @description 节点上下文菜单集合
* @type {IParam[]}
* @memberof TreeControlState
*/
contextMenus: IParam[];
/** /**
* @description 默认展开节点 * @description 默认展开节点
* @type {string[]} * @type {string[]}
......
...@@ -31,7 +31,7 @@ export class TreeControl extends MDControl { ...@@ -31,7 +31,7 @@ export class TreeControl extends MDControl {
* @param { nativeEvent: MouseEvent, node: any, selected: boolean } e * @param { nativeEvent: MouseEvent, node: any, selected: boolean } e
* @memberof TreeControl * @memberof TreeControl
*/ */
public treeNodeSelect(nodeId: string, e: { nativeEvent: MouseEvent, node: any, selected: boolean }) { public onTreeNodeSelect(nodeId: string, e: { nativeEvent: MouseEvent, node: any, selected: boolean }) {
if (e.node.disabled) { if (e.node.disabled) {
e.node.isCurrent = false; e.node.isCurrent = false;
return; return;
...@@ -92,7 +92,7 @@ export class TreeControl extends MDControl { ...@@ -92,7 +92,7 @@ export class TreeControl extends MDControl {
return null; return null;
} }
const { const {
controlService, data, viewParams, srfnodefilter controlService, viewParams, srfnodefilter
} = this.state; } = this.state;
let tempViewParams: any = deepCopy(viewParams); let tempViewParams: any = deepCopy(viewParams);
let curNode: any = {}; let curNode: any = {};
...@@ -121,21 +121,22 @@ export class TreeControl extends MDControl { ...@@ -121,21 +121,22 @@ export class TreeControl extends MDControl {
if (!response || response.status !== 200) { if (!response || response.status !== 200) {
return null; return null;
} }
const items = response.data; const data = response.data;
this.formatExpanded(items); this.formatExpanded(data);
this.formatAppendCaption(items); this.formatAppendCaption(data);
const isRoot = !node || !node.parent; const isRoot = !node || !node.parent;
const { items } = toRefs(this.state);
if (isFirst) { if (isFirst) {
data.splice(0, data.length); items.value.splice(0, items.value.length);
items.forEach((item: any) => { data.forEach((item: any) => {
data.push(item); items.value.push(item);
}); });
} else { } else {
node.dataRef.children = items; node.dataRef.children = data;
} }
const isSelectedAll = node?.checked; const isSelectedAll = node?.checked;
this.setDefaultSelection(items, isRoot, isSelectedAll); this.setDefaultSelection(data, isRoot, isSelectedAll);
this.emit("ctrlEvent", { tag: this.props.name, action: "load", data: items }); this.emit("ctrlEvent", { tag: this.props.name, action: "load", data: data });
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
...@@ -162,6 +163,56 @@ export class TreeControl extends MDControl { ...@@ -162,6 +163,56 @@ export class TreeControl extends MDControl {
return load; return load;
} }
public useRefresh() {
const { viewSubject, controlName } = this.state;
/**
* 刷新行为
*
* @param [opt={}]
* @return {*}
*/
const refresh = async (opt: any = {}) => {
if (opt && opt.target) {
if (opt.target === 'parent') {
this.refreshParent();
} else if (opt.target === 'all') {
this.refreshAll();
}
} else {
this.load(opt);
}
};
// 在类里绑定能力方法
this.refresh = refresh;
// 订阅viewSubject,监听load行为
if (viewSubject) {
let subscription = viewSubject.subscribe(({ tag, action, data }: IActionParam) => {
if (Object.is(controlName, tag) && Object.is('refresh', action)) {
refresh(data);
}
});
// 部件卸载时退订viewSubject
onUnmounted(() => {
subscription.unsubscribe();
});
}
return refresh;
}
protected refreshParent() {
const { currentSelectedNode } = this.state;
console.log(1111, "刷新父", currentSelectedNode);
}
protected refreshAll() {
const { currentSelectedNode } = this.state;
console.log(1111, "刷新全部", currentSelectedNode);
}
/** /**
* @description 设置默认展开节点 * @description 设置默认展开节点
* @protected * @protected
...@@ -318,6 +369,32 @@ export class TreeControl extends MDControl { ...@@ -318,6 +369,32 @@ export class TreeControl extends MDControl {
} }
} }
/**
* @description 树节点上下文菜单点击
*
* @protected
* @param {*} node 节点
* @param {*} { key, domEvent: event } key:行为标识,event:鼠标源事件
* @return {*}
* @memberof TreeControl
*/
protected onContextMenuClick(node: any, { key, domEvent: event }: any) {
const { context, viewParams, contextMenus } = this.state;
const action = contextMenus[node.nodeType]?.find((item: IParam) => item.name === key);
if (!action) {
console.warn("上下文菜单执行参数不足");
return;
}
const inputParam = {
context: context,
viewParams: viewParams,
data: [node.curData],
event: event,
actionEnvironment: this
};
App.getAppActionService().execute(action, inputParam);
}
/** /**
* @description 安装部件所有功能模块的方法 * @description 安装部件所有功能模块的方法
* @return {*} * @return {*}
...@@ -327,7 +404,8 @@ export class TreeControl extends MDControl { ...@@ -327,7 +404,8 @@ export class TreeControl extends MDControl {
const superParams = super.moduleInstall(); const superParams = super.moduleInstall();
return { return {
...superParams, ...superParams,
treeNodeSelect: this.treeNodeSelect.bind(this), onTreeNodeSelect: this.onTreeNodeSelect.bind(this),
onContextMenuClick: this.onContextMenuClick.bind(this),
load: this.useLoad(), load: this.useLoad(),
}; };
} }
......
...@@ -192,7 +192,7 @@ export class TreeService<T extends ControlVOBase> extends ControlServiceBase<T> ...@@ -192,7 +192,7 @@ export class TreeService<T extends ControlVOBase> extends ControlServiceBase<T>
text: node.text, text: node.text,
textFormat: node.textFormat, textFormat: node.textFormat,
tooltip: node.tooltip, tooltip: node.tooltip,
nodeType: node.treeNodeType, nodeType: node.nodeType,
iconcls: node.iconcls, iconcls: node.iconcls,
isUseLangRes: false, isUseLangRes: false,
srfappctx: context, srfappctx: context,
...@@ -399,19 +399,18 @@ export class TreeService<T extends ControlVOBase> extends ControlServiceBase<T> ...@@ -399,19 +399,18 @@ export class TreeService<T extends ControlVOBase> extends ControlServiceBase<T>
for (const item of codeItems) { for (const item of codeItems) {
const treeNode: any = { const treeNode: any = {
srfappctx: context, srfappctx: context,
curData: item curData: item,
nodeType: node.nodeType,
}; };
// 处理值 // 处理值
if (node.codeList && node.codeList.type === 'STATIC') { if (node.codeList && node.codeList.type === 'STATIC') {
Object.assign(treeNode, { Object.assign(treeNode, {
// TODO 多语言 // TODO 多语言
text: item.text, text: item.text,
nodeType: 'STATIC'
}); });
} else { } else {
Object.assign(treeNode, { Object.assign(treeNode, {
text: item.text, text: item.text,
nodeType: node.treeNodeType,
appEntityName: node.appDataEntity?.codeName, appEntityName: node.appDataEntity?.codeName,
}); });
} }
......
...@@ -10,3 +10,9 @@ ...@@ -10,3 +10,9 @@
transform: translate(40px, -1px); transform: translate(40px, -1px);
} }
} }
// 树节点上下文菜单
.tree-node__context-menu {
.context-menu-item__icon {
padding-right: 6px;
}
}
\ No newline at end of file
...@@ -203,11 +203,24 @@ export const ctrlState = { ...@@ -203,11 +203,24 @@ export const ctrlState = {
}, },
counterService: ref(null), counterService: ref(null),
{{/and}} {{/and}}
contextMenus: {
{{#each ctrl.psDETreeNodes as | treeNode |}}
{{#if (and treeNode.psDEContextMenu treeNode.psDEContextMenu.psDEToolbarItems)}}
{{treeNode.nodeType}}: [
{{#each treeNode.psDEContextMenu.psDEToolbarItems as | item |}}
{{#neq item.itemType "SEPERATOR"}}
{{> @macro/front-end/widgets/tree-detail/tree-node-context-menu-item.hbs item=item owner=treeNode.nodeType}}
{{/neq}}
{{/each}}
],
{{/if}}
{{/each}}
},
controlCodeName: '{{ctrl.codeName}}', controlCodeName: '{{ctrl.codeName}}',
controlName: '{{ctrl.name}}', controlName: '{{ctrl.name}}',
controlService: new TreeService<ControlVO>(ControlVO, new {{pascalCase ctrl.psAppDataEntity.codeName}}Service() ), controlService: new TreeService<ControlVO>(ControlVO, new {{pascalCase ctrl.psAppDataEntity.codeName}}Service() ),
currentSelectedNode: {}, currentSelectedNode: {},
data: [], items: [],
outputIconDefault: {{#eq ctrl.outputIconDefault false}}false{{else}}true{{/eq}}, outputIconDefault: {{#eq ctrl.outputIconDefault false}}false{{else}}true{{/eq}},
echoSelectedNodes: [], echoSelectedNodes: [],
expandedKeys: [], expandedKeys: [],
......
...@@ -47,7 +47,7 @@ const getCustomText = (scriptCode: any) => { ...@@ -47,7 +47,7 @@ const getCustomText = (scriptCode: any) => {
} }
// 安装功能模块,提供状态和能力方法 // 安装功能模块,提供状态和能力方法
const { name, state, load, treeNodeSelect } = new TreeControl(ctrlState, props, emit).moduleInstall(); const { name, state, load, onTreeNodeSelect, onContextMenuClick } = new TreeControl(ctrlState, props, emit).moduleInstall();
{{#and ctrl.psAppCounterRef ctrl.psAppCounterRef.psAppCounter}} {{#and ctrl.psAppCounterRef ctrl.psAppCounterRef.psAppCounter}}
// 获取计数器数据 // 获取计数器数据
...@@ -67,7 +67,7 @@ defineExpose({ name, state }); ...@@ -67,7 +67,7 @@ defineExpose({ name, state });
<a-tree <a-tree
class="app-tree{{#if ctrl.psSysCss}} {{ctrl.psSysCss.cssName}}{{/if}}" class="app-tree{{#if ctrl.psSysCss}} {{ctrl.psSysCss.cssName}}{{/if}}"
:blockNode="true" :blockNode="true"
:tree-data="state.data" :tree-data="state.items"
:load-data="load" :load-data="load"
:fieldNames="{ title: 'text', key: 'id' }" :fieldNames="{ title: 'text', key: 'id' }"
:checkable="state.isMultiple" :checkable="state.isMultiple"
...@@ -75,7 +75,7 @@ defineExpose({ name, state }); ...@@ -75,7 +75,7 @@ defineExpose({ name, state });
show-icon show-icon
v-model:expandedKeys="state.expandedKeys" v-model:expandedKeys="state.expandedKeys"
v-model:selectedKeys="state.selectedKeys" v-model:selectedKeys="state.selectedKeys"
@select="treeNodeSelect"> @select="onTreeNodeSelect">
<template #icon="node"> <template #icon="node">
<span class="app-tree-node__icon"> <span class="app-tree-node__icon">
<template v-if="node.iconCustomCode && node.iconScriptCode"> <template v-if="node.iconCustomCode && node.iconScriptCode">
...@@ -94,6 +94,7 @@ defineExpose({ name, state }); ...@@ -94,6 +94,7 @@ defineExpose({ name, state });
</template> </template>
<template #title="node"> <template #title="node">
{{#if (and ctrl.psAppCounterRef ctrl.psAppCounterRef.psAppCounter)}} {{#if (and ctrl.psAppCounterRef ctrl.psAppCounterRef.psAppCounter)}}
<a-dropdown :trigger="['contextmenu']">
<span <span
:class="['app-tree-node__text', node.cssName]" :class="['app-tree-node__text', node.cssName]"
:title="node.tooltip ? node.tooltip : node.text"> :title="node.tooltip ? node.tooltip : node.text">
...@@ -120,7 +121,20 @@ defineExpose({ name, state }); ...@@ -120,7 +121,20 @@ defineExpose({ name, state });
</template> </template>
</template> </template>
</span> </span>
<template #overlay v-if="state.contextMenus[node.nodeType] && state.contextMenus[node.nodeType].length">
<a-menu class="tree-node__context-menu" @click="(event) => onContextMenuClick(node, event)">
<AppTreeContextMenuItem
v-for="(item, index) in state.contextMenus[node.nodeType]"
:key="index"
:menu="item"
:context="state.context"
:viewParams="state.viewParams"
/>
</a-menu>
</template>
</a-dropdown>
{{else}} {{else}}
<a-dropdown :trigger="['contextmenu']">
<span <span
:class="['app-tree-node__text', node.cssName]" :class="['app-tree-node__text', node.cssName]"
:title="node.tooltip ? node.tooltip : node.text"> :title="node.tooltip ? node.tooltip : node.text">
...@@ -134,6 +148,18 @@ defineExpose({ name, state }); ...@@ -134,6 +148,18 @@ defineExpose({ name, state });
<span>\{{node.text}}</span> <span>\{{node.text}}</span>
</template> </template>
</span> </span>
<template #overlay v-if="state.contextMenus[node.nodeType] && state.contextMenus[node.nodeType].length">
<a-menu class="tree-node__context-menu" @click="(event) => onContextMenuClick(node, event)">
<AppTreeContextMenuItem
v-for="(item, index) in state.contextMenus[node.nodeType]"
:key="index"
:menu="item"
:context="state.context"
:viewParams="state.viewParams"
/>
</a-menu>
</template>
</a-dropdown>
{{/if}} {{/if}}
</template> </template>
</a-tree> </a-tree>
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册