提交 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 {
case 'Refresh':
this.refresh(params);
break;
case 'RefreshParent':
this.refreshParent(params);
break;
case 'RefreshAll':
this.refreshAll(params);
break;
case 'Exit':
this.exit(params);
break;
......@@ -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 {
*/
currentSelectedNode: IParam;
/**
* @description 节点上下文菜单集合
* @type {IParam[]}
* @memberof TreeControlState
*/
contextMenus: IParam[];
/**
* @description 默认展开节点
* @type {string[]}
......
......@@ -31,7 +31,7 @@ export class TreeControl extends MDControl {
* @param { nativeEvent: MouseEvent, node: any, selected: boolean } e
* @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) {
e.node.isCurrent = false;
return;
......@@ -92,7 +92,7 @@ export class TreeControl extends MDControl {
return null;
}
const {
controlService, data, viewParams, srfnodefilter
controlService, viewParams, srfnodefilter
} = this.state;
let tempViewParams: any = deepCopy(viewParams);
let curNode: any = {};
......@@ -121,21 +121,22 @@ export class TreeControl extends MDControl {
if (!response || response.status !== 200) {
return null;
}
const items = response.data;
this.formatExpanded(items);
this.formatAppendCaption(items);
const data = response.data;
this.formatExpanded(data);
this.formatAppendCaption(data);
const isRoot = !node || !node.parent;
const { items } = toRefs(this.state);
if (isFirst) {
data.splice(0, data.length);
items.forEach((item: any) => {
data.push(item);
items.value.splice(0, items.value.length);
data.forEach((item: any) => {
items.value.push(item);
});
} else {
node.dataRef.children = items;
node.dataRef.children = data;
}
const isSelectedAll = node?.checked;
this.setDefaultSelection(items, isRoot, isSelectedAll);
this.emit("ctrlEvent", { tag: this.props.name, action: "load", data: items });
this.setDefaultSelection(data, isRoot, isSelectedAll);
this.emit("ctrlEvent", { tag: this.props.name, action: "load", data: data });
} catch (error) {
console.error(error);
}
......@@ -162,6 +163,56 @@ export class TreeControl extends MDControl {
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 设置默认展开节点
* @protected
......@@ -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 安装部件所有功能模块的方法
* @return {*}
......@@ -327,7 +404,8 @@ export class TreeControl extends MDControl {
const superParams = super.moduleInstall();
return {
...superParams,
treeNodeSelect: this.treeNodeSelect.bind(this),
onTreeNodeSelect: this.onTreeNodeSelect.bind(this),
onContextMenuClick: this.onContextMenuClick.bind(this),
load: this.useLoad(),
};
}
......
......@@ -192,7 +192,7 @@ export class TreeService<T extends ControlVOBase> extends ControlServiceBase<T>
text: node.text,
textFormat: node.textFormat,
tooltip: node.tooltip,
nodeType: node.treeNodeType,
nodeType: node.nodeType,
iconcls: node.iconcls,
isUseLangRes: false,
srfappctx: context,
......@@ -399,19 +399,18 @@ export class TreeService<T extends ControlVOBase> extends ControlServiceBase<T>
for (const item of codeItems) {
const treeNode: any = {
srfappctx: context,
curData: item
curData: item,
nodeType: node.nodeType,
};
// 处理值
if (node.codeList && node.codeList.type === 'STATIC') {
Object.assign(treeNode, {
// TODO 多语言
text: item.text,
nodeType: 'STATIC'
});
} else {
Object.assign(treeNode, {
text: item.text,
nodeType: node.treeNodeType,
appEntityName: node.appDataEntity?.codeName,
});
}
......
......@@ -9,4 +9,10 @@
line-height: 16px;
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 = {
},
counterService: ref(null),
{{/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}}',
controlName: '{{ctrl.name}}',
controlService: new TreeService<ControlVO>(ControlVO, new {{pascalCase ctrl.psAppDataEntity.codeName}}Service() ),
currentSelectedNode: {},
data: [],
items: [],
outputIconDefault: {{#eq ctrl.outputIconDefault false}}false{{else}}true{{/eq}},
echoSelectedNodes: [],
expandedKeys: [],
......
......@@ -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}}
// 获取计数器数据
......@@ -67,7 +67,7 @@ defineExpose({ name, state });
<a-tree
class="app-tree{{#if ctrl.psSysCss}} {{ctrl.psSysCss.cssName}}{{/if}}"
:blockNode="true"
:tree-data="state.data"
:tree-data="state.items"
:load-data="load"
:fieldNames="{ title: 'text', key: 'id' }"
:checkable="state.isMultiple"
......@@ -75,7 +75,7 @@ defineExpose({ name, state });
show-icon
v-model:expandedKeys="state.expandedKeys"
v-model:selectedKeys="state.selectedKeys"
@select="treeNodeSelect">
@select="onTreeNodeSelect">
<template #icon="node">
<span class="app-tree-node__icon">
<template v-if="node.iconCustomCode && node.iconScriptCode">
......@@ -94,21 +94,50 @@ defineExpose({ name, state });
</template>
<template #title="node">
{{#if (and ctrl.psAppCounterRef ctrl.psAppCounterRef.psAppCounter)}}
<span
:class="['app-tree-node__text', node.cssName]"
:title="node.tooltip ? node.tooltip : node.text">
<a-badge v-if="node.counterId && counterData.hasOwnProperty(node.counterId)" class="node__text-badge" :count="counterData[node.counterId]">
<template v-if="node.textCustomCode && node.textScriptCode">
<span :domPropsInnerHtml="getCustomText(node.textScriptCode)"></span>
</template>
<template v-else-if="node.html">
<span :domPropsInnerHtml="node.html"></span>
</template>
<a-dropdown :trigger="['contextmenu']">
<span
:class="['app-tree-node__text', node.cssName]"
:title="node.tooltip ? node.tooltip : node.text">
<a-badge v-if="node.counterId && counterData.hasOwnProperty(node.counterId)" class="node__text-badge" :count="counterData[node.counterId]">
<template v-if="node.textCustomCode && node.textScriptCode">
<span :domPropsInnerHtml="getCustomText(node.textScriptCode)"></span>
</template>
<template v-else-if="node.html">
<span :domPropsInnerHtml="node.html"></span>
</template>
<template v-else>
<span>\{{node.text}}</span>
</template>
</a-badge>
<template v-else>
<span>\{{node.text}}</span>
<template v-if="node.textCustomCode && node.textScriptCode">
<span :domPropsInnerHtml="getCustomText(node.textScriptCode)"></span>
</template>
<template v-else-if="node.html">
<span :domPropsInnerHtml="node.html"></span>
</template>
<template v-else>
<span>\{{node.text}}</span>
</template>
</template>
</a-badge>
<template v-else>
</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}}
<a-dropdown :trigger="['contextmenu']">
<span
:class="['app-tree-node__text', node.cssName]"
:title="node.tooltip ? node.tooltip : node.text">
<template v-if="node.textCustomCode && node.textScriptCode">
<span :domPropsInnerHtml="getCustomText(node.textScriptCode)"></span>
</template>
......@@ -118,22 +147,19 @@ defineExpose({ name, state });
<template v-else>
<span>\{{node.text}}</span>
</template>
</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>
</span>
{{else}}
<span
:class="['app-tree-node__text', node.cssName]"
:title="node.tooltip ? node.tooltip : node.text">
<template v-if="node.textCustomCode && node.textScriptCode">
<span :domPropsInnerHtml="getCustomText(node.textScriptCode)"></span>
</template>
<template v-else-if="node.html">
<span :domPropsInnerHtml="node.html"></span>
</template>
<template v-else>
<span>\{{node.text}}</span>
</template>
</span>
</a-dropdown>
{{/if}}
</template>
</a-tree>
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册