diff --git a/packages/tree-design/CHANGELOG.md b/packages/tree-design/CHANGELOG.md index 25f636bdaa2521bea5912eb189912331563d5233..506e2eb69a567fcb6ae72cf0bfdb1788c3f82f57 100644 --- a/packages/tree-design/CHANGELOG.md +++ b/packages/tree-design/CHANGELOG.md @@ -9,14 +9,16 @@ ### Change -- 更新树设计工具操作和预览区样式 +- 更新关系节点拖拽样式,更新预览区暗色主题样式 +- 更新节点和节点关系支持拖拽,节点和节点关系服务重写 +- 更新树设计工具操作和预览区样式 ### Add -- 更新预览区默认展开根节点,左侧预览区树节点点击时,操作区进行对应节点选中 -- 更新树设计工具操作区适配暗黑主题 -- 新增树设计工具预览区树壳组件 -- 更新树设计工具操作区组件 +- 更新预览区默认展开根节点,左侧预览区树节点点击时,操作区进行对应节点选中 +- 更新树设计工具操作区适配暗黑主题 +- 新增树设计工具预览区树壳组件 +- 更新树设计工具操作区组件 ## [0.0.3-alpha.20] - 2024-09-10 diff --git a/packages/tree-design/src/components/tree-shell/tree-shell.scss b/packages/tree-design/src/components/tree-shell/tree-shell.scss index ca1cc0508f4407da427a4bb0f2bc81db9e1d3bb5..2fbd3ec3a1ac3e8a537b8404eb3fde0a25787730 100644 --- a/packages/tree-design/src/components/tree-shell/tree-shell.scss +++ b/packages/tree-design/src/components/tree-shell/tree-shell.scss @@ -44,3 +44,25 @@ $tree-shell: ( } } } + + +:root.studio_dark { + @include b('tree-shell') { + @include m('light') { + .#{bem('control-treeview-tree')} { + &.el-tree { + @include mixin-light-theme; + + .el-tree-node { + &:focus { + outline: unset; + } + &.is-current > .el-tree-node__content { + @include mixin-light-theme; + } + } + } + } + } + } +} diff --git a/packages/tree-design/src/components/tree-shell/tree-shell.tsx b/packages/tree-design/src/components/tree-shell/tree-shell.tsx index 6297228a270537234a9acd9f80244fc101d4d4da..62b2ade2522abfd64d0e723a4d755758af0d9a4f 100644 --- a/packages/tree-design/src/components/tree-shell/tree-shell.tsx +++ b/packages/tree-design/src/components/tree-shell/tree-shell.tsx @@ -51,6 +51,7 @@ export default defineComponent({ appId: props.context!.srfappid, id: item.psdetreenodersname, searchmode: item.searchmode, + ordervalue: item.ordervalue, childDETreeNodeId: cnode?.nodetype?.toLowerCase(), parentDETreeNodeId: pnode?.nodetype?.toLowerCase(), }; @@ -65,7 +66,6 @@ export default defineComponent({ pickupDEFName: item.psdername.split('_').at(-1), minorCodeName: `${cnode?.psdename}s`, minorServiceCodeName: `${cnode?.psdename}s`, - orderValue: 100, serviceCodeName: cnode?.psdename, name: cnode?.psdename, }, @@ -102,7 +102,6 @@ export default defineComponent({ const tempItems: IData[] = []; props.items.forEach((item: IData) => { // 只有存在关系的节点才绘制 - const pids: string[] = []; let hasRsTag: boolean = false; props.rsDatas.forEach((rss: IData) => { if ( @@ -111,9 +110,6 @@ export default defineComponent({ ) { hasRsTag = true; } - if (rss.cpsdetreenodeid === item.srfkey) { - pids.push(rss.ppsdetreenodeid); - } }); if (hasRsTag) { if (item.rootnode === 1) { @@ -128,7 +124,6 @@ export default defineComponent({ _nodeId: item.nodetype, isRoot: item.rootnode === 1, _disableSelect: false, - _pid: pids, }); } }); @@ -137,14 +132,8 @@ export default defineComponent({ // 初始化树模型 const init = () => { - const detreeNodeRSs = parseTreeModelRS( - props.majorData?.psdetreenoderss, - props.majorData?.psdetreenodes, - ); - const detreeNodes = parseTreeModelNode( - detreeNodeRSs, - props.majorData?.psdetreenodes, - ); + const detreeNodeRSs = parseTreeModelRS(props.rsDatas, props.items); + const detreeNodes = parseTreeModelNode(detreeNodeRSs, props.items); const model: IDETree = { appId: props.context!.srfappid, modelId: 'design_tree', diff --git a/packages/tree-design/src/panel-items/tree_design_operation/tree_design_operation.controller.ts b/packages/tree-design/src/panel-items/tree_design_operation/tree_design_operation.controller.ts index 322529d7cc7b21c8915e1d58c220e16587d2e469..49767019cbacd2d97afb4fe60421c3090395a035 100644 --- a/packages/tree-design/src/panel-items/tree_design_operation/tree_design_operation.controller.ts +++ b/packages/tree-design/src/panel-items/tree_design_operation/tree_design_operation.controller.ts @@ -6,7 +6,7 @@ import { } from '@ibiz-template-plugin/design-base'; import { IAppDataEntity, IDEEditForm } from '@ibiz/model-core'; import { IAppDEService, getControl } from '@ibiz-template/runtime'; -import { createUUID } from 'qx-util'; +import { createUUID, generateOrderValue } from 'qx-util'; import { IPortalMessage } from '@ibiz-template/core'; export class TreeDesignOperationController extends DesignOperationController { @@ -111,7 +111,8 @@ export class TreeDesignOperationController extends DesignOperationController { } /** - * 加载后 + * 加载后-根据数据和关系构建一个树形结构数据,第一层为主数据,值为{ data: majorData,children:[]} + * childern 为所有节点数据的集合,里面每一项格式也是{data: IData,children:[]},其中data就是节点项的数据,里面的children则是包含当前节点下的所有关系节点,格式为{data:IData},data是关系数据 * * @protected * @param {IData} args @@ -190,10 +191,9 @@ export class TreeDesignOperationController extends DesignOperationController { public async addItemNode(event: MouseEvent): Promise { event.stopPropagation(); event.preventDefault(); - const tempNodeData: IData = {}; - this.fillDefault(tempNodeData); - const result = await this.itemService.createTemp(this.panel.context, [ - tempNodeData, + const draftData = await this.itemService.getDraft(this.panel.context, {}); + const result = await this.itemService.create(this.panel.context, [ + draftData.data, ]); if (result.ok && Array.isArray(result.data)) { await this.view.evt.emit('onCreateSuccess', undefined); @@ -250,21 +250,38 @@ export class TreeDesignOperationController extends DesignOperationController { * @memberof TreeDesignOperationController */ public async handleAddItem(items: IData[], data: IData): Promise { - const rss = items.map((item: IData) => { - const param = { - ppsdetreenodeid: data.srfkey, - ppsdetreenodename: data.srfmajortext, - cpsdetreenodeid: item.psdetreenodeid, - cpsdetreenodename: item.psdetreenodename, - psdetreenodersname: `${data.text}-${item.text}`, - psdetreenodersid: createUUID(), - psdetreeviewid: data.psdetreeviewid, - }; - return param; - }); + const tempRss = await Promise.all( + items.map(async (item: IData) => { + const draftData = await this.nodeRsService.getDraft( + this.panel.context, + {}, + ); + const param = { + ...draftData.data, + ppsdetreenodeid: data.srfkey, + ppsdetreenodename: data.srfmajortext, + cpsdetreenodeid: item.psdetreenodeid, + cpsdetreenodename: item.psdetreenodename, + psdetreenodersname: `${data.text}-${item.text}`, + psdetreenodersid: createUUID(), + psdetreeviewid: data.psdetreeviewid, + }; + return param; + }), + ); - const result = await this.nodeRsService.createTemp(this.panel.context, rss); + const result = await this.nodeRsService.create(this.panel.context, tempRss); if (result.ok && Array.isArray(result.data)) { + // 更新关系节点的ordervalue; + const rsDatas = await this.getNodeRss(); + const tempItems = rsDatas.filter((_item: IData) => { + return _item.ppsdetreenodeid === data.srfkey; + }); + tempItems.forEach((_item: IData, index: number) => { + _item.ordervalue = generateOrderValue(index); + _item.srfordervalue = generateOrderValue(index); + }); + await this.nodeRsService.update(this.panel.context, tempItems); await this.view.evt.emit('onCreateSuccess', undefined); const item = result.data[result.data.length - 1]; if (item) { @@ -279,42 +296,15 @@ export class TreeDesignOperationController extends DesignOperationController { } } - /** - * 填充节点数据 - * - * @param {*} context - * @param {*} entity - * @memberof TreeDesignOperationController - */ - protected fillDefault(entity: IData): void { - const detailNames = this.state.items.map(detail => detail.nodetype); - let nStartIndex = 0; - let nodeTypeName = ''; - while (true) { - const strDefaultName = `node${ - nStartIndex === 0 ? '' : `_${nStartIndex}` - }`; - if (detailNames.indexOf(strDefaultName) === -1) { - nodeTypeName = strDefaultName; - break; - } - nStartIndex += 1; - } - entity.psdetreenodename = `节点名称${nStartIndex === 0 ? '' : nStartIndex}`; - entity.nodetype = nodeTypeName; - entity.psdetreenodeid = `tempKey_${createUUID()}`; - entity.rootnode = '0'; - entity.appendpnodeid = '0'; - entity.treenodetype = 'STATIC'; - } - /** * 移除节点项 * * @param {string} key * @memberof TreeDesignOperationController */ - public removeItem(data: IData): void { + public removeItem(event: MouseEvent, data: IData): void { + event.preventDefault(); + event.stopPropagation(); this.remove(data); } @@ -364,4 +354,39 @@ export class TreeDesignOperationController extends DesignOperationController { }); } } + + /** + * 计算并保存拖拽后的项的顺序 + * + * @memberof TreeDesignOperationController + */ + public async calcItemsOrder(): Promise { + const nodes: ITreeNode[] = []; + const rss: IData[] = []; + this.state.treeData[0].children?.forEach( + (item: ITreeNode, index: number) => { + if (item.data.rootnode) { + item.data.srfordervalue = 1; + } else { + item.data.srfordervalue = 100 * (index + 1); + } + nodes.push(item.data); + if (item.children) { + const tempRs = item.children.map((child: IData, _index: number) => { + return { + ...child.data, + ordervalue: generateOrderValue(_index), + srfordervalue: generateOrderValue(_index), + }; + }); + rss.push(...tempRs); + } + }, + ); + // 更新关系节点 + await this.nodeRsService.update(this.panel.context, rss); + // 更新节点 + await this.itemService.update(this.panel.context, nodes); + await this.view.evt.emit('onUpdateSuccess', undefined); + } } diff --git a/packages/tree-design/src/panel-items/tree_design_operation/tree_design_operation.scss b/packages/tree-design/src/panel-items/tree_design_operation/tree_design_operation.scss index 45bb2c9d901095157e081e22ea3fc5d537be0827..3b55a635cc44f9b863f3ad2a3c21f8f2518beb24 100644 --- a/packages/tree-design/src/panel-items/tree_design_operation/tree_design_operation.scss +++ b/packages/tree-design/src/panel-items/tree_design_operation/tree_design_operation.scss @@ -67,8 +67,14 @@ $tree_design_operation: ( } @include b('tree_design_operation-tree-item') { + user-select: none; @include set-component-css-var(tree_design_operation, $tree_design_operation); - + @include when('moving'){ + cursor: move; + @include e('node'){ + cursor: move; + } + } width: 100%; @include e('node') { display: flex; @@ -151,6 +157,9 @@ $tree_design_operation: ( height: getCssVar(tree_design_operation, children-item-height); padding-left: getCssVar(tree_design_operation, children-item-padding); border: 1px solid getCssVar(color, border); + @include when('moving'){ + cursor: move; + } @include m('label') { flex: 1; } @@ -190,15 +199,6 @@ $tree_design_operation: ( background-color: transparent; font-size: getCssVar(font-size,header-6); } - @include e('caption') { - background-color: getCssVar(color, bg, 0); - &:hover { - background-color: getCssVar(color, bg, 3); - } - @include when('selected') { - background-color: getCssVar(tree_design_operation, item-selected-bg); - } - } } @include b('tree_design_operation-tree-item') { @include e('node') { @@ -235,3 +235,13 @@ $tree_design_operation: ( } } } +.dragClass{ + @include set-component-css-var(tree_design_operation, $tree_design_operation); + padding-left: getCssVar(tree_design_operation, item-padding-left); + border-style: dotted; + font-size: getCssVar(font-size, regular); +} +.chosenClass{ + @include set-component-css-var(tree_design_operation, $tree_design_operation); + color: getCssVar(color, primary, text); +} diff --git a/packages/tree-design/src/panel-items/tree_design_operation/tree_design_operation.tsx b/packages/tree-design/src/panel-items/tree_design_operation/tree_design_operation.tsx index 3cac6e5186079e13123e19aeb348eb005dc30453..fae257a6c928b643ab1bde51142842ccb3443dbb 100644 --- a/packages/tree-design/src/panel-items/tree_design_operation/tree_design_operation.tsx +++ b/packages/tree-design/src/panel-items/tree_design_operation/tree_design_operation.tsx @@ -1,12 +1,16 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { PropType, computed, defineComponent, ref } from 'vue'; +import { PropType, defineComponent, ref } from 'vue'; import { useNamespace } from '@ibiz-template/vue3-util'; import { IPanelRawItem } from '@ibiz/model-core'; +import draggable from 'vuedraggable'; import './tree_design_operation.scss'; import { TreeDesignOperationController } from './tree_design_operation.controller'; export default defineComponent({ name: 'IBizTreeDesignOperation', + components: { + draggable, + }, props: { modelData: { type: Object as PropType, @@ -21,6 +25,7 @@ export default defineComponent({ const c = props.controller; const ns = useNamespace('tree_design_operation'); const state = c.state; + const isMoving = ref(false); // 过滤搜索值 const searchValue = ref(''); @@ -51,6 +56,34 @@ export default defineComponent({ collapseItems.value = state.items.map((item: IData) => item.srfkey); }; + // 阻止默认事件 + const onDragenter = (e: Event) => { + e.preventDefault(); + }; + const onDragleave = (e: Event) => { + e.preventDefault(); + }; + const onDragover = (e: Event) => { + e.preventDefault(); + }; + + /** + * 拖动结束 + * + */ + const onMoveEnd = () => { + isMoving.value = false; + c.calcItemsOrder(); + }; + + /** + * 开始拖动 + * + */ + const onStartMoving = () => { + isMoving.value = true; + }; + // 绘制关系子项 const renderRsItems = (pData: IData, context: IData) => { const { data } = context; @@ -59,6 +92,7 @@ export default defineComponent({ class={[ ns.be('tree-item', 'rs-item'), ns.is('selected', state.activeNode === data.srfkey), + ns.is('moving', isMoving.value), ]} onClick={() => c.onSelect(data)} > @@ -79,7 +113,8 @@ export default defineComponent({ }; // 绘制头部 - const renderHeader = (data: IData) => { + const renderHeader = (context: IData) => { + const { data } = context; return (
{ const { data, children } = context; return ( -
+
c.removeItem(data)} + onClick={(event: MouseEvent) => c.removeItem(event, data)} > - {children.map((child: IData) => { - return renderRsItems(data, child); - })} + + {{ + item: (_data: IData) => { + const { element } = _data; + return renderRsItems(data, element); + }, + }} +
); @@ -203,41 +260,31 @@ export default defineComponent({ // 绘制项 const renderItem = (context: IData) => { - const { data, children } = context; - const header = renderHeader(data); - const content = children - .filter((item: IData) => { - return item.data.text.indexOf(searchValue.value) > -1; - }) - .map((child: IData) => { - return renderNode(child); - }); - return [header, content]; + return context.children.map((item: IData) => { + if (item.data.text.indexOf(searchValue.value) < 0) return null; + return renderNode(item); + }); }; - // 树节点数据 - const nodes = computed(() => { - if (state.treeData && state.treeData.length > 0) { - const items = state.treeData[0].children || []; - const index = items.findIndex((item: IData) => { - return item.data.rootnode === 1; - }); - if (index !== -1) { - const root = items.splice(index, 1); - items.unshift(...root); - } - return items.filter((item: IData) => { - return item.label.indexOf(searchValue.value) !== -1; - }); - } - return []; - }); - - return { ns, state, nodes, renderItem, renderHeader }; + return { + ns, + state, + renderItem, + renderHeader, + onDragover, + onDragleave, + onDragenter, + }; }, render() { return ( -
+
+ {this.renderHeader(this.state.treeData[0])} {this.state.treeData.map((item: IData) => { return this.renderItem(item); })} diff --git a/packages/tree-design/src/service/psdetree-node-rs/psdetree-node-rs.service.ts b/packages/tree-design/src/service/psdetree-node-rs/psdetree-node-rs.service.ts index 307721cd880e7d3fee17430f4761d4b7f3745e3a..c59a37155df5a6064797c1c5bc588c39f77c429c 100644 --- a/packages/tree-design/src/service/psdetree-node-rs/psdetree-node-rs.service.ts +++ b/packages/tree-design/src/service/psdetree-node-rs/psdetree-node-rs.service.ts @@ -15,6 +15,29 @@ export class PSDETreeNodeRSService extends DEService { params2?: IParams, header?: IData, ): Promise { + if (id === 'Create' && params) { + if (Array.isArray(params)) { + await Promise.all( + params.map(item => { + return this.fillDefault(item); + }), + ); + } else { + await this.fillDefault(params); + } + } return super.exec(id, context, params, params2); } + + /** + * 填充默认数据 + * + * @protected + * @param {IData} entity + * @memberof PSDETreeNodeRSService + */ + protected fillDefault(entity: IData): void { + entity.validflag = '1'; + entity.searchmode = '3'; + } } diff --git a/packages/tree-design/src/service/psdetree-node/psdetree-node.service.ts b/packages/tree-design/src/service/psdetree-node/psdetree-node.service.ts index 34e1f91ca67972dc9fdea9f63619633e8e5fc9ba..e0a7d1f5bb2cfc3453e0404d29f00c7e8810d903 100644 --- a/packages/tree-design/src/service/psdetree-node/psdetree-node.service.ts +++ b/packages/tree-design/src/service/psdetree-node/psdetree-node.service.ts @@ -1,6 +1,8 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ +/* eslint-disable no-constant-condition */ import { DEService, IDataEntity } from '@ibiz-template/runtime'; import { IHttpResponse } from '@ibiz-template/core'; +import { createUUID } from 'qx-util'; import { PSDETreeNode } from '../../entity'; export class PSDETreeNodeService extends DEService { @@ -15,6 +17,49 @@ export class PSDETreeNodeService extends DEService { params2?: IParams, header?: IData, ): Promise { + if (id === 'Create' && params) { + if (Array.isArray(params)) { + await Promise.all( + params.map(item => { + return this.fillDefault(context, item); + }), + ); + } else { + await this.fillDefault(context, params); + } + } return super.exec(id, context, params, params2); } + + /** + * 填充默认数据 + * + * @protected + * @param {IData} entity + * @memberof PSDETreeNodeService + */ + protected async fillDefault(context: IContext, entity: IData): Promise { + const result = await this.fetchDefault(context); + const detailNames = result.data.map((detail: IData) => detail.nodetype); + let nStartIndex = 0; + let nodeTypeName = ''; + while (true) { + const strDefaultName = `node${ + nStartIndex === 0 ? '' : `_${nStartIndex}` + }`; + if (detailNames.indexOf(strDefaultName) === -1) { + nodeTypeName = strDefaultName; + break; + } + nStartIndex += 1; + } + entity.psdetreenodename = `节点名称${nStartIndex === 0 ? '' : nStartIndex}`; + entity.nodetype = nodeTypeName; + entity.srfordervalue = nStartIndex === 0 ? 1 : nStartIndex * 100; + entity.ordervalue = nStartIndex === 0 ? 1 : nStartIndex * 100; + entity.psdetreenodeid = `tempKey_${createUUID()}`; + entity.rootnode = '0'; + entity.appendpnodeid = '0'; + entity.treenodetype = 'STATIC'; + } }