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

update:更新

1、新增代码表类型树节点支持
2、新增树节点自定义图标、自定义标题支持
3、增加部件计数器支持
4、删除多余输出语句
上级 f774df1d
......@@ -39,7 +39,6 @@ const itemClick = (item: IParam) => {
};
const hasCounter = (item: any) => {
console.log(item.counterId, props.counterData);
if (item.counterId && props.counterData && props.counterData.hasOwnProperty(item.counterId)) {
return true;
}
......
import { IParam, ViewDetail } from "../common";
import { IAppActionService, IAppAuthService, IAppCodeListService, IAppFuncService, IAppNotificationService, IOpenViewService } from "../service";
import { IAppActionService, IAppAuthService, IAppCodeListService, IAppCounterService, IAppFuncService, IAppNotificationService, IOpenViewService } from "../service";
/**
......@@ -67,6 +67,17 @@ export interface IApp {
*/
getCodeListService(): IAppCodeListService;
/**
* 获取计数器服务
*
* @param {IParam} counterRef 计数器引用
* @param {IParam} [context] 上下文
* @param {IParam} [viewParams] 视图参数
* @return {*} {IAppCounterService}
* @memberof IApp
*/
getCounterService(counterRef: IParam, context?: IParam, viewParams?: IParam): IAppCounterService;
/**
* 获取UI服务
*
......
import { ControlPropsBase, ControlStateBase, IActionParam, IParam, UIBase } from '@core';
import { ControlPropsBase, ControlStateBase, IActionParam, IAppCounterService, IParam, UIBase } from '@core';
/**
* @description 部件基类
......@@ -67,6 +67,26 @@ export class ControlBase {
this.state.viewParams = viewParams;
}
/**
* @description 使用计数器服务模块
* @memberof ControlBase
*/
public useCounterService() {
const { appCounterRef, context, viewParams } = this.state;
const { counterService } = toRefs(this.state);
if (appCounterRef) {
const _counterService = App.getCounterService(appCounterRef, context, viewParams);
_counterService.execute().then(() => {
counterService.value = _counterService;
});
}
onUnmounted(() => {
if (counterService && counterService.value) {
counterService.value.destory();
}
});
}
/**
* 获取当前激活数据
*
......@@ -101,7 +121,10 @@ export class ControlBase {
*/
public moduleInstall() {
this.setState();
// 处理导航参数
this.useControlContextParams();
// 使用计数器服务
this.useCounterService();
return {
state: this.state,
name: this.state.controlName,
......
......@@ -256,6 +256,23 @@ export class TreeControl extends MDControl {
}
}
}
// 默认选中
const defualtSelect = items.find((item: any) => item.selected);
if (defualtSelect) {
if (isMultiple && selectedNodes.findIndex((node: any) => node.id === defualtSelect.id) === -1) {
selectedNodes.push(deepCopy(defualtSelect));
// 设置选中样式
selectedKeys.push(defualtSelect.id);
} else if (!isMultiple) {
selectedNodes.splice(0, selectedNodes.length);
currentSelectedNode.value = deepCopy(defualtSelect);
selectedNodes.push(currentSelectedNode.value);
// 设置选中样式
selectedKeys.splice(0, selectedKeys.length);
selectedKeys.push(defualtSelect.id);
}
this.emit("ctrlEvent", { tag: this.props.name, action: "selectionchange", data: selectedNodes });
}
// 回显已选数据
if (echoSelectedNodes && echoSelectedNodes.length > 0) {
const checkedNodes = items.filter((item: IParam) => {
......@@ -263,6 +280,7 @@ export class TreeControl extends MDControl {
if (Object.is(item.srfkey, val.srfkey) && Object.is(item.srfmajortext, val.srfmajortext)) {
val.used = true;
selectedNodes.push(val);
selectedKeys.push(val.id);
this.emit("ctrlEvent", { tag: this.props.name, action: "selectionchange", data: selectedNodes });
return true;
}
......@@ -273,14 +291,18 @@ export class TreeControl extends MDControl {
echoSelectedNodes = echoSelectedNodes.filter((item: any) => !item.used);
if (!isSelectedAll) {
if (isMultiple) {
selectedNodes.push([...checkedNodes]);
// selectedNodes = selectedNodes.concat(checkedNodes);
// TODO 设置选中树节点
checkedNodes.push((node: any) => {
selectedNodes.push(node);
selectedKeys.push(node.id);
});
} else {
// TODO 设置选中树节点高亮
currentSelectedNode.value = deepCopy(checkedNodes[0]);
selectedNodes.splice(0, selectedNodes.length);
selectedNodes.push(currentSelectedNode.value);
// 设置选中样式
selectedKeys.splice(0, selectedKeys.length);
selectedKeys.push(currentSelectedNode.value.id);
}
}
}
......@@ -288,7 +310,10 @@ export class TreeControl extends MDControl {
// 父节点选中树,选中所有子节点
if (isSelectedAll) {
const leafNodes = items.filter((item: any) => item.isLeaf);
selectedNodes = selectedNodes.concat(leafNodes);
leafNodes.forEach((node: any) => {
selectedNodes.push(node);
selectedKeys.push(node.id);
});
this.emit("ctrlEvent", { tag: this.props.name, action: 'selectionchange', data: selectedNodes });
}
}
......
import { ControlServiceBase, ControlVOBase, deepCopy, IContext, IParam, isEmpty, TreeNodeRSVO, TreeNodeVO } from "@core";
import { ControlServiceBase, ControlVOBase, deepCopy, IAppCodeListService, IContext, IParam, isEmpty, isExistAndNotEmpty, TreeNodeRSVO, TreeNodeVO } from "@core";
/**
* @description 树部件服务
......@@ -16,6 +16,14 @@ export class TreeService<T extends ControlVOBase> extends ControlServiceBase<T>
*/
public TREENODE_SEPARATOR: string = ';';
/**
* @description 代码表服务
* @private
* @type {IAppCodeListService}
* @memberof TreeService
*/
private codeListService: IAppCodeListService = App.getCodeListService();
/**
* @description 获取节点
* @param {IContext} [context={}] 应用上下文
......@@ -174,15 +182,19 @@ export class TreeService<T extends ControlVOBase> extends ControlServiceBase<T>
return;
}
const treeNode: any = {
text: node.text,
tooltip: node.tooltip,
cssName: node.cssName,
nodeType: node.treeNodeType,
isUseLangRes: false,
allowDrag: node.allowDrag,
allowDrop: node.allowDrop,
allowEditText: node.allowEditText,
allowOrder: node.allowOrder,
appendCaption: node.appendCaption,
counterId: node.counterId,
cssName: node.cssName,
text: node.text,
textFormat: node.textFormat,
tooltip: node.tooltip,
nodeType: node.treeNodeType,
iconcls: node.iconcls,
isUseLangRes: false,
srfappctx: context,
srfmajortext: node.text,
enableckeck: node.enableCheck,
......@@ -213,8 +225,15 @@ export class TreeService<T extends ControlVOBase> extends ControlServiceBase<T>
resolve(list);
} else if (node.treeNodeType == 'CODELIST') {
// 代码表节点
const codeListItems: any[] = [];
// TODO 待补充代码表服务
if (node.codeList && isExistAndNotEmpty(node.codeList.tag)) {
this.codeListService.getCodeListItems({ tag: node.codeList.tag, context, viewParams: {} }).then((items: any[]) => {
const treeNodes: any[] = this.transFormCodeListData(items, context, filter, node);
list.push(...treeNodes);
resolve(list);
}).catch((error: any) => {
resolve([]);
});
}
} else if (node.treeNodeType == 'DE' && node.appDataEntity) {
// 实体节点
let bFirst: boolean = true;
......@@ -296,39 +315,27 @@ export class TreeService<T extends ControlVOBase> extends ControlServiceBase<T>
} else if (node.icon) {
Object.assign(treeNode, { icon: node.icon });
}
if (node.enableCheck) {
Object.assign(treeNode, { enablecheck: true });
}
if (node.disableSelect) {
Object.assign(treeNode, { disabled: true });
}
if (node.allowDrag) {
Object.assign(treeNode, { allowDrag: true });
}
if (node.allowDrop) {
Object.assign(treeNode, { allowDrop: true });
}
if (node.allowEditText) {
Object.assign(treeNode, { allowEditText: true });
}
if (node.allowOrder) {
Object.assign(treeNode, { allowOrder: true });
}
if (node.cssName) {
Object.assign(treeNode, { cssName: node.cssName });
}
if (node.expanded) {
Object.assign(treeNode, { expanded: node.expandFirstOnly ? bFirst : true });
} else {
Object.assign(treeNode, { expanded: filter.isAutoExpand });
}
if (node.appendCaption) {
Object.assign(treeNode, { appendCaption: true });
}
if (node.textFormat) {
Object.assign(treeNode, { textFormat: node.textFormat });
}
Object.assign(treeNode, { isLeaf: !node.hasPSDETreeNodeRSs });
Object.assign(treeNode, {
appendCaption: node.appendCaption,
appEntityCodeName: deCodeName,
allowDrag: node.allowDrag,
allowDrog: node.allowDrop,
allowEditText: node.allowEditText,
allowOrder: node.allowOrder,
curData: entity,
cssName: node.cssName,
counterMode: node.counterMode,
disabled: node.disableSelect,
enablecheck: node.enableCheck,
expanded: node.expanded ? node.expandFirstOnly ? bFirst : true : filter.isAutoExpand,
textFormat: node.textFormat,
selected: node.selected,
isLeaf: !node.hasPSDETreeNodeRSs,
navfilter: node.navFilter,
nodeid: treeNode.srfkey,
nodeid2: filter.strRealNodeId,
nodeType: node.nodeType,
});
if (node.leafFlagPSAppDEField?.codeName) {
const leafFlag = entity[node.leafFlagPSAppDEField.codeName.toLowerCase()];
if (leafFlag != null && leafFlag != undefined) {
......@@ -357,22 +364,6 @@ export class TreeService<T extends ControlVOBase> extends ControlServiceBase<T>
}
})
}
Object.assign(treeNode, { selected: node.selected });
if (node.navFilter) {
Object.assign(treeNode, { navfilter: node.navFilter });
}
Object.assign(treeNode, { curData: entity });
if (node.counterId) {
Object.assign(treeNode, { counterId: node.counterId });
}
// 为1时计数器不显示0值
if (node.counterMode) {
Object.assign(treeNode, { counterMode: node.counterMode });
}
Object.assign(treeNode, { nodeid: treeNode.srfkey });
Object.assign(treeNode, { nodeid2: filter.strRealNodeId });
Object.assign(treeNode, { nodeType: node.nodeType, appEntityCodeName: deCodeName });
list.push(treeNode);
resolve(list);
bFirst = false;
......@@ -390,6 +381,97 @@ export class TreeService<T extends ControlVOBase> extends ControlServiceBase<T>
});
}
/**
* 翻译代码表数据
*
* @private
* @param {any[]} codeItems 代码表项
* @param {*} context 应用上下文
* @param {*} filter 过滤参数
* @param {TreeNodeVO} node 树节点
* @return {*} {any[]}
* @memberof TreeService
*/
private transFormCodeListData(codeItems: any[], context: any, filter: any, node: TreeNodeVO): any[] {
const treeNodes: any[] = [];
let bFirst: boolean = true;
if (codeItems.length) {
for (const item of codeItems) {
const treeNode: any = {
srfappctx: context,
curData: item
};
// 处理值
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,
});
}
// 快速搜索过滤
if (node.enableQuickSearch && filter.srfnodefilter) {
const pattern = new RegExp(`${node.text}`, 'i');
if (filter.srfnodefilter.search(pattern) === -1) {
continue;
}
}
// 主信息属性、主键
Object.assign(treeNode, {
srfmajortext: treeNode.text,
srfkey: item.value
});
// 节点标识
let strNodeId: string = `${node.nodeType}${this.TREENODE_SEPARATOR}${item.value}`;
if (node.appendPNodeId) {
strNodeId += `${this.TREENODE_SEPARATOR}${filter.realnodeid}`;
}
Object.assign(treeNode, { id: strNodeId });
Object.assign(treeNode, {
appendCaption: node.appendCaption,
allowDrag: node.allowDrag,
allowDrog: node.allowDrop,
allowEditText: node.allowEditText,
allowOrder: node.allowOrder,
cssName: node.cssName,
counterId: node.counterId,
counterMode: node.counterMode,
disabled: node.disableSelect,
enablecheck: node.enableCheck,
expanded: node.expanded ? node.expandFirstOnly ? bFirst : true : filter.isAutoExpand,
iconcls: node.iconcls,
icon: node.icon,
selected: node.selected,
navfilter: node.navFilter,
navigateContext: node.navigateContext,
navgateParams: node.navigateParams,
nodeid: treeNode.srfkey,
nodeid2: filter.strRealNodeId,
});
if (item.codeItems?.length) {
const children = this.transFormCodeListData(item.codeItems, context, filter, node);
Object.assign(treeNode, { leaf: false, children: children });
} else {
// TODO 动态代码表的子节点
Object.assign(node, { leaf: true });
}
treeNodes.push(treeNode);
}
}
bFirst = false;
return treeNodes;
}
/**
* @description 获取查询集合
* @private
......@@ -479,20 +561,21 @@ export class TreeService<T extends ControlVOBase> extends ControlServiceBase<T>
if ((resNavParams && Object.keys(resNavParams).length > 0) || (resParams && Object.keys(resParams).length > 0)) {
let tempViewParamData: any = {};
let tempViewParams: any = {};
if (filter && filter.viewparams) {
tempViewParams = filter.viewparams;
tempViewParamData = deepCopy(filter.viewparams);
if (filter && filter.viewParams) {
tempViewParams = filter.viewParams;
tempViewParamData = deepCopy(filter.viewParams);
}
if (Object.keys(resNavParams).length > 0) {
if (resNavParams && Object.keys(resNavParams).length > 0) {
Object.keys(resNavParams).forEach((item: any) => {
let curDataObj: any = resNavParams[item];
this.handleCustomDataLogic(context, tempViewParams, curDataObj, tempViewParamData, item, filter?.srfparentdata);
});
}
if (Object.keys(resParams).length > 0) {
if (resParams && Object.keys(resParams).length > 0) {
Object.keys(resParams).forEach((item: any) => {
let curDataObj: any = resParams[item];
tempViewParamData[item.toLowerCase()] = curDataObj.value;
console.log(11111, curDataObj);
tempViewParamData[item.toLowerCase()] = curDataObj;
});
}
Object.assign(filter, { viewparams: tempViewParamData });
......@@ -513,43 +596,27 @@ export class TreeService<T extends ControlVOBase> extends ControlServiceBase<T>
* @memberof TreeService
*/
public handleCustomDataLogic(context: any, viewparams: any, curNavData: any, tempData: any, item: string, parentData?: any) {
// 直接值直接赋值
if (curNavData.isRawValue) {
if (isEmpty(curNavData.value)) {
Object.defineProperty(tempData, item.toLowerCase(), {
value: null,
writable: true,
enumerable: true,
configurable: true,
});
} else {
Object.defineProperty(tempData, item.toLowerCase(), {
value: curNavData.value,
writable: true,
enumerable: true,
configurable: true,
});
}
} else {
if (curNavData && curNavData.startsWith('%') && curNavData.endsWith('%')) {
const param = curNavData.slice(1, curNavData.length - 1)?.toLowerCase();
// 先从导航上下文取数,没有再从导航参数(URL)取数,如果导航上下文和导航参数都没有则为null
if (parentData && parentData[curNavData.value.toLowerCase()] != null) {
if (parentData && param && parentData[param] != null) {
Object.defineProperty(tempData, item.toLowerCase(), {
value: parentData[curNavData.value.toLowerCase()],
value: parentData[param],
writable: true,
enumerable: true,
configurable: true,
});
} else if (context[curNavData.value.toLowerCase()] != null) {
} else if (context[param] != null) {
Object.defineProperty(tempData, item.toLowerCase(), {
value: context[curNavData.value.toLowerCase()],
value: context[param],
writable: true,
enumerable: true,
configurable: true,
});
} else {
if (viewparams[curNavData.value.toLowerCase()] != null) {
if (viewparams[param] != null) {
Object.defineProperty(tempData, item.toLowerCase(), {
value: viewparams[curNavData.value.toLowerCase()],
value: viewparams[param],
writable: true,
enumerable: true,
configurable: true,
......@@ -563,6 +630,23 @@ export class TreeService<T extends ControlVOBase> extends ControlServiceBase<T>
});
}
}
} else {
// 直接值
if (isEmpty(curNavData.value)) {
Object.defineProperty(tempData, item.toLowerCase(), {
value: null,
writable: true,
enumerable: true,
configurable: true,
});
} else {
Object.defineProperty(tempData, item.toLowerCase(), {
value: curNavData.value,
writable: true,
enumerable: true,
configurable: true,
});
}
}
}
......
.app-tree {
// 设置徽标高度
.node__text-badge {
height: 16px;
}
// 设置节点徽标位置
.ant-badge-count {
height: 16px;
line-height: 16px;
transform: translate(40px, -1px);
}
}
\ No newline at end of file
......@@ -6,4 +6,5 @@
@use './app-tab-exp-panel.scss';
@use './app-tab-view-panel.scss';
@use './app-portlet.scss';
@use './app-grid.scss';
\ No newline at end of file
@use './app-grid.scss';
@use './app-tree.scss';
\ No newline at end of file
......@@ -38,13 +38,14 @@ export class ControlVO extends ControlVOBase implements TreeControlVO {
{{#if treeNode.psAppCodeList}}
codeList: {
codeName: '{{treeNode.psAppCodeList.codeName}}',
tag: '{{treeNode.psAppCodeList.codeListTag}}',
type: '{{treeNode.psAppCodeList.codeListType}}'
},
{{/if}}
counterId: '{{treeNode.counterId}}',
counterMode: {{treeNode.counterMode}},
{{#if treeNode.psSysCss}}
cssName: '{{treeNode.psSysCss.cssName}}'
cssName: '{{treeNode.psSysCss.cssName}}',
{{/if}}
{{#if treeNode.psDETreeNodeDataItems}}
deTreeNodeDataItems: [
......@@ -184,11 +185,30 @@ export class ControlVO extends ControlVOBase implements TreeControlVO {
}
export const ctrlState = {
appEntityCodeName: '{{ctrl.appEntity.codeName}}',
appDeCodeName:'{{ctrl.appEntity.codeName}}',
appDeLogicName: '{{ctrl.appEntity.logicName}}',
appDeKeyFieldName: '{{#if ctrl.appEntity.keyPSAppDEField}}{{ctrl.appEntity.keyPSAppDEField.codeName}}{{/if}}',
appDeMajorFieldName: '{{#if ctrl.appEntity.majorPSAppDEField}}{{ctrl.appEntity.majorPSAppDEField.codeName}}{{/if}}',
{{#and ctrl.psAppCounterRef ctrl.psAppCounterRef.psAppCounter}}
appCounterRef: {
{{#with ctrl.psAppCounterRef.psAppCounter as | counter |}}
id: '{{ctrl.psAppCounterRef.id}}',
getAction: '{{counter.getPSAppDEAction.codeName}}',
timer: {{#if counter.timer}}{{counter.timer}}{{else}}6000{{/if}},
{{#if counter.psAppDataEntity}}
deCodeName: '{{lowerCase counter.psAppDataEntity.codeName}}'
{{/if}}
{{/with}}
},
counterService: ref(null),
{{/and}}
controlCodeName: '{{ctrl.codeName}}',
controlName: '{{ctrl.name}}',
controlService: new TreeService<ControlVO>(ControlVO, new {{pascalCase ctrl.psAppDataEntity.codeName}}Service() ),
currentSelectedNode: {},
data: [],
outputIconDefault: {{#eq ctrl.outputIconDefault false}}false{{else}}true{{/eq}},
echoSelectedNodes: [],
expandedKeys: [],
selectedKeys: [],
......
<script setup lang="ts">
import { Subject } from 'rxjs';
import { IActionParam, IParam, ControlAction, TreeControl, IContext } from '@core';
import { FileTextOutlined } from '@ant-design/icons-vue';
import { ctrlState } from './{{spinalCase ctrl.codeName}}-tree-state';
interface Props {
......@@ -28,15 +29,40 @@ interface CtrlEmit {
(name: "ctrlEvent", value: IActionParam): void;
}
const emit = defineEmits<CtrlEmit>();
// 获取自定义图标
const getCustomIcon = (scriptCode: any) => {
let icon: string = '';
const code = scriptCode.replace(new RegExp('return', 'g'), `icon =`);
eval(code);
return icon;
}
// 获取自定义文本
const getCustomText = (scriptCode: any) => {
let text: string = '';
const code = scriptCode.replace(new RegExp('return', 'g'), `text =`);
eval(code);
return text;
}
// 安装功能模块,提供状态和能力方法
const { name, state, load, treeNodeSelect } = new TreeControl(ctrlState, props, emit).moduleInstall();
{{#and ctrl.psAppCounterRef ctrl.psAppCounterRef.psAppCounter}}
// 获取计数器数据
const counterData = computed(() => {
const { counterService } = state;
if (counterService) {
return counterService.data;
}
return {};
})
{{/and}}
// 暴露内部状态及能力
defineExpose({ name, state });
</script>
// TODO 树节点待支持图标和自定义绘制
<template>
<a-tree
class="app-tree{{#if ctrl.psSysCss}} {{ctrl.psSysCss.cssName}}{{/if}}"
......@@ -46,13 +72,69 @@ defineExpose({ name, state });
:fieldNames="{ title: 'text', key: 'id' }"
:checkable="state.isMultiple"
:multiple="state.isMultiple"
show-icon
v-model:expandedKeys="state.expandedKeys"
v-model:selectedKeys="state.selectedKeys"
@select="treeNodeSelect">
<template #title="{ text, id }">
<div class="app-tree-node">
<span class="tree-node__title">\{{ text }}</span>
</div>
<template #icon="node">
<span class="app-tree-node__icon">
<template v-if="node.iconCustomCode && node.iconScriptCode">
<span :domPropsInnerHtml="getCustomIcon(node.iconScriptCode)"></span>
</template>
<template v-else-if="node.iconcls">
<i :class="node.iconcls"></i>
</template>
<template v-else-if="node.icon">
<img :src="node.icon" style='width:14px;height:14px;vertical-align: bottom;'/>
</template>
<template v-else-if="state.outputIconDefault">
<FileTextOutlined />
</template>
</span>
</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>
<template v-else>
<span>\{{node.text}}</span>
</template>
</a-badge>
<template v-else>
<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>
</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>
{{/if}}
</template>
</a-tree>
</template>
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册