feat: add hyperlink
This commit is contained in:
@@ -111,6 +111,9 @@
|
|||||||
<i></i>
|
<i></i>
|
||||||
<input type="file" id="image" accept=".png, .jpg, .jpeg">
|
<input type="file" id="image" accept=".png, .jpg, .jpeg">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="menu-item__hyperlink">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="menu-divider"></div>
|
<div class="menu-divider"></div>
|
||||||
<div class="menu-item">
|
<div class="menu-item">
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M8.9 8.192l4.242 4.243-.707.707L8.192 8.9 3.95 13.142l-.707-.707 4.242-4.243L3.243 3.95l.707-.707 4.242 4.242 4.243-4.242.707.707L8.9 8.192z" fill="#6A6A6A" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 276 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><g transform="rotate(45 5.5 13.328)" fill="#3D4757" fill-rule="evenodd"><path d="M7 6H6V3.515a2.5 2.5 0 10-5 0V6H0V3.515a3.5 3.5 0 117 0V6zm0 4v2.5a3.5 3.5 0 01-7 0V10h1v2.5a2.5 2.5 0 105 0V10h1z" fill-rule="nonzero"/><rect x="3.062" y="5.209" width="1" height="5.5" rx=".5"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 349 B |
@@ -0,0 +1,136 @@
|
|||||||
|
import { EditorComponent, EDITOR_COMPONENT } from '../../editor'
|
||||||
|
import './dialog.css'
|
||||||
|
|
||||||
|
export interface IDialogData {
|
||||||
|
type: string;
|
||||||
|
label: string;
|
||||||
|
name: string;
|
||||||
|
value?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IDialogConfirm {
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IDialogOptions {
|
||||||
|
onClose?: () => void;
|
||||||
|
onCancel?: () => void;
|
||||||
|
onConfirm?: (payload: IDialogConfirm[]) => void;
|
||||||
|
title: string;
|
||||||
|
data: IDialogData[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Dialog {
|
||||||
|
|
||||||
|
private options: IDialogOptions
|
||||||
|
private mask: HTMLDivElement | null
|
||||||
|
private container: HTMLDivElement | null
|
||||||
|
private inputList: HTMLInputElement[]
|
||||||
|
|
||||||
|
constructor(options: IDialogOptions) {
|
||||||
|
this.options = options
|
||||||
|
this.mask = null
|
||||||
|
this.container = null
|
||||||
|
this.inputList = []
|
||||||
|
this._render()
|
||||||
|
}
|
||||||
|
|
||||||
|
private _render() {
|
||||||
|
const { title, data, onClose, onCancel, onConfirm } = this.options
|
||||||
|
// 渲染遮罩层
|
||||||
|
const mask = document.createElement('div')
|
||||||
|
mask.classList.add('dialog-mask')
|
||||||
|
mask.setAttribute(EDITOR_COMPONENT, EditorComponent.COMPONENT)
|
||||||
|
document.body.append(mask)
|
||||||
|
// 渲染容器
|
||||||
|
const container = document.createElement('div')
|
||||||
|
container.classList.add('dialog-container')
|
||||||
|
container.setAttribute(EDITOR_COMPONENT, EditorComponent.COMPONENT)
|
||||||
|
// 弹窗
|
||||||
|
const dialogContainer = document.createElement('div')
|
||||||
|
dialogContainer.classList.add('dialog')
|
||||||
|
container.append(dialogContainer)
|
||||||
|
// 标题容器
|
||||||
|
const titleContainer = document.createElement('div')
|
||||||
|
titleContainer.classList.add('dialog-title')
|
||||||
|
// 标题&关闭按钮
|
||||||
|
const titleSpan = document.createElement('span')
|
||||||
|
titleSpan.append(document.createTextNode(title))
|
||||||
|
const titleClose = document.createElement('i')
|
||||||
|
titleClose.onclick = () => {
|
||||||
|
if (onClose) {
|
||||||
|
onClose()
|
||||||
|
}
|
||||||
|
this._dispose()
|
||||||
|
}
|
||||||
|
titleContainer.append(titleSpan)
|
||||||
|
titleContainer.append(titleClose)
|
||||||
|
dialogContainer.append(titleContainer)
|
||||||
|
// 选项容器
|
||||||
|
const optionContainer = document.createElement('div')
|
||||||
|
optionContainer.classList.add('dialog-option')
|
||||||
|
// 选项
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const option = data[i]
|
||||||
|
const optionItemContainer = document.createElement('div')
|
||||||
|
optionItemContainer.classList.add('dialog-option__item')
|
||||||
|
// 选项名称
|
||||||
|
const optionName = document.createElement('span')
|
||||||
|
optionName.append(document.createTextNode(option.label))
|
||||||
|
optionItemContainer.append(optionName)
|
||||||
|
// 选项输入框
|
||||||
|
const optionInput = document.createElement('input')
|
||||||
|
optionInput.type = option.type
|
||||||
|
optionInput.name = option.name
|
||||||
|
optionInput.value = option.value || ''
|
||||||
|
optionInput.placeholder = option.placeholder || ''
|
||||||
|
optionItemContainer.append(optionInput)
|
||||||
|
optionContainer.append(optionItemContainer)
|
||||||
|
this.inputList.push(optionInput)
|
||||||
|
}
|
||||||
|
dialogContainer.append(optionContainer)
|
||||||
|
// 按钮容器
|
||||||
|
const menuContainer = document.createElement('div')
|
||||||
|
menuContainer.classList.add('dialog-menu')
|
||||||
|
// 取消按钮
|
||||||
|
const cancelBtn = document.createElement('button')
|
||||||
|
cancelBtn.classList.add('dialog-menu__cancel')
|
||||||
|
cancelBtn.append(document.createTextNode('取消'))
|
||||||
|
cancelBtn.type = 'default'
|
||||||
|
cancelBtn.onclick = () => {
|
||||||
|
if (onCancel) {
|
||||||
|
onCancel()
|
||||||
|
}
|
||||||
|
this._dispose()
|
||||||
|
}
|
||||||
|
menuContainer.append(cancelBtn)
|
||||||
|
// 确认按钮
|
||||||
|
const confirmBtn = document.createElement('button')
|
||||||
|
confirmBtn.append(document.createTextNode('确定'))
|
||||||
|
confirmBtn.type = 'primary'
|
||||||
|
confirmBtn.onclick = () => {
|
||||||
|
if (onConfirm) {
|
||||||
|
const payload = this.inputList.map<IDialogConfirm>(input => ({
|
||||||
|
name: input.name,
|
||||||
|
value: input.value
|
||||||
|
}))
|
||||||
|
onConfirm(payload)
|
||||||
|
}
|
||||||
|
this._dispose()
|
||||||
|
}
|
||||||
|
menuContainer.append(confirmBtn)
|
||||||
|
dialogContainer.append(menuContainer)
|
||||||
|
// 渲染
|
||||||
|
document.body.append(container)
|
||||||
|
this.container = container
|
||||||
|
this.mask = mask
|
||||||
|
}
|
||||||
|
|
||||||
|
private _dispose() {
|
||||||
|
this.mask?.remove()
|
||||||
|
this.container?.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
.dialog-mask {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: .5;
|
||||||
|
background: #000000;
|
||||||
|
z-index: 99;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
overflow: auto;
|
||||||
|
z-index: 999;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog {
|
||||||
|
position: absolute;
|
||||||
|
padding: 0 30px 30px;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0 2px 12px 0 rgb(56 56 56 / 20%);
|
||||||
|
border: 1px solid #e2e6ed;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-title {
|
||||||
|
position: relative;
|
||||||
|
border-bottom: 1px solid #e2e6ed;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
height: 60px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-title i {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
background: url(../../assets/images/close.svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-option__item {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
height: 30px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-option__item span {
|
||||||
|
margin-right: 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #3d4757;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-option__item input {
|
||||||
|
width: 276px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid #d3d3d3;
|
||||||
|
min-height: 30px;
|
||||||
|
line-height: 17px;
|
||||||
|
padding: 5px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
outline: none;
|
||||||
|
appearance: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-option__item input:focus {
|
||||||
|
border-color: #4991f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-menu {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-menu button {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
border: 1px solid #e2e6ed;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: #ffffff;
|
||||||
|
line-height: 22px;
|
||||||
|
padding: 0 16px;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-menu button:hover {
|
||||||
|
background: rgba(25, 55, 88, .04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-menu__cancel {
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-menu button[type='primary'] {
|
||||||
|
color: #ffffff;
|
||||||
|
background: #4991f2;
|
||||||
|
border-color: #4991f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-menu button[type='primary']:hover {
|
||||||
|
background: #5b9cf3;
|
||||||
|
border-color: #5b9cf3;
|
||||||
|
}
|
||||||
@@ -306,4 +306,28 @@
|
|||||||
|
|
||||||
.contextmenu-delete-table {
|
.contextmenu-delete-table {
|
||||||
background-image: url(../../assets/images/delete-table.svg);
|
background-image: url(../../assets/images/delete-table.svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hyperlink-popup {
|
||||||
|
min-width: 100px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 20px;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 2px 12px 0 rgb(98 107 132 / 20%);
|
||||||
|
border-radius: 2px;
|
||||||
|
color: #3d4757;
|
||||||
|
padding: 16px;
|
||||||
|
white-space: nowrap;
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hyperlink-popup a {
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
color: #0000ff;
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { IElement } from "../.."
|
||||||
import { RowFlex } from "../../dataset/enum/Row"
|
import { RowFlex } from "../../dataset/enum/Row"
|
||||||
import { IDrawImagePayload } from "../../interface/Draw"
|
import { IDrawImagePayload } from "../../interface/Draw"
|
||||||
import { CommandAdapt } from "./CommandAdapt"
|
import { CommandAdapt } from "./CommandAdapt"
|
||||||
@@ -34,6 +35,7 @@ export class Command {
|
|||||||
private static deleteTableCol: Function
|
private static deleteTableCol: Function
|
||||||
private static deleteTable: Function
|
private static deleteTable: Function
|
||||||
private static image: Function
|
private static image: Function
|
||||||
|
private static hyperlink: Function
|
||||||
private static search: Function
|
private static search: Function
|
||||||
private static print: Function
|
private static print: Function
|
||||||
private static pageScaleRecovery: Function
|
private static pageScaleRecovery: Function
|
||||||
@@ -71,6 +73,7 @@ export class Command {
|
|||||||
Command.deleteTableCol = adapt.deleteTableCol.bind(adapt)
|
Command.deleteTableCol = adapt.deleteTableCol.bind(adapt)
|
||||||
Command.deleteTable = adapt.deleteTable.bind(adapt)
|
Command.deleteTable = adapt.deleteTable.bind(adapt)
|
||||||
Command.image = adapt.image.bind(adapt)
|
Command.image = adapt.image.bind(adapt)
|
||||||
|
Command.hyperlink = adapt.hyperlink.bind(adapt)
|
||||||
Command.search = adapt.search.bind(adapt)
|
Command.search = adapt.search.bind(adapt)
|
||||||
Command.print = adapt.print.bind(adapt)
|
Command.print = adapt.print.bind(adapt)
|
||||||
Command.pageScaleRecovery = adapt.pageScaleRecovery.bind(adapt)
|
Command.pageScaleRecovery = adapt.pageScaleRecovery.bind(adapt)
|
||||||
@@ -165,7 +168,7 @@ export class Command {
|
|||||||
return Command.rowMargin(payload)
|
return Command.rowMargin(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 表格、图片上传、搜索、打印
|
// 表格、图片上传、超链接、搜索、打印
|
||||||
public executeInsertTable(row: number, col: number) {
|
public executeInsertTable(row: number, col: number) {
|
||||||
return Command.insertTable(row, col)
|
return Command.insertTable(row, col)
|
||||||
}
|
}
|
||||||
@@ -198,6 +201,10 @@ export class Command {
|
|||||||
return Command.deleteTable()
|
return Command.deleteTable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public executeHyperlink(payload: IElement) {
|
||||||
|
return Command.hyperlink(payload)
|
||||||
|
}
|
||||||
|
|
||||||
public executeImage(payload: IDrawImagePayload) {
|
public executeImage(payload: IDrawImagePayload) {
|
||||||
return Command.image(payload)
|
return Command.image(payload)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -654,6 +654,30 @@ export class CommandAdapt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public hyperlink(payload: IElement) {
|
||||||
|
const { startIndex, endIndex } = this.range.getRange()
|
||||||
|
if (startIndex === 0 && endIndex === 0) return
|
||||||
|
const elementList = this.draw.getElementList()
|
||||||
|
const { valueList, url } = payload
|
||||||
|
const hyperlinkId = getUUID()
|
||||||
|
const newElementList = valueList?.map<IElement>(v => ({
|
||||||
|
url,
|
||||||
|
hyperlinkId,
|
||||||
|
value: v.value,
|
||||||
|
type: ElementType.HYPERLINK
|
||||||
|
}))
|
||||||
|
if (!newElementList) return
|
||||||
|
const start = startIndex + 1
|
||||||
|
if (startIndex === endIndex) {
|
||||||
|
elementList.splice(start, 0, ...newElementList)
|
||||||
|
} else {
|
||||||
|
elementList.splice(start, endIndex - startIndex, ...newElementList)
|
||||||
|
}
|
||||||
|
const curIndex = start + newElementList.length - 1
|
||||||
|
this.range.setRange(curIndex, curIndex)
|
||||||
|
this.draw.render({ curIndex })
|
||||||
|
}
|
||||||
|
|
||||||
public image(payload: IDrawImagePayload) {
|
public image(payload: IDrawImagePayload) {
|
||||||
const { startIndex, endIndex } = this.range.getRange()
|
const { startIndex, endIndex } = this.range.getRange()
|
||||||
if (startIndex === 0 && endIndex === 0) return
|
if (startIndex === 0 && endIndex === 0) return
|
||||||
@@ -706,7 +730,8 @@ export class CommandAdapt {
|
|||||||
// 搜索文本
|
// 搜索文本
|
||||||
function searchClosure(payload: string | null, type: EditorContext, elementList: IElement[], restArgs?: ISearchResultRestArgs) {
|
function searchClosure(payload: string | null, type: EditorContext, elementList: IElement[], restArgs?: ISearchResultRestArgs) {
|
||||||
if (!payload) return
|
if (!payload) return
|
||||||
const text = elementList.map(e => !e.type || e.type === ElementType.TEXT ? e.value : ZERO)
|
const { TEXT, HYPERLINK } = ElementType
|
||||||
|
const text = elementList.map(e => !e.type || e.type === TEXT || e.type === HYPERLINK ? e.value : ZERO)
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join('')
|
.join('')
|
||||||
const matchStartIndexList = []
|
const matchStartIndexList = []
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import { GlobalObserver } from "../observer/GlobalObserver"
|
|||||||
import { TableParticle } from "./particle/table/TableParticle"
|
import { TableParticle } from "./particle/table/TableParticle"
|
||||||
import { ISearchResult } from "../../interface/Search"
|
import { ISearchResult } from "../../interface/Search"
|
||||||
import { TableTool } from "./particle/table/TableTool"
|
import { TableTool } from "./particle/table/TableTool"
|
||||||
|
import { HyperlinkParticle } from "./particle/HyperlinkParticle"
|
||||||
|
|
||||||
export class Draw {
|
export class Draw {
|
||||||
|
|
||||||
@@ -54,6 +55,7 @@ export class Draw {
|
|||||||
private tableParticle: TableParticle
|
private tableParticle: TableParticle
|
||||||
private tableTool: TableTool
|
private tableTool: TableTool
|
||||||
private pageNumber: PageNumber
|
private pageNumber: PageNumber
|
||||||
|
private hyperlinkParticle: HyperlinkParticle
|
||||||
|
|
||||||
private rowList: IRow[]
|
private rowList: IRow[]
|
||||||
private painterStyle: IElementStyle | null
|
private painterStyle: IElementStyle | null
|
||||||
@@ -92,6 +94,7 @@ export class Draw {
|
|||||||
this.tableParticle = new TableParticle(this)
|
this.tableParticle = new TableParticle(this)
|
||||||
this.tableTool = new TableTool(this)
|
this.tableTool = new TableTool(this)
|
||||||
this.pageNumber = new PageNumber(this)
|
this.pageNumber = new PageNumber(this)
|
||||||
|
this.hyperlinkParticle = new HyperlinkParticle(this)
|
||||||
new GlobalObserver(this)
|
new GlobalObserver(this)
|
||||||
|
|
||||||
this.canvasEvent = new CanvasEvent(this)
|
this.canvasEvent = new CanvasEvent(this)
|
||||||
@@ -251,6 +254,10 @@ export class Draw {
|
|||||||
return this.tableTool
|
return this.tableTool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getHyperlinkParticle(): HyperlinkParticle {
|
||||||
|
return this.hyperlinkParticle
|
||||||
|
}
|
||||||
|
|
||||||
public getRowCount(): number {
|
public getRowCount(): number {
|
||||||
return this.rowList.length
|
return this.rowList.length
|
||||||
}
|
}
|
||||||
@@ -431,11 +438,10 @@ export class Draw {
|
|||||||
const ascent = metrics.boundingBoxAscent + rowMargin
|
const ascent = metrics.boundingBoxAscent + rowMargin
|
||||||
const descent = metrics.boundingBoxDescent + rowMargin
|
const descent = metrics.boundingBoxDescent + rowMargin
|
||||||
const height = ascent + descent
|
const height = ascent + descent
|
||||||
const rowElement: IRowElement = {
|
const rowElement: IRowElement = Object.assign(element, {
|
||||||
...element,
|
|
||||||
metrics,
|
metrics,
|
||||||
style: this._getFont(element, scale)
|
style: this._getFont(element, scale)
|
||||||
}
|
})
|
||||||
// 超过限定宽度
|
// 超过限定宽度
|
||||||
const preElement = elementList[i - 1]
|
const preElement = elementList[i - 1]
|
||||||
if (
|
if (
|
||||||
@@ -509,9 +515,21 @@ export class Draw {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
positionList.push(positionItem)
|
positionList.push(positionItem)
|
||||||
|
// 元素绘制
|
||||||
|
if (element.type === ElementType.IMAGE) {
|
||||||
|
this.textParticle.complete()
|
||||||
|
this.imageParticle.render(ctx, element, x, y + offsetY)
|
||||||
|
} else if (element.type === ElementType.TABLE) {
|
||||||
|
this.tableParticle.render(ctx, element, x, y)
|
||||||
|
} else if (element.type === ElementType.HYPERLINK) {
|
||||||
|
this.textParticle.complete()
|
||||||
|
this.hyperlinkParticle.render(ctx, element, x, y + offsetY)
|
||||||
|
} else {
|
||||||
|
this.textParticle.record(ctx, element, x, y + offsetY)
|
||||||
|
}
|
||||||
// 下划线绘制
|
// 下划线绘制
|
||||||
if (element.underline) {
|
if (element.underline) {
|
||||||
this.underline.render(ctx, x, y + curRow.height, metrics.width)
|
this.underline.render(ctx, element.color!, x, y + curRow.height, metrics.width)
|
||||||
}
|
}
|
||||||
// 删除线绘制
|
// 删除线绘制
|
||||||
if (element.strikeout) {
|
if (element.strikeout) {
|
||||||
@@ -521,15 +539,6 @@ export class Draw {
|
|||||||
if (element.highlight) {
|
if (element.highlight) {
|
||||||
this.highlight.render(ctx, element.highlight, x, y, metrics.width, curRow.height)
|
this.highlight.render(ctx, element.highlight, x, y, metrics.width, curRow.height)
|
||||||
}
|
}
|
||||||
// 元素绘制
|
|
||||||
if (element.type === ElementType.IMAGE) {
|
|
||||||
this.textParticle.complete()
|
|
||||||
this.imageParticle.render(ctx, element, x, y + offsetY)
|
|
||||||
} else if (element.type === ElementType.TABLE) {
|
|
||||||
this.tableParticle.render(ctx, element, x, y)
|
|
||||||
} else {
|
|
||||||
this.textParticle.record(ctx, element, x, y + offsetY)
|
|
||||||
}
|
|
||||||
// 选区绘制
|
// 选区绘制
|
||||||
const { startIndex, endIndex } = this.range.getRange()
|
const { startIndex, endIndex } = this.range.getRange()
|
||||||
if (startIndex !== endIndex && startIndex < index && index <= endIndex) {
|
if (startIndex !== endIndex && startIndex < index && index <= endIndex) {
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import { IElement } from "../../.."
|
||||||
|
import { IEditorOption } from "../../../interface/Editor"
|
||||||
|
import { IElementPosition } from "../../../interface/Element"
|
||||||
|
import { IRowElement } from "../../../interface/Row"
|
||||||
|
import { Draw } from "../Draw"
|
||||||
|
|
||||||
|
export class HyperlinkParticle {
|
||||||
|
|
||||||
|
private draw: Draw
|
||||||
|
private options: Required<IEditorOption>
|
||||||
|
private container: HTMLDivElement
|
||||||
|
private hyperlinkPopupContainer: HTMLDivElement
|
||||||
|
private hyperlinkDom: HTMLAnchorElement
|
||||||
|
|
||||||
|
constructor(draw: Draw) {
|
||||||
|
this.draw = draw
|
||||||
|
this.options = draw.getOptions()
|
||||||
|
this.container = draw.getContainer()
|
||||||
|
const { hyperlinkPopupContainer, hyperlinkDom } = this._createHyperlinkPopupDom()
|
||||||
|
this.hyperlinkDom = hyperlinkDom
|
||||||
|
this.hyperlinkPopupContainer = hyperlinkPopupContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createHyperlinkPopupDom() {
|
||||||
|
const hyperlinkPopupContainer = document.createElement('div')
|
||||||
|
hyperlinkPopupContainer.classList.add('hyperlink-popup')
|
||||||
|
const hyperlinkDom = document.createElement('a')
|
||||||
|
hyperlinkDom.target = '_blank'
|
||||||
|
hyperlinkPopupContainer.append(hyperlinkDom)
|
||||||
|
this.container.append(hyperlinkPopupContainer)
|
||||||
|
return { hyperlinkPopupContainer, hyperlinkDom }
|
||||||
|
}
|
||||||
|
|
||||||
|
public drawHyperlinkPopup(element: IElement, position: IElementPosition) {
|
||||||
|
const { coordinate: { leftTop: [left, top] }, lineHeight } = position
|
||||||
|
const height = this.draw.getHeight()
|
||||||
|
const pageGap = this.draw.getPageGap()
|
||||||
|
const preY = this.draw.getPageNo() * (height + pageGap)
|
||||||
|
// 位置
|
||||||
|
this.hyperlinkPopupContainer.style.display = 'block'
|
||||||
|
this.hyperlinkPopupContainer.style.left = `${left}px`
|
||||||
|
this.hyperlinkPopupContainer.style.top = `${top + preY + lineHeight}px`
|
||||||
|
// 标签
|
||||||
|
const url = element.url || '#'
|
||||||
|
this.hyperlinkDom.href = url
|
||||||
|
this.hyperlinkDom.innerText = url
|
||||||
|
}
|
||||||
|
|
||||||
|
public clearHyperlinkPopup() {
|
||||||
|
this.hyperlinkPopupContainer.style.display = 'none'
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(ctx: CanvasRenderingContext2D, element: IRowElement, x: number, y: number) {
|
||||||
|
ctx.save()
|
||||||
|
ctx.font = element.style
|
||||||
|
if (!element.color) {
|
||||||
|
element.color = this.options.defaultHyperlinkColor
|
||||||
|
}
|
||||||
|
ctx.fillStyle = element.color
|
||||||
|
if (element.underline === undefined) {
|
||||||
|
element.underline = true
|
||||||
|
}
|
||||||
|
ctx.fillText(element.value, x, y)
|
||||||
|
ctx.restore()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,10 +9,10 @@ export class Underline {
|
|||||||
this.options = draw.getOptions()
|
this.options = draw.getOptions()
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(ctx: CanvasRenderingContext2D, x: number, y: number, width: number) {
|
public render(ctx: CanvasRenderingContext2D, color: string, x: number, y: number, width: number) {
|
||||||
const { underlineColor } = this.options
|
const { underlineColor } = this.options
|
||||||
ctx.save()
|
ctx.save()
|
||||||
ctx.strokeStyle = underlineColor
|
ctx.strokeStyle = color || underlineColor
|
||||||
ctx.beginPath()
|
ctx.beginPath()
|
||||||
ctx.moveTo(x, y)
|
ctx.moveTo(x, y)
|
||||||
ctx.lineTo(x + width, y)
|
ctx.lineTo(x + width, y)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { ElementType } from "../.."
|
||||||
import { ZERO } from "../../dataset/constant/Common"
|
import { ZERO } from "../../dataset/constant/Common"
|
||||||
import { ElementStyleKey } from "../../dataset/enum/ElementStyle"
|
import { ElementStyleKey } from "../../dataset/enum/ElementStyle"
|
||||||
import { MouseEventButton } from "../../dataset/enum/Event"
|
import { MouseEventButton } from "../../dataset/enum/Event"
|
||||||
@@ -6,6 +7,7 @@ import { IElement } from "../../interface/Element"
|
|||||||
import { writeTextByElementList } from "../../utils/clipboard"
|
import { writeTextByElementList } from "../../utils/clipboard"
|
||||||
import { Cursor } from "../cursor/Cursor"
|
import { Cursor } from "../cursor/Cursor"
|
||||||
import { Draw } from "../draw/Draw"
|
import { Draw } from "../draw/Draw"
|
||||||
|
import { HyperlinkParticle } from "../draw/particle/HyperlinkParticle"
|
||||||
import { ImageParticle } from "../draw/particle/ImageParticle"
|
import { ImageParticle } from "../draw/particle/ImageParticle"
|
||||||
import { TableTool } from "../draw/particle/table/TableTool"
|
import { TableTool } from "../draw/particle/table/TableTool"
|
||||||
import { HistoryManager } from "../history/HistoryManager"
|
import { HistoryManager } from "../history/HistoryManager"
|
||||||
@@ -27,6 +29,7 @@ export class CanvasEvent {
|
|||||||
private historyManager: HistoryManager
|
private historyManager: HistoryManager
|
||||||
private imageParticle: ImageParticle
|
private imageParticle: ImageParticle
|
||||||
private tableTool: TableTool
|
private tableTool: TableTool
|
||||||
|
private hyperlinkParticle: HyperlinkParticle
|
||||||
|
|
||||||
constructor(draw: Draw) {
|
constructor(draw: Draw) {
|
||||||
this.isAllowDrag = false
|
this.isAllowDrag = false
|
||||||
@@ -42,6 +45,7 @@ export class CanvasEvent {
|
|||||||
this.historyManager = this.draw.getHistoryManager()
|
this.historyManager = this.draw.getHistoryManager()
|
||||||
this.imageParticle = this.draw.getImageParticle()
|
this.imageParticle = this.draw.getImageParticle()
|
||||||
this.tableTool = this.draw.getTableTool()
|
this.tableTool = this.draw.getTableTool()
|
||||||
|
this.hyperlinkParticle = this.draw.getHyperlinkParticle()
|
||||||
}
|
}
|
||||||
|
|
||||||
public register() {
|
public register() {
|
||||||
@@ -160,20 +164,26 @@ export class CanvasEvent {
|
|||||||
isComputeRowList: false
|
isComputeRowList: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
const elementList = this.draw.getElementList()
|
||||||
|
const positionList = this.position.getPositionList()
|
||||||
|
const curIndex = isTable ? tdValueIndex! : index
|
||||||
|
const curElement = elementList[curIndex]
|
||||||
// 图片尺寸拖拽组件
|
// 图片尺寸拖拽组件
|
||||||
this.imageParticle.clearResizer()
|
this.imageParticle.clearResizer()
|
||||||
if (isDirectHitImage) {
|
if (isDirectHitImage) {
|
||||||
const elementList = this.draw.getElementList()
|
this.imageParticle.drawResizer(curElement, positionList[curIndex])
|
||||||
const positionList = this.position.getPositionList()
|
|
||||||
const curIndex = isTable ? tdValueIndex! : index
|
|
||||||
this.imageParticle.drawResizer(elementList[curIndex], positionList[curIndex])
|
|
||||||
}
|
}
|
||||||
// 表格工具组件
|
// 表格工具组件
|
||||||
this.tableTool.dispose()
|
this.tableTool.dispose()
|
||||||
if (isTable) {
|
if (isTable) {
|
||||||
const elementList = this.draw.getOriginalElementList()
|
const originalElementList = this.draw.getOriginalElementList()
|
||||||
const positionList = this.position.getOriginalPositionList()
|
const originalPositionList = this.position.getOriginalPositionList()
|
||||||
this.tableTool.render(elementList[index], positionList[index])
|
this.tableTool.render(originalElementList[index], originalPositionList[index])
|
||||||
|
}
|
||||||
|
// 超链接
|
||||||
|
this.hyperlinkParticle.clearHyperlinkPopup()
|
||||||
|
if (curElement.type === ElementType.HYPERLINK) {
|
||||||
|
this.hyperlinkParticle.drawHyperlinkPopup(curElement, positionList[curIndex])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,6 +325,7 @@ export class CanvasEvent {
|
|||||||
if (!this.cursor) return
|
if (!this.cursor) return
|
||||||
const cursorPosition = this.position.getCursorPosition()
|
const cursorPosition = this.position.getCursorPosition()
|
||||||
if (!data || !cursorPosition || this.isCompositing) return
|
if (!data || !cursorPosition || this.isCompositing) return
|
||||||
|
const { TEXT, HYPERLINK } = ElementType
|
||||||
const text = data.replaceAll(`\n`, ZERO)
|
const text = data.replaceAll(`\n`, ZERO)
|
||||||
const elementList = this.draw.getElementList()
|
const elementList = this.draw.getElementList()
|
||||||
const agentDom = this.cursor.getAgentDom()
|
const agentDom = this.cursor.getAgentDom()
|
||||||
@@ -330,18 +341,32 @@ export class CanvasEvent {
|
|||||||
restArg = { tdId, trId, tableId }
|
restArg = { tdId, trId, tableId }
|
||||||
}
|
}
|
||||||
const element = elementList[endIndex]
|
const element = elementList[endIndex]
|
||||||
const inputData: IElement[] = text.split('').map(value => ({
|
const inputData: IElement[] = text.split('').map(value => {
|
||||||
value,
|
const newElement: IElement = {
|
||||||
font: element.font,
|
value,
|
||||||
size: element.size,
|
...restArg
|
||||||
bold: element.bold,
|
}
|
||||||
color: element.color,
|
if (
|
||||||
highlight: element.highlight,
|
!element.type
|
||||||
italic: element.italic,
|
|| element.type === TEXT
|
||||||
underline: element.underline,
|
|| (element.type === HYPERLINK && elementList[endIndex + 1]?.type === HYPERLINK)
|
||||||
strikeout: element.strikeout,
|
) {
|
||||||
...restArg
|
if (element.type) {
|
||||||
}))
|
newElement.type = element.type
|
||||||
|
}
|
||||||
|
newElement.font = element.font
|
||||||
|
newElement.size = element.size
|
||||||
|
newElement.bold = element.bold
|
||||||
|
newElement.color = element.color
|
||||||
|
newElement.highlight = element.highlight
|
||||||
|
newElement.italic = element.italic
|
||||||
|
newElement.underline = element.underline
|
||||||
|
newElement.strikeout = element.strikeout
|
||||||
|
newElement.url = element.url
|
||||||
|
newElement.hyperlinkId = element.hyperlinkId
|
||||||
|
}
|
||||||
|
return newElement
|
||||||
|
})
|
||||||
let start = 0
|
let start = 0
|
||||||
if (isCollspace) {
|
if (isCollspace) {
|
||||||
start = index + 1
|
start = index + 1
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { IEditorOption } from "../../interface/Editor"
|
|||||||
import { findParent } from "../../utils"
|
import { findParent } from "../../utils"
|
||||||
import { Cursor } from "../cursor/Cursor"
|
import { Cursor } from "../cursor/Cursor"
|
||||||
import { Draw } from "../draw/Draw"
|
import { Draw } from "../draw/Draw"
|
||||||
|
import { HyperlinkParticle } from "../draw/particle/HyperlinkParticle"
|
||||||
import { ImageParticle } from "../draw/particle/ImageParticle"
|
import { ImageParticle } from "../draw/particle/ImageParticle"
|
||||||
import { TableTool } from "../draw/particle/table/TableTool"
|
import { TableTool } from "../draw/particle/table/TableTool"
|
||||||
import { RangeManager } from "../range/RangeManager"
|
import { RangeManager } from "../range/RangeManager"
|
||||||
@@ -18,6 +19,7 @@ export class GlobalEvent {
|
|||||||
private range: RangeManager
|
private range: RangeManager
|
||||||
private imageParticle: ImageParticle
|
private imageParticle: ImageParticle
|
||||||
private tableTool: TableTool
|
private tableTool: TableTool
|
||||||
|
private hyperlinkParticle: HyperlinkParticle
|
||||||
|
|
||||||
constructor(draw: Draw, canvasEvent: CanvasEvent) {
|
constructor(draw: Draw, canvasEvent: CanvasEvent) {
|
||||||
this.draw = draw
|
this.draw = draw
|
||||||
@@ -28,6 +30,7 @@ export class GlobalEvent {
|
|||||||
this.range = draw.getRange()
|
this.range = draw.getRange()
|
||||||
this.imageParticle = draw.getImageParticle()
|
this.imageParticle = draw.getImageParticle()
|
||||||
this.tableTool = draw.getTableTool()
|
this.tableTool = draw.getTableTool()
|
||||||
|
this.hyperlinkParticle = draw.getHyperlinkParticle()
|
||||||
}
|
}
|
||||||
|
|
||||||
public register() {
|
public register() {
|
||||||
@@ -70,6 +73,7 @@ export class GlobalEvent {
|
|||||||
this.range.setRange(0, 0)
|
this.range.setRange(0, 0)
|
||||||
this.imageParticle.clearResizer()
|
this.imageParticle.clearResizer()
|
||||||
this.tableTool.dispose()
|
this.tableTool.dispose()
|
||||||
|
this.hyperlinkParticle.clearHyperlinkPopup()
|
||||||
}
|
}
|
||||||
|
|
||||||
public setDragState() {
|
public setDragState() {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export enum EditorComponent {
|
export enum EditorComponent {
|
||||||
|
COMPONENT = 'component',
|
||||||
MENU = 'menu',
|
MENU = 'menu',
|
||||||
MAIN = 'main',
|
MAIN = 'main',
|
||||||
FOOTER = 'footer',
|
FOOTER = 'footer',
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export enum ElementType {
|
export enum ElementType {
|
||||||
TEXT = 'text',
|
TEXT = 'text',
|
||||||
IMAGE = 'image',
|
IMAGE = 'image',
|
||||||
TABLE = 'table'
|
TABLE = 'table',
|
||||||
|
HYPERLINK = 'hyperlink'
|
||||||
}
|
}
|
||||||
+6
-1
@@ -13,6 +13,8 @@ import { globalMenus } from './core/contextmenu/menus/GlobalMenus'
|
|||||||
import { ContextMenu } from './core/contextmenu/ContextMenu'
|
import { ContextMenu } from './core/contextmenu/ContextMenu'
|
||||||
import { tableMenus } from './core/contextmenu/menus/tableMenus'
|
import { tableMenus } from './core/contextmenu/menus/tableMenus'
|
||||||
import { IRegisterContextMenu } from './interface/contextmenu/ContextMenu'
|
import { IRegisterContextMenu } from './interface/contextmenu/ContextMenu'
|
||||||
|
import { EditorComponent } from './dataset/enum/Editor'
|
||||||
|
import { EDITOR_COMPONENT } from './dataset/constant/Editor'
|
||||||
|
|
||||||
export default class Editor {
|
export default class Editor {
|
||||||
|
|
||||||
@@ -49,6 +51,7 @@ export default class Editor {
|
|||||||
margins: [100, 120, 100, 120],
|
margins: [100, 120, 100, 120],
|
||||||
tdPadding: 5,
|
tdPadding: 5,
|
||||||
defaultTdHeight: 40,
|
defaultTdHeight: 40,
|
||||||
|
defaultHyperlinkColor: '#0000FF',
|
||||||
...options
|
...options
|
||||||
}
|
}
|
||||||
formatElementList(elementList)
|
formatElementList(elementList)
|
||||||
@@ -74,7 +77,9 @@ export default class Editor {
|
|||||||
export {
|
export {
|
||||||
Editor,
|
Editor,
|
||||||
RowFlex,
|
RowFlex,
|
||||||
ElementType
|
ElementType,
|
||||||
|
EditorComponent,
|
||||||
|
EDITOR_COMPONENT
|
||||||
}
|
}
|
||||||
|
|
||||||
// 对外类型
|
// 对外类型
|
||||||
|
|||||||
@@ -26,4 +26,5 @@ export interface IEditorOption {
|
|||||||
margins?: [top: number, right: number, bootom: number, left: number],
|
margins?: [top: number, right: number, bootom: number, left: number],
|
||||||
tdPadding?: number;
|
tdPadding?: number;
|
||||||
defaultTdHeight?: number;
|
defaultTdHeight?: number;
|
||||||
|
defaultHyperlinkColor?: string;
|
||||||
}
|
}
|
||||||
@@ -35,9 +35,15 @@ export interface ITableElement {
|
|||||||
tableId?: string;
|
tableId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IHyperlinkElement {
|
||||||
|
valueList?: IElement[];
|
||||||
|
url?: string;
|
||||||
|
hyperlinkId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export type ITable = ITableAttr & ITableElement
|
export type ITable = ITableAttr & ITableElement
|
||||||
|
|
||||||
export type IElement = IElementBasic & IElementStyle & ITable
|
export type IElement = IElementBasic & IElementStyle & ITable & IHyperlinkElement
|
||||||
|
|
||||||
export interface IElementMetrics {
|
export interface IElementMetrics {
|
||||||
width: number;
|
width: number;
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ export function writeText(text: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function writeTextByElementList(elementList: IElement[]) {
|
export function writeTextByElementList(elementList: IElement[]) {
|
||||||
|
const { TEXT, HYPERLINK } = ElementType
|
||||||
const text = elementList
|
const text = elementList
|
||||||
.map(p => !p.type || p.type === ElementType.TEXT ? p.value : '')
|
.map(p => !p.type || p.type === TEXT || p.type === HYPERLINK ? p.value : '')
|
||||||
.join('')
|
.join('')
|
||||||
writeText(text)
|
writeText(text)
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,8 @@ export function formatElementList(elementList: IElement[]) {
|
|||||||
value: ZERO
|
value: ZERO
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for (let i = 0; i < elementList.length; i++) {
|
let i = 0
|
||||||
|
while (i < elementList.length) {
|
||||||
const el = elementList[i]
|
const el = elementList[i]
|
||||||
if (el.type === ElementType.TABLE) {
|
if (el.type === ElementType.TABLE) {
|
||||||
const tableId = getUUID()
|
const tableId = getUUID()
|
||||||
@@ -32,6 +33,23 @@ export function formatElementList(elementList: IElement[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (el.type === ElementType.HYPERLINK) {
|
||||||
|
const valueList = el.valueList || []
|
||||||
|
// 移除父节点
|
||||||
|
elementList.splice(i, 1)
|
||||||
|
// 追加字节点
|
||||||
|
if (valueList.length) {
|
||||||
|
const hyperlinkId = getUUID()
|
||||||
|
for (let v = 0; v < valueList.length; v++) {
|
||||||
|
const value = valueList[v]
|
||||||
|
value.type = el.type
|
||||||
|
value.url = el.url
|
||||||
|
value.hyperlinkId = hyperlinkId
|
||||||
|
elementList.splice(i, 0, value)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i--
|
||||||
}
|
}
|
||||||
if (el.value === '\n') {
|
if (el.value === '\n') {
|
||||||
el.value = ZERO
|
el.value = ZERO
|
||||||
@@ -39,5 +57,6 @@ export function formatElementList(elementList: IElement[]) {
|
|||||||
if (el.type === ElementType.IMAGE) {
|
if (el.type === ElementType.IMAGE) {
|
||||||
el.id = getUUID()
|
el.id = getUUID()
|
||||||
}
|
}
|
||||||
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+54
-2
@@ -1,9 +1,10 @@
|
|||||||
import './style.css'
|
import './style.css'
|
||||||
import Editor, { ElementType, IElement, RowFlex } from './editor'
|
import Editor, { ElementType, IElement, RowFlex } from './editor'
|
||||||
|
import { Dialog } from './components/dialog/Dialog'
|
||||||
|
|
||||||
window.onload = function () {
|
window.onload = function () {
|
||||||
|
|
||||||
const text = `人民医院门诊病历\n主诉:\n发热三天,咳嗽五天。\n现病史:\n患者于三天前无明显诱因,感冒后发现面部水肿,无皮疹,尿量减少,出现乏力,在外治疗无好转,现来我院就诊。\n既往史:\n有糖尿病10年,有高血压2年,有传染性疾病1年。没有报告其他既往疾病。\n流行病史:\n否认14天内接触过新冠肺炎确诊患者、疑似患者、无症状感染者及其密切接触者;否认14天内去过以下场所:水产、肉类批发市场,农贸市场,集市,大型超市,夜市;否认14天内与以下场所工作人员密切接触:水产、肉类批发市场,农贸市场,集市,大型超市;否认14天内周围(如家庭、办公室)有2例以上聚集性发病;否认14天内接触过有发热或呼吸道症状的人员;否认14天内自身有发热或呼吸道症状;否认14天内接触过纳入隔离观察的人员及其他可能与新冠肺炎关联的情形;陪同家属{有无选择代码}有以上情况。\n体格检查:\nT:36.5℃,P:80bpm,R:20次/分,BP:120/80mmHg;\n辅助检查:\n2020年6月10日,普放:血细胞比容36.50%(偏低)40~50;单核细胞绝对值0.75*10^9/L(偏高)参考值:0.1~0.6;\n门诊诊断:\n1.高血压\n2.糖尿病\n3.病毒性感冒\n4.过敏性鼻炎\n5.过敏性鼻息肉\n处置治疗:\n1.超声引导下甲状腺细针穿刺术;\n2.乙型肝炎表面抗体测定;\n3.膜式病变细胞采集术、后颈皮下肤层;\n电子签名:【】\n其他记录:`
|
const text = `人民医院门诊病历\n主诉:\n发热三天,咳嗽五天。\n现病史:\n患者于三天前无明显诱因,感冒后发现面部水肿,无皮疹,尿量减少,出现乏力,在外治疗无好转,现来我院就诊。\n既往史:\n有糖尿病10年,有高血压2年,有传染性疾病1年。没有报告其他既往疾病。\n流行病史:\n否认14天内接触过确诊患者、疑似患者、无症状感染者及其密切接触者;否认14天内去过以下场所:水产、肉类批发市场,农贸市场,集市,大型超市,夜市;否认14天内与以下场所工作人员密切接触:水产、肉类批发市场,农贸市场,集市,大型超市;否认14天内周围(如家庭、办公室)有2例以上聚集性发病;否认14天内接触过有发热或呼吸道症状的人员;否认14天内自身有发热或呼吸道症状;否认14天内接触过纳入隔离观察的人员及其他可能与新冠肺炎关联的情形;陪同家属{有无选择代码}有以上情况。\n体格检查:\nT:36.5℃,P:80bpm,R:20次/分,BP:120/80mmHg;\n辅助检查:\n2020年6月10日,普放:血细胞比容36.50%(偏低)40~50;单核细胞绝对值0.75*10^9/L(偏高)参考值:0.1~0.6;\n门诊诊断:\n1.高血压\n2.糖尿病\n3.病毒性感冒\n4.过敏性鼻炎\n5.过敏性鼻息肉\n处置治疗:\n1.超声引导下甲状腺细针穿刺术;\n2.乙型肝炎表面抗体测定;\n3.膜式病变细胞采集术、后颈皮下肤层;\n电子签名:【】\n其他记录:`
|
||||||
// 模拟行居中
|
// 模拟行居中
|
||||||
const centerText = ['人民医院门诊病历']
|
const centerText = ['人民医院门诊病历']
|
||||||
const centerIndex: number[] = centerText.map(c => {
|
const centerIndex: number[] = centerText.map(c => {
|
||||||
@@ -62,7 +63,25 @@ window.onload = function () {
|
|||||||
size: 16
|
size: 16
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
data.splice(595, 0, {
|
data.splice(137, 0, {
|
||||||
|
type: ElementType.HYPERLINK,
|
||||||
|
value: '',
|
||||||
|
valueList: [{
|
||||||
|
value: '新',
|
||||||
|
size: 16
|
||||||
|
}, {
|
||||||
|
value: '冠',
|
||||||
|
size: 16
|
||||||
|
}, {
|
||||||
|
value: '肺',
|
||||||
|
size: 16
|
||||||
|
}, {
|
||||||
|
value: '炎',
|
||||||
|
size: 16
|
||||||
|
}],
|
||||||
|
url: 'https://hufe.club/canvas-editor'
|
||||||
|
})
|
||||||
|
data.splice(592, 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==`,
|
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,
|
width: 89,
|
||||||
height: 32,
|
height: 32,
|
||||||
@@ -386,6 +405,39 @@ window.onload = function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const hyperlinkDom = document.querySelector<HTMLDivElement>('.menu-item__hyperlink')!
|
||||||
|
hyperlinkDom.onclick = function () {
|
||||||
|
console.log('hyperlink')
|
||||||
|
new Dialog({
|
||||||
|
title: '超链接',
|
||||||
|
data: [{
|
||||||
|
type: 'text',
|
||||||
|
label: '文本',
|
||||||
|
name: 'name',
|
||||||
|
placeholder: '请输入文本'
|
||||||
|
}, {
|
||||||
|
type: 'text',
|
||||||
|
label: '链接',
|
||||||
|
name: 'url',
|
||||||
|
placeholder: '请输入链接'
|
||||||
|
}],
|
||||||
|
onConfirm: (payload) => {
|
||||||
|
const name = payload.find(p => p.name === 'name')?.value
|
||||||
|
if (!name) return
|
||||||
|
const url = payload.find(p => p.name === 'url')?.value
|
||||||
|
if (!url) return
|
||||||
|
instance.command.executeHyperlink({
|
||||||
|
type: ElementType.HYPERLINK,
|
||||||
|
value: '',
|
||||||
|
url,
|
||||||
|
valueList: name.split('').map(n => ({
|
||||||
|
value: n,
|
||||||
|
size: 16
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
const collspanDom = document.querySelector<HTMLDivElement>('.menu-item__search__collapse')
|
const collspanDom = document.querySelector<HTMLDivElement>('.menu-item__search__collapse')
|
||||||
const searchInputDom = document.querySelector<HTMLInputElement>('.menu-item__search__collapse__search input')
|
const searchInputDom = document.querySelector<HTMLInputElement>('.menu-item__search__collapse__search input')
|
||||||
document.querySelector<HTMLDivElement>('.menu-item__search')!.onclick = function () {
|
document.querySelector<HTMLDivElement>('.menu-item__search')!.onclick = function () {
|
||||||
|
|||||||
@@ -357,6 +357,10 @@ ul {
|
|||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menu-item__hyperlink i {
|
||||||
|
background-image: url('./assets/images/hyperlink.svg');
|
||||||
|
}
|
||||||
|
|
||||||
.menu-item__search {
|
.menu-item__search {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user