feat: add title element

pr675
Hufe921 3 years ago committed by Hufe
parent 189ca73c32
commit 9701b2153e

@ -111,6 +111,21 @@
</div>
<div class="menu-divider"></div>
<div class="menu-item">
<div class="menu-item__title">
<i></i>
<span class="select" title="切换标题">正文</span>
<div class="options">
<ul>
<li style="font-size:16px;">正文</li>
<li data-level="first" style="font-size:26px;">标题1</li>
<li data-level="second" style="font-size:24px;">标题2</li>
<li data-level="third" style="font-size:22px;">标题3</li>
<li data-level="fourth" style="font-size:20px;">标题4</li>
<li data-level="fifth" style="font-size:18px;">标题5</li>
<li data-level="sixth" style="font-size:16px;">标题6</li>
</ul>
</div>
</div>
<div class="menu-item__left">
<i></i>
</div>

@ -0,0 +1 @@
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><g fill="#3D4757" fill-rule="evenodd"><path d="M14 1a1 1 0 011 1v12a1 1 0 01-1 1H2a1 1 0 01-1-1V2a1 1 0 011-1h12zm0 1H2v12h12V2z" fill-rule="nonzero"/><path fill-rule="nonzero" d="M4 11h8v1H4zm0-3h4v1H4zm0-3h2v1H4z"/><path d="M9 5h1v4H9z"/><path d="M7 5h5v1H7z"/></g></svg>

After

Width:  |  Height:  |  Size: 336 B

@ -1,4 +1,4 @@
import { IElement, ImageDisplay, INavigateInfo, TableBorder, VerticalAlign } from '../..'
import { IElement, ImageDisplay, INavigateInfo, TableBorder, TitleLevel, VerticalAlign } from '../..'
import { EditorMode, PageMode, PaperDirection } from '../../dataset/enum/Editor'
import { RowFlex } from '../../dataset/enum/Row'
import { IDrawImagePayload, IPainterOptions } from '../../interface/Draw'
@ -33,6 +33,7 @@ export class Command {
private static subscript: CommandAdapt['subscript']
private static color: CommandAdapt['color']
private static highlight: CommandAdapt['highlight']
private static title: CommandAdapt['title']
private static left: CommandAdapt['rowFlex']
private static center: CommandAdapt['rowFlex']
private static right: CommandAdapt['rowFlex']
@ -109,6 +110,7 @@ export class Command {
Command.subscript = adapt.subscript.bind(adapt)
Command.color = adapt.color.bind(adapt)
Command.highlight = adapt.highlight.bind(adapt)
Command.title = adapt.title.bind(adapt)
Command.left = adapt.rowFlex.bind(adapt)
Command.center = adapt.rowFlex.bind(adapt)
Command.right = adapt.rowFlex.bind(adapt)
@ -260,6 +262,11 @@ export class Command {
return Command.highlight(payload)
}
// 标题、对齐方式
public executeTitle(payload: TitleLevel | null) {
return Command.title(payload)
}
public executeLeft() {
return Command.left(RowFlex.LEFT)
}

@ -1,5 +1,6 @@
import { WRAP, ZERO } from '../../dataset/constant/Common'
import { EDITOR_ELEMENT_STYLE_ATTR } from '../../dataset/constant/Element'
import { titleSizeMapping } from '../../dataset/constant/Title'
import { defaultWatermarkOption } from '../../dataset/constant/Watermark'
import { ControlComponent, ImageDisplay } from '../../dataset/enum/Control'
import { EditorContext, EditorMode, PageMode, PaperDirection } from '../../dataset/enum/Editor'
@ -7,6 +8,7 @@ import { ElementType } from '../../dataset/enum/Element'
import { ElementStyleKey } from '../../dataset/enum/ElementStyle'
import { RowFlex } from '../../dataset/enum/Row'
import { TableBorder } from '../../dataset/enum/table/Table'
import { TitleLevel } from '../../dataset/enum/Title'
import { VerticalAlign } from '../../dataset/enum/VerticalAlign'
import { IDrawImagePayload, IPainterOptions } from '../../interface/Draw'
import { IEditorOption, IEditorResult } from '../../interface/Editor'
@ -379,6 +381,63 @@ export class CommandAdapt {
})
}
public title(payload: TitleLevel | null) {
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const { startIndex, endIndex } = this.range.getRange()
if (!~startIndex && !~endIndex) return
// 需要改变的元素列表
let changeElementList: IElement[] = []
const elementList = this.draw.getElementList()
if (startIndex === endIndex) {
// 选区行信息
const rangeRow = this.range.getRangeRow()
if (!rangeRow) return
const positionList = this.position.getPositionList()
for (let p = 0; p < positionList.length; p++) {
const position = positionList[p]
const rowSet = rangeRow.get(position.pageNo)
if (!rowSet) continue
if (rowSet.has(position.rowNo)) {
changeElementList.push(elementList[p])
}
}
} else {
changeElementList = elementList.slice(startIndex + 1, endIndex + 1)
}
// 检验数据合法性
const isExistNotTextElement = !!changeElementList.find(el =>
el.type &&
el.type !== ElementType.TEXT &&
el.type !== ElementType.TITLE
)
if (isExistNotTextElement) return
// 设置值
const titleId = getUUID()
const titleOptions = this.draw.getOptions().title
changeElementList.forEach(el => {
if (payload) {
el.type = ElementType.TITLE
el.level = payload
el.titleId = titleId
el.size = titleOptions[titleSizeMapping[payload]]
el.bold = true
} else {
if (el.type === ElementType.TITLE) {
delete el.type
delete el.titleId
delete el.level
delete el.size
delete el.bold
}
}
})
// 光标定位
const isSetCursor = startIndex === endIndex
const curIndex = isSetCursor ? endIndex : startIndex
this.draw.render({ curIndex, isSetCursor })
}
public rowFlex(payload: RowFlex) {
const isReadonly = this.draw.isReadonly()
if (isReadonly) return

@ -27,7 +27,7 @@ export function input(data: string, host: CanvasEvent) {
cursor.clearAgentDomValue()
}
const activeControl = control.getActiveControl()
const { TEXT, HYPERLINK, SUBSCRIPT, SUPERSCRIPT, DATE } = ElementType
const { TEXT, HYPERLINK, SUBSCRIPT, SUPERSCRIPT, DATE, TITLE } = ElementType
const text = data.replaceAll(`\n`, ZERO)
const rangeManager = draw.getRange()
const { startIndex, endIndex } = rangeManager.getRange()
@ -55,6 +55,7 @@ export function input(data: string, host: CanvasEvent) {
|| (!copyElement.type && copyElement.value !== ZERO)
|| (copyElement.type === HYPERLINK && nextElement?.type === HYPERLINK)
|| (copyElement.type === DATE && nextElement?.type === DATE)
|| copyElement.type === TITLE
|| (copyElement.type === SUBSCRIPT && nextElement?.type === SUBSCRIPT)
|| (copyElement.type === SUPERSCRIPT && nextElement?.type === SUPERSCRIPT)
) {

@ -152,6 +152,7 @@ export class RangeManager {
const rowFlex = curElement.rowFlex || null
const rowMargin = curElement.rowMargin || this.options.defaultRowMargin
const dashArray = curElement.dashArray || []
const level = curElement.level || null
// 菜单
const painter = !!this.draw.getPainterStyle()
const undo = this.historyManager.isCanUndo()
@ -171,7 +172,8 @@ export class RangeManager {
highlight,
rowFlex,
rowMargin,
dashArray
dashArray,
level
})
}
@ -198,7 +200,8 @@ export class RangeManager {
highlight: null,
rowFlex: null,
rowMargin,
dashArray: []
dashArray: [],
level: null
})
}

@ -26,7 +26,9 @@ export const EDITOR_ELEMENT_COPY_ATTR: Array<keyof IElement> = [
'url',
'hyperlinkId',
'dateId',
'dateFormat'
'dateFormat',
'level',
'titleId'
]
export const EDITOR_ELEMENT_ZIP_ATTR: Array<keyof IElement> = [
@ -52,7 +54,8 @@ export const EDITOR_ELEMENT_ZIP_ATTR: Array<keyof IElement> = [
'control',
'checkbox',
'dateFormat',
'block'
'block',
'level'
]
export const TEXTLIKE_ELEMENT_TYPE: ElementType[] = [
@ -61,7 +64,8 @@ export const TEXTLIKE_ELEMENT_TYPE: ElementType[] = [
ElementType.SUBSCRIPT,
ElementType.SUPERSCRIPT,
ElementType.CONTROL,
ElementType.DATE
ElementType.DATE,
ElementType.TITLE
]
export const INLINE_ELEMENT_TYPE: ElementType[] = [

@ -0,0 +1,38 @@
import { ITitleOption, ITitleSizeOption } from '../../interface/Title'
import { TitleLevel } from '../enum/Title'
export const defaultTitleOption: Readonly<Required<ITitleOption>> = {
defaultFirstSize: 26,
defaultSecondSize: 24,
defaultThirdSize: 22,
defaultFourthSize: 20,
defaultFifthSize: 18,
defaultSixthSize: 16
}
export const titleSizeMapping: Record<TitleLevel, keyof ITitleSizeOption> = {
[TitleLevel.FIRST]: 'defaultFirstSize',
[TitleLevel.SECOND]: 'defaultSecondSize',
[TitleLevel.THIRD]: 'defaultThirdSize',
[TitleLevel.FOURTH]: 'defaultFourthSize',
[TitleLevel.FIFTH]: 'defaultFifthSize',
[TitleLevel.SIXTH]: 'defaultSixthSize'
}
export const titleOrderNumberMapping: Record<TitleLevel, number> = {
[TitleLevel.FIRST]: 1,
[TitleLevel.SECOND]: 2,
[TitleLevel.THIRD]: 3,
[TitleLevel.FOURTH]: 4,
[TitleLevel.FIFTH]: 5,
[TitleLevel.SIXTH]: 6
}
export const titleNodeNameMapping: Record<string, TitleLevel> = {
'H1': TitleLevel.FIRST,
'H2': TitleLevel.SECOND,
'H3': TitleLevel.THIRD,
'H4': TitleLevel.FOURTH,
'H5': TitleLevel.FIFTH,
'H6': TitleLevel.SIXTH
}

@ -12,5 +12,6 @@ export enum ElementType {
LATEX = 'latex',
TAB = 'tab',
DATE = 'date',
BLOCK = 'block'
BLOCK = 'block',
TITLE = 'title'
}

@ -0,0 +1,8 @@
export enum TitleLevel {
FIRST = 'first',
SECOND = 'second',
THIRD = 'third',
FOURTH = 'fourth',
FIFTH = 'fifth',
SIXTH = 'sixth'
}

@ -38,6 +38,9 @@ import { TableBorder } from './dataset/enum/table/Table'
import { IFooter } from './interface/Footer'
import { defaultFooterOption } from './dataset/constant/Footer'
import { MaxHeightRatio, NumberType } from './dataset/enum/Common'
import { ITitleOption } from './interface/Title'
import { defaultTitleOption } from './dataset/constant/Title'
import { TitleLevel } from './dataset/enum/Title'
export default class Editor {
@ -75,6 +78,10 @@ export default class Editor {
...defaultCursorOption,
...options.cursor
}
const titleOptions: Required<ITitleOption> = {
...defaultTitleOption,
...options.title
}
const editorOptions: DeepRequired<IEditorOption> = {
mode: EditorMode.EDIT,
@ -117,7 +124,8 @@ export default class Editor {
watermark: waterMarkOptions,
control: controlOptions,
checkbox: checkboxOptions,
cursor: cursorOptions
cursor: cursorOptions,
title: titleOptions
}
// 数据处理
let headerElementList: IElement[] = []
@ -190,7 +198,8 @@ export {
PaperDirection,
TableBorder,
MaxHeightRatio,
NumberType
NumberType,
TitleLevel
}
// 对外类型

@ -7,6 +7,7 @@ import { IFooter } from './Footer'
import { IHeader } from './Header'
import { IMargin } from './Margin'
import { IPageNumber } from './PageNumber'
import { ITitleOption } from './Title'
import { IWatermark } from './Watermark'
export interface IEditorData {
@ -56,6 +57,7 @@ export interface IEditorOption {
control?: IControlOption;
checkbox?: ICheckboxOption;
cursor?: ICursorOption;
title?: ITitleOption;
}
export interface IEditorResult {

@ -1,6 +1,7 @@
import { ControlComponent, ImageDisplay } from '../dataset/enum/Control'
import { ElementType } from '../dataset/enum/Element'
import { RowFlex } from '../dataset/enum/Row'
import { TitleLevel } from '../dataset/enum/Title'
import { TableBorder } from '../dataset/enum/table/Table'
import { IBlock } from './Block'
import { ICheckbox } from './Checkbox'
@ -30,6 +31,12 @@ export interface IElementStyle {
letterSpacing?: number;
}
export interface ITitleElement {
valueList?: IElement[];
level?: TitleLevel;
titleId?: string;
}
export interface ITableAttr {
colgroup?: IColgroup[];
trList?: ITr[];
@ -97,6 +104,7 @@ export type IElement = IElementBasic
& IDateElement
& IImageElement
& IBlockElement
& ITitleElement
export interface IElementMetrics {
width: number;

@ -1,4 +1,4 @@
import { EditorZone, ElementType, PageMode } from '..'
import { EditorZone, ElementType, PageMode, TitleLevel } from '..'
import { RowFlex } from '../dataset/enum/Row'
import { IControl } from './Control'
import { IEditorResult } from './Editor'
@ -19,6 +19,7 @@ export interface IRangeStyle {
rowFlex: RowFlex | null;
rowMargin: number;
dashArray: number[];
level: TitleLevel | null;
}
export type IRangeStyleChange = (payload: IRangeStyle) => void

@ -0,0 +1,10 @@
export interface ITitleSizeOption {
defaultFirstSize?: number;
defaultSecondSize?: number;
defaultThirdSize?: number;
defaultFourthSize?: number;
defaultFifthSize?: number;
defaultSixthSize?: number;
}
export type ITitleOption = ITitleSizeOption & {}

@ -1,6 +1,7 @@
import { IEditorOption, IElement, RowFlex } from '..'
import { ZERO } from '../dataset/constant/Common'
import { TEXTLIKE_ELEMENT_TYPE } from '../dataset/constant/Element'
import { titleNodeNameMapping, titleOrderNumberMapping } from '../dataset/constant/Title'
import { ControlComponent } from '../dataset/enum/Control'
import { ElementType } from '../dataset/enum/Element'
import { DeepRequired } from '../interface/Common'
@ -35,6 +36,33 @@ export function writeClipboardItem(text: string, html: string) {
}
}
export function convertElementToDom(element: IElement, options: DeepRequired<IEditorOption>): HTMLElement {
const isBlock = element.rowFlex === RowFlex.CENTER || element.rowFlex === RowFlex.RIGHT
const dom = document.createElement(isBlock ? 'p' : 'span')
dom.style.fontFamily = element.font || options.defaultFont
if (element.rowFlex) {
const isAlignment = element.rowFlex === RowFlex.ALIGNMENT
dom.style.textAlign = isAlignment ? 'justify' : element.rowFlex
}
if (element.color) {
dom.style.color = element.color
}
if (element.bold) {
dom.style.fontWeight = '600'
}
if (element.italic) {
dom.style.fontStyle = 'italic'
}
if (element.size) {
dom.style.fontSize = `${element.size}px`
}
if (element.highlight) {
dom.style.backgroundColor = element.highlight
}
dom.innerText = element.value.replace(new RegExp(`${ZERO}`, 'g'), '\n')
return dom
}
export function writeElementList(elementList: IElement[], options: DeepRequired<IEditorOption>) {
const clipboardDom: HTMLDivElement = document.createElement('div')
function buildDomFromElementList(payload: IElement[]) {
@ -61,11 +89,18 @@ export function writeElementList(elementList: IElement[], options: DeepRequired<
clipboardDom.append(tableDom)
} else if (element.type === ElementType.HYPERLINK) {
const a = document.createElement('a')
a.innerText = element.valueList![0].value
a.innerText = element.valueList!.map(v => v.value).join('')
if (element.url) {
a.href = element.url
}
clipboardDom.append(a)
} else if (element.type === ElementType.TITLE) {
const h = document.createElement(`h${titleOrderNumberMapping[element.level!]}`)
element.valueList!.forEach(el => {
const dom = convertElementToDom(el, options)
h.append(dom)
})
clipboardDom.append(h)
} else if (element.type === ElementType.IMAGE) {
const img = document.createElement('img')
if (element.value) {
@ -98,29 +133,12 @@ export function writeElementList(elementList: IElement[], options: DeepRequired<
text = element.value
}
if (!text) continue
const isBlock = element.rowFlex === RowFlex.CENTER || element.rowFlex === RowFlex.RIGHT
const dom = document.createElement(isBlock ? 'p' : 'span')
dom.innerText = text.replace(new RegExp(`${ZERO}`, 'g'), '\n')
dom.style.fontFamily = element.font || options.defaultFont
if (element.rowFlex) {
const isAlignment = element.rowFlex === RowFlex.ALIGNMENT
dom.style.textAlign = isAlignment ? 'justify' : element.rowFlex
}
if (element.color) {
dom.style.color = element.color
}
if (element.bold) {
dom.style.fontWeight = '600'
}
if (element.italic) {
dom.style.fontStyle = 'italic'
}
if (element.size) {
dom.style.fontSize = `${element.size}px`
}
if (element.highlight) {
dom.style.backgroundColor = element.highlight
// 前一个元素是标题,移除首行换行符
if (payload[e - 1]?.type === ElementType.TITLE) {
text = text.replace(/^\n/, '')
}
const dom = convertElementToDom(element, options)
dom.innerText = text.replace(new RegExp(`${ZERO}`, 'g'), '\n')
clipboardDom.append(dom)
}
}
@ -186,6 +204,19 @@ export function getElementListByHTML(htmlText: string, options: IGetElementListB
url: aElement.href
})
}
} else if (/H[1-6]/.test(node.nodeName)) {
const hElement = node as HTMLTitleElement
const valueList = getElementListByHTML(hElement.innerHTML, options)
.filter(el => !el.type || el.type === ElementType.TEXT)
elementList.push({
value: '',
type: ElementType.TITLE,
level: titleNodeNameMapping[node.nodeName],
valueList
})
elementList.push({
value: '\n'
})
} else if (node.nodeName === 'HR') {
elementList.push({
value: '\n',

@ -5,9 +5,22 @@ import { defaultCheckboxOption } from '../dataset/constant/Checkbox'
import { ZERO } from '../dataset/constant/Common'
import { defaultControlOption } from '../dataset/constant/Control'
import { EDITOR_ELEMENT_ZIP_ATTR } from '../dataset/constant/Element'
import { titleSizeMapping } from '../dataset/constant/Title'
import { ControlComponent, ControlType } from '../dataset/enum/Control'
import { ITd } from '../interface/table/Td'
export function unzipElementList(elementList: IElement[]): IElement[] {
const result: IElement[] = []
for (let v = 0; v < elementList.length; v++) {
const valueItem = elementList[v]
const textList = splitText(valueItem.value)
for (let d = 0; d < textList.length; d++) {
result.push({ ...valueItem, value: textList[d] })
}
}
return result
}
interface IFormatElementListOption {
isHandleFirstElement?: boolean;
editorOptions: Required<IEditorOption>;
@ -58,19 +71,12 @@ export function formatElementList(elementList: IElement[], options: IFormatEleme
}
}
} else if (el.type === ElementType.HYPERLINK) {
const valueList = el.valueList || []
// 移除父节点
elementList.splice(i, 1)
// 追加字节点
// 元素展开
const valueList = unzipElementList(el.valueList || [])
// 追加节点
if (valueList.length) {
// 元素展开
if (valueList[0].value.length > 1) {
const deleteValue = valueList.splice(0, 1)[0]
const deleteTextList = splitText(deleteValue.value)
for (let d = 0; d < deleteTextList.length; d++) {
valueList.splice(d, 0, { ...deleteValue, value: deleteTextList[d] })
}
}
const hyperlinkId = getUUID()
for (let v = 0; v < valueList.length; v++) {
const value = valueList[v]
@ -83,19 +89,12 @@ export function formatElementList(elementList: IElement[], options: IFormatEleme
}
i--
} else if (el.type === ElementType.DATE) {
const valueList = el.valueList || []
// 移除父节点
elementList.splice(i, 1)
// 追加字节点
// 元素展开
const valueList = unzipElementList(el.valueList || [])
// 追加节点
if (valueList.length) {
// 元素展开
if (valueList[0].value.length > 1) {
const deleteValue = valueList.splice(0, 1)[0]
const deleteTextList = splitText(deleteValue.value)
for (let d = 0; d < deleteTextList.length; d++) {
valueList.splice(d, 0, { ...deleteValue, value: deleteTextList[d] })
}
}
const dateId = getUUID()
for (let v = 0; v < valueList.length; v++) {
const value = valueList[v]
@ -107,6 +106,31 @@ export function formatElementList(elementList: IElement[], options: IFormatEleme
}
}
i--
} else if (el.type === ElementType.TITLE) {
// 移除父节点
elementList.splice(i, 1)
// 元素展开
const valueList = unzipElementList(el.valueList || [])
// 追加节点
if (valueList.length) {
const titleId = getUUID()
const titleOptions = editorOptions.title
for (let v = 0; v < valueList.length; v++) {
const value = valueList[v]
value.titleId = titleId
value.type = el.type
value.level = el.level
if (!value.size) {
value.size = titleOptions[titleSizeMapping[value.level!]]
}
if (value.bold === undefined) {
value.bold = true
}
elementList.splice(i, 0, value)
i++
}
}
i--
} else if (el.type === ElementType.CONTROL) {
const { prefix, postfix, value, placeholder, code, type, valueSets } = el.control!
const controlId = getUUID()
@ -370,6 +394,29 @@ export function zipElementList(payload: IElement[]): IElement[] {
}
dateElement.valueList = zipElementList(valueList)
element = dateElement
} else if (element.type === ElementType.TITLE) {
// 标题处理
const titleId = element.titleId
const level = element.level
const titleElement: IElement = {
type: ElementType.TITLE,
value: '',
level
}
const valueList: IElement[] = []
while (e < elementList.length) {
const titleE = elementList[e]
if (titleId !== titleE.titleId) {
e--
break
}
delete titleE.type
delete titleE.level
valueList.push(titleE)
e++
}
titleElement.valueList = zipElementList(valueList)
element = titleElement
} else if (element.type === ElementType.CONTROL) {
// 控件处理
const controlId = element.controlId

@ -1,7 +1,7 @@
import { data, options } from './mock'
import './style.css'
import prism from 'prismjs'
import Editor, { BlockType, Command, ControlType, EditorMode, ElementType, IBlock, IElement, KeyMap, PageMode, PaperDirection, RowFlex } from './editor'
import Editor, { BlockType, Command, ControlType, EditorMode, ElementType, IBlock, IElement, KeyMap, PageMode, PaperDirection, RowFlex, TitleLevel } from './editor'
import { Dialog } from './components/dialog/Dialog'
import { formatPrismToken } from './utils/prism'
import { Signature } from './components/signature/Signature'
@ -175,6 +175,19 @@ window.onload = function () {
highlightControlDom?.click()
}
const titleDom = document.querySelector<HTMLDivElement>('.menu-item__title')!
const titleSelectDom = titleDom.querySelector<HTMLDivElement>('.select')!
const titleOptionDom = titleDom.querySelector<HTMLDivElement>('.options')!
titleDom.onclick = function () {
console.log('title')
titleOptionDom.classList.toggle('visible')
}
titleOptionDom.onclick = function (evt) {
const li = evt.target as HTMLLIElement
const level = <TitleLevel>li.dataset.level
instance.command.executeTitle(level || null)
}
const leftDom = document.querySelector<HTMLDivElement>('.menu-item__left')!
leftDom.title = `左对齐(${isApple ? '⌘' : 'Ctrl'}+L)`
leftDom.onclick = function () {
@ -1056,6 +1069,17 @@ window.onload = function () {
payload.undo ? undoDom.classList.remove('no-allow') : undoDom.classList.add('no-allow')
payload.redo ? redoDom.classList.remove('no-allow') : redoDom.classList.add('no-allow')
payload.painter ? painterDom.classList.add('active') : painterDom.classList.remove('active')
// 标题
titleOptionDom.querySelectorAll<HTMLLIElement>('li').forEach(li => li.classList.remove('active'))
if (payload.level) {
const curTitleDom = titleOptionDom.querySelector<HTMLLIElement>(`[data-level='${payload.level}']`)!
titleSelectDom.innerText = curTitleDom.innerText
curTitleDom.classList.add('active')
} else {
titleSelectDom.innerText = '正文'
titleOptionDom.querySelector('li:first-child')!.classList.add('active')
}
}
instance.listener.visiblePageNoListChange = function (payload) {

@ -1,13 +1,17 @@
import { ControlType, ElementType, IEditorOption, IElement } from './editor'
import { ControlType, ElementType, IEditorOption, IElement, TitleLevel } from './editor'
const text = `主诉:\n发热三天咳嗽五天。\n现病史\n患者于三天前无明显诱因感冒后发现面部水肿无皮疹尿量减少出现乏力在外治疗无好转现来我院就诊。\n既往史\n有糖尿病10年有高血压2年有传染性疾病1年。报告其他既往疾病。\n流行病史\n否认14天内接触过确诊患者、疑似患者、无症状感染者及其密切接触者否认14天内去过以下场所水产、肉类批发市场农贸市场集市大型超市夜市否认14天内与以下场所工作人员密切接触水产、肉类批发市场农贸市场集市大型超市否认14天内周围如家庭、办公室有2例以上聚集性发病否认14天内接触过有发热或呼吸道症状的人员否认14天内自身有发热或呼吸道症状否认14天内接触过纳入隔离观察的人员及其他可能与新冠肺炎关联的情形陪同家属无以上情况。\n体格检查\nT39.5℃P80bpmR20次/分BP120/80mmHg\n辅助检查\n2020年6月10日普放血细胞比容36.50%偏低4050单核细胞绝对值0.75*10/L偏高参考值0.10.6\n门诊诊断\n1.高血压\n2.糖尿病\n3.病毒性感冒\n4.过敏性鼻炎\n5.过敏性鼻息肉\n处置治疗\n1.超声引导下甲状腺细针穿刺术;\n2.乙型肝炎表面抗体测定;\n3.膜式病变细胞采集术、后颈皮下肤层;\n电子签名【】\n其他记录`
// 模拟加粗字
const boldText = ['主诉:', '现病史:', '既往史:', '流行病史:', '体格检查:', '辅助检查:', '门诊诊断:', '处置治疗:', '电子签名:', '其他记录:']
const boldIndex: number[] = boldText.map(b => {
const i = text.indexOf(b)
return ~i ? Array(b.length).fill(i).map((_, j) => i + j) : []
}).flat()
// 模拟标题
const titleText = ['主诉:', '现病史:', '既往史:', '流行病史:', '体格检查:', '辅助检查:', '门诊诊断:', '处置治疗:', '电子签名:', '其他记录:']
const titleMap: Map<number, string> = new Map()
for (let t = 0; t < titleText.length; t++) {
const value = titleText[t]
const i = text.indexOf(value)
if (~i) {
titleMap.set(i, value)
}
}
// 模拟颜色字
const colorText = ['传染性疾病']
@ -23,36 +27,46 @@ const highlightIndex: number[] = highlightText.map(b => {
return ~i ? Array(b.length).fill(i).map((_, j) => i + j) : []
}).flat()
const elementList: IElement[] = []
// 组合纯文本数据
const elementList: IElement[] = text.split('').map((value, index) => {
if (boldIndex.includes(index)) {
return {
value,
size: 18,
bold: true
}
}
if (colorIndex.includes(index)) {
return {
const textList = text.split('')
let index = 0
while (index < textList.length) {
const value = textList[index]
const title = titleMap.get(index)
if (title) {
elementList.push({
value: '',
type: ElementType.TITLE,
level: TitleLevel.FIRST,
valueList: [{
value: title,
size: 18
}]
})
index += title.length - 1
} else if (colorIndex.includes(index)) {
elementList.push({
value,
color: '#FF0000',
size: 16
}
}
if (highlightIndex.includes(index)) {
return {
})
} else if (highlightIndex.includes(index)) {
elementList.push({
value,
highlight: '#F2F27F'
}
}
return {
value,
size: 16
})
} else {
elementList.push({
value,
size: 16
})
}
})
index++
}
// 模拟文本控件
elementList.splice(14, 0, {
elementList.splice(12, 0, {
type: ElementType.CONTROL,
value: '',
control: {
@ -65,7 +79,7 @@ elementList.splice(14, 0, {
})
// 模拟下拉控件
elementList.splice(102, 0, {
elementList.splice(94, 0, {
type: ElementType.CONTROL,
value: '',
control: {
@ -89,7 +103,7 @@ elementList.splice(102, 0, {
})
// 模拟超链接
elementList.splice(128, 0, {
elementList.splice(116, 0, {
type: ElementType.HYPERLINK,
value: '',
valueList: [{
@ -109,20 +123,20 @@ elementList.splice(128, 0, {
})
// 模拟下标
elementList.splice(361, 0, {
elementList.splice(345, 0, {
value: '∆',
color: '#FF0000',
type: ElementType.SUBSCRIPT
})
// 模拟上标
elementList.splice(449, 0, {
elementList.splice(429, 0, {
value: '9',
type: ElementType.SUPERSCRIPT
})
// 模拟图片
elementList.splice(575, 0, {
elementList.splice(543, 0, {
value: `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFkAAAAgCAYAAAB5JtSmAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAQ0SURBVGhD7dhrUSNBFAVgvKACEVjAAhJQgAIUYAABGEAABvgfAdn6UnWou01PppOZhIXNj1P9vo9zH5PK1Waz2V5wWlxIPgMuJJ8Bi0h+fn7eXl9fb29ubrYPDw/dO/8DHh8fu/vB4kym4Orqaofb29vund8OSSbhemewSrugBMnG3vlvw9vb265yn56edmtz/t/f33+5C8MkixQSZSsl9UzLOHUmcwTYAN/Rpl5eXnY+pnIB0Xd3d7s5m3rvDsrkCGszNiQ7r/tr4v39fSc/uipOqRcqufTHBiO78GGdzG5xcLtIFmVde7L9NsvXRo9s84+Pj+79pUAwn5GcD1wIz5r+fYGeJdnjGiF9hwL7iWAcfX19/evtKVHJXrtN8Rf4A3TVczqhrut5i1mSZQgnIriSWtdzP2N+EvIhi3/GWqHWtWXuy2IYbheiKarJZIZknkxyrryc2Utrgal+9S8iScUXIx/3kcxfe/jotcuDezLFlIbARDrzHpytXdKnQr4xyc74Vu9YV5Ih2Q/tT7mDSEYw5ZU4wu3nJx64k/1z9umlUG0hah/JSbC6Jzi5exDJWoTHERoBxu8uf/pT1j3HDkUIJitjbRfRA/iwVzlgy1RCfSF5ili9xj7BUWKs9wJZ3MpditYu+lsc+/PRx53cVF9Pdg/syE9Hb6cS75PkmhUEUFofmTvLGEXKimHueJP9Y3swWQwGLUiA9xEbHKuvgs4pPe1+1myTAKlw81buJ8kigjAXKauXPLQPhEYgJSEYsgdTUR0BmTVgc6C359wcvKGnBrGO8dO5VlD1ZZ519nrBHvrwKVMCas9hgL0YUI2wV98fC4FqCWizzXyqF44A0ZKLHkilgvPs1zbiTuZIdZ414KvqGCKZYx4zple+MSrrJVncAyL02/TOqncJwVMglx5zI4QDZ5WPvBGEcNP+7TlEcqJIAQFGsIdQjmZt7MlYA5yiI3pOQTCQXUm2TuVmXgmewxDJQDgl6deJJoU5y7p9uwZagmu1mCvbNoOOBfkhOf6lRZjzPb8qRjBMMiUhM9GNMZQq5/oRXBP7Mlj/i12A7EMIaJGqDcl8I79+/N1xTvdINQ2TDAQSvI9Md479vdqCHKSFQKAfEmgBqCTDkjaSgOZXQkg2jy1ti0xApnBQJo/0obQRipeQXbN3CmxKGQch5xgki4Efghl/kFqzPD//2DnXIodIRpaoETaXxcmwGNO7N4I2Oyuc6b+xK/tL9IH3kY/E+r1JdST4yM+7VUiuJbuPZHBeHZcNvXtziMMV9mRuvUOX8Vg9IFjRx9dUYM3s2oJyNx9ahFfSWwyRHKHG3nmL2q/mojyFVAWnEdi2Hg7OBXwUCCKr1QEtoe0+/9jI3xqIiuF2QRD0zqcwpfQnge9TVSI4tWrNe79shj98F0xDC0N4bTUVF5LPgAvJJ8dm+wcP2iJuZNdC5QAAAABJRU5ErkJggg==`,
width: 89,
height: 32,

@ -78,7 +78,7 @@ ul {
display: flex;
align-items: center;
justify-content: center;
margin: 0 3px;
margin: 0 2px;
}
.menu-item>div:hover {
@ -261,6 +261,25 @@ ul {
background-color: #ffff00;
}
.menu-item .menu-item__title {
width: 60px;
position: relative;
}
.menu-item__title .select {
width: calc(100% - 20px);
height: 100%;
}
.menu-item__title i {
transform: translateX(-5px);
background-image: url('./assets/images/title.svg');
}
.menu-item__title .options {
width: 80px;
}
.menu-item__left i {
background-image: url('./assets/images/left.svg');
}
@ -467,7 +486,7 @@ ul {
}
.menu-item__date .options {
width: 150px;
width: 160px;
}
.menu-item__block i {

Loading…
Cancel
Save