diff --git a/src/common/app-rawitem/app-rawitem.tsx b/src/common/app-rawitem/app-rawitem.tsx index 356ce3076606e43acd582c90a16327763a97b32b..f7e311dd79839b1d7ee45f95f2445e54afe56d7d 100644 --- a/src/common/app-rawitem/app-rawitem.tsx +++ b/src/common/app-rawitem/app-rawitem.tsx @@ -57,18 +57,7 @@ export const AppRawItem = defineComponent({ ].includes(props.type) ) { if (props.content && typeof props.content === 'string') { - const items = props.content.match(/\{{(.+?)\}}/g); - if (items) { - items.forEach((item: string) => { - rawItemText.value = (props.content as string).replace( - /\{{(.+?)\}}/, - // eslint-disable-next-line no-eval - eval(item.substring(2, item.length - 2)), - ); - }); - } else { - rawItemText.value = props.content; - } + rawItemText.value = props.content; rawItemText.value = rawItemText.value.replaceAll('<', '<'); rawItemText.value = rawItemText.value.replaceAll('>', '>'); rawItemText.value = rawItemText.value.replaceAll('&nbsp;', ' '); diff --git a/src/common/index.ts b/src/common/index.ts index 27256c728792fdfd429863e5c9d7e105c753368a..f46693211940de9504824f3171a33b82d7ef7d90 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -8,7 +8,7 @@ import { IBizRow } from './row/row'; import { IBizControlBase } from './control-base/control-base'; import { IBizControlShell } from './control-shell/control-shell'; import { IBizViewShell } from './view-shell/view-shell'; -import { AppRawItem } from './app-rawitem/app-rawitem'; +import { IBizRawItem } from './rawitem/rawitem'; export * from './icon/icon'; export * from './keep-alive/keep-alive'; @@ -19,7 +19,7 @@ export * from './action-toolbar/action-toolbar'; export * from './control-base/control-base'; export * from './control-shell/control-shell'; export * from './view-shell/view-shell'; -export * from './app-rawitem/app-rawitem'; +export * from './rawitem/rawitem'; export const IBizCommonComponents = { install: (v: App) => { @@ -32,7 +32,7 @@ export const IBizCommonComponents = { v.component(IBizActionToolbar.name, IBizActionToolbar); v.component(IBizViewShell.name, IBizViewShell); v.component(IBizControlShell.name, IBizControlShell); - v.component(AppRawItem.name, AppRawItem); + v.component(IBizRawItem.name, IBizRawItem); }, }; diff --git a/src/common/rawitem/rawitem.tsx b/src/common/rawitem/rawitem.tsx new file mode 100644 index 0000000000000000000000000000000000000000..235d05043373fdf98a62cd3aa0bcb9b8bb160525 --- /dev/null +++ b/src/common/rawitem/rawitem.tsx @@ -0,0 +1,181 @@ +import { useNamespace } from '@ibiz-template/vue3-util'; +import { defineComponent, ref } from 'vue'; +import { createUUID } from 'qx-util'; + +export const IBizRawItem = defineComponent({ + name: 'IBizRawItem', + props: { + type: { + type: String, + required: true, + }, + content: { + type: [String, Object], + }, + }, + setup(props) { + const ns = useNamespace('rawitem'); + + // 视频类型内容参数 + const playerParams = ref({ + id: createUUID(), + path: '', + mute: true, + autoplay: true, + replay: false, + showcontrols: true, + }); + + // 分割线类型参数 + const dividerParams = ref({ + contentPosition: 'center', + html: '', + }); + + // 类型参数 + const alertParams = ref({ + type: 'info', + title: '', + closeabled: true, + showIcon: false, + }); + + // 文本类型显示值 + const rawItemText = ref(''); + + if ( + [ + 'TEXT', + 'HEADING1', + 'HEADING2', + 'HEADING3', + 'HEADING4', + 'HEADING5', + 'HEADING6', + 'PARAGRAPH', + 'HTML', + ].includes(props.type) + ) { + if (props.content && typeof props.content === 'string') { + rawItemText.value = props.content; + rawItemText.value = rawItemText.value.replaceAll('<', '<'); + rawItemText.value = rawItemText.value.replaceAll('>', '>'); + rawItemText.value = rawItemText.value.replaceAll('&nbsp;', ' '); + rawItemText.value = rawItemText.value.replaceAll(' ', ' '); + } + } + + if (['VIDEO', 'DIVIDER', 'INFO', 'WARNING', 'ERROR'].includes(props.type)) { + if (props.content) { + let rawConfig = {}; + try { + if (typeof props.content === 'string') { + // eslint-disable-next-line no-new-func + const func = new Function(`return (${props.content});`); + rawConfig = func(); + switch (props.type) { + case 'VIDEO': + Object.assign(playerParams.value, rawConfig); + break; + case 'DIVIDER': + Object.assign(dividerParams.value, rawConfig); + break; + case 'INFO': + case 'WARNING': + case 'ERROR': + alertParams.value.type = props.type.toLocaleLowerCase(); + Object.assign(alertParams.value, rawConfig); + break; + default: + break; + } + } + } catch { + ibiz.log.error(`${props.type}类型自定义参数配置错误`); + } + } + } + + return { ns, rawItemText, playerParams, dividerParams, alertParams }; + }, + render() { + if (this.type === 'IMAGE') { + return ( + + ); + } + if (this.type === 'TEXT') { + return {this.rawItemText}; + } + if (this.type === 'HEADING1') { + return

{this.rawItemText}

; + } + if (this.type === 'HEADING2') { + return

{this.rawItemText}

; + } + if (this.type === 'HEADING3') { + return

{this.rawItemText}

; + } + if (this.type === 'HEADING4') { + return

{this.rawItemText}

; + } + if (this.type === 'HEADING5') { + return
{this.rawItemText}
; + } + if (this.type === 'HEADING6') { + return
{this.rawItemText}
; + } + if (this.type === 'PARAGRAPH') { + return

{this.rawItemText}

; + } + if (this.type === 'HTML') { + return ( +
+ ); + } + if (this.type === 'VIDEO') { + return ( +
+ +
+ ); + } + if (this.type === 'DIVIDER') { + return ( + + + + ); + } + if ( + this.type === 'INFO' || + this.type === 'WARNING' || + this.type === 'ERROR' + ) { + return ( + + ); + } + if (['MARKDOWN', 'PLACEHOLDER'].includes(this.type)) { + return
{this.type}类型暂未支持
; + } + return null; + }, +}); diff --git a/src/control/form/edit-form/edit-form.controller.ts b/src/control/form/edit-form/edit-form.controller.ts index eb8f2d5e4037cc060e0e381eca922f997ae3ff74..a046d2781d72fce83317513eaa22d2187765067a 100644 --- a/src/control/form/edit-form/edit-form.controller.ts +++ b/src/control/form/edit-form/edit-form.controller.ts @@ -62,7 +62,7 @@ export class EditFormController * @author lxm * @date 2022-08-19 14:08:50 */ - async load(): Promise { + async load(): Promise { this.isNewData = !hasDeCodeName(this.context, this.model.appDataEntityId!); const queryParams = { ...this.params }; diff --git a/src/control/form/edit-form/edit-form.service.ts b/src/control/form/edit-form/edit-form.service.ts index e7a69ec0612551ba4db4e41c22ef91db3173e446..cadeb06c160729ab78403561ccb29d751395bb5a 100644 --- a/src/control/form/edit-form/edit-form.service.ts +++ b/src/control/form/edit-form/edit-form.service.ts @@ -87,17 +87,17 @@ export class EditFormService< * @author lxm * @date 2022-09-07 19:09:11 * @param {IParams} context 上下文 - * @param {ControlVO} data 数据 + * @param {IData} data 数据 * @returns {*} */ async create( context: IParams, - data: ControlVO, + data: IData, ): Promise> { let res = await this.exec( this.model.createControlAction!.appDEMethodId!, context, - data.getOrigin(), + data instanceof ControlVO ? data.getOrigin() : data, ); res = this.handleResponse(res); return res as IHttpResponse; @@ -109,17 +109,17 @@ export class EditFormService< * @author lxm * @date 2022-09-07 19:09:11 * @param {IParams} context 上下文 - * @param {ControlVO} data 数据 + * @param {IData} data 数据 * @returns {*} */ async update( context: IParams, - data: ControlVO, + data: IData, ): Promise> { let res = await this.exec( this.model.updateControlAction!.appDEMethodId!, context, - data.getOrigin(), + data instanceof ControlVO ? data.getOrigin() : data, ); res = this.handleResponse(res); return res as IHttpResponse; @@ -131,19 +131,23 @@ export class EditFormService< * @author lxm * @date 2022-09-07 19:09:11 * @param {IParams} context 上下文 - * @param {ControlVO} data 数据 + * @param {IData} data 数据 * @returns {*} */ async goBack( context: IParams, - data: ControlVO, + data: IData, ): Promise> { const wizardForm = this.model as IDEWizardEditForm; const methodName = wizardForm.goBackControlAction?.appDEMethodId; if (!methodName) { throw new RuntimeModelError(this.model, '缺少返回操作实体行为'); } - let res = await this.exec(methodName, context, data.getOrigin()); + let res = await this.exec( + methodName, + context, + data instanceof ControlVO ? data.getOrigin() : data, + ); res = this.handleResponse(res); return res as IHttpResponse; } @@ -174,14 +178,14 @@ export class EditFormService< * @author lxm * @date 2022-09-07 19:09:11 * @param {IParams} context 上下文 - * @param {ControlVO} data 数据 + * @param {IData} data 数据 * @param {IParams} [params={}] 视图参数 * @returns {*} */ async wfStart( context: IParams, params: IParams, - data: ControlVO, + data: IData, ): Promise> { const wfForm = this.model as IWFEditForm; const methodName = wfForm.wfstartControlAction?.appDEMethodId; @@ -192,7 +196,7 @@ export class EditFormService< methodName, context, params, - data.getOrigin(), + data instanceof ControlVO ? data.getOrigin() : data, ); } @@ -202,14 +206,14 @@ export class EditFormService< * @author lxm * @date 2022-09-07 19:09:11 * @param {IParams} context 上下文 - * @param {ControlVO} data 数据 + * @param {IData} data 数据 * @param {IParams} [params={}] 视图参数 * @returns {*} */ async wfSubmit( context: IParams, params: IParams, - data: ControlVO, + data: IData, ): Promise> { const wfForm = this.model as IWFEditForm; const methodName = wfForm.wfsubmitControlAction?.appDEMethodId; @@ -220,7 +224,7 @@ export class EditFormService< methodName, context, params, - data.getOrigin(), + data instanceof ControlVO ? data.getOrigin() : data, ); } diff --git a/src/control/form/edit-form/edit-form.tsx b/src/control/form/edit-form/edit-form.tsx index ce5860f255526d6024c8bb1205b2430e8c69be9e..61cc82f23cb03962d99b6bdd7285c49e3856b4a8 100644 --- a/src/control/form/edit-form/edit-form.tsx +++ b/src/control/form/edit-form/edit-form.tsx @@ -1,7 +1,7 @@ /* eslint-disable no-param-reassign */ import { useControlController, useNamespace } from '@ibiz-template/vue3-util'; import { IDEEditForm } from '@ibiz/model-core'; -import { defineComponent, PropType, reactive } from 'vue'; +import { defineComponent, PropType, reactive, watch } from 'vue'; import { EditFormController } from './edit-form.controller'; export const EditFormControl = defineComponent({ @@ -13,11 +13,24 @@ export const EditFormControl = defineComponent({ }, context: { type: Object as PropType, required: true }, params: { type: Object as PropType, default: () => ({}) }, + isSimple: { type: Boolean, required: false }, + data: { type: Object as PropType, required: false }, }, setup() { const c = useControlController( (...args) => new EditFormController(...args), ); + + watch( + () => c.state.data, + (newVal, oldVal) => { + if (newVal && newVal !== oldVal) { + c.state.isLoaded = true; + } + }, + { immediate: true }, + ); + const ns = useNamespace(`control-${c.model.controlType!.toLowerCase()}`); c.evt.on('onCreated', () => { diff --git a/src/control/form/form-detail/form-mdctrl/form-mdctrl.controller.ts b/src/control/form/form-detail/form-mdctrl/form-mdctrl.controller.ts new file mode 100644 index 0000000000000000000000000000000000000000..cf3f86f3f9ada607bd1107f8ab3c9afc7de728ad --- /dev/null +++ b/src/control/form/form-detail/form-mdctrl/form-mdctrl.controller.ts @@ -0,0 +1,119 @@ +import { + EventBase, + getControlProvider, + IControlProvider, +} from '@ibiz-template/runtime'; +import { IControl, IDEFormMDCtrl } from '@ibiz/model-core'; +import { FormDetailController } from '../form-detail'; +import { FormMDCtrlState } from './form-mdctrl.state'; + +/** + * 表单多数据部件控制器 + * + * @author lxm + * @date 2022-09-04 15:09:52 + * @export + * @class FormMDCtrlController + * @extends {FormDetailController} + */ +export class FormMDCtrlController extends FormDetailController { + declare state: FormMDCtrlState; + + protected createState(): FormMDCtrlState { + return new FormMDCtrlState(this.parent?.state); + } + + /** + * 所有部件的适配器 + * + * @author lxm + * @date 2022-08-24 20:08:07 + * @type {{ [key: string]: IControlProvider }} + */ + providers: { [key: string]: IControlProvider } = {}; + + /** + * 嵌入表单模型 + * @return {*} + * @author: zhujiamin + * @Date: 2023-05-26 10:44:10 + */ + formModel: IControl | null = null; + + protected async onInit(): Promise { + await super.onInit(); + // 编辑表单适配器 + const mdCtrl = this.model.contentControl; + if (mdCtrl && this.model.contentType === 'FORM') { + this.formModel = mdCtrl; + const formProvider = await getControlProvider(this.formModel); + if (formProvider) { + this.providers[this.formModel.id!] = formProvider; + } + } + } + + /** + * 内部表单数据发生改变,同步contentCtrlData并设置外部表单值 + * @param {EventBase} arg + * @param {number} index + * @return {*} + * @author: zhujiamin + * @Date: 2023-05-26 14:38:42 + */ + onFormDataChange(arg: EventBase, index: number) { + this.state.contentCtrlData[index] = arg.data[0]; + this.setFormDataValue(); + } + + /** + * 手动通知外部表单值变更 + * @return {*} + * @author: zhujiamin + * @Date: 2023-05-26 14:49:39 + */ + setFormDataValue() { + if (this.model.appDEFieldId) { + this.form.setDataValue( + this.model.appDEFieldId, + this.state.contentCtrlData, + ); + } + } + + /** + * 加载数据,要在表单加载完成之后再去加载 + * @return {*} + * @author: zhujiamin + * @Date: 2023-05-06 14:50:11 + */ + async loadData() { + if (this.model.appDEFieldId) { + this.state.contentCtrlData = this.data[this.model.appDEFieldId] || []; + } + } + + /** + * 处理删除 + * @param {IData} args + * @param {number} index + * @return {*} + * @author: zhujiamin + * @Date: 2023-05-06 14:54:55 + */ + async handleRemove(args: IData, index: number) { + this.state.contentCtrlData.splice(index, 1); + this.setFormDataValue(); + } + + /** + * 处理添加 + * @return {*} + * @author: zhujiamin + * @Date: 2023-05-06 14:59:24 + */ + async handleAdd() { + this.state.contentCtrlData.push({}); + this.setFormDataValue(); + } +} diff --git a/src/control/form/form-detail/form-mdctrl/form-mdctrl.provider.ts b/src/control/form/form-detail/form-mdctrl/form-mdctrl.provider.ts new file mode 100644 index 0000000000000000000000000000000000000000..f0b0150f8cc175174f6b8a94f46215330186e5fe --- /dev/null +++ b/src/control/form/form-detail/form-mdctrl/form-mdctrl.provider.ts @@ -0,0 +1,27 @@ +import { IFormDetailProvider } from '@ibiz-template/runtime'; +import { IDEFormMDCtrl } from '@ibiz/model-core'; +import { FormController } from '../../form/form.controller'; +import { FormGroupPanelController } from '../form-group-panel'; +import { FormMDCtrlController } from './form-mdctrl.controller'; +/** + * 表单多数据部件适配器 + * + * @author lxm + * @date 2022-09-19 22:09:03 + * @export + * @class FormMDCtrlProvider + * @implements {EditorProvider} + */ +export class FormMDCtrlProvider implements IFormDetailProvider { + component: string = 'IBizFormMDCtrl'; + + async createController( + detailModel: IDEFormMDCtrl, + form: FormController, + parent: FormGroupPanelController | undefined, + ): Promise { + const c = new FormMDCtrlController(detailModel, form, parent); + await c.init(); + return c; + } +} diff --git a/src/control/form/form-detail/form-mdctrl/form-mdctrl.scss b/src/control/form/form-detail/form-mdctrl/form-mdctrl.scss new file mode 100644 index 0000000000000000000000000000000000000000..2751fae3db9b3a7e729f0187aec27912099e3fc2 --- /dev/null +++ b/src/control/form/form-detail/form-mdctrl/form-mdctrl.scss @@ -0,0 +1,29 @@ +@include b(form-mdctrl) { + @include b(form-mdctrl-main) { + @include b(form-mdctrl-form-content) { + @include flex(row); + } + + @include b(form-mdctrl-btn) { + cursor: pointer; + @include flex(column, flex-start, center); + } + + @include b(form-mdctrl-title) { + @include flex(row, space-between, center); + } + + @include b(form-mdctrl-remove-btn) { + color: getCssVar('color', 'danger'); + text-align: right; + cursor: pointer; + box-shadow: none; + } + + @include b(form-mdctrl-add-btn) { + color: getCssVar('color', 'primary'); + cursor: pointer; + box-shadow: none; + } + } +} diff --git a/src/control/form/form-detail/form-mdctrl/form-mdctrl.state.ts b/src/control/form/form-detail/form-mdctrl/form-mdctrl.state.ts new file mode 100644 index 0000000000000000000000000000000000000000..30613bc2b2e91224f8441c101e565d6277a61ac0 --- /dev/null +++ b/src/control/form/form-detail/form-mdctrl/form-mdctrl.state.ts @@ -0,0 +1,16 @@ +import { FormDetailState } from '../form-detail'; + +/** + * 表单多数据部件状态 + * @return {*} + * @author: zhujiamin + * @Date: 2023-01-04 10:26:34 + */ +export class FormMDCtrlState extends FormDetailState { + /** + * 多数据内容数据 + * + * @type {Array} + */ + contentCtrlData: Array = []; +} diff --git a/src/control/form/form-detail/form-mdctrl/form-mdctrl.tsx b/src/control/form/form-detail/form-mdctrl/form-mdctrl.tsx new file mode 100644 index 0000000000000000000000000000000000000000..41ff9971c96fc56619a14c95c6b49f068b423523 --- /dev/null +++ b/src/control/form/form-detail/form-mdctrl/form-mdctrl.tsx @@ -0,0 +1,111 @@ +/* eslint-disable prefer-const */ +import { defineComponent, h, PropType, resolveComponent, watch } from 'vue'; +import { useController, useNamespace } from '@ibiz-template/vue3-util'; +import './form-mdctrl.scss'; +import { IDEFormMDCtrl } from '@ibiz/model-core'; +import { EventBase } from '@ibiz-template/runtime'; +import { FormMDCtrlController } from './form-mdctrl.controller'; + +export const FormMDCtrl = defineComponent({ + name: 'IBizFormMDCtrl', + props: { + modelData: { + type: Object as PropType, + required: true, + }, + controller: { + type: FormMDCtrlController, + required: true, + }, + }, + setup(props) { + const ns = useNamespace('form-mdctrl'); + + useController(props.controller); + + const c = props.controller; + + watch( + () => c.form.state.isLoaded, + (n, o) => { + if (n !== o && n === true) { + c.loadData(); + } + }, + ); + + return { ns, c }; + }, + render() { + const renderFormContent = () => { + return ( + this.c.state.contentCtrlData.length > 0 && + this.c.state.contentCtrlData.map((data: IData, index: number) => { + let formComponent = null; + const { formModel } = this.c; + if (formModel && this.c.providers[formModel.id!]) { + const tempContext = this.c.form.context.clone(); + formComponent = h( + resolveComponent(this.c.providers[formModel.id!].component), + { + modelData: formModel, + context: tempContext, + params: this.c.form.params, + isSimple: true, + data, + onFormDataChange: (arg: EventBase) => + this.c.onFormDataChange(arg, index), + }, + ); + } + return ( +
+ {formComponent} +
+ this.c.handleRemove(data, index)} + > + {{ + reference: () => { + return ( + + 删除 + + ); + }, + }} + +
+
+ ); + }) + ); + }; + + const renderMainContent = () => { + return ( +
+ {[ +
+ {this.modelData.caption} + this.c.handleAdd()} + > + 添加 + +
, + renderFormContent(), + ]} +
+ ); + }; + + return
{renderMainContent()}
; + }, +}); + +export default FormMDCtrl; diff --git a/src/control/form/form-detail/form-mdctrl/index.ts b/src/control/form/form-detail/form-mdctrl/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..5ced077c0986de0d3e10b6f5d6b980cb5fa18cca --- /dev/null +++ b/src/control/form/form-detail/form-mdctrl/index.ts @@ -0,0 +1,17 @@ +import { registerFormDetailProvider } from '@ibiz-template/runtime'; +import { withInstall } from '@ibiz-template/vue3-util'; +import { App } from 'vue'; +import FormMDCtrl from './form-mdctrl'; +import { FormMDCtrlProvider } from './form-mdctrl.provider'; + +export * from './form-mdctrl.provider'; +export * from './form-mdctrl.state'; +export * from './form-mdctrl.controller'; + +export const IBizFormMDCtrl = withInstall(FormMDCtrl, function (v: App) { + v.component(FormMDCtrl.name, FormMDCtrl); + // 表单按钮 + registerFormDetailProvider('MDCTRL', () => new FormMDCtrlProvider()); +}); + +export default IBizFormMDCtrl; diff --git a/src/control/form/form-detail/index.ts b/src/control/form/form-detail/index.ts index 6f750b6177a8fcb84eb60ec0b228a506e0817970..737e972a919f8dfeb1e9975e3122b55814312c5f 100644 --- a/src/control/form/form-detail/index.ts +++ b/src/control/form/form-detail/index.ts @@ -4,3 +4,4 @@ export * from './form-item/index'; export * from './form-page/index'; export * from './form-button/index'; export * from './form-druipart/index'; +export * from './form-mdctrl/index'; diff --git a/src/control/form/form/form.controller.ts b/src/control/form/form/form.controller.ts index 1fe55b95361e21ba8aac6829158b5b33c0483224..a3a74d799c42c147a1037f5f7e3f690d12f0742d 100644 --- a/src/control/form/form/form.controller.ts +++ b/src/control/form/form/form.controller.ts @@ -2,6 +2,7 @@ import { RuntimeError, debounceAndAsyncMerge } from '@ibiz-template/core'; import { ControlController, + ControllerEvent, ControlVO, FormNotifyState, getFormDetailProvider, @@ -33,6 +34,10 @@ export abstract class FormController< extends ControlController implements IFormController { + protected get _evt(): ControllerEvent { + return this.evt; + } + /** * 所有表单项成员的控制器 * @@ -66,9 +71,9 @@ export abstract class FormController< * @author chitanda * @date 2023-01-04 10:01:46 * @readonly - * @type {ControlVO} + * @type {IData} */ - get data(): ControlVO { + get data(): IData { return this.state.data; } @@ -233,6 +238,11 @@ export abstract class FormController< // 设置正在处理状态 this.state.processing = true; + + // 如果是简易模式需要直接抛出去 + if (this.state.isSimple) { + await this._evt.emit('onFormDataChange', undefined); + } try { await this.dataChangeNotify([name]); } finally { diff --git a/src/control/form/form/index.ts b/src/control/form/form/index.ts index cdf0265ad5f0d9b3a93593a7b151d3fcc1151dc2..a0872613504cb99636fbe3f552150312d0f6fc32 100644 --- a/src/control/form/form/index.ts +++ b/src/control/form/form/index.ts @@ -7,6 +7,7 @@ import { IBizFormGroupPanel, IBizFormItem, IBizFormPage, + IBizFormMDCtrl, } from '../form-detail'; export * from './form.controller'; @@ -18,6 +19,7 @@ export const IBizFormControl = withInstall(FormControl, function (v: App) { v.use(IBizFormGroupPanel); v.use(IBizFormButton); v.use(IBizFormDRUIPart); + v.use(IBizFormMDCtrl); // 表单直接内容 // registerFormDetailProvider('RAWITEM', new FormRawItemProvider()); diff --git a/src/editor/autocomplete/autocomplete-editor.controller.ts b/src/editor/autocomplete/autocomplete-editor.controller.ts index 1df93ef0a009125dac1f5e027a961ce87c5749e9..945f9b92ba21e9b94ccc6d474118438c1920243d 100644 --- a/src/editor/autocomplete/autocomplete-editor.controller.ts +++ b/src/editor/autocomplete/autocomplete-editor.controller.ts @@ -1,6 +1,11 @@ import { IHttpResponse, RuntimeModelError } from '@ibiz-template/core'; import { EditorController } from '@ibiz-template/runtime'; -import { IAppDataEntity, IAutoComplete } from '@ibiz/model-core'; +import { + IAppDataEntity, + IAppDEACMode, + IAutoComplete, + IDEACModeDataItem, +} from '@ibiz/model-core'; /** * 自动完成编辑器控制器 @@ -17,20 +22,15 @@ export class AutoCompleteEditorController extends EditorController { super.onInit(); - this.valueItem = this.parent.valueItemName?.toLowerCase() || ''; if (this.model.appDataEntityId) { this.appDataEntity = await ibiz.hub.getAppDataEntity( this.model.appDataEntityId, this.context.srfappid, )!; if (this.appDataEntity) { - this.keyName = this.appDataEntity?.keyAppDEFieldId || ''; - this.textName = this.appDataEntity?.majorAppDEFieldId || ''; + this.keyName = this.appDataEntity.keyAppDEFieldId!; + this.textName = this.appDataEntity.majorAppDEFieldId!; this.getAcParams(); this.sort = this.getAcSort(); } @@ -79,23 +88,34 @@ export class AutoCompleteEditorController extends EditorController { + if (dataItem.id !== 'value' && dataItem.id !== 'text') { + this.dataItems.push(dataItem); + } + }); + } + } } /** * 获取自填模式sort排序 */ public getAcSort() { - // if (this.model.deACMode) { - // const { sortField, sortDir } = this.model.deACMode; - // if (sortField && sortDir) { - // return `${sortField},${sortDir}`; - // } - // } + if (this.deACMode) { + const { minorSortAppDEFieldId, minorSortDir } = this.deACMode; + if (minorSortAppDEFieldId && minorSortDir) { + return `${minorSortAppDEFieldId.toLowerCase()},${minorSortDir.toLowerCase()}`; + } + } return undefined; } @@ -136,15 +156,31 @@ export class AutoCompleteEditorController extends EditorController>} + * @returns {*} {Promise>} */ async calcFillDataItems( - _data: IData, + data: IData, // eslint-disable-next-line @typescript-eslint/no-explicit-any - ): Promise> { - // if (this.model.deACMode) { - // return DEACModeUtil.calcFillDataItems(data, this.model.deACMode); - // } + ): Promise> { + if (this.deACMode) { + if (this.dataItems.length === 0) { + return []; + } + const result = await Promise.all( + this.dataItems.map(item => { + const value = data[item.appDEFieldId!]; + if (item.format) { + // todo 值格式化 + } else if (item.convertToCodeItemText && item.codeListId) { + // todo 代码表转换为文本值 + } else if (item.customCode) { + // todo 脚本代码 + } + return { id: item.id!, value }; + }), + ); + return result; + } return []; } } diff --git a/src/editor/autocomplete/ibiz-autocomplete/ibiz-autocomplete.tsx b/src/editor/autocomplete/ibiz-autocomplete/ibiz-autocomplete.tsx index d3ff1d4a85dcc4c492455f3f44552ae6dee4946a..ec77c44af00197c3be0af0b9b69da82e7fc27b2a 100644 --- a/src/editor/autocomplete/ibiz-autocomplete/ibiz-autocomplete.tsx +++ b/src/editor/autocomplete/ibiz-autocomplete/ibiz-autocomplete.tsx @@ -5,7 +5,7 @@ import { useNamespace, } from '@ibiz-template/vue3-util'; import './ibiz-autocomplete.scss'; -import { isEmpty } from 'ramda'; +import { debounce } from 'lodash-es'; import { AutoCompleteEditorController } from '../autocomplete-editor.controller'; export const IBizAutoComplete = defineComponent({ @@ -25,6 +25,18 @@ export const IBizAutoComplete = defineComponent({ // 实体数据集 const items: Ref = ref([]); + // 获取实体数据后,需要判断一次当前值是否在返回数据中 + watch(items, (newVal, oldVal) => { + if (oldVal.length === 0 && newVal.length > 0) { + const index = newVal.findIndex((item: IData) => + Object.is(item[c.keyName], props.value), + ); + if (index !== -1) { + curValue.value = newVal[index][c.textName]; + } + } + }); + // 是否显示所有数据 const isShowAll = ref(true); @@ -35,21 +47,16 @@ export const IBizAutoComplete = defineComponent({ () => props.value, newVal => { if (newVal || newVal === null) { - curValue.value = newVal; if (newVal === null) { curValue.value = ''; } - const value = props.data[c.valueItem]; const index = items.value.findIndex((item: IData) => - Object.is(item[c.keyName], value), + Object.is(item[c.keyName], newVal), ); if (index !== -1) { - return; - } - // items里匹配不到当前值项值时,生成自身的选项 - items.value = []; - if (!isEmpty(newVal) && !isEmpty(value)) { - items.value.push({ [c.textName]: newVal, [c.keyName]: value }); + curValue.value = items.value[index][c.textName]; + } else { + curValue.value = newVal; } } }, @@ -62,15 +69,12 @@ export const IBizAutoComplete = defineComponent({ const dataItems = await c.calcFillDataItems(data); if (dataItems.length) { dataItems.forEach(dataItem => { - emit('change', dataItem.value, dataItem.name); + emit('change', dataItem.value, dataItem.id); }); } - // 处理值项和本身的值 - if (c.valueItem) { - emit('change', data[c.keyName], c.valueItem); - } - emit('change', data[c.textName]); + // 处理本身的值 + emit('change', data[c.keyName]); }; // 往外抛值 @@ -92,21 +96,19 @@ export const IBizAutoComplete = defineComponent({ } } }; + // 开始时搜索一次拿items + onSearch(''); // 清除 const onClear = () => { - // zjm todo 实体自填模式相关 // 清空回填数据 - // const dataItems = c.model.deACMode?.dataItems; - // if (dataItems?.length) { - // dataItems.forEach(dataItem => { - // emit('change', null, dataItem.name); - // }); - // } - // if (c.valueItem) { - // emit('change', null, c.valueItem); - // } - // emit('change', null); + const dataItems = c.dataItems; + if (dataItems.length > 0) { + dataItems.forEach(dataItem => { + emit('change', null, dataItem.id); + }); + } + emit('change', null); }; // 聚焦 @@ -140,6 +142,29 @@ export const IBizAutoComplete = defineComponent({ ); }); + let isDebounce = false; + let blurCacheValue: string | undefined; + // 防抖值变更回调 + const debounceChange = debounce( + (val: string | number) => { + // 拦截掉blur触发后change + if (blurCacheValue !== val) { + emit('change', val); + } + blurCacheValue = undefined; + isDebounce = false; + }, + 300, + { leading: true }, + ); + // 输入完成后抛值 + const handleInput = (val: string | number) => { + if (editorType !== 'AC_FS' && editorType !== 'AC_FS_NOBUTTON') { + isDebounce = true; + debounceChange(val); + } + }; + return { ns, c, @@ -151,6 +176,9 @@ export const IBizAutoComplete = defineComponent({ onClear, onFocus, onACSelect, + items, + handleInput, + isDebounce, }; }, render() { @@ -167,16 +195,13 @@ export const IBizAutoComplete = defineComponent({ fetch-suggestions={this.onSearch} onClear={this.onClear} disabled={this.disabled || this.readonly} + onSelect={this.onACSelect} + onInput={this.handleInput} > {{ default: ({ item }: { item: IData }) => { return ( -
{ - this.onACSelect(item); - }} - > +
{item[this.c.textName]}
); diff --git a/src/editor/data-picker/ibiz-picker-dropdown/ibiz-picker-dropdown.tsx b/src/editor/data-picker/ibiz-picker-dropdown/ibiz-picker-dropdown.tsx index 4de698ecabea2f3811b940e79c0779e88e12c3ca..7eee183c0206476f9b9412a0f8e1bcb6a0cc8ca3 100644 --- a/src/editor/data-picker/ibiz-picker-dropdown/ibiz-picker-dropdown.tsx +++ b/src/editor/data-picker/ibiz-picker-dropdown/ibiz-picker-dropdown.tsx @@ -71,7 +71,7 @@ export const IBizPickerDropDown = defineComponent({ const dataItems = await c.calcFillDataItems(item); if (dataItems.length) { dataItems.forEach(dataItem => { - emit('change', dataItem.value, dataItem.name); + emit('change', dataItem.value, dataItem.id); }); } @@ -129,18 +129,17 @@ export const IBizPickerDropDown = defineComponent({ // 清除 const onClear = () => { - // zjm todo 实体自填模式相关 // 清空回填数据 - // const dataItems = c.model.deACMode?.dataItems; - // if (dataItems?.length) { - // dataItems.forEach(dataItem => { - // emit('change', null, dataItem.name); - // }); - // } - // if (c.valueItem) { - // emit('change', null, c.valueItem); - // } - // emit('change', null); + const dataItems = c.dataItems; + if (dataItems?.length) { + dataItems.forEach(dataItem => { + emit('change', null, dataItem.id); + }); + } + if (c.valueItem) { + emit('change', null, c.valueItem); + } + emit('change', null); }; return { ns, diff --git a/src/editor/data-picker/ibiz-picker-select-view/ibiz-picker-select-view.tsx b/src/editor/data-picker/ibiz-picker-select-view/ibiz-picker-select-view.tsx index ad121378d3aa845327e855073b647f131c9c51bb..a84fb2c6b276133deb63ee3120765ac9804bdb6d 100644 --- a/src/editor/data-picker/ibiz-picker-select-view/ibiz-picker-select-view.tsx +++ b/src/editor/data-picker/ibiz-picker-select-view/ibiz-picker-select-view.tsx @@ -143,18 +143,17 @@ export const IBizPickerSelectView = defineComponent({ // 清除 const onClear = () => { - // zjm todo 实体自填模式相关 // 清空回填数据 - // const dataItems = c.model.deACMode?.dataItems; - // if (dataItems?.length) { - // dataItems.forEach(dataItem => { - // emit('change', null, dataItem.name); - // }); - // } - // if (c.valueItem) { - // emit('change', null, c.valueItem); - // } - // emit('change', null); + const dataItems = c.dataItems; + if (dataItems?.length) { + dataItems.forEach(dataItem => { + emit('change', null, dataItem.id); + }); + } + if (c.valueItem) { + emit('change', null, c.valueItem); + } + emit('change', null); }; // 视图数据改变 diff --git a/src/editor/data-picker/ibiz-picker/ibiz-picker.tsx b/src/editor/data-picker/ibiz-picker/ibiz-picker.tsx index a5e5e0e6a35de3fa2da7f14ebb44a20dd4244a6f..99a39649879c69a30bbaf75c03fadb477c55fc1f 100644 --- a/src/editor/data-picker/ibiz-picker/ibiz-picker.tsx +++ b/src/editor/data-picker/ibiz-picker/ibiz-picker.tsx @@ -60,7 +60,7 @@ export const IBizPicker = defineComponent({ const dataItems = await c.calcFillDataItems(data); if (dataItems.length) { dataItems.forEach(dataItem => { - emit('change', dataItem.value, dataItem.name); + emit('change', dataItem.value, dataItem.id); }); } @@ -111,18 +111,17 @@ export const IBizPicker = defineComponent({ // 清除 const onClear = () => { - // zjm todo 实体自填模式相关 // 清空回填数据 - // const dataItems = c.model.deACMode?.dataItems; - // if (dataItems?.length) { - // dataItems.forEach(dataItem => { - // emit('change', null, dataItem.name); - // }); - // } - // if (c.valueItem) { - // emit('change', null, c.valueItem); - // } - // emit('change', null); + const dataItems = c.dataItems; + if (dataItems?.length) { + dataItems.forEach(dataItem => { + emit('change', null, dataItem.id); + }); + } + if (c.valueItem) { + emit('change', null, c.valueItem); + } + emit('change', null); }; // 聚焦 diff --git a/src/editor/data-picker/picker-editor.controller.ts b/src/editor/data-picker/picker-editor.controller.ts index cdaa2b5fc0bc7e9ae6c62f65e1b758daa515d910..62203de712c4cc268554ba190ccb5472aaa9b757 100644 --- a/src/editor/data-picker/picker-editor.controller.ts +++ b/src/editor/data-picker/picker-editor.controller.ts @@ -1,6 +1,12 @@ import { IHttpResponse, RuntimeModelError } from '@ibiz-template/core'; import { EditorController, OpenAppViewCommand } from '@ibiz-template/runtime'; -import { IAppDataEntity, IAppView, IPicker } from '@ibiz/model-core'; +import { + IAppDataEntity, + IAppDEACMode, + IAppView, + IDEACModeDataItem, + IPicker, +} from '@ibiz/model-core'; /** * 数据选择编辑器控制器 @@ -37,12 +43,12 @@ export class PickerEditorController extends EditorController { /** * 主键属性名称 */ - public keyName: string = ''; + public keyName: string = 'srfkey'; /** * 主文本属性名称 */ - public textName: string = ''; + public textName: string = 'srfmajortext'; /** * 实体codeName @@ -74,19 +80,28 @@ export class PickerEditorController extends EditorController { */ public appDataEntity: IAppDataEntity | null = null; + /** + * 实体自填模式模型 + */ + public deACMode: IAppDEACMode | null = null; + + /** + * 自填数据项集合(已排除了value和text) + */ + public dataItems: IDEACModeDataItem[] = []; + protected async onInit(): Promise { super.onInit(); this.initParams(); - // zjm todo 值项名称父模型没有valueItemName - this.valueItem = this.parent.valueItemName?.toLowerCase() || ''; + this.valueItem = this.model.valueItemName?.toLowerCase() || ''; if (this.model.appDataEntityId) { this.appDataEntity = await ibiz.hub.getAppDataEntity( this.model.appDataEntityId, this.context.srfappid, )!; if (this.appDataEntity) { - this.keyName = this.appDataEntity?.keyAppDEFieldId || ''; - this.textName = this.appDataEntity?.majorAppDEFieldId || ''; + this.keyName = this.appDataEntity.keyAppDEFieldId!; + this.textName = this.appDataEntity.majorAppDEFieldId!; this.getAcParams(); this.sort = this.getAcSort(); } @@ -141,23 +156,34 @@ export class PickerEditorController extends EditorController { if (this.model.appDEDataSetId) { this.interfaceName = this.model.appDEDataSetId; } - // zjm todo 实体自填模式模型 - // if (this.model.deACMode) { - // this.textName = this.model.deACMode.textFieldName || this.textName; - // this.keyName = this.model.deACMode.valueFieldName || this.keyName; - // } + if (this.appDataEntity?.appDEACModes) { + this.deACMode = this.appDataEntity.appDEACModes[0]; + if (this.deACMode.textAppDEFieldId) { + this.textName = this.deACMode.textAppDEFieldId; + } + if (this.deACMode.valueAppDEFieldId) { + this.keyName = this.deACMode.valueAppDEFieldId; + } + if (this.deACMode.deacmodeDataItems) { + this.deACMode.deacmodeDataItems.forEach(dataItem => { + if (dataItem.id !== 'value' && dataItem.id !== 'text') { + this.dataItems.push(dataItem); + } + }); + } + } } /** * 获取自填模式sort排序 */ public getAcSort() { - // if (this.model.deACMode) { - // const { sortField, sortDir } = this.model.deACMode; - // if (sortField && sortDir) { - // return `${sortField},${sortDir}`; - // } - // } + if (this.deACMode) { + const { minorSortAppDEFieldId, minorSortDir } = this.deACMode; + if (minorSortAppDEFieldId && minorSortDir) { + return `${minorSortAppDEFieldId.toLowerCase()},${minorSortDir.toLowerCase()}`; + } + } return undefined; } @@ -232,7 +258,9 @@ export class PickerEditorController extends EditorController { this.context, this.params, ); - context.srfkey = data[this.valueItem]; + if (data[this.valueItem]) { + context.srfkey = data[this.valueItem]; + } const { linkAppViewId } = this.model; if (!linkAppViewId) { throw new RuntimeModelError(this.model, '请配置数据链接视图'); @@ -251,15 +279,31 @@ export class PickerEditorController extends EditorController { * @author lxm * @date 2022-10-24 16:10:24 * @param {IData} data 选中数据 - * @returns {*} {Promise>} + * @returns {*} {Promise>} */ async calcFillDataItems( - _data: IData, + data: IData, // eslint-disable-next-line @typescript-eslint/no-explicit-any - ): Promise> { - // if (this.model.deACMode) { - // return DEACModeUtil.calcFillDataItems(data, this.model.deACMode); - // } + ): Promise> { + if (this.deACMode) { + if (this.dataItems.length === 0) { + return []; + } + const result = await Promise.all( + this.dataItems.map(item => { + const value = data[item.appDEFieldId!]; + if (item.format) { + // todo 值格式化 + } else if (item.convertToCodeItemText && item.codeListId) { + // todo 代码表转换为文本值 + } else if (item.customCode) { + // todo 脚本代码 + } + return { id: item.id!, value }; + }), + ); + return result; + } return []; } } diff --git a/src/editor/date-range/date-range-editor.controller.ts b/src/editor/date-range/date-range-editor.controller.ts new file mode 100644 index 0000000000000000000000000000000000000000..03f0bfaceee5763be6694a6c2516524a0f6e2fce --- /dev/null +++ b/src/editor/date-range/date-range-editor.controller.ts @@ -0,0 +1,53 @@ +import { EditorController } from '@ibiz-template/runtime'; +import { IDateRange } from '@ibiz/model-core'; + +/** + * 时间范围编辑器控制器 + * + * @export + * @class DateRangeEditorController + * @extends {EditorController} + */ +export class DateRangeEditorController extends EditorController { + /** + * 占位 + * @return {*} + * @author: zhujiamin + * @Date: 2022-08-25 14:33:14 + */ + public placeHolder = '请选择日期'; + + /** + * 根据编辑器类型获取格式化 + * + * @author lxm + * @date 2022-11-03 16:11:21 + * @public + * @returns {*} {string} + */ + public getFormatByType(): string { + switch (this.model.editorType) { + // 时间范围选择器 + case 'DATERANGE': + return 'YYYY-MM-DD HH:mm:ss'; + // 时间范围选择器(YYYY-MM-DD) + case 'DATERANGE_NOTIME': + return 'YYYY-MM-DD'; + default: + return 'YYYY-MM-DD HH:mm:ss'; + } + } + + /** + * 值格式化 + * @return {*} + * @author: zhujiamin + * @Date: 2022-08-25 14:33:14 + */ + public valueFormat: string | undefined; + + protected async onInit(): Promise { + super.onInit(); + this.valueFormat = this.getFormatByType(); + } +} diff --git a/src/editor/date-range/date-range-editor.provider.ts b/src/editor/date-range/date-range-editor.provider.ts new file mode 100644 index 0000000000000000000000000000000000000000..11a252a3f32054e266154c6298ed2085f3b302b1 --- /dev/null +++ b/src/editor/date-range/date-range-editor.provider.ts @@ -0,0 +1,28 @@ +import { + IEditorContainerController, + IEditorProvider, +} from '@ibiz-template/runtime'; +import { IDateRange } from '@ibiz/model-core'; +import { DateRangeEditorController } from './date-range-editor.controller'; + +/** + * 数值范围编辑器适配器 + * + * @export + * @class DateRangeEditorProvider + * @implements {EditorProvider} + */ +export class DateRangeEditorProvider implements IEditorProvider { + formEditor: string = 'IBizDateRangePicker'; + + gridEditor: string = 'IBizDateRangePicker'; + + async createController( + editorModel: IDateRange, + parentController: IEditorContainerController, + ): Promise { + const c = new DateRangeEditorController(editorModel, parentController); + await c.init(); + return c; + } +} diff --git a/src/editor/date-range/ibiz-date-range-picker/ibiz-date-range-picker.scss b/src/editor/date-range/ibiz-date-range-picker/ibiz-date-range-picker.scss new file mode 100644 index 0000000000000000000000000000000000000000..c709f7d67314af040421ccefd113987d7ccdeda6 --- /dev/null +++ b/src/editor/date-range/ibiz-date-range-picker/ibiz-date-range-picker.scss @@ -0,0 +1,5 @@ +@include b(date-range-picker) { + .el-date-editor { + width: 100%; + } +} diff --git a/src/editor/date-range/ibiz-date-range-picker/ibiz-date-range-picker.tsx b/src/editor/date-range/ibiz-date-range-picker/ibiz-date-range-picker.tsx new file mode 100644 index 0000000000000000000000000000000000000000..4f48650ebadd65e7ef5f1f59c5d0ae705925e7ae --- /dev/null +++ b/src/editor/date-range/ibiz-date-range-picker/ibiz-date-range-picker.tsx @@ -0,0 +1,149 @@ +import { computed, defineComponent, Ref, ref } from 'vue'; +import { + getEditorEmits, + getDateRangeProps, + useNamespace, +} from '@ibiz-template/vue3-util'; +import './ibiz-date-range-picker.scss'; +import { DateRangeEditorController } from '../date-range-editor.controller'; + +export const IBizDateRangePicker = defineComponent({ + name: 'IBizDateRangePicker', + props: getDateRangeProps(), + emits: getEditorEmits(), + setup(props, { emit }) { + const ns = useNamespace('date-range-picker'); + + const c = props.controller; + + const editorModel = c.model; + + // 值分割符 + let valueSeparator = '-'; + // 在范围选择器里取消两个日期面板之间的联动 + let unlinkPanels = false; + // 开始占位提示 + let startPlaceHolder = '开始时间'; + // 结束占位提示 + let endPlaceHolder = '结束时间'; + // 选择范围时的分隔符 + let rangeSeparator = '至'; + if (editorModel.editorParams) { + if (editorModel.editorParams.valueseparator) { + valueSeparator = editorModel.editorParams.valueseparator; + } + if (editorModel.editorParams.startplaceholder) { + startPlaceHolder = editorModel.editorParams.startplaceholder; + } + if (editorModel.editorParams.endplaceholder) { + endPlaceHolder = editorModel.editorParams.endplaceholder; + } + if (editorModel.editorParams.rangeseparator) { + rangeSeparator = editorModel.editorParams.rangeseparator; + } + if (editorModel.editorParams.unlinkpanels) { + unlinkPanels = c.handleStringToBoolean( + editorModel.editorParams.unlinkpanels, + ); + } + } + + // 类型 + const type = ref('daterange'); + switch (editorModel.editorType) { + case 'DATERANGE': + type.value = 'datetimerange'; + break; + case 'DATERANGE_NOTIME': + type.value = 'daterange'; + break; + default: + type.value = 'datetimerange'; + } + + // 格式 + const format = ref('YYYY-MM-DD'); + // 值格式化 + const valueFormat = c!.valueFormat; + if (valueFormat) { + format.value = valueFormat; + } + + // 关系表单项集合 + const refFormItem: Ref = ref([]); + const editorItems = editorModel.editorItems; + if (editorItems && editorItems.length > 0) { + const editorItemNames: string[] = editorItems.map( + (item: IData) => item.id, + ); + refFormItem.value = editorItemNames; + } + + // 当前值 + const curValue = computed({ + get() { + let value: string[] = []; + if (refFormItem.value) { + refFormItem.value.forEach((name: string) => { + if (props.data[name]) { + value.push(props.data[name]); + } + }); + } else if (props.value && typeof props.value === 'string') { + value = props.value.split(valueSeparator); + } + return value; + }, + set(dates: string[]) { + if (dates && dates.length > 0) { + emit('change', dates.join(valueSeparator)); + if (refFormItem.value) { + dates.forEach((date: string, index: number) => { + emit('change', date, refFormItem.value[index]); + }); + } + } else { + emit('change', null); + if (refFormItem.value) { + refFormItem.value.forEach((date: string, index: number) => { + emit('change', null, refFormItem.value[index]); + }); + } + } + }, + }); + + return { + ns, + c, + refFormItem, + curValue, + type, + format, + valueSeparator, + startPlaceHolder, + endPlaceHolder, + rangeSeparator, + unlinkPanels, + }; + }, + render() { + return ( +
+ +
+ ); + }, +}); diff --git a/src/editor/date-range/index.ts b/src/editor/date-range/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..313dfa995e0ca24654f9d412ea57fd0f01df4573 --- /dev/null +++ b/src/editor/date-range/index.ts @@ -0,0 +1,3 @@ +export { IBizDateRangePicker } from './ibiz-date-range-picker/ibiz-date-range-picker'; +export * from './date-range-editor.controller'; +export * from './date-range-editor.provider'; diff --git a/src/editor/index.ts b/src/editor/index.ts index 6503166dc8b038f8e7f68c482618a435ee2f73bd..a9ebb02c3cc350156faa293ac813da63893b40db 100644 --- a/src/editor/index.ts +++ b/src/editor/index.ts @@ -53,6 +53,11 @@ import { IBizPickerSelectView, DataPickerEditorProvider, } from './data-picker'; +import { + IBizNumberRangePicker, + NumberRangeEditorProvider, +} from './number-range'; +import { IBizDateRangePicker, DateRangeEditorProvider } from './date-range'; export const IBizEditor = { install: (v: App) => { @@ -90,6 +95,8 @@ export const IBizEditor = { v.component(IBizPickerLink.name, IBizPickerLink); v.component(IBizPickerEmbedView.name, IBizPickerEmbedView); v.component(IBizPickerSelectView.name, IBizPickerSelectView); + v.component(IBizNumberRangePicker.name, IBizNumberRangePicker); + v.component(IBizDateRangePicker.name, IBizDateRangePicker); // 标签 registerEditorProvider('SPAN', () => new SpanEditorProvider()); @@ -237,6 +244,17 @@ export const IBizEditor = { 'PICKUPVIEW', () => new DataPickerEditorProvider('PICKUPVIEW'), ); + // 数值范围 + registerEditorProvider( + 'NUMBERRANGE', + () => new NumberRangeEditorProvider(), + ); + // 时间范围 + registerEditorProvider('DATERANGE', () => new DateRangeEditorProvider()); + registerEditorProvider( + 'DATERANGE_NOTIME', + () => new DateRangeEditorProvider(), + ); }, }; diff --git a/src/editor/list-box/list-box-picker-editor.controller.ts b/src/editor/list-box/list-box-picker-editor.controller.ts index 31eb524e8606fe3a101c910e8d24a198e92f3eaa..e030c0ed999eac64bc3c5a80315899d0f1e7b0bf 100644 --- a/src/editor/list-box/list-box-picker-editor.controller.ts +++ b/src/editor/list-box/list-box-picker-editor.controller.ts @@ -1,4 +1,4 @@ -import { IHttpResponse } from '@ibiz-template/core'; +import { IHttpResponse, RuntimeModelError } from '@ibiz-template/core'; import { EditorController } from '@ibiz-template/runtime'; import { IAppDataEntity, IListBoxPicker } from '@ibiz/model-core'; @@ -12,12 +12,12 @@ export class ListBoxPickerEditorController extends EditorController { super.onInit(); if (this.model.editorType === 'LISTBOXPICKUP') { - // zjm todo 列表框选择模型缺少实体请求相关的,如appDataEntityId - // this.appDataEntity = await ibiz.hub.getAppDataEntity( - // this.model.appDataEntityId!, - // this.context.srfappid, - // )!; - + this.appDataEntity = await ibiz.hub.getAppDataEntity( + this.model.appDataEntityId!, + this.context.srfappid, + ); if (this.appDataEntity) { - this.keyName = this.appDataEntity?.keyAppDEFieldId || ''; - this.textName = this.appDataEntity?.majorAppDEFieldId || ''; + this.keyName = this.appDataEntity.keyAppDEFieldId!; + this.textName = this.appDataEntity.majorAppDEFieldId!; this.getAcParams(); } } @@ -58,9 +56,9 @@ export class ListBoxPickerEditorController extends EditorController>} * @memberof PickerEditorController */ - public async getServiceData(_data: IData): Promise> { - // const { context, params } = this.handlePublicParams( - // data, - // this.context, - // this.params, - // ); - // Object.assign(params, { size: 1000 }); - // if (this.serviceName && this.interfaceName) { - // const deService = await this.app.es.getService(this.serviceName); - // const res = await deService.exec(this.interfaceName, context, params); - // return res as IHttpResponse; - // } - // throw new DefectModelError(this.model.source, '请配置实体和实体数据集'); - return {} as IHttpResponse; + public async getServiceData(data: IData): Promise> { + const { context, params } = this.handlePublicParams( + data, + this.context, + this.params, + ); + Object.assign(params, { size: 1000 }); + if (this.serviceName && this.interfaceName) { + const app = ibiz.hub.getApp(this.appDataEntity!.appId); + const deService = await app.deService.getService(this.serviceName); + const res = await deService.exec(this.interfaceName, context, params); + return res as IHttpResponse; + } + throw new RuntimeModelError(this.model, '请配置实体和实体数据集'); } } diff --git a/src/editor/number-range/ibiz-number-range-picker/ibiz-number-range-picker.scss b/src/editor/number-range/ibiz-number-range-picker/ibiz-number-range-picker.scss new file mode 100644 index 0000000000000000000000000000000000000000..354c292aa2bd5ca37a5d7369190854f8c15eaba6 --- /dev/null +++ b/src/editor/number-range/ibiz-number-range-picker/ibiz-number-range-picker.scss @@ -0,0 +1,8 @@ +@include b(number-range-picker) { + width: 100%; + @include flex(row); + + .el-input-number { + flex: 1; + } +} diff --git a/src/editor/number-range/ibiz-number-range-picker/ibiz-number-range-picker.tsx b/src/editor/number-range/ibiz-number-range-picker/ibiz-number-range-picker.tsx new file mode 100644 index 0000000000000000000000000000000000000000..311d2cf61ee7dd8189fc3cab5235731c915daa0a --- /dev/null +++ b/src/editor/number-range/ibiz-number-range-picker/ibiz-number-range-picker.tsx @@ -0,0 +1,151 @@ +import { defineComponent, Ref, ref, watch } from 'vue'; +import { + getEditorEmits, + getNumberRangeProps, + useNamespace, +} from '@ibiz-template/vue3-util'; +import './ibiz-number-range-picker.scss'; +import { NumberRangeEditorController } from '../number-range-editor.controller'; + +export const IBizNumberRangePicker = defineComponent({ + name: 'IBizNumberRangePicker', + props: getNumberRangeProps(), + emits: getEditorEmits(), + setup(props, { emit }) { + const ns = useNamespace('number-range-picker'); + + const c = props.controller; + + const editorModel = c.model; + + // 最大值 + let max = Infinity; + // 最小值 + let min = -Infinity; + // 数值精度 + let precision = 0; + // 值分割符 + let valueSeparator = '-'; + // 开始占位提示 + let startPlaceHolder = '请输入开始数字'; + // 结束占位提示 + let endPlaceHolder = '请输入结束数字'; + // 选择范围时的分隔符 + let rangeSeparator = '~'; + if (editorModel.editorParams) { + if (editorModel.editorParams.maxvalue) { + max = c.handleStringToNumber(editorModel.editorParams.maxvalue); + } + if (editorModel.editorParams.minvalue) { + min = c.handleStringToNumber(editorModel.editorParams.minvalue); + } + if (editorModel.editorParams.precision) { + precision = c.handleStringToNumber(editorModel.editorParams.precision); + } + if (editorModel.editorParams.valueseparator) { + valueSeparator = editorModel.editorParams.valueseparator; + } + if (editorModel.editorParams.startplaceholder) { + startPlaceHolder = editorModel.editorParams.startplaceholder; + } + if (editorModel.editorParams.endplaceholder) { + endPlaceHolder = editorModel.editorParams.endplaceholder; + } + if (editorModel.editorParams.rangeseparator) { + rangeSeparator = editorModel.editorParams.rangeseparator; + } + } + + // 数据 + const items: number[] = []; + + // 关系表单项集合 + const refFormItem: Ref = ref([]); + const editorItems = editorModel.editorItems; + if (editorItems && editorItems.length > 0) { + const editorItemNames: string[] = editorItems.map( + (item: IData) => item.id, + ); + refFormItem.value = editorItemNames; + } + + // 范围最小值 + const minValue = ref(null); + + // 范围最大值 + const maxValue = ref(null); + + watch( + () => props.value, + (newVal, oldVal) => { + if (newVal !== oldVal && typeof newVal === 'string') { + minValue.value = newVal.split(valueSeparator)[0] + ? Number(newVal.split(valueSeparator)[0]) + : null; + maxValue.value = newVal.split(valueSeparator)[1] + ? Number(newVal.split(valueSeparator)[1]) + : null; + } + }, + { immediate: true }, + ); + + // 处理值变化 + const handleChange = (value: number, index: number) => { + items[index] = value; + if (items.length === 2) { + emit('change', items.join(valueSeparator)); + } + if (refFormItem.value) { + const valueName = refFormItem.value[index]; + emit('change', value, valueName); + } + }; + + return { + ns, + c, + refFormItem, + minValue, + maxValue, + handleChange, + max, + min, + precision, + valueSeparator, + startPlaceHolder, + endPlaceHolder, + rangeSeparator, + }; + }, + render() { + return ( +
+ this.handleChange(val, 0)} + > +
{this.rangeSeparator}
+ this.handleChange(val, 1)} + > +
+ ); + }, +}); diff --git a/src/editor/number-range/index.ts b/src/editor/number-range/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ce262868b4b9614b492ac1eb08562140546d9ddb --- /dev/null +++ b/src/editor/number-range/index.ts @@ -0,0 +1,3 @@ +export { IBizNumberRangePicker } from './ibiz-number-range-picker/ibiz-number-range-picker'; +export * from './number-range-editor.controller'; +export * from './number-range-editor.provider'; diff --git a/src/editor/number-range/number-range-editor.controller.ts b/src/editor/number-range/number-range-editor.controller.ts new file mode 100644 index 0000000000000000000000000000000000000000..0f21ca6b97b9172077e320a5c4ca3e03de208c2f --- /dev/null +++ b/src/editor/number-range/number-range-editor.controller.ts @@ -0,0 +1,11 @@ +import { EditorController } from '@ibiz-template/runtime'; +import { INumberRange } from '@ibiz/model-core'; + +/** + * 数值范围编辑器控制器 + * + * @export + * @class NumberRangeEditorController + * @extends {EditorController} + */ +export class NumberRangeEditorController extends EditorController {} diff --git a/src/editor/number-range/number-range-editor.provider.ts b/src/editor/number-range/number-range-editor.provider.ts new file mode 100644 index 0000000000000000000000000000000000000000..02695c6c714a807d9d38e48d25a81210a065a372 --- /dev/null +++ b/src/editor/number-range/number-range-editor.provider.ts @@ -0,0 +1,28 @@ +import { + IEditorContainerController, + IEditorProvider, +} from '@ibiz-template/runtime'; +import { INumberRange } from '@ibiz/model-core'; +import { NumberRangeEditorController } from './number-range-editor.controller'; + +/** + * 数值范围编辑器适配器 + * + * @export + * @class NumberRangeEditorProvider + * @implements {EditorProvider} + */ +export class NumberRangeEditorProvider implements IEditorProvider { + formEditor: string = 'IBizNumberRangePicker'; + + gridEditor: string = 'IBizNumberRangePicker'; + + async createController( + editorModel: INumberRange, + parentController: IEditorContainerController, + ): Promise { + const c = new NumberRangeEditorController(editorModel, parentController); + await c.init(); + return c; + } +} diff --git a/src/editor/raw/ibiz-raw/ibiz-raw.tsx b/src/editor/raw/ibiz-raw/ibiz-raw.tsx index 3f2c232b88ea82e739b352da4592b26a4f9f2b2f..f9669216408204541cb7cfbe82b5c7924f5dfb9e 100644 --- a/src/editor/raw/ibiz-raw/ibiz-raw.tsx +++ b/src/editor/raw/ibiz-raw/ibiz-raw.tsx @@ -39,11 +39,11 @@ export const IBizRaw = defineComponent({ this.readonly ? this.ns.m('readonly') : '', ]} > - + >
); }, diff --git a/src/editor/span/span-editor.controller.ts b/src/editor/span/span-editor.controller.ts index a7af2e7cb48eb7419ab8bfe041fd5353f0a4a20e..b9aa1a9e9e4971fb7db4e12a63fb0284e79f4cc2 100644 --- a/src/editor/span/span-editor.controller.ts +++ b/src/editor/span/span-editor.controller.ts @@ -1,4 +1,4 @@ -import { ISpan, IAppView, IAppCodeList } from '@ibiz/model-core'; +import { ISpan, IAppCodeList } from '@ibiz/model-core'; import { CodeListEditorController, OpenAppViewCommand, @@ -17,11 +17,6 @@ export class SpanEditorController extends CodeListEditorController { */ public valueItem = ''; - /** - *链接视图相关参数 - */ - public linkView: IAppView | null = null; - /** * 代码表模型 * @return {*} @@ -32,8 +27,10 @@ export class SpanEditorController extends CodeListEditorController { protected async onInit(): Promise { super.onInit(); - // zjm todo 值项名称父没有valueItemName - this.valueItem = this.parent.valueItemName?.toLowerCase() || ''; + // span-link临时用editorItems + if (this.model?.editorItems?.[0]) { + this.valueItem = this.model.editorItems[0].id!; + } // 初始化代码表 if (this.model.appCodeListId) { const app = await ibiz.hub.getApp(this.context.srfappid); @@ -50,7 +47,9 @@ export class SpanEditorController extends CodeListEditorController { this.context, this.params, ); - context.srfkey = data[this.valueItem]; + if (data[this.valueItem]) { + context.srfkey = data[this.valueItem]; + } const { linkAppViewId } = this.model; if (!linkAppViewId) { throw new RuntimeModelError(this.model, '请配置数据链接视图'); diff --git a/src/editor/stepper/stepper-editor.controller.ts b/src/editor/stepper/stepper-editor.controller.ts index 4ca70e33128c3c9d8e31febd7dcbcfffff7a4e9a..be31f108a561b08b71533b42842f781bf84d675f 100644 --- a/src/editor/stepper/stepper-editor.controller.ts +++ b/src/editor/stepper/stepper-editor.controller.ts @@ -8,4 +8,12 @@ import { IStepper } from '@ibiz/model-core'; * @class StepperEditorController * @extends {EditorController} */ -export class StepperEditorController extends EditorController {} +export class StepperEditorController extends EditorController { + /** + * 占位 + * @return {*} + * @author: zhujiamin + * @Date: 2022-08-25 14:33:14 + */ + public placeHolder = '请输入'; +} diff --git a/src/editor/upload/upload-editor.controller.ts b/src/editor/upload/upload-editor.controller.ts index 8098ef29288b1c94595e6796e5c777e7507713ac..26a6b4a46b1ce15676bd97e2ef336059a708a284 100644 --- a/src/editor/upload/upload-editor.controller.ts +++ b/src/editor/upload/upload-editor.controller.ts @@ -1,4 +1,8 @@ -import { downloadFileFromBlob, RuntimeError } from '@ibiz-template/core'; +import { + downloadFileFromBlob, + RuntimeError, + RuntimeModelError, +} from '@ibiz-template/core'; import { convertNavData, EditorController } from '@ibiz-template/runtime'; import { IFileUploader } from '@ibiz/model-core'; import qs from 'qs'; @@ -63,12 +67,24 @@ export class UploadEditorController extends EditorController { this.accept = accept; } if (uploadparams) { - // eslint-disable-next-line no-eval - this.uploadParams = eval(`(${uploadparams})`); + try { + this.uploadParams = JSON.parse(uploadparams); + } catch (error) { + throw new RuntimeModelError( + uploadparams, + `配置uploadparams没有按标准JSON格式`, + ); + } } if (exportparams) { - // eslint-disable-next-line no-eval - this.exportParams = eval(`(${exportparams})`); + try { + this.exportParams = JSON.parse(exportparams); + } catch (error) { + throw new RuntimeModelError( + exportparams, + `配置exportparams没有按标准JSON格式`, + ); + } } } }