diff --git a/packages/portal-design/public/assets/svg/container.svg b/packages/portal-design/public/assets/svg/container.svg new file mode 100644 index 0000000000000000000000000000000000000000..bfb2bf45f0196f27bab2735f758a179028f3d72f --- /dev/null +++ b/packages/portal-design/public/assets/svg/container.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/portal-design/public/assets/svg/rawitem.svg b/packages/portal-design/public/assets/svg/rawitem.svg new file mode 100644 index 0000000000000000000000000000000000000000..4c63f8335a0f3575638bfdecb8a750f7637cb6e5 --- /dev/null +++ b/packages/portal-design/public/assets/svg/rawitem.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/portal-design/public/assets/svg/sysportlet.svg b/packages/portal-design/public/assets/svg/sysportlet.svg new file mode 100644 index 0000000000000000000000000000000000000000..8c506557bb076ae59226c91666cf346db6db532f --- /dev/null +++ b/packages/portal-design/public/assets/svg/sysportlet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/portal-design/src/global.ts b/packages/portal-design/src/global.ts new file mode 100644 index 0000000000000000000000000000000000000000..0fa10431b9670ddb5003e3e2fafbf06ce1dfd368 --- /dev/null +++ b/packages/portal-design/src/global.ts @@ -0,0 +1,7 @@ +// 文件路径: [插件项目的根目录]/src/global.ts + +import { PluginStaticResource } from '@ibiz-template/runtime'; + +const resource = new PluginStaticResource(import.meta.url); + +export { resource }; diff --git a/packages/portal-design/src/index.ts b/packages/portal-design/src/index.ts index fb95456ef3670fea20386ddc6f3d2e445486c6c2..c5a1f3a30a737c34b23fd0b0efa129f0a18479ec 100644 --- a/packages/portal-design/src/index.ts +++ b/packages/portal-design/src/index.ts @@ -2,10 +2,12 @@ import { App } from 'vue'; import DesignBase from '@ibiz-template-plugin/design-base'; import views from './views'; +import PanelItems from './panel-items'; export default { install(app: App) { app.use(DesignBase as any); app.use(views); + app.use(PanelItems); }, }; diff --git a/packages/portal-design/src/panel-items/index.ts b/packages/portal-design/src/panel-items/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..85af544231e6fce5bf0a9523e9f93692891170d7 --- /dev/null +++ b/packages/portal-design/src/panel-items/index.ts @@ -0,0 +1,10 @@ +import { App } from 'vue'; +import PortalDesignMaterial from './portal-design-material'; +import PortalDesignStructure from './portal-design-structure'; + +export default { + install(app: App): void { + app.use(PortalDesignMaterial); + app.use(PortalDesignStructure); + }, +}; diff --git a/packages/portal-design/src/panel-items/portal-design-material/index.ts b/packages/portal-design/src/panel-items/portal-design-material/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..fb8cdf8401b168a0a970fa72f7c45a5135bbd471 --- /dev/null +++ b/packages/portal-design/src/panel-items/portal-design-material/index.ts @@ -0,0 +1,14 @@ +import { App } from 'vue'; +import { registerPanelItemProvider } from '@ibiz-template/runtime'; +import PortalDesignMaterial from './portal-design-material'; +import { PortalDesignMaterialProvider } from './portal-design-material.provider'; + +export default { + install(app: App): void { + app.component('IBizPortalDesignMaterial', PortalDesignMaterial); + registerPanelItemProvider( + 'RAWITEM_PORTAL_DESIGN_MATERIAL', + () => new PortalDesignMaterialProvider(), + ); + }, +}; diff --git a/packages/portal-design/src/panel-items/portal-design-material/portal-design-material.controller.ts b/packages/portal-design/src/panel-items/portal-design-material/portal-design-material.controller.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8e6350c8ca5935d2377b7910dc549057634b212 --- /dev/null +++ b/packages/portal-design/src/panel-items/portal-design-material/portal-design-material.controller.ts @@ -0,0 +1,65 @@ +import { PanelItemController } from '@ibiz-template/runtime'; +import { ICodeItem } from '@ibiz/model-core'; +import { PortalDesignMaterialState } from './portal-design-material.state'; + +export class PortalDesignMaterialController extends PanelItemController { + declare state: PortalDesignMaterialState; + + protected createState(): PortalDesignMaterialState { + return new PortalDesignMaterialState(this.parent?.state); + } + + /** + * 素材分组 + * + * @author zhanghengfeng + * @date 2024-11-20 17:11:48 + * @type {ICodeItem[]} + */ + groups: ICodeItem[] = []; + + /** + * 初始化 + * + * @author zhanghengfeng + * @date 2024-11-20 17:11:07 + * @protected + * @return {*} {Promise} + */ + protected async onInit(): Promise { + await super.onInit(); + const appId = this.model.appId; + this.groups = [ + { + appId, + text: '布局容器', + codeItems: [ + { + appId, + text: '布局容器', + value: 'CONTAINER', + iconPath: './assets/svg/container.svg', + }, + ], + }, + { + appId, + text: '基础项成员', + codeItems: [ + { + appId, + text: '系统门户部件', + value: 'SYSPORTLET', + iconPath: './assets/svg/sysportlet.svg', + }, + { + appId, + text: '直接内容', + value: 'RAWITEM', + iconPath: './assets/svg/rawitem.svg', + }, + ], + }, + ]; + } +} diff --git a/packages/portal-design/src/panel-items/portal-design-material/portal-design-material.provider.ts b/packages/portal-design/src/panel-items/portal-design-material/portal-design-material.provider.ts new file mode 100644 index 0000000000000000000000000000000000000000..7873f1a76581f349c35bb0efb0574579a8d898bf --- /dev/null +++ b/packages/portal-design/src/panel-items/portal-design-material/portal-design-material.provider.ts @@ -0,0 +1,21 @@ +import { + IPanelItemController, + IPanelItemProvider, + IPanelController, +} from '@ibiz-template/runtime'; +import { IPanelItem } from '@ibiz/model-core'; +import { PortalDesignMaterialController } from './portal-design-material.controller'; + +export class PortalDesignMaterialProvider implements IPanelItemProvider { + component = 'IBizPortalDesignMaterial'; + + async createController( + panelItem: IPanelItem, + panel: IPanelController, + parent?: IPanelItemController, + ): Promise { + const c = new PortalDesignMaterialController(panelItem, panel, parent); + await c.init(); + return c; + } +} diff --git a/packages/portal-design/src/panel-items/portal-design-material/portal-design-material.scss b/packages/portal-design/src/panel-items/portal-design-material/portal-design-material.scss new file mode 100644 index 0000000000000000000000000000000000000000..fc9a241ac06e00acc8ad20386a95353e0e2a1ca2 --- /dev/null +++ b/packages/portal-design/src/panel-items/portal-design-material/portal-design-material.scss @@ -0,0 +1,123 @@ +/* stylelint-disable selector-class-pattern */ +@include b(portal-design-material) { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + background: rgba(var(#{getCssVarName(grey, 0)}), 1); + + .el-collapse { + --el-collapse-header-height: 28px; + --el-collapse-header-bg-color: transparent; + --el-collapse-content-bg-color: #{getCssVar(color, bg, 1)}; + --el-collapse-header-text-color: #{getCssVar(color, text, 1)}; + --el-collapse-header-font-size: 12px; + + border: none; + + .el-collapse-item__header { + padding: 0 12px; + border: none; + } + + .el-collapse-item__wrap { + border: none; + } + + .el-collapse-item__content { + padding: 4px 16px 16px; + } + } +} + +@include b(portal-design-material-header) { + flex: 0 0 auto; + padding: 2px 0; + + .el-input__wrapper { + --el-input-bg-color: #{getCssVar(color, bg, 1)}; + } +} + +@include b(portal-design-material-content) { + flex: 1 1 0; + overflow: auto; +} + +@include b(portal-design-material-group-header) { + margin-right: 12px; + overflow: hidden; + color: getCssVar(color, text, 1); + text-overflow: ellipsis; + white-space: nowrap; +} + +@include b(portal-design-material-group-content) { + display: flex; + flex-wrap: wrap; + + @include m(empty) { + justify-content: center; + } +} + +@include b(portal-design-material-group-item) { + position: relative; + flex: 0 0 auto; + width: 50%; + height: 30px; + padding: 0 4px; + margin-top: 8px; + overflow: hidden; + line-height: 1.5; + border-radius: 3px; + + &:hover { + @include b(portal-design-material-group-item-svg) { + stroke: #06d6a0; + stroke-dasharray: 50 0; + stroke-dashoffset: 0; + stroke-width: 3px; + } + } +} + +@include b(portal-design-material-group-item-svg) { + fill: transparent; + stroke: #009ffd; + stroke-dasharray: 100 400; + stroke-dashoffset: -175; + stroke-width: 6px; + transition: all 1s ease; +} + +@include b(portal-design-material-group-item-content) { + position: absolute; + top: 0; + left: 0; + display: flex; + align-items: center; + width: 100%; + height: 100%; + padding: 4px 4px 4px 14px; + font-size: 12px; + cursor: move; + border-radius: 3px; + + @include e(icon) { + display: flex; + width: 16px; + font-size: 16px; + + img { + width: 100%; + } + } + + @include e(text) { + margin-left: 2px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} diff --git a/packages/portal-design/src/panel-items/portal-design-material/portal-design-material.state.ts b/packages/portal-design/src/panel-items/portal-design-material/portal-design-material.state.ts new file mode 100644 index 0000000000000000000000000000000000000000..61d3d221a5abe69437053ef97b87634d91b62604 --- /dev/null +++ b/packages/portal-design/src/panel-items/portal-design-material/portal-design-material.state.ts @@ -0,0 +1,3 @@ +import { PanelItemState } from '@ibiz-template/runtime'; + +export class PortalDesignMaterialState extends PanelItemState {} diff --git a/packages/portal-design/src/panel-items/portal-design-material/portal-design-material.tsx b/packages/portal-design/src/panel-items/portal-design-material/portal-design-material.tsx new file mode 100644 index 0000000000000000000000000000000000000000..ea9f791f4a9c086233a596b03feba8a181cf49f1 --- /dev/null +++ b/packages/portal-design/src/panel-items/portal-design-material/portal-design-material.tsx @@ -0,0 +1,152 @@ +import { useNamespace } from '@ibiz-template/vue3-util'; +import { ICodeItem, IPanelItem } from '@ibiz/model-core'; +import { PropType, defineComponent, ref } from 'vue'; +import draggable from 'vuedraggable'; +import { resource } from '../../global'; +import { PortalDesignMaterialController } from './portal-design-material.controller'; +import './portal-design-material.scss'; + +export default defineComponent({ + name: 'IBizPortalDesignMaterial', + components: { + draggable, + }, + props: { + modelData: { + type: Object as PropType, + required: true, + }, + controller: { + type: PortalDesignMaterialController, + required: true, + }, + }, + setup(props) { + const ns = useNamespace('portal-design-material'); + + // 搜索值 + const searchValue = ref(''); + + // 收缩面板值 + const collapseValue = ref(props.controller.groups.map((_, i) => `${i}`)); + + return { + ns, + searchValue, + collapseValue, + }; + }, + render() { + return ( +
+
+ } + clearable={true} + > +
+
+ + {this.controller.groups.map((group, i) => { + const items = group.codeItems?.filter(item => { + if (this.searchValue) { + const regExp = this.searchValue.trim().toLowerCase(); + const text = item.text?.toLowerCase(); + if (text && text.indexOf(regExp) === -1) { + return false; + } + } + return true; + }); + return ( + + {{ + title: () => { + return ( +
+ {group.text} +
+ ); + }, + default: () => { + if (!items?.length) { + return ( +
+ 暂无数据 +
+ ); + } + return ( + + {{ + item: ({ element }: { element: ICodeItem }) => { + const item = element; + return ( +
+ + + +
+
+ {item.iconPath ? ( + + ) : null} +
+
+ {item.text} +
+
+
+ ); + }, + }} +
+ ); + }, + }} +
+ ); + })} +
+
+
+ ); + }, +}); diff --git a/packages/portal-design/src/panel-items/portal-design-structure/index.ts b/packages/portal-design/src/panel-items/portal-design-structure/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..9e2120afb3b5c8d0e9ed9fe58ab767ad73552ea5 --- /dev/null +++ b/packages/portal-design/src/panel-items/portal-design-structure/index.ts @@ -0,0 +1,14 @@ +import { App } from 'vue'; +import { registerPanelItemProvider } from '@ibiz-template/runtime'; +import PortalDesignStructure from './portal-design-structure'; +import { PortalDesignStructureProvider } from './portal-design-structure.provider'; + +export default { + install(app: App): void { + app.component('IBizPortalDesignStructure', PortalDesignStructure); + registerPanelItemProvider( + 'RAWITEM_PORTAL_DESIGN_STRUCTURE', + () => new PortalDesignStructureProvider(), + ); + }, +}; diff --git a/packages/portal-design/src/panel-items/portal-design-structure/portal-design-structure.controller.ts b/packages/portal-design/src/panel-items/portal-design-structure/portal-design-structure.controller.ts new file mode 100644 index 0000000000000000000000000000000000000000..dee0507902783cbf982af65a4867700027a5b256 --- /dev/null +++ b/packages/portal-design/src/panel-items/portal-design-structure/portal-design-structure.controller.ts @@ -0,0 +1,10 @@ +import { PanelItemController } from '@ibiz-template/runtime'; +import { PortalDesignStructureState } from './portal-design-structure.state'; + +export class PortalDesignStructureController extends PanelItemController { + declare state: PortalDesignStructureState; + + protected createState(): PortalDesignStructureState { + return new PortalDesignStructureState(this.parent?.state); + } +} diff --git a/packages/portal-design/src/panel-items/portal-design-structure/portal-design-structure.provider.ts b/packages/portal-design/src/panel-items/portal-design-structure/portal-design-structure.provider.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4183f84dd247f857ab9211ba54219ee10fdcf26 --- /dev/null +++ b/packages/portal-design/src/panel-items/portal-design-structure/portal-design-structure.provider.ts @@ -0,0 +1,21 @@ +import { + IPanelItemController, + IPanelItemProvider, + IPanelController, +} from '@ibiz-template/runtime'; +import { IPanelItem } from '@ibiz/model-core'; +import { PortalDesignStructureController } from './portal-design-structure.controller'; + +export class PortalDesignStructureProvider implements IPanelItemProvider { + component = 'IBizPortalDesignStructure'; + + async createController( + panelItem: IPanelItem, + panel: IPanelController, + parent?: IPanelItemController, + ): Promise { + const c = new PortalDesignStructureController(panelItem, panel, parent); + await c.init(); + return c; + } +} diff --git a/packages/portal-design/src/panel-items/portal-design-structure/portal-design-structure.scss b/packages/portal-design/src/panel-items/portal-design-structure/portal-design-structure.scss new file mode 100644 index 0000000000000000000000000000000000000000..3afd363adef29c66c32fc3548b597ae560087bcf --- /dev/null +++ b/packages/portal-design/src/panel-items/portal-design-structure/portal-design-structure.scss @@ -0,0 +1,31 @@ +@include b(portal-design-structure) { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; +} + +@include b(portal-design-structure-header) { + flex: 0 0 auto; + padding: 2px 0; +} + +@include b(portal-design-structure-content) { + flex: 1 1 0; + overflow: auto; +} + +@include b(portal-design-structure-item) { + display: flex; + align-items: center; + width: 100%; + overflow: hidden; + line-height: 1.5; + + @include e(text) { + flex: 1 1 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} diff --git a/packages/portal-design/src/panel-items/portal-design-structure/portal-design-structure.state.ts b/packages/portal-design/src/panel-items/portal-design-structure/portal-design-structure.state.ts new file mode 100644 index 0000000000000000000000000000000000000000..aaa374a63ac5b883d1e580bbab46fbbd8e837751 --- /dev/null +++ b/packages/portal-design/src/panel-items/portal-design-structure/portal-design-structure.state.ts @@ -0,0 +1,12 @@ +import { PanelItemState } from '@ibiz-template/runtime'; + +export class PortalDesignStructureState extends PanelItemState { + /** + * 树数据 + * + * @author zhanghengfeng + * @date 2024-11-20 17:11:27 + * @type {IData[]} + */ + treeData: IData[] = []; +} diff --git a/packages/portal-design/src/panel-items/portal-design-structure/portal-design-structure.tsx b/packages/portal-design/src/panel-items/portal-design-structure/portal-design-structure.tsx new file mode 100644 index 0000000000000000000000000000000000000000..48039fb1a6a1274001e173a3b932799a738f0dcc --- /dev/null +++ b/packages/portal-design/src/panel-items/portal-design-structure/portal-design-structure.tsx @@ -0,0 +1,116 @@ +import { useNamespace } from '@ibiz-template/vue3-util'; +import { IPanelItem } from '@ibiz/model-core'; +import { PropType, defineComponent, ref } from 'vue'; +import { PortalDesignStructureController } from './portal-design-structure.controller'; +import './portal-design-structure.scss'; + +export default defineComponent({ + name: 'IBizPortalDesignStructure', + props: { + modelData: { + type: Object as PropType, + required: true, + }, + controller: { + type: PortalDesignStructureController, + required: true, + }, + }, + setup() { + const ns = useNamespace('portal-design-structure'); + + // 搜索值 + const searchValue = ref(''); + + // el-tree实例 + const tree = ref(); + + // 是否允许拖拽 + const allowDrag = (_node: IData) => { + return true; + }; + + // 是否允许放置 + const allowDrop = (_draggingNode: IData, dropNode: IData, type: string) => { + if (Object.is(type, 'inner')) { + return false; + } + if (dropNode.level === 1) { + return false; + } + return true; + }; + + // 绘制树节点 + const renderTreeItem = (_h: IData, context: IData) => { + const { data } = context; + return ( +
+ {data.text} +
+ ); + }; + + // 过滤树 + const filterTree = () => { + if (tree.value) { + tree.value.filter?.(searchValue.value); + } + }; + + // 过滤树节点 + const filterTreeNode = (value: string, data: IData) => { + if (value) { + const regExp = value.trim().toLowerCase(); + const text = data.text?.toLowerCase(); + if (text && text.indexOf(regExp) === -1) { + return false; + } + } + return true; + }; + + return { + ns, + searchValue, + tree, + allowDrag, + allowDrop, + renderTreeItem, + filterTree, + filterTreeNode, + }; + }, + render() { + return ( +
+
+ } + clearable={true} + onInput={() => this.filterTree()} + > +
+
+ +
+
+ ); + }, +}); diff --git a/packages/portal-design/src/views/index.ts b/packages/portal-design/src/views/index.ts index 59238a1e96b59a83f1de86906bba65c74cd9a5a3..ae0a974be075038b9254e87746e283658a4f1f1f 100644 --- a/packages/portal-design/src/views/index.ts +++ b/packages/portal-design/src/views/index.ts @@ -6,11 +6,11 @@ import { PortalDesignViewProvider } from './portal-design-view/portal-design-vie export default { install(app: App) { registerViewProvider( - 'VIEW_CUSTOM_DASHBOARD_DESIGN_VIEW', + 'VIEW_CUSTOM_PORTAL_DESIGN_VIEW', () => new PortalDesignViewProvider(), ); registerViewProvider( - 'VIEW_CUSTOM_DASHBOARD_DESIGN_VIEW_DESIGN', + 'VIEW_CUSTOM_PORTAL_DESIGN_VIEW_DESIGN', () => new PortalDesignViewProvider(), ); },