diff --git a/packages/dnd-design/public/assets/svg/lightning.svg b/packages/dnd-design/public/assets/svg/lightning.svg
new file mode 100644
index 0000000000000000000000000000000000000000..58f4201bcda31d8bff8416d2213085967a17d186
--- /dev/null
+++ b/packages/dnd-design/public/assets/svg/lightning.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/packages/dnd-design/src/components/dnd-draggable-item/dnd-draggable-item.scss b/packages/dnd-design/src/components/dnd-draggable-item/dnd-draggable-item.scss
index 2a3c6b571e9278dbad9fb083d673ec911505b30b..04fbd01a99072e7cf9ec13bbce2d413bb56fdaeb 100644
--- a/packages/dnd-design/src/components/dnd-draggable-item/dnd-draggable-item.scss
+++ b/packages/dnd-design/src/components/dnd-draggable-item/dnd-draggable-item.scss
@@ -23,10 +23,6 @@
> .#{bem(dnd-design-draggable-item-content)} {
outline: 2px solid #{getCssVar(color-primary)};
}
-
- > .#{bem(dnd-design-draggable-item-actions)} {
- display: flex;
- }
}
&:hover {
@@ -54,20 +50,26 @@
top: 0;
right: 0;
z-index: 10;
- display: none;
+ display: flex;
flex-direction: row;
+ padding: 0;
margin: 0;
list-style: none;
@include e(item) {
+ display: flex;
+ align-items: center;
+ justify-content: center;
width: 26px;
height: 26px;
padding: 3px 4px;
color: #{getCssVar(color-primary-text)};
cursor: pointer;
background-color: #{getCssVar(color-primary)};
- border: 1px solid #{getCssVar(color-border)};
- border-radius: 3px;
+
+ &:hover {
+ background-color: #{getCssVar(color, primary, hover)};
+ }
}
}
diff --git a/packages/dnd-design/src/components/dnd-draggable-item/dnd-draggable-item.tsx b/packages/dnd-design/src/components/dnd-draggable-item/dnd-draggable-item.tsx
index 85d2f6d725630d824f0afb4236f31af58b2a6ebe..3c92eda96823f5a71f5d5d9d10e07638a9717265 100644
--- a/packages/dnd-design/src/components/dnd-draggable-item/dnd-draggable-item.tsx
+++ b/packages/dnd-design/src/components/dnd-draggable-item/dnd-draggable-item.tsx
@@ -26,6 +26,9 @@ export default defineComponent({
isShowMask: {
type: Boolean,
},
+ isShowLogicButton: {
+ type: Boolean,
+ },
},
setup(props, { emit }) {
const ns = useNamespace('dnd-design-draggable-item');
@@ -50,6 +53,16 @@ export default defineComponent({
class={[this.ns.b(), this.ns.is('select', this.isSelect)]}
style={this.layoutStyle}
>
+
+ {this.isShowMask &&
}
+ {this.$slots.default?.()}
+
+
{modelStateUtil.isEnableDrag(this.modelState) && (
);
},
diff --git a/packages/dnd-design/src/controller/dnd-item-controller/dnd-item-controller.tsx b/packages/dnd-design/src/controller/dnd-item-controller/dnd-item-controller.tsx
index 3e23e596275199ae696b8f1e8ea6e060365f136a..1f0ee0cdd30a514598a8b11e6b459b6172249ae8 100644
--- a/packages/dnd-design/src/controller/dnd-item-controller/dnd-item-controller.tsx
+++ b/packages/dnd-design/src/controller/dnd-item-controller/dnd-item-controller.tsx
@@ -7,6 +7,7 @@ import {
IDndItemController,
} from '../../interface';
import { SelectState } from '../../utils';
+import { resource } from '../../global';
/**
* 拖拽项控制器
@@ -22,9 +23,18 @@ export class DndItemController implements IDndItemController {
readonly select!: SelectState;
actions: IActionItem[] = [
+ {
+ icon: (
+
+ ),
+ text: '表单项逻辑',
+ tooltip: '表单项逻辑',
+ command: 'logic',
+ },
{
icon: ,
text: '删除',
+ tooltip: '删除',
command: 'delete',
},
];
diff --git a/packages/dnd-design/src/panel-items/dnd-design/dnd-design.controller.ts b/packages/dnd-design/src/panel-items/dnd-design/dnd-design.controller.ts
index fa7b0e712c9a802b711962611215311f5c1c1fcc..e072ef905939326b17aff1de1ddd25583c4e59f9 100644
--- a/packages/dnd-design/src/panel-items/dnd-design/dnd-design.controller.ts
+++ b/packages/dnd-design/src/panel-items/dnd-design/dnd-design.controller.ts
@@ -1,12 +1,23 @@
import { reactive } from 'vue';
-import { IPortalMessage, RuntimeModelError } from '@ibiz-template/core';
+import {
+ IPortalMessage,
+ RuntimeError,
+ RuntimeModelError,
+} from '@ibiz-template/core';
import {
IDataEntity,
IAppDEService,
PanelItemController,
getControl,
+ getUIActionById,
+ UIActionUtil,
} from '@ibiz-template/runtime';
-import { IPanelContainer, IDEForm } from '@ibiz/model-core';
+import {
+ IPanelContainer,
+ IDEForm,
+ IDEToolbar,
+ IDETBUIActionItem,
+} from '@ibiz/model-core';
import { ascSort, createUUID } from 'qx-util';
import { DndDesignPanelItemState } from './dnd-design.state';
import { dndProviderRegister, modelStateUtil } from '../../utils';
@@ -94,10 +105,196 @@ export class DndDesignPanelItemController
await this.load();
this.state.uuid = createUUID();
});
+ this.view.evt.on('onStencilAdd', async e => {
+ if (!e || !e.stencil) {
+ return;
+ }
+ const id = this.view.select.data?.srfkey;
+ this.handleStencilAdd(e.stencil, id);
+ });
await this.load();
this.subscribeMessage();
}
+ /**
+ * 处理素材添加
+ *
+ * @author zhanghengfeng
+ * @date 2025-02-12 22:02:48
+ * @param {IData} stencil
+ * @param {string} [id]
+ * @param {IDataEntity} [child]
+ * @return {*} {void}
+ */
+ handleStencilAdd(stencil: IData, id?: string, child?: IDataEntity): void {
+ if (!id) {
+ return;
+ }
+ const parent = this.items.find(item => item.srfkey === id);
+ if (!parent) {
+ return;
+ }
+ const type = parent.srftype;
+ if (!type) {
+ return;
+ }
+ const container = [
+ 'GROUPPANEL',
+ 'FORMPAGE',
+ 'TABPAGE',
+ 'TABPANEL',
+ 'MDCTRL',
+ ];
+ if (!container.includes(type)) {
+ this.handleStencilAdd(stencil, parent.srfpkey, child || parent);
+ return;
+ }
+ if (type === 'TABPANEL') {
+ return;
+ }
+ if (type === 'MDCTRL' && parent.mdctrltype !== 'REPEATER') {
+ return;
+ }
+ const children: IDataEntity[] = parent.children || [];
+ let newIndex = children.length;
+ if (child) {
+ const index = children.findIndex(item => item.srfkey === child.srfkey);
+ if (index !== -1) {
+ newIndex = index + 1;
+ }
+ }
+ this.add(
+ {
+ added: {
+ element: stencil,
+ newIndex,
+ },
+ },
+ children,
+ parent,
+ );
+ }
+
+ /**
+ * 更新逻辑映射map
+ *
+ * @author zhanghengfeng
+ * @date 2025-02-12 22:02:38
+ * @protected
+ * @return {*} {Promise}
+ */
+ protected async updateLogicMap(): Promise {
+ const appId = this.view.context.srfappid;
+ if (!appId) {
+ return;
+ }
+ const app = ibiz.hub.getApp(appId);
+ if (!app) {
+ return;
+ }
+ const entity = await ibiz.hub.getAppDataEntity('PSDEFDLogic', appId);
+ if (!entity) {
+ return;
+ }
+ const service = await app.deService.getService(
+ this.view.context,
+ entity.id!,
+ );
+ if (!service) {
+ return;
+ }
+ const res = await service.fetchDefault(this.view.context);
+ const map: Record = {};
+ if (res && Array.isArray(res.data)) {
+ res.data.forEach(item => {
+ const key = item.psdeformdetailid;
+ if (map[key]) {
+ map[key] += 1;
+ } else {
+ map[key] = 1;
+ }
+ });
+ }
+ this.state.logicMap = map;
+ }
+
+ /**
+ * 监听数据变化
+ *
+ * @author zhanghengfeng
+ * @date 2025-02-12 22:02:29
+ * @protected
+ * @param {IPortalMessage} msg
+ */
+ protected onDEDataChange(msg: IPortalMessage): void {
+ if (msg && msg.data && typeof msg.data === 'object') {
+ const data = msg.data as IDataEntity;
+ if (data.srfdecodename === 'PSDEFDLogic') {
+ this.updateLogicMap();
+ }
+ }
+ }
+
+ /**
+ * 打开逻辑视图
+ *
+ * @author zhanghengfeng
+ * @date 2025-02-12 22:02:40
+ * @param {IDataEntity} item
+ * @return {*} {Promise}
+ */
+ async openLogicView(item: IDataEntity): Promise {
+ if (!item) {
+ return;
+ }
+ const structure = getControl(
+ this.view.model,
+ 'structuretoolbar',
+ ) as IDEToolbar;
+ if (!structure) {
+ return;
+ }
+ const toolbarItems = structure.detoolbarItems || [];
+ if (toolbarItems && toolbarItems.length) {
+ const action = toolbarItems.find(toolbarItem => {
+ if (item.srftype === 'FORMITEM' || item.srftype === 'FORMITEMEX') {
+ return toolbarItem.id === 'formitem';
+ }
+ return toolbarItem.id === 'default';
+ });
+ if (action && action.itemType === 'DEUIACTION') {
+ const actionId = (action as IDETBUIActionItem).uiactionId;
+ if (!actionId) {
+ return;
+ }
+ const uiAction = await getUIActionById(actionId, action.appId);
+ if (!uiAction) {
+ throw new RuntimeError(
+ ibiz.i18n.t('runtime.controller.control.toolbar.noFound', {
+ actionId,
+ }),
+ );
+ }
+ const context = this.view.context.clone();
+ delete context.srfrunmode;
+ const modelState = this.getModelState(item);
+ if (!modelStateUtil.isEnableUpdate(modelState)) {
+ context.srfreadonly = true;
+ }
+ await UIActionUtil.execAndResolved(
+ actionId,
+ {
+ context,
+ params: this.view.params,
+ data: [item],
+ view: this.view,
+ },
+ action.appId,
+ );
+ }
+ }
+ }
+
/**
* 更新隐藏表单项可见性
*
@@ -189,9 +386,11 @@ export class DndDesignPanelItemController
*/
protected subscribeMessage(): void {
this.onDataUpdate = this.onDataUpdate.bind(this);
+ this.onDEDataChange = this.onDEDataChange.bind(this);
this.refresh = this.refresh.bind(this);
this.view.evt.on('onRefreshView', this.refresh);
ibiz.mc.command.update.on(this.onDataUpdate);
+ ibiz.mc.command.change.on(this.onDEDataChange);
}
/**
@@ -203,6 +402,7 @@ export class DndDesignPanelItemController
protected unsubscribeMessage(): void {
this.view.evt.off('onRefreshView', this.refresh);
ibiz.mc.command.update.off(this.onDataUpdate);
+ ibiz.mc.command.change.off(this.onDEDataChange);
}
/**
@@ -245,6 +445,7 @@ export class DndDesignPanelItemController
* @return {*} {Promise}
*/
protected async load(): Promise {
+ await this.updateLogicMap();
const result = await this.service.fetchDefault(this.panel.context);
this.items = result.data as IDataEntity[];
this.items.forEach(item => {
@@ -325,12 +526,10 @@ export class DndDesignPanelItemController
// 移入到根节点修改父为空
item.srfpkey = undefined;
}
- const { oldIndex, newIndex } = added;
- this.move(items, oldIndex, newIndex);
+ this.move(items, 0, items.length - 1);
}
} else if (moved && moved.element) {
- const { oldIndex, newIndex } = moved;
- this.move(items, oldIndex, newIndex);
+ this.move(items, 0, items.length - 1);
}
}
}
diff --git a/packages/dnd-design/src/panel-items/dnd-design/dnd-design.state.ts b/packages/dnd-design/src/panel-items/dnd-design/dnd-design.state.ts
index 7f37a874c2448a17c37ca36a849e3631a3161e7a..c3c65eec11b8f00b722968f57157b88e2cc9bc60 100644
--- a/packages/dnd-design/src/panel-items/dnd-design/dnd-design.state.ts
+++ b/packages/dnd-design/src/panel-items/dnd-design/dnd-design.state.ts
@@ -38,4 +38,13 @@ export class DndDesignPanelItemState extends PanelItemState {
* @type {boolean}
*/
hiddenFormItemVisible: boolean = true;
+
+ /**
+ * 逻辑映射map
+ *
+ * @author zhanghengfeng
+ * @date 2025-02-12 22:02:01
+ * @type {Record}
+ */
+ logicMap: Record = {};
}
diff --git a/packages/dnd-design/src/panel-items/dnd-design/dnd-design.tsx b/packages/dnd-design/src/panel-items/dnd-design/dnd-design.tsx
index 97f25e6921e13220759482e6861edebdb200dbce..77864cedeba8ebc771a2c6e288ce812843b8887d 100644
--- a/packages/dnd-design/src/panel-items/dnd-design/dnd-design.tsx
+++ b/packages/dnd-design/src/panel-items/dnd-design/dnd-design.tsx
@@ -110,8 +110,13 @@ export default defineComponent({
actions={controller.actions}
modelState={state}
isShowMask={c.isShowMask(item)}
+ isShowLogicButton={!!c.state.logicMap[item.srfkey]}
onClick={(e: MouseEvent) => onSelect(e, item)}
onAction={(action: IActionItem) => {
+ if (action.command === 'logic') {
+ c.openLogicView(item);
+ return;
+ }
controller.onAction(action).then((result: boolean) => {
if (result === false) {
if (action.command === 'delete') {
diff --git a/packages/dnd-design/src/panel-items/dnd-stencil/dnd-stencil.tsx b/packages/dnd-design/src/panel-items/dnd-stencil/dnd-stencil.tsx
index 057daa82c42e747efa56728a84d0f31cdd68d2ed..e4fb42160a42246ae2af3d820a11b19794b0243f 100644
--- a/packages/dnd-design/src/panel-items/dnd-stencil/dnd-stencil.tsx
+++ b/packages/dnd-design/src/panel-items/dnd-stencil/dnd-stencil.tsx
@@ -132,6 +132,12 @@ export default defineComponent({
key={data.index}
class={[ns.b('handle')]}
title={item.text}
+ onDblclick={e => {
+ e.stopPropagation();
+ props.controller.view?.evt.emit('onStencilAdd', {
+ stencil: clone(item),
+ });
+ }}
>