diff --git a/docs/en/guide/command-execute.md b/docs/en/guide/command-execute.md index c2463e6..7a21361 100644 --- a/docs/en/guide/command-execute.md +++ b/docs/en/guide/command-execute.md @@ -813,3 +813,13 @@ Usage: ```javascript instance.command.executeLocationGroup(groupId: string) ``` + +## executeSetControlValue + +Feature: Set control value + +Usage: + +```javascript +instance.command.executeSetControlValue(payload: ISetControlOption) +``` diff --git a/docs/en/guide/command-get.md b/docs/en/guide/command-get.md index 6913322..ecf708b 100644 --- a/docs/en/guide/command-get.md +++ b/docs/en/guide/command-get.md @@ -178,3 +178,16 @@ Usage: ```javascript const groupIds = await instance.command.getGroupIds() ``` + +## getControlValue + +Feature: Get control value + +Usage: + +```javascript +const { + value: string | null + innerText: string | null +} = await instance.command.getControlValue(payload: IGetControlValueOption) +``` diff --git a/docs/guide/command-execute.md b/docs/guide/command-execute.md index 533c341..0d2127d 100644 --- a/docs/guide/command-execute.md +++ b/docs/guide/command-execute.md @@ -813,3 +813,13 @@ instance.command.executeDeleteGroup(groupId: string) ```javascript instance.command.executeLocationGroup(groupId: string) ``` + +## executeSetControlValue + +功能:设置控件值 + +用法: + +```javascript +instance.command.executeSetControlValue(payload: ISetControlOption) +``` diff --git a/docs/guide/command-get.md b/docs/guide/command-get.md index 847351c..d18fb05 100644 --- a/docs/guide/command-get.md +++ b/docs/guide/command-get.md @@ -178,3 +178,16 @@ const locale = await instance.command.getLocale() ```javascript const groupIds = await instance.command.getGroupIds() ``` + +## getControlValue + +功能:获取控件值 + +用法: + +```javascript +const { + value: string | null + innerText: string | null +} = await instance.command.getControlValue(payload: IGetControlValueOption) +``` diff --git a/src/editor/core/command/Command.ts b/src/editor/core/command/Command.ts index 32c1d13..d75b640 100644 --- a/src/editor/core/command/Command.ts +++ b/src/editor/core/command/Command.ts @@ -81,6 +81,7 @@ export class Command { public executeSetGroup: CommandAdapt['setGroup'] public executeDeleteGroup: CommandAdapt['deleteGroup'] public executeLocationGroup: CommandAdapt['locationGroup'] + public executeSetControlValue: CommandAdapt['setControlValue'] public getCatalog: CommandAdapt['getCatalog'] public getImage: CommandAdapt['getImage'] public getOptions: CommandAdapt['getOptions'] @@ -96,6 +97,7 @@ export class Command { public getSearchNavigateInfo: CommandAdapt['getSearchNavigateInfo'] public getLocale: CommandAdapt['getLocale'] public getGroupIds: CommandAdapt['getGroupIds'] + public getControlValue: CommandAdapt['getControlValue'] constructor(adapt: CommandAdapt) { // 全局命令 @@ -201,5 +203,8 @@ export class Command { this.getSearchNavigateInfo = adapt.getSearchNavigateInfo.bind(adapt) this.getLocale = adapt.getLocale.bind(adapt) this.getGroupIds = adapt.getGroupIds.bind(adapt) + // 控件 + this.executeSetControlValue = adapt.setControlValue.bind(adapt) + this.getControlValue = adapt.getControlValue.bind(adapt) } } diff --git a/src/editor/core/command/CommandAdapt.ts b/src/editor/core/command/CommandAdapt.ts index b6db916..40bf9cf 100644 --- a/src/editor/core/command/CommandAdapt.ts +++ b/src/editor/core/command/CommandAdapt.ts @@ -18,6 +18,11 @@ import { TitleLevel } from '../../dataset/enum/Title' import { VerticalAlign } from '../../dataset/enum/VerticalAlign' import { ICatalog } from '../../interface/Catalog' import { DeepRequired } from '../../interface/Common' +import { + IGetControlValueOption, + IGetControlValueResult, + ISetControlOption +} from '../../interface/Control' import { IAppendElementListOption, IDrawImagePayload, @@ -2004,4 +2009,16 @@ export class CommandAdapt { isSubmitHistory: false }) } + + public getControlValue( + payload: IGetControlValueOption + ): IGetControlValueResult | null { + return this.draw.getControl().getValueByConceptId(payload) + } + + public setControlValue(payload: ISetControlOption) { + const isReadonly = this.draw.isReadonly() + if (isReadonly) return + this.draw.getControl().setValueByConceptId(payload) + } } diff --git a/src/editor/core/draw/control/Control.ts b/src/editor/core/draw/control/Control.ts index bdfb90a..f078cb0 100644 --- a/src/editor/core/draw/control/Control.ts +++ b/src/editor/core/draw/control/Control.ts @@ -2,9 +2,13 @@ import { ControlComponent, ControlType } from '../../../dataset/enum/Control' import { ElementType } from '../../../dataset/enum/Element' import { IControl, + IControlContext, IControlInitOption, IControlInstance, - IControlOption + IControlOption, + IGetControlValueOption, + IGetControlValueResult, + ISetControlOption } from '../../../interface/Control' import { IEditorData } from '../../../interface/Editor' import { IElement, IElementPosition } from '../../../interface/Element' @@ -13,6 +17,7 @@ import { IRange } from '../../../interface/Range' import { deepClone, nextTick, splitText } from '../../../utils' import { formatElementContext, + formatElementList, pickElementAttr, zipElementList } from '../../../utils/element' @@ -402,4 +407,142 @@ export class Control { } return this.activeControl.cut() } + + public getValueByConceptId( + payload: IGetControlValueOption + ): IGetControlValueResult { + const { conceptId } = payload + const elementList = [ + ...this.draw.getHeaderElementList(), + ...this.draw.getOriginalMainElementList(), + ...this.draw.getFooterElementList() + ] + const result: IGetControlValueResult = [] + let i = 0 + while (i < elementList.length) { + const element = elementList[i] + i++ + if (element?.control?.conceptId !== conceptId) continue + const { type, code, valueSets } = element.control! + let j = i + let textControlValue = '' + while (j < elementList.length) { + const nextElement = elementList[j] + if (nextElement.controlId !== element.controlId) break + if ( + type === ControlType.TEXT && + nextElement.controlComponent === ControlComponent.VALUE + ) { + textControlValue += nextElement.value + } + j++ + } + if (type === ControlType.TEXT) { + result.push({ + value: textControlValue || null, + innerText: textControlValue || null + }) + } else if (type === ControlType.SELECT || type === ControlType.CHECKBOX) { + const innerText = code + ?.split(',') + .map( + selectCode => + valueSets?.find(valueSet => valueSet.code === selectCode)?.value + ) + .filter(Boolean) + .join('') + result.push({ + value: code || null, + innerText: innerText || null + }) + } + i = j + } + return result + } + + public setValueByConceptId(payload: ISetControlOption) { + const isReadonly = this.draw.isReadonly() + if (isReadonly) return + let isExistSet = false + const { conceptId, value } = payload + const data = [ + this.draw.getHeaderElementList(), + this.draw.getOriginalMainElementList(), + this.draw.getFooterElementList() + ] + for (const elementList of data) { + let i = 0 + while (i < elementList.length) { + const element = elementList[i] + i++ + if (element?.control?.conceptId !== conceptId) continue + isExistSet = true + const { type } = element.control! + // 当前控件结束索引 + let currentEndIndex = i + while (currentEndIndex < elementList.length) { + const nextElement = elementList[currentEndIndex] + if (nextElement.controlId !== element.controlId) break + currentEndIndex++ + } + // 模拟光标选区上下文 + const fakeRange = { + startIndex: i - 1, + endIndex: currentEndIndex - 2 + } + const controlContext: IControlContext = { + range: fakeRange, + elementList + } + if (type === ControlType.TEXT) { + const formatValue = [{ value }] + formatElementList(formatValue, { + isHandleFirstElement: false, + editorOptions: this.draw.getOptions() + }) + const text = new TextControl(element, this) + if (value) { + text.setValue(formatValue, controlContext) + } else { + text.clearValue(controlContext) + } + } else if (type === ControlType.SELECT) { + const select = new SelectControl(element, this) + if (value) { + select.setSelect(value, controlContext) + } else { + select.clearSelect(controlContext) + } + } else if (type === ControlType.CHECKBOX) { + const checkbox = new CheckboxControl(element, this) + const checkboxElementList = elementList.slice( + fakeRange.startIndex + 1, + fakeRange.endIndex + 1 + ) + const codes = value?.split(',') || [] + for (const checkElement of checkboxElementList) { + if (checkElement.controlComponent === ControlComponent.CHECKBOX) { + const checkboxItem = checkElement.checkbox! + checkboxItem.value = codes.includes(checkboxItem.code!) + } + } + checkbox.setSelect(controlContext) + } + // 修改后控件结束索引 + let newEndIndex = i + while (newEndIndex < elementList.length) { + const nextElement = elementList[newEndIndex] + if (nextElement.controlId !== element.controlId) break + newEndIndex++ + } + i = newEndIndex + } + } + if (isExistSet) { + this.draw.render({ + isSetCursor: false + }) + } + } } diff --git a/src/editor/core/draw/control/checkbox/CheckboxControl.ts b/src/editor/core/draw/control/checkbox/CheckboxControl.ts index 5d182e6..2f4885a 100644 --- a/src/editor/core/draw/control/checkbox/CheckboxControl.ts +++ b/src/editor/core/draw/control/checkbox/CheckboxControl.ts @@ -1,6 +1,9 @@ import { ControlComponent } from '../../../../dataset/enum/Control' import { KeyMap } from '../../../../dataset/enum/KeyMap' -import { IControlInstance } from '../../../../interface/Control' +import { + IControlContext, + IControlInstance +} from '../../../../interface/Control' import { IElement } from '../../../../interface/Element' import { Control } from '../Control' @@ -63,10 +66,10 @@ export class CheckboxControl implements IControlInstance { return -1 } - public setSelect() { + public setSelect(context: IControlContext = {}) { const { control } = this.element - const elementList = this.control.getElementList() - const { startIndex } = this.control.getRange() + const elementList = context.elementList || this.control.getElementList() + const { startIndex } = context.range || this.control.getRange() const startElement = elementList[startIndex] const data: string[] = [] // 向左查找 diff --git a/src/editor/core/draw/control/select/SelectControl.ts b/src/editor/core/draw/control/select/SelectControl.ts index 6285489..4c345a9 100644 --- a/src/editor/core/draw/control/select/SelectControl.ts +++ b/src/editor/core/draw/control/select/SelectControl.ts @@ -6,7 +6,10 @@ import { EDITOR_ELEMENT_STYLE_ATTR } from '../../../../dataset/constant/Element' import { ControlComponent } from '../../../../dataset/enum/Control' import { EditorComponent } from '../../../../dataset/enum/Editor' import { KeyMap } from '../../../../dataset/enum/KeyMap' -import { IControlInstance } from '../../../../interface/Control' +import { + IControlContext, + IControlInstance +} from '../../../../interface/Control' import { IElement } from '../../../../interface/Element' import { omitObject, splitText } from '../../../../utils' import { formatElementContext } from '../../../../utils/element' @@ -135,9 +138,9 @@ export class SelectControl implements IControlInstance { return this.clearSelect() } - public clearSelect(): number { - const elementList = this.control.getElementList() - const { startIndex } = this.control.getRange() + public clearSelect(context: IControlContext = {}): number { + const elementList = context.elementList || this.control.getElementList() + const { startIndex } = context.range || this.control.getRange() const startElement = elementList[startIndex] let leftIndex = -1 let rightIndex = -1 @@ -177,7 +180,7 @@ export class SelectControl implements IControlInstance { return preIndex } - public setSelect(code: string) { + public setSelect(code: string, context: IControlContext = {}) { const control = this.element.control! const valueSets = control.valueSets if (!Array.isArray(valueSets) || !valueSets.length) return @@ -185,10 +188,10 @@ export class SelectControl implements IControlInstance { const valueSet = valueSets.find(v => v.code === code) if (!valueSet) return // 清空选项 - const startIndex = this.clearSelect() + const startIndex = this.clearSelect(context) this.control.removePlaceholder(startIndex) // 插入 - const elementList = this.control.getElementList() + const elementList = context.elementList || this.control.getElementList() const startElement = elementList[startIndex] const anchorElement = startElement.controlComponent === ControlComponent.PREFIX @@ -206,12 +209,14 @@ export class SelectControl implements IControlInstance { formatElementContext(elementList, [newElement], startIndex) draw.spliceElementList(elementList, start + i, 0, newElement) } - // render - const newIndex = start + data.length - 1 - this.control.repaintControl(newIndex) // 设置状态 this.element.control!.code = code - this.destroy() + // 重新渲染控件 + if (!context.range) { + const newIndex = start + data.length - 1 + this.control.repaintControl(newIndex) + this.destroy() + } } private _createSelectPopupDom() { diff --git a/src/editor/core/draw/control/text/TextControl.ts b/src/editor/core/draw/control/text/TextControl.ts index dbec717..d95a95c 100644 --- a/src/editor/core/draw/control/text/TextControl.ts +++ b/src/editor/core/draw/control/text/TextControl.ts @@ -1,7 +1,10 @@ import { EDITOR_ELEMENT_STYLE_ATTR } from '../../../../dataset/constant/Element' import { ControlComponent } from '../../../../dataset/enum/Control' import { KeyMap } from '../../../../dataset/enum/KeyMap' -import { IControlInstance } from '../../../../interface/Control' +import { + IControlContext, + IControlInstance +} from '../../../../interface/Control' import { IElement } from '../../../../interface/Element' import { omitObject } from '../../../../utils' import { formatElementContext } from '../../../../utils/element' @@ -58,9 +61,9 @@ export class TextControl implements IControlInstance { return data } - public setValue(data: IElement[]): number { - const elementList = this.control.getElementList() - const range = this.control.getRange() + public setValue(data: IElement[], context: IControlContext = {}): number { + const elementList = context.elementList || this.control.getElementList() + const range = context.range || this.control.getRange() // 收缩边界到Value内 this.control.shrinkBoundary() const { startIndex, endIndex } = range @@ -91,6 +94,20 @@ export class TextControl implements IControlInstance { return start + data.length - 1 } + public clearValue(context: IControlContext = {}): number { + const elementList = context.elementList || this.control.getElementList() + const range = context.range || this.control.getRange() + const { startIndex, endIndex } = range + this.control + .getDraw() + .spliceElementList(elementList, startIndex + 1, endIndex - startIndex) + const value = this.getValue() + if (!value.length) { + this.control.addPlaceholder(startIndex) + } + return startIndex + } + public keydown(evt: KeyboardEvent): number { const elementList = this.control.getElementList() const range = this.control.getRange() diff --git a/src/editor/interface/Control.ts b/src/editor/interface/Control.ts index b0b848c..b50fd8a 100644 --- a/src/editor/interface/Control.ts +++ b/src/editor/interface/Control.ts @@ -1,6 +1,7 @@ import { ControlType } from '../dataset/enum/Control' import { ICheckbox } from './Checkbox' import { IElement } from './Element' +import { IRange } from './Range' export interface IValueSet { value: string @@ -65,3 +66,22 @@ export interface IControlInstance { cut(): number } + +export interface IControlContext { + range?: IRange + elementList?: IElement[] +} + +export interface IGetControlValueOption { + conceptId: string +} + +export type IGetControlValueResult = { + value: string | null + innerText: string | null +}[] + +export interface ISetControlOption { + conceptId: string + value: string +} diff --git a/src/mock.ts b/src/mock.ts index 03030d7..2b0425d 100644 --- a/src/mock.ts +++ b/src/mock.ts @@ -103,6 +103,7 @@ elementList.splice(12, 0, { type: ElementType.CONTROL, value: '', control: { + conceptId: '1', type: ControlType.TEXT, value: null, placeholder: '其他补充', @@ -116,6 +117,7 @@ elementList.splice(94, 0, { type: ElementType.CONTROL, value: '', control: { + conceptId: '2', type: ControlType.SELECT, value: null, code: null, @@ -337,6 +339,7 @@ elementList.push( { type: ElementType.CONTROL, control: { + conceptId: '3', type: ControlType.CHECKBOX, code: '98175', value: '', @@ -406,6 +409,7 @@ elementList.push( type: ElementType.CONTROL, value: '', control: { + conceptId: '4', type: ControlType.TEXT, value: null, placeholder: '',