diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f26beeb6cc0ec76da27fc16d36f03db07d91377..e418b372ffdaf8487f6a11653d995cdf236b062a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ ## [Unreleased] +### Added + +- 新增直接内容编辑器 +- 新增列表门户部件 + ## [0.0.28] - 2024-10-18 ### Added diff --git a/src/control/dashboard/index.ts b/src/control/dashboard/index.ts index b5b7a4bd59f17320ab68eafc77a1d21587f19cce..a3dfde36c50e57f1d05743c4c0b878f692d8e092 100644 --- a/src/control/dashboard/index.ts +++ b/src/control/dashboard/index.ts @@ -6,6 +6,7 @@ import { DashboardProvider } from './dashboard.provider'; import { IBizContainerPortlet, IBizMenuPortlet, + IBizListPortlet, IBizViewPortlet, PortletLayout, } from './portlet'; @@ -24,6 +25,7 @@ export const IBizDashboardControl = withInstall( v.component(PortletLayout.name, PortletLayout); v.use(IBizContainerPortlet); v.use(IBizMenuPortlet); + v.use(IBizListPortlet); v.use(IBizViewPortlet); }, ); diff --git a/src/control/dashboard/portlet/index.ts b/src/control/dashboard/portlet/index.ts index 1336f028f56504da68ef3ef6ce20257dd939e0c1..e372de509e0157e6c9f71c5e13dd255b629e7ac6 100644 --- a/src/control/dashboard/portlet/index.ts +++ b/src/control/dashboard/portlet/index.ts @@ -3,3 +3,4 @@ export * from './container-portlet'; export * from './portlet-layout/portlet-layout'; export * from './menu-portlet'; export * from './view-portlet'; +export * from './list-portlet'; diff --git a/src/control/dashboard/portlet/list-portlet/index.ts b/src/control/dashboard/portlet/list-portlet/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..027714e6494130d73be6ee4b240ce4fc07b39b29 --- /dev/null +++ b/src/control/dashboard/portlet/list-portlet/index.ts @@ -0,0 +1,14 @@ +import { registerPortletProvider } from '@ibiz-template/runtime'; +import { withInstall } from '@ibiz-template/vue3-util'; +import { App } from 'vue'; +import { ListPortlet } from './list-portlet'; +import { ListPortletProvider } from './list-portlet.provider'; + +export * from './list-portlet'; + +export const IBizListPortlet = withInstall(ListPortlet, function (v: App) { + v.component(ListPortlet.name, ListPortlet); + registerPortletProvider('LIST', () => new ListPortletProvider()); +}); + +export default IBizListPortlet; diff --git a/src/control/dashboard/portlet/list-portlet/list-portlet.provider.ts b/src/control/dashboard/portlet/list-portlet/list-portlet.provider.ts new file mode 100644 index 0000000000000000000000000000000000000000..537dc347c79f34be112a2fb8a97ad24a973b8df2 --- /dev/null +++ b/src/control/dashboard/portlet/list-portlet/list-portlet.provider.ts @@ -0,0 +1,30 @@ +import { + IDashboardController, + IPortletContainerController, + IPortletProvider, + ListPortletController, +} from '@ibiz-template/runtime'; +import { IDBListPortletPart } from '@ibiz/model-core'; + +/** + * 列表门户部件适配器 + * + * @author zk + * @date 2023-07-12 08:07:58 + * @export + * @class ListPortletProvider + * @implements {IPortletProvider} + */ +export class ListPortletProvider implements IPortletProvider { + component: string = 'IBizListPortlet'; + + async createController( + portletModel: IDBListPortletPart, + dashboard: IDashboardController, + parent?: IPortletContainerController, + ): Promise { + const c = new ListPortletController(portletModel, dashboard, parent); + await c.init(); + return c; + } +} diff --git a/src/control/dashboard/portlet/list-portlet/list-portlet.tsx b/src/control/dashboard/portlet/list-portlet/list-portlet.tsx new file mode 100644 index 0000000000000000000000000000000000000000..6fd1fdc6f1530b976a2549f6081f8dab007f24b5 --- /dev/null +++ b/src/control/dashboard/portlet/list-portlet/list-portlet.tsx @@ -0,0 +1,69 @@ +import { useNamespace } from '@ibiz-template/vue3-util'; +import { + defineComponent, + PropType, + resolveComponent, + h, + onMounted, + onBeforeUnmount, +} from 'vue'; +import { IDBListPortletPart } from '@ibiz/model-core'; +import { ControlType, ListPortletController } from '@ibiz-template/runtime'; + +export const ListPortlet = defineComponent({ + name: 'IBizListPortlet', + props: { + modelData: { + type: Object as PropType, + required: true, + }, + controller: { + type: ListPortletController, + required: true, + }, + }, + setup(props) { + const ns = useNamespace( + `portlet-${props.modelData.portletType?.toLowerCase()}`, + ); + + const list = props.modelData.controls?.find(item => { + return item.controlType === ControlType.LIST; + }); + + let timerTag: NodeJS.Timeout | undefined; + + onMounted(() => { + const timer = props.controller.model.timer; + if (timer && timer > 0) { + timerTag = setInterval(() => { + props.controller.refresh(); + }, timer); + } + }); + + onBeforeUnmount(() => { + clearInterval(timerTag); + }); + + return { ns, list }; + }, + + render() { + const classArr: string[] = [ + this.ns.b(), + this.ns.m(this.modelData.codeName), + ...this.controller.containerClass, + ]; + const { context, params } = this.controller; + return ( + + {h(resolveComponent('IBizControlShell'), { + context, + params, + modelData: this.list, + })} + + ); + }, +}); diff --git a/src/control/dashboard/portlet/portlet-layout/portlet-layout.scss b/src/control/dashboard/portlet/portlet-layout/portlet-layout.scss index b91a3186cac7a02230223b7a62b31be1c32d574d..feb39369d4bd9e3e823e839ba09e4886615edcf4 100644 --- a/src/control/dashboard/portlet/portlet-layout/portlet-layout.scss +++ b/src/control/dashboard/portlet/portlet-layout/portlet-layout.scss @@ -2,13 +2,13 @@ $portlet-layout: (bg-color: transparent, header-height: rem(40px), header-padding: rem(16px), header-margin: 0, - header-bg-color:transparent, + header-bg-color: getCssVar(color, bg, 0), header-border-bottom: rem(1px) solid getCssVar(color, border), caption-max-width: rem(300px), caption-font-weight: 600, caption-font-size: getCssVar(font-size, header, 5), caption-color: getCssVar(color, text, 1), - content-bg-color:transparent, + content-bg-color: transparent, content-padding: 0, content-margin: 0, border-radius:getCssVar(border-radius, medium), diff --git a/src/editor/index.ts b/src/editor/index.ts index 5e815af23b2c0f35fa5b8bbb1bcbc41ce95c05fc..54f72fb31116b5720622bb61fb02f7e30fb47e7d 100644 --- a/src/editor/index.ts +++ b/src/editor/index.ts @@ -12,6 +12,7 @@ import { CheckBoxListEditorProvider, IBizCheckboxList } from './check-box-list'; import { IBizSwitch, SwitchEditorProvider } from './switch'; import { IBizRadio, RadioButtonListEditorProvider } from './radio-button-list'; import { IBizSlider, SliderEditorProvider } from './slider'; +import { IBizRaw, RawEditorProvider } from './raw'; import { IBizStepper, StepperEditorProvider } from './stepper'; import { IBizRate, RateEditorProvider } from './rate'; import { IBizDatePicker, DatePickerEditorProvider } from './date-picker'; @@ -53,6 +54,7 @@ export const IBizEditor = { v.component(IBizEmojiPicker.name, IBizEmojiPicker); v.component(IBizCheckboxList.name, IBizCheckboxList); v.component(IBizSlider.name, IBizSlider); + v.component(IBizRaw.name, IBizRaw); v.component(IBizStepper.name, IBizStepper); v.component(IBizRate.name, IBizRate); v.component(IBizDatePicker.name, IBizDatePicker); @@ -135,6 +137,9 @@ export const IBizEditor = { // 滑动输入条 registerEditorProvider('MOBSLIDER', () => new SliderEditorProvider()); + // 直接内容 + registerEditorProvider('RAW', () => new RawEditorProvider()); + // 步进器 registerEditorProvider('MOBSTEPPER', () => new StepperEditorProvider()); diff --git a/src/editor/raw/ibiz-raw/ibiz-raw.scss b/src/editor/raw/ibiz-raw/ibiz-raw.scss new file mode 100644 index 0000000000000000000000000000000000000000..f5dac3c9034e65532670b519d32886a255b54ee8 --- /dev/null +++ b/src/editor/raw/ibiz-raw/ibiz-raw.scss @@ -0,0 +1,14 @@ +@include b(raw){ + line-height: getCssVar(form-item, line-height); + color:getCssVar(form-item, text-color); +} + + +@include b(form-item){ + + @include b(raw) { + @include when(show-default){ + padding: getCssVar(form-item, hover-edit-padding); + } + } +} \ No newline at end of file diff --git a/src/editor/raw/ibiz-raw/ibiz-raw.tsx b/src/editor/raw/ibiz-raw/ibiz-raw.tsx new file mode 100644 index 0000000000000000000000000000000000000000..33cc1f729673d913c73b88f7a4154f53f4577c76 --- /dev/null +++ b/src/editor/raw/ibiz-raw/ibiz-raw.tsx @@ -0,0 +1,112 @@ +import { computed, defineComponent, Ref, ref, watch } from 'vue'; +import { + getEditorEmits, + getRawProps, + useNamespace, +} from '@ibiz-template/vue3-util'; +import { RawEditorController } from '../raw-editor.controller'; +import './ibiz-raw.scss'; + +export const IBizRaw = defineComponent({ + name: 'IBizRaw', + props: getRawProps(), + emits: getEditorEmits(), + setup(props) { + const ns = useNamespace('raw'); + const c = props.controller; + const editorModel = c.model; + + // 传入内容 + const content: Ref = ref(''); + + // 类型 + let type = 'TEXT'; + // handlerBars模版 + let template = ''; + if (editorModel.contentType) { + type = editorModel.contentType; + } + if (editorModel.editorParams && editorModel.editorParams.contenttype) { + type = editorModel.editorParams.contenttype; + } + if (editorModel.editorParams && editorModel.editorParams.template) { + template = editorModel.editorParams.template.replace(/\/\/n/g, '\n'); + } + if (editorModel.editorParams && editorModel.editorParams.TEMPLATE) { + template = editorModel.editorParams.TEMPLATE.replace(/\/\/n/g, '\n'); + } + + // 是否显示表单默认内容 + const showFormDefaultContent = computed(() => { + if ( + props.controlParams && + props.controlParams.editmode === 'hover' && + !props.readonly + ) { + return true; + } + return false; + }); + + watch( + () => props.value, + async (newVal, oldVal) => { + if (newVal !== oldVal) { + if ( + typeof newVal === 'string' || + typeof newVal === 'number' || + !newVal + ) { + content.value = newVal; + } + if (template && newVal) { + let obj = newVal as IData; + if (typeof newVal === 'string') { + try { + obj = JSON.parse(newVal); + } catch (error) { + ibiz.log.error('JSON字符串转换错误'); + } + } + if (!Array.isArray(obj)) { + // 不是数组,合并父数据 + Object.assign(obj, { data: { ...props.data } }); + } + content.value = await ibiz.util.hbs.render(template, obj); + } + } + }, + { + immediate: true, + }, + ); + + return { + ns, + content, + type, + template, + showFormDefaultContent, + }; + }, + render() { + return ( +
+ {this.content && ( + + )} +
+ ); + }, +}); diff --git a/src/editor/raw/index.ts b/src/editor/raw/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ea51841051eec5ac82333e33561cf3738428d5e5 --- /dev/null +++ b/src/editor/raw/index.ts @@ -0,0 +1,3 @@ +export { IBizRaw } from './ibiz-raw/ibiz-raw'; +export * from './raw-editor.controller'; +export * from './raw-editor.provider'; diff --git a/src/editor/raw/raw-editor.controller.ts b/src/editor/raw/raw-editor.controller.ts new file mode 100644 index 0000000000000000000000000000000000000000..5950671a3442ac129eef1c9a1521af16c0cb3ac9 --- /dev/null +++ b/src/editor/raw/raw-editor.controller.ts @@ -0,0 +1,11 @@ +import { EditorController } from '@ibiz-template/runtime'; +import { IRaw } from '@ibiz/model-core'; + +/** + * 直接内容编辑器控制器 + * + * @export + * @class RawEditorController + * @extends {EditorController} + */ +export class RawEditorController extends EditorController {} diff --git a/src/editor/raw/raw-editor.provider.ts b/src/editor/raw/raw-editor.provider.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4302f7e3bb486be12d8c7862e48cc0a5f08826b --- /dev/null +++ b/src/editor/raw/raw-editor.provider.ts @@ -0,0 +1,29 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { + IEditorContainerController, + IEditorProvider, +} from '@ibiz-template/runtime'; +import { IRaw } from '@ibiz/model-core'; +import { RawEditorController } from './raw-editor.controller'; + +/** + * 直接内容编辑器适配器 + * + * @export + * @class RawEditorProvider + * @implements {EditorProvider} + */ +export class RawEditorProvider implements IEditorProvider { + formEditor: string = 'IBizRaw'; + + gridEditor: string = 'IBizRaw'; + + async createController( + editorModel: IRaw, + parentController: IEditorContainerController, + ): Promise { + const c = new RawEditorController(editorModel, parentController); + await c.init(); + return c; + } +}