患者相关文件

This commit is contained in:
xiaoxiao
2025-07-11 17:15:50 +08:00
parent 971cd1c332
commit 4df444ed0e
17 changed files with 1159 additions and 69 deletions
@@ -0,0 +1,218 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// [Start RichTextModel]
export class RichTextModel {
// All the text
text: string = '';
// Array of information
textArray: RichTextContentModel[] = [];
// fontSize
fontSize: number = 16;
}
export class RichTextContentModel {
// The index value of a single piece of information throughout the text
index: number = 0;
// The length of a single text (the agreed length in the case of an image)
length: number = 0;
// The type of text
type: string = '';
// images
images: string[] = [];
// content
content: string = '';
// Hyperlinks
link: string = '';
// fontColor
fontColor: string = '#000';
// fontSize
fontSize: number = 16;
// Image width
imgWidth: number = 16;
// Image height
imgHeight: number = 16;
// If the number of lines exceeds the limit, the entire message will be intercepted, and the content to be displayed will be intercepted
shortContent: string = '';
}
// [End RichTextModel]
// [Start TextExpand_TabData]
export class TabData {
id: number;
name: string | Resource;
// ItemList: ItemData[] = [
// new ItemData(),
// new ItemData(),
// new ItemData()
// ];
constructor(id: number, name: string | Resource) {
this.id = id;
this.name = name
}
}
export class ItemData {
// profileImg: Resource = $r('app.media.head_0');
// profileImg1: Resource = $r('app.media.head_1');
// rawTitle: Resource | string = $r('app.string.text_expand_long_title')
// imgUrlList: Resource[] | string[] = [
// $r('app.media.text_expand_img2'),
// $r('app.media.text_expand_img3'),
// $r('app.media.text_expand_img4')
// ];
// imgUrl: Resource | string = $r('app.media.text_expand_img2')
// iconUrlList: Resource[] | string[] = [
// $r('app.media.ic_pl_light'),
// $r('app.media.ic_sc_light'),
// $r('app.media.ic_dz_light'),
// $r('app.media.ic_fx_light')
// ]
}
// [End TextExpand_TabData]
// [Start RichTextExpandModel]
/**
* Rich text expands the view model
* @param {RichTextContentModel[]} textContentArray - Textual content
* @param {boolean} needProcess - Whether to display the Expand and collapse button
* @param {exceedOneLine} boolean - When adding the word 'collapse', more than one line needs to be wrapped
*/
export class RichTextExpandModel {
textContentArray: RichTextContentModel[] = [];
needProcess: boolean = true;
exceedOneLine: boolean = false;
}
// [End RichTextExpandModel]
// [Start RichTextSectionAttribute]
/**
* Rich Text Attribute
*
* @param {ResourceStr} title - Textual content
* @param {number} {maxLines} - maxLines
* @param {ResourceStr} {fontColor} - fontColor
* @param { Resource | number | string} {fontSize} - fontSize
* @param { number } {imgWidth} - Image width
* @param { number } {lineHeight} - Image height
* @param {number} lineHeight - lineHeight
* @param {Resource | number | string} contraintWidth - Sets the maximum width of the text on the line
*/
export class RichTextSectionAttribute {
title: ResourceStr = '';
maxLines: number;
fontColor: ResourceStr;
fontSize: number;
imgWidth: number;
imgHeight: number;
lineHeight: number;
constraintWidth: number;
constructor(title: ResourceStr = '', maxLines: number = 3, fontColor: ResourceStr = '#000',
fontSize: number = 16, imgWidth: number = 0, imgHeight: number = 0, lineHeight: number = 16,
constraintWidth: number = 350) {
this.title = title;
this.maxLines = maxLines;
this.fontColor = fontColor;
this.fontSize = fontSize;
this.imgWidth = imgWidth;
this.imgHeight = imgHeight;
this.lineHeight = lineHeight;
this.constraintWidth = constraintWidth;
}
}
// [End RichTextSectionAttribute]
// [Start LastSpanAttribute]
/**
* Text that controls text folding
*
* @param {number} lastSpanType - Type (0 for text)
* @param {number} charactersNumber - The number of characters in the collapsed text or image
* @param {ResourceStr[]} -Text or image content
* @param {size} Text or image size
* @param {color} color
*/
export class LastSpanAttribute {
lastSpanType: number;
charactersNumber: number;
content: string[];
size: ResourceStr | number;
color: ResourceStr | Color;
constructor(lastSpanType: number, charactersNumber: number = 1,
content: string[], size: ResourceStr | number, color: ResourceStr | Color = Color.Orange) {
this.lastSpanType = lastSpanType;
this.charactersNumber = charactersNumber;
this.content = content;
this.size = size;
this.color = color;
}
}
// [End LastSpanAttribute]
// [Start TextExpandModel]
/**
* Plain text expands the view model
* @param {ResourceStr} title - Textual content
* @param {boolean} needProcess - Whether to display the Expand and collapse button
* @param {exceedOneLine} boolean - When adding the word 'collapse', more than one line needs to be wrapped
*/
export class TextExpandModel {
title: ResourceStr = '';
needProcess: boolean = true;
exceedOneLine: boolean = false;
}
// [End TextExpandModel]
// [Start TextSectionAttribute]
/**
* Plain Text Attribute
*
* @param {ResourceStr} title - Textual content
* @param {number} {maxLines} - maxLines
* @param {ResourceStr} {fontColor} - fontColor
* @param { Resource | number | string} {fontSize} - fontSize
* @param {number} lineHeight - lineHeight
* @param {Resource | number | string} contraintWidth - Sets the maximum width of the text on the line
*/
export class TextSectionAttribute {
title: ResourceStr = '';
maxLines: number;
fontColor: ResourceStr;
fontSize: Resource | number | string;
lineHeight: number;
constraintWidth: Resource | number | string;
constructor(title: ResourceStr = '', maxLines: number = 2, fontColor: ResourceStr = '#666666',
fontSize: Resource | number | string = '15vp', lineHeight: number = 16,
constraintWidth: Resource | number | string = 350) {
this.title = title;
this.maxLines = maxLines;
this.fontColor = fontColor;
this.fontSize = fontSize;
this.lineHeight = lineHeight;
this.constraintWidth = constraintWidth;
}
}
// [End TextSectionAttribute]
@@ -0,0 +1,241 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// [Start TextUtils]
import { BusinessError } from '@kit.BasicServicesKit';
import { RichTextContentModel, RichTextModel, RichTextSectionAttribute, TextSectionAttribute } from './Models';
import { text } from '@kit.ArkGraphics2D';
const suffix: string = '...';
export class TextUtils {
/**
* Gets the collapsed short paragraph string
*
* @param uiContext UI Context
* @param textSectionAttribute Plain Text Attribute
* @param lastSpan Expand the collapse button text
* @returns Short paragraph strings
*/
// [Start TextUtils_getShortText]
public static getShortText(uiContext: UIContext, textSectionAttribute: TextSectionAttribute, lastSpan: string): string {
let text = TextUtils.getStringFromResource(uiContext, textSectionAttribute.title);
const minLinesTextSize: SizeOptions | undefined = uiContext?.getMeasureUtils().measureTextSize({
textContent: text,
fontSize: textSectionAttribute.fontSize,
maxLines: textSectionAttribute.maxLines,
wordBreak: WordBreak.BREAK_ALL,
constraintWidth: textSectionAttribute.constraintWidth
});
const minHeight: Length | undefined = minLinesTextSize?.height;
if (minHeight === undefined) {
return '';
}
// Use the dichotomy to find strings that are exactly two lines in length
let textStr: string[] = Array.from(text); //Split the string to avoid special characters and inconsistent sizes
let leftCursor: number = 0;
let rightCursor: number = textStr.length;
let cursor: number = Math.floor(rightCursor / 2);
let tempTitle: string = '';
while (true) {
tempTitle = text.substring(0, cursor) + suffix + lastSpan;
const currentLinesTextSize: SizeOptions | undefined = uiContext?.getMeasureUtils().measureTextSize({
textContent: tempTitle,
fontSize: textSectionAttribute.fontSize,
wordBreak: WordBreak.BREAK_ALL,
constraintWidth: textSectionAttribute.constraintWidth
});
const currentLineHeight: Length | undefined = currentLinesTextSize?.height;
if (currentLineHeight === undefined) {
return '';
}
if (currentLineHeight > minHeight) {
// The current character has exceeded two lines, continue to look to the left
rightCursor = cursor;
cursor = leftCursor + Math.floor((cursor - leftCursor) / 2);
} else {
// The current character is less than two lines, it may be OK, but you still need to look to the right
leftCursor = cursor;
cursor += Math.floor((rightCursor - cursor) / 2);
}
if (Math.abs(rightCursor - leftCursor) <= 1) {
// The two pointers basically coincide, which means that they have been found
break;
}
}
return text.substring(0, cursor) + suffix;
}
// [End TextUtils_getShortText]
// [Start TextUtils_getStringFromResource]
public static getStringFromResource(uiContext: UIContext, source: Resource | string): string {
try {
if (typeof source === 'string') {
return source;
}
if (uiContext?.getHostContext()) {
return uiContext?.getHostContext()!.resourceManager.getStringSync(source);
}
return '';
} catch (error) {
let code = (error as BusinessError).code;
let message = (error as BusinessError).message;
console.log('getStringFromResource' + code + message);
return '';
}
}
// [End TextUtils_getStringFromResource]
/**
* Set up paragraph layout
* @param uiContext UI Context
* @param contentArray Typography content
* @param fontSize
* @param textWidth
*/
public static getParagraph(uiContext: UIContext, contentArray: RichTextContentModel[], fontSize: number,
textMaxWidth: number): text.Paragraph {
// Set up paragraph layout
// [Start TextUtils_paragraphBuilder]
let myTextStyle: text.TextStyle = {
fontSize: uiContext?.fp2px(fontSize)
};
let myParagraphStyle: text.ParagraphStyle = {
textStyle: myTextStyle,
align: text.TextAlign.START,
maxLines: 300, // Just specify a large enough number of rows
breakStrategy: text.BreakStrategy.GREEDY,
wordBreak: text.WordBreak.BREAK_WORD
};
let fontCollection = new text.FontCollection();
let paragraphGraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection);
// [End TextUtils_paragraphBuilder]
contentArray.forEach((item, index) => {
if (item.type === 'topic') {
// The text specifies the style
paragraphGraphBuilder.pushStyle({
fontSize: fontSize,
});
paragraphGraphBuilder.addText(item.content);
} else if (item.type === 'images') {
item.images.forEach(() => {
// Add a placeholder to specify the style
// [Start TextUtils_addPlaceholder]
paragraphGraphBuilder.addPlaceholder({
width: item.imgWidth,
height: item.imgHeight,
align: text.PlaceholderAlignment.BOTTOM_OF_ROW_BOX,
baseline: text.TextBaseline.IDEOGRAPHIC,
baselineOffset: 0
});
// [End TextUtils_addPlaceholder]
});
} else if (item.type === 'link') {
// [Start TextUtils_addText]
paragraphGraphBuilder.pushStyle({
fontSize: fontSize,
});
paragraphGraphBuilder.addText(item.content);
// [End TextUtils_addText]
} else {
paragraphGraphBuilder.pushStyle({
fontSize: fontSize,
});
paragraphGraphBuilder.addText(item.content);
}
})
// [Start TextUtils_getParagraph_build]
let paragraph = paragraphGraphBuilder.build();
paragraph.layoutSync(textMaxWidth);
// [End TextUtils_getParagraph_build]
return paragraph;
}
// [End TextUtils_getParagraph]
// [Start TextUtils_getShortRichText]
/**
* Get the collapsed dash word data
*
* @param uiContext UI Context
* @param dataModel Content Model
* @param textSectionAttribute Rich Text Attribute
* @param lastSpan Expand the collapse button text
* @returns Short paragraph strings
*/
public static getShortRichText(uiContext: UIContext, dataModel: RichTextModel, textSectionAttribute: RichTextSectionAttribute,
lastSpan: string): RichTextContentModel[] {
let paragraph =
TextUtils.getParagraph(uiContext, dataModel.textArray, dataModel.fontSize, textSectionAttribute.constraintWidth);
const minLinesTextSize: SizeOptions | undefined = uiContext?.getMeasureUtils().measureTextSize({
textContent: suffix + lastSpan,
fontSize: dataModel.fontSize,
});
const widthMore = uiContext?.px2vp(Number(minLinesTextSize?.width));
// Calculates the coordinates of the last text before three points
let x: number = 0;
let y: number = 0;
// [Start TextUtils_getShortRichText_y]
for (let i = 0; i < textSectionAttribute.maxLines; i++) {
y += i === textSectionAttribute.maxLines - 1 ? paragraph.getLineHeight(i) / 2 : paragraph.getLineHeight(i);
}
// [End TextUtils_getShortRichText_y]
// [Start TextUtils_getShortRichText_x]
if (paragraph.getLineWidth(textSectionAttribute.maxLines - 1) + Number(widthMore) >
textSectionAttribute.constraintWidth) {
x = textSectionAttribute.constraintWidth - Number(widthMore);
} else {
x = paragraph.getLineWidth(textSectionAttribute.maxLines - 1)
}
// [End TextUtils_getShortRichText_x]
// [Start TextUtils_getShortRichText_Index]
// The conversion coordinates correspond to the index
let positionWithAffinity = paragraph.getGlyphPositionAtCoordinate(x, y);
let index = 0;
if (positionWithAffinity.affinity === text.Affinity.UPSTREAM) {
index = positionWithAffinity.position;
} else {
index = positionWithAffinity.position + 1;
}
// [Start TextUtils_getShortRichText_Index]
// The position of the last character
let lastIndex = index - 1;
let shortContentArray: RichTextContentModel[] = [];
for (let i = 0; i < dataModel.textArray.length; i++) {
let model = dataModel.textArray[i];
// Determine which text message is in the truncated position, process it, and sort out the display content
if (0 <= lastIndex - model.index && lastIndex - model.index <= model.length) {
model.shortContent = model.content.substring(0, lastIndex - model.index) + suffix;
let b = lastIndex - model.index;
let a = model.content.substring(0, lastIndex - model.index);
shortContentArray.push(model);
return shortContentArray;
} else {
shortContentArray.push(model);
}
}
return [];
}
}
// [End TextUtils]