From 4df444ed0ee9f5ced686de9bc04e6c4535d0859e Mon Sep 17 00:00:00 2001 From: xiaoxiao Date: Fri, 11 Jul 2025 17:15:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=82=A3=E8=80=85=E7=9B=B8=E5=85=B3=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- commons/basic/Index.ets | 4 +- .../src/main/ets/Views/InputPopWindow.ets | 53 ++++ .../src/main/ets/constants/BasicConstant.ets | 1 + features/patient/Index.ets | 4 +- .../ets/components/GroupManagementComp.ets | 231 +++++++++++++++ .../main/ets/components/PatientApplyPage.ets | 2 +- .../ets/components/PatientDetailsComp.ets | 262 +++++++++++++++--- .../main/ets/components/PatientSetMsgPage.ets | 45 +-- .../src/main/ets/models/ApplyModel.ets | 9 + .../patient/src/main/ets/utils/Models.ets | 218 +++++++++++++++ .../patient/src/main/ets/utils/TextUtils.ets | 241 ++++++++++++++++ .../src/main/ets/views/TextExpandView.ets | 141 ++++++++++ .../base/media/course_invoice_to_details.png | Bin 0 -> 968 bytes .../base/media/patient_details_man.png | Bin 0 -> 3027 bytes .../base/media/patient_details_wuman.png | Bin 0 -> 1877 bytes .../PatientsPage/GroupManagementPage.ets | 14 + .../resources/base/profile/main_pages.json | 3 +- 17 files changed, 1159 insertions(+), 69 deletions(-) create mode 100644 commons/basic/src/main/ets/Views/InputPopWindow.ets create mode 100644 features/patient/src/main/ets/components/GroupManagementComp.ets create mode 100644 features/patient/src/main/ets/utils/Models.ets create mode 100644 features/patient/src/main/ets/utils/TextUtils.ets create mode 100644 features/patient/src/main/ets/views/TextExpandView.ets create mode 100644 features/patient/src/main/resources/base/media/course_invoice_to_details.png create mode 100644 features/patient/src/main/resources/base/media/patient_details_man.png create mode 100644 features/patient/src/main/resources/base/media/patient_details_wuman.png create mode 100644 products/expert/src/main/ets/pages/PatientsPage/GroupManagementPage.ets diff --git a/commons/basic/Index.ets b/commons/basic/Index.ets index 59bdaab..b1b63bf 100644 --- a/commons/basic/Index.ets +++ b/commons/basic/Index.ets @@ -83,4 +83,6 @@ export { PhotoGrids } from './src/main/ets/components/PhotoGrids' export { ViewImageInfo } from './src/main/ets/models/ViewImageInfo' -export { ChangePhotoGrids } from './src/main/ets/components/ChangePhotoGrids' \ No newline at end of file +export { ChangePhotoGrids } from './src/main/ets/components/ChangePhotoGrids' + +export { InputPopWindow } from './src/main/ets/Views/InputPopWindow' \ No newline at end of file diff --git a/commons/basic/src/main/ets/Views/InputPopWindow.ets b/commons/basic/src/main/ets/Views/InputPopWindow.ets new file mode 100644 index 0000000..779aa61 --- /dev/null +++ b/commons/basic/src/main/ets/Views/InputPopWindow.ets @@ -0,0 +1,53 @@ +@CustomDialog +export struct InputPopWindow { + controller: CustomDialogController; // 控制器(必须) + @Prop title: string; // 提示语(从父组件传入) + @Link inputValue: string; // 输入框值(双向绑定) + + // 按钮回调函数(通过构造函数传入) + private cancel?: () => void; + private confirm?: (value: string) => void; + + build() { + Column() { + // 提示语标题 + Text(this.title) + .fontSize(18) + .margin({ top: 20, bottom: 15 }); + + // 输入框 + TextInput({ placeholder: '请输入内容', text: this.inputValue }) + .width('90%') + .height(50) + .onChange((value: string) => { + this.inputValue = value; // 双向绑定更新值 + }) + .border({ width: 1, color: '#CCCCCC' }) + .borderRadius(4) + + // 按钮行(取消 + 确定) + Flex({ justifyContent: FlexAlign.SpaceAround }) { + Button('取消') + .backgroundColor('#FFFFFF') + .fontColor('#666666') + .onClick(() => { + this.cancel?.(); // 触发取消回调 + this.controller.close(); // 关闭弹窗 + }) + + Button('确定') + .backgroundColor('#317AFF') + .fontColor('#FFFFFF') + .onClick(() => { + this.confirm?.(this.inputValue); // 传递输入值给父组件 + this.controller.close(); + }) + } + .margin({ top: 20, bottom: 10 }) + .width('100%') + } + .width('100%') + .padding(10) + .borderRadius(16) // 圆角弹窗 + } +} diff --git a/commons/basic/src/main/ets/constants/BasicConstant.ets b/commons/basic/src/main/ets/constants/BasicConstant.ets index 4a221f9..ebaac48 100644 --- a/commons/basic/src/main/ets/constants/BasicConstant.ets +++ b/commons/basic/src/main/ets/constants/BasicConstant.ets @@ -40,6 +40,7 @@ export class BasicConstant { static readonly patientCard = BasicConstant.urlExpertAPI+'patientCard' static readonly toAddNickname = BasicConstant.urlExpert+'toAddNickname' static readonly patientDetail = BasicConstant.urlExpert+'patientDetail' + static readonly GroupList = BasicConstant.urlExpertApp+'GroupList' static readonly getStartpage=BasicConstant.urlExpertApp + "startpage"; static readonly meetingListV2=BasicConstant.urlExpertAPI + "meetingListV2"; static readonly meetingV2Video=BasicConstant.urlExpertAPI + "meetingV2Video"; diff --git a/features/patient/Index.ets b/features/patient/Index.ets index 8751295..9d8ad09 100644 --- a/features/patient/Index.ets +++ b/features/patient/Index.ets @@ -14,4 +14,6 @@ export { BuildOrEditGroupPage } from './src/main/ets/components/BuildOrEditGroup export { PatientsListComp } from './src/main/ets/components/PatientsListComp' -export { PatientDetailsComp } from './src/main/ets/components/PatientDetailsComp' \ No newline at end of file +export { PatientDetailsComp } from './src/main/ets/components/PatientDetailsComp' + +export { GroupManagementComp } from './src/main/ets/components/GroupManagementComp' \ No newline at end of file diff --git a/features/patient/src/main/ets/components/GroupManagementComp.ets b/features/patient/src/main/ets/components/GroupManagementComp.ets new file mode 100644 index 0000000..39d6191 --- /dev/null +++ b/features/patient/src/main/ets/components/GroupManagementComp.ets @@ -0,0 +1,231 @@ +import { BasicConstant, hdHttp, HdResponse, authStore, HdNav , HdLoadingDialog, ChangeUtil,DefaultHintProWindows,InputPopWindow } from '@itcast/basic/Index' +import { promptAction, router } from '@kit.ArkUI' +import { groupModel } from '../models/PatientsGroupModel' +import HashMap from '@ohos.util.HashMap'; +import { BusinessError } from '@kit.BasicServicesKit'; + +@Component +export struct GroupManagementComp { + @State params:Record = router.getParams() as Record + private hintWindowDialog!: CustomDialogController + @State dialogInputValue: string = ''; // 绑定输入框的值 + // InputPopWindow: CustomDialogController; // 控制器实例 + @State groupList: Array> = [] + @State selectedGroups: Array> = [] + + dialog: CustomDialogController = new CustomDialogController({ + builder: HdLoadingDialog({ message: '加载中...' }), + customStyle: true, + alignment: DialogAlignment.Center + }) + + private hintPopWindowDialog() { + this.hintWindowDialog = new CustomDialogController({ + builder:DefaultHintProWindows({ + controller:this.hintWindowDialog, + message:'最多只能选三项', + confirmTitleColor: '#333333', + selectedButton: (index:number)=>{ + this.hintWindowDialog.close(); + } + }), + alignment: DialogAlignment.Center, + cornerRadius:24, + backgroundColor: ('rgba(0,0,0,0.5)'), + }) + } + + aboutToAppear() { + this.hintPopWindowDialog() + this.addShowTagAction() + this.fetchGroups() + } + + addShowTagAction() { + if (!ChangeUtil.stringIsUndefinedAndNull(this.params.groupNames)) { + this.selectedGroups = convertToRecordArray(String(this.params.groupNames),String(this.params.groupUuids)) + } + } + + fetchGroups() { + this.dialog.open() + hdHttp.post(BasicConstant.GroupList, { + "expert_uuid": authStore.getUser().uuid + } as Record).then(async (res: HdResponse) => { + this.dialog.close(); + let json:Record>> = JSON.parse(res+'') as Record>> + if(json.code == '1') { + console.info('上一层传过来的group:',this.params.groupNames) + // groupUuids + this.groupList = json.data as Array> + } else { + console.error('获取分组列表信息失败:'+json.message) + promptAction.showToast({ message: String(json.message), duration: 1000 }) + } + }).catch((err: BusinessError) => { + this.dialog.close(); + console.error(`Response fails: ${err}`); + }) + } + + onSelectGroup(item: Record) { + const idx = this.selectedGroups.findIndex(g => g.uuid === item.uuid) + if (idx > -1) { + this.selectedGroups.splice(idx, 1) + this.selectedGroups = [...this.selectedGroups] + } else { + if (this.selectedGroups.length >= 3) { + this.hintWindowDialog.open() + return + } + this.selectedGroups.push(item) + this.selectedGroups = [...this.selectedGroups] + } + } + + getSelected(item:Record):boolean { + let selected = this.selectedGroups.some(g => g.uuid === item.uuid) + return selected + } + + isChangeColor(showItem:Record):boolean { + return this.selectedGroups.some(item=>`${item.uuid}` === `${showItem.uuid}`) + } + + onAddGroup() { + + } + + confirmAddGroup() { + // if (!this.newGroupName.trim()) { + // promptAction.showToast({ message: '请输入分组名', duration: 1000 }) + // return + // } + // if (this.newGroupName.length > 10) { + // promptAction.showToast({ message: '最多10个字符', duration: 1000 }) + // return + // } + // this.addLoading = true + // const params = { + // expert_uuid: authStore.getUser().uuid, + // name: this.newGroupName.trim(), + // patient_uuid: '' + // } + // hdHttp.post(BasicConstant.addGroup, params).then(async (res: HdResponse) => { + // this.addLoading = false + // let json = JSON.parse(res + '') as { code: number, message: string } + // if (json.code === 1) { + // this.showAddDialog = false + // this.addDialog.close() + // this.fetchGroups() + // promptAction.showToast({ message: '添加成功', duration: 1000 }) + // } else { + // promptAction.showToast({ message: json.message, duration: 1000 }) + // } + // }).catch(() => { + // this.addLoading = false + // }) + } + + build() { + Column() { + HdNav({ title: '分组管理', showRightIcon: false, hasBorder: true, rightText: '保存', showRightText: true }) + // 已选分组 + Row() { + Flex({ justifyContent: FlexAlign.Start, wrap: FlexWrap.Wrap }) { + ForEach(this.selectedGroups, (item: Record) => { + Text(item.name) + .border({ width: 1, color: $r('app.color.main_color') }) + .fontColor($r('app.color.main_color')) + .fontSize(16) + .borderRadius(10) + .padding({ + left: 10, + right: 10, + top: 5, + bottom: 5 + }) + .margin({ right: 10 }) + .borderRadius(20) + }) + } + } + .alignItems(VerticalAlign.Top) + .justifyContent(FlexAlign.Start) + .width('100%').height(100) + .backgroundColor(Color.White) + .padding({left:10,top:10,right:10}) + Column() { + Row() { + Text('所有分组').fontColor($r('app.color.main_color')).fontSize(15) + Text('(选择或取消分组)').fontColor('#999999').fontSize(15) + } + .margin({ left: 10, top: 10 }) + .justifyContent(FlexAlign.Start) + + Row() { + Flex({ justifyContent: FlexAlign.Start, wrap: FlexWrap.Wrap }) { + ForEach(this.groupList, (item: Record) => { + Text(item.name) + .border({ width: 1, color: this.getSelected(item)||this.isChangeColor(item) ? '#981308' : '#999999' }) + .fontColor(this.getSelected(item)||this.isChangeColor(item) ? '#981308' : '#999999') + .fontSize(16) + .padding({ + left: 10, + right: 10, + top: 5, + bottom: 5 + }) + .margin({ left: 10, top: 10}) + .borderRadius(10) + .textAlign(TextAlign.Center) + .backgroundColor(Color.White) + .onClick(() => this.onSelectGroup(item)) + }) + } + } + .justifyContent(FlexAlign.Start) + } + .width('100%') + .height('40%') + .alignItems(HorizontalAlign.Start) + .justifyContent(FlexAlign.Start) + .backgroundColor(Color.White) + .margin({top:10}) + .layoutWeight(1) + + Text('添加分组') + .width('100%') + .height(50) + .fontSize(20) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .backgroundColor('#3CC7C0') + .margin({bottom:10}) + .onClick(()=>this.onAddGroup()) + } + .height('100%') + .backgroundColor('#f4f4f4') + .justifyContent(FlexAlign.Start) + .alignItems(HorizontalAlign.Start) + } +} + +export function convertToRecordArray( + namesStr: string, + uuidsStr: string +): Record[] { + const names: string[] = namesStr.split(",").map(item => item.trim()); + const uuids: string[] = uuidsStr.split(",").map(item => item.trim()); + + const maxLength: number = Math.max(names.length, uuids.length); + const result: Record[] = []; + + for (let i = 0; i < maxLength; i++) { + const name: string = i < names.length ? names[i] : ""; + const uuid: string = i < uuids.length ? uuids[i] : ""; + const newObject:Record = {"name":name,"uuid":uuid} as Record + result.push(newObject); + } + return result; +} diff --git a/features/patient/src/main/ets/components/PatientApplyPage.ets b/features/patient/src/main/ets/components/PatientApplyPage.ets index 84c8b66..d67346d 100644 --- a/features/patient/src/main/ets/components/PatientApplyPage.ets +++ b/features/patient/src/main/ets/components/PatientApplyPage.ets @@ -181,7 +181,7 @@ export struct PatientApplyPage { .onClick(()=>{ router.pushUrl({ url: 'pages/WebView/WebPage', // 目标url - params: {url:BasicConstant.wxUrl+'expert/expertcodeimg?expert_uuid='+authStore.getUser().uuid,title:'我的二维码'} + params: {url:BasicConstant.wxUrl+'expert/expertcodeimg?expert_uuid='+authStore.getUser().uuid,title:'随访二维码'} }) }) }.width('100%').height(56).backgroundColor(Color.White).alignItems(VerticalAlign.Top) diff --git a/features/patient/src/main/ets/components/PatientDetailsComp.ets b/features/patient/src/main/ets/components/PatientDetailsComp.ets index e6d037f..909113b 100644 --- a/features/patient/src/main/ets/components/PatientDetailsComp.ets +++ b/features/patient/src/main/ets/components/PatientDetailsComp.ets @@ -1,11 +1,13 @@ -import { authStore, HdNav, PositionSelectedSheet } from '@itcast/basic'; -import { promptAction, router } from '@kit.ArkUI' -import { HdLoadingDialog,DefaultHintProWindows } from '@itcast/basic' +import { authStore, ChangeUtil, HdNav } from '@itcast/basic'; +import { LevelMode, promptAction, router } from '@kit.ArkUI' +import { HdLoadingDialog } from '@itcast/basic' import { BasicConstant,hdHttp, HdResponse ,logger} from '@itcast/basic/Index' import { BusinessError } from '@kit.BasicServicesKit'; import HashMap from '@ohos.util.HashMap'; -import { patientListModel } from '../models/PatientsGroupModel' -import measure from '@ohos.measure'; +import { TextSectionAttribute,LastSpanAttribute } from '../utils/Models' +import { applyListModel } from '../models/ApplyModel' +import { TextExpandView } from '../views/TextExpandView' +import call from '@ohos.telephony.call' @Component export struct PatientDetailsComp { @@ -16,10 +18,13 @@ export struct PatientDetailsComp { @State footerArray:Array> = [] @State patientCase:Array> = [] @State patientData:Record = {} - @State patientData2:Record = {} - @State medicalHistoryContent:string = '' - @State isExpanded: boolean = false; // 展开状态 - @State showExpandBtn: boolean = false; // 是否显示操作按钮 + @State patientData2:applyListModel = {} + @State patientGroupData:Record = {} + @State patientAge:string = '' + @State nationName:string = '' + @State addresString:string = '' + @State medicalHistoryContent:TextSectionAttribute = new TextSectionAttribute() + @State lastSpanAttribute:LastSpanAttribute = new LastSpanAttribute(0, 7, ['展开全部', '收起'], 15, $r('app.color.main_color')) dialog: CustomDialogController = new CustomDialogController({ builder: HdLoadingDialog({ message: '加载中...' }), @@ -50,6 +55,7 @@ export struct PatientDetailsComp { router.back() } else { if(json.code == '200') { + this.patientGroupData = json this.getPatientDetailsData(String(json.group["name"])) } else { console.error('患者详情请求失败:'+json.message) @@ -71,16 +77,8 @@ export struct PatientDetailsComp { logger.info('Response toAddNickname'+res); let json:Record> = JSON.parse(res+'') as Record>; if(json.code == '1') { - this.getPatientData() this.patientData = json.patientEx as Record - let nickname = this.patientData.nickname - let note = this.patientData.note - let mobile = this.patientData.mobile - if (nickname.length>0) { - this.groupArray = [{"title":"备注","content":String(nickname),"prompt":"给患者添加备注名"},{"title":"分组","content":String(groupType),"prompt":"通过分组给患者分类"},{"title":"描述","content":String(note),"prompt":"补充患者关键信息,方便随访患者"},{"title":"电话号码","content":String(mobile),"prompt":""}] - } else { - this.groupArray = [{"title":"分组","content":String(groupType),"prompt":"通过分组给患者分类"},{"title":"描述","content":String(note),"prompt":"补充患者关键信息,方便随访患者"},{"title":"电话号码","content":String(mobile),"prompt":""}] - } + this.getPatientData(groupType) } else { console.error('获取患者信息失败:'+json.message) promptAction.showToast({ message: String(json.message), duration: 1000 }) @@ -91,7 +89,7 @@ export struct PatientDetailsComp { }) } - getPatientData() { + getPatientData(groupType:string) { this.dialog.open() hdHttp.post(BasicConstant.patientDetail, { "patientUuid":String(this.params.patient_uuid) @@ -100,9 +98,46 @@ export struct PatientDetailsComp { logger.info('Response patientDetail'+res); let json:Record | Array>> = JSON.parse(res+'') as Record | Array>>; if(json.code == '1') { - this.patientData2 = json.data as Record - this.medicalHistoryContent = String(json.medicalHistoryContent) + this.patientData2 = json.data as applyListModel + this.patientData2.note = String(this.patientGroupData.group["note"]) + this.patientData2.nickname = String(this.patientData.nickname) + this.patientData2.groupType = String(this.patientGroupData.group["name"]) + this.patientData2.groupUuid = String(this.patientGroupData.group["uuid"]) + this.patientData2.patientUuid = String(this.patientData2.uuid) + if (String(json.age) == '0') { + this.patientAge = '0' + } else if (String(json.age) == '-1') { + this.patientAge = '未知' + } else { + this.patientAge = String(json.age) + } + if (ChangeUtil.stringIsUndefinedAndNull(String(this.patientData2.nationName))) { + this.nationName = '未知' + } else { + this.nationName = String(this.patientData2.nationName) + } + let countyName = ChangeUtil.stringIsUndefinedAndNull(String(this.patientData2.countyName))?'':String(this.patientData2.countyName) + let provName = ChangeUtil.stringIsUndefinedAndNull(String(this.patientData2.provName))?'':String(this.patientData2.provName) + let cityName = ChangeUtil.stringIsUndefinedAndNull(String(this.patientData2.cityName))?'':String(this.patientData2.cityName) + if (String(countyName) == String(cityName)) { + this.addresString = String(provName)+String(cityName) + } else { + this.addresString = String(provName)+String(provName)+String(countyName) + } + if (this.addresString.length <= 0) { + this.addresString = '未知' + } + let content = ChangeUtil.stringIsUndefinedAndNull(String(json.medicalHistoryContent))?'':String(json.medicalHistoryContent) + this.medicalHistoryContent = new TextSectionAttribute(content, 2, '#666666', 15, 16, 350) this.patientCase = json.patientCase as Array> + let nickname = this.patientData.nickname + let note = this.patientData.note + let mobile = this.patientData2.mobile + if (ChangeUtil.stringIsUndefinedAndNull(String(nickname))) { + this.groupArray = [{"title":"备注","content":String(nickname),"prompt":"给患者添加备注名"},{"title":"分组","content":String(groupType),"prompt":"通过分组给患者分类"},{"title":"描述","content":String(note),"prompt":"补充患者关键信息,方便随访患者"},{"title":"电话号码","content":String(mobile),"prompt":""}] + } else { + this.groupArray = [{"title":"分组","content":String(groupType),"prompt":"通过分组给患者分类"},{"title":"描述","content":String(note),"prompt":"补充患者关键信息,方便随访患者"},{"title":"电话号码","content":String(mobile),"prompt":""}] + } } else { console.error('获取患者信息失败:'+json.message) promptAction.showToast({ message: String(json.message), duration: 1000 }) @@ -130,50 +165,186 @@ export struct PatientDetailsComp { } }) Scroll(this.scroller){ - this.historyView() - this.footerView() - }.width('100%').height('calc(100% - 56vp)').backgroundColor('#f4f4f4') + Column(){ + this.patientsView() + this.otherMsgView() + this.historyView() + if (this.patientCase.length > 0) { + this.patientCaseView() + } + this.footerView() + } + .width('100%') + .justifyContent(FlexAlign.Start) + } + .width('100%') + .height('calc(100% - 56vp)') + .backgroundColor('#f4f4f4') .scrollBar(BarState.Off) + .align(Alignment.TopStart) } .width('100%').height('100%') } .height('100%') } + @Builder + patientsView(){ + Row(){ + Image(BasicConstant.urlImage+this.patientData2.photo) + .alt($r('app.media.userPhoto_default')) + .width(60) + .height(60) + .borderRadius(6) + .margin({left:15,top:15}) + Column(){ + Row({space:5}){ + Text(ChangeUtil.stringIsUndefinedAndNull(this.patientData.nickname)?this.patientData2.realName:this.patientData.nickname) + .fontSize(18) + .fontColor('#333333') + Image(String(this.patientData2.sex) == '0'?$r('app.media.patient_details_man'):$r('app.media.patient_details_wuman')) + .width(18) + .height(18) + } + .margin({top:15}) + .justifyContent(FlexAlign.Start) + .alignItems(VerticalAlign.Top) + if (!ChangeUtil.stringIsUndefinedAndNull(this.patientData.nickname)) { + Text('昵称:'+String(this.patientData2.realName)) + .fontSize(14) + .fontColor('#666666') + .margin({top:8}) + } + Text('年龄:'+this.patientAge+' | '+'民族:'+this.nationName) + .fontSize(14) + .fontColor('#666666') + .margin({top:8}) + Text('城区:'+this.addresString) + .fontSize(14) + .fontColor('#666666') + .margin({top:8,bottom:30}) + } + .margin({left:15}) + .justifyContent(FlexAlign.Start) + .alignItems(HorizontalAlign.Start) + } + .width('100%') + .backgroundColor(Color.White) + .justifyContent(FlexAlign.Start) + .alignItems(VerticalAlign.Top) + .margin({bottom:15}) + } + + @Builder + otherMsgView(){ + List(){ + ForEach(this.groupArray,(item:Record)=>{ + ListItem(){ + Row() { + Text(item.title) + .fontSize(15) + .fontColor('#333333') + .margin({left:15}) + .layoutWeight(1) + Text(ChangeUtil.stringIsUndefinedAndNull(item.content)?item.prompt:item.content) + .fontSize(15) + .fontColor(!ChangeUtil.stringIsUndefinedAndNull(item.content)&&item.title == '电话号码'?$r('app.color.main_color'):'#666666') + .textAlign(TextAlign.End) + .margin({right:5}) + .maxLines(1) + .textOverflow({overflow:TextOverflow.Ellipsis}) + .width('calc(100% - 100vp)') + Image($r('app.media.course_invoice_to_details')) + .width(6) + .height(10) + .margin({right:10}) + .visibility(item.title == '电话号码'?Visibility.Hidden:Visibility.Visible) + } + .width('100%') + .height(49) + .backgroundColor(Color.White) + .onClick(()=>{ + if (item.title == '电话号码') { + if (call.hasVoiceCapability() && !ChangeUtil.stringIsUndefinedAndNull(item.content)) { + call.makeCall(item.content, (err) => { + if (err) console.error("拨号失败:" + JSON.stringify(err)); + }); + } + } else { + router.pushUrl({ + url:'pages/PatientsPage/PatientMsgSetPage', + params:{"model":this.patientData2} + }) + } + }) + }.width('100%').height(50) + }) + } + .width('100%') + .margin({bottom:15}) + } + @Builder historyView(){ Column({space:10}){ Text('患者病史') .fontSize(15) .fontColor('#333333') - - Text(this.medicalHistoryContent) - .fontSize(16) - .lineHeight(22) - .maxLines(this.isExpanded ? 0 : 2) - .textOverflow({ overflow: TextOverflow.Ellipsis }) - .onAreaChange((_, area) => { - let fullHeight = measure.measureTextSize({ - textContent: this.medicalHistoryContent, - fontSize: 15, - maxLines:2 - }).height; - this.showExpandBtn = Number(area.height) < Number(fullHeight); + + if (this.medicalHistoryContent.title) { + TextExpandView({ + textSectionAttribute: this.medicalHistoryContent, + lastSpanAttribute: this.lastSpanAttribute }) - // 操作按钮(独立可点击区域) - if (this.showExpandBtn) { - Text(this.isExpanded ? "...收起" : "..展开全部") - .fontSize(15) - .fontColor($r('app.color.main_color')) // 红色标识可点击 - .onClick(() => { - this.isExpanded = !this.isExpanded; // 切换状态 - }) + } else { + Text('暂无') + .fontSize(14) + .fontColor('#666666') + .width('100%') + .textAlign(TextAlign.Start) } } .alignItems(HorizontalAlign.Start) .backgroundColor(Color.White) .width('100%') .padding(15) + .margin({bottom:15}) + } + + @Builder + patientCaseView(){ + Column(){ + Text('检查报告') + .fontSize(15) + .fontColor('#333333') + .margin({bottom:10}) + + Grid(){ + ForEach(this.patientCase,(item:Record)=>{ + GridItem(){ + Column(){ + Text(String(item.createDate).substring(0,10)) + .fontSize(15) + .fontColor('#999999') + Text(String(item.diseaseName)) + .fontSize(15) + .fontColor('#333333') + .margin({top:10}) + } + .justifyContent(FlexAlign.Center) + .width(130) + .height(70) + .backgroundColor('#f4f4f4') + .borderRadius(3) + } + }) + } + } + .alignItems(HorizontalAlign.Start) + .backgroundColor(Color.White) + .width('100%') + .padding(15) + .margin({bottom:15}) } @Builder @@ -186,6 +357,7 @@ export struct PatientDetailsComp { .width(20).height(20) Text(item.title) .fontSize(15) + .fontColor('#333333') } .height(49) .width('100%') diff --git a/features/patient/src/main/ets/components/PatientSetMsgPage.ets b/features/patient/src/main/ets/components/PatientSetMsgPage.ets index 09c046e..473666d 100644 --- a/features/patient/src/main/ets/components/PatientSetMsgPage.ets +++ b/features/patient/src/main/ets/components/PatientSetMsgPage.ets @@ -1,4 +1,4 @@ -import { authStore, HdNav } from '@itcast/basic'; +import { authStore, ChangeUtil, HdNav } from '@itcast/basic'; import { applyListModel } from '../models/ApplyModel' import HashMap from '@ohos.util.HashMap'; import { HdLoadingDialog } from '@itcast/basic' @@ -20,14 +20,14 @@ interface paramsCallData { @Component export struct PatientSetMsgPage { - @State params:paramsCallData = router.getParams() as paramsCallData; - @State noteName: string | undefined = ''; - @State contentFrist:string | undefined = ''; - @State groupName: string = '通过分组给患者分类'; - @State maxDescribe:string = '0'; - @State descibe:string = ''; - @State isNote:boolean = false; - @State isDescibe:boolean = false; + @State params:paramsCallData = router.getParams() as paramsCallData + @State noteName: string | undefined = ChangeUtil.stringIsUndefinedAndNull(this.params.model.nickname)?'':String(this.params.model.nickname) + @State contentFrist:string | undefined = '' + @State groupName: string = ChangeUtil.stringIsUndefinedAndNull(this.params.model.groupType)?'通过分组给患者分类':String(this.params.model.groupType) + @State maxDescribe:string = '0' + @State descibe:string = ChangeUtil.stringIsUndefinedAndNull(this.params.model.note)?'':String(this.params.model.note) + @State isNote:boolean = false + @State isDescibe:boolean = false dialog: CustomDialogController = new CustomDialogController({ builder: HdLoadingDialog({ message: '加载中...' }), @@ -108,16 +108,18 @@ export struct PatientSetMsgPage { } }) - Row() { - Text('申请消息为:'+this.contentFrist) - .fontSize(15).fontColor('#666666') - Text('填入') - .fontSize(15).fontColor('#3CC7C0') - }.justifyContent(FlexAlign.Start).margin({left:15,top:5}) - // .visibility(this.contentFrist?Visibility.Visible:Visibility.Hidden) - .onClick(()=>{ + if (!ChangeUtil.stringIsUndefinedAndNull(this.contentFrist)) { + Row() { + Text('申请消息为:'+this.contentFrist) + .fontSize(15).fontColor('#666666') + Text('填入') + .fontSize(15).fontColor('#3CC7C0') + }.justifyContent(FlexAlign.Start).margin({left:15,top:5}) + // .visibility(this.contentFrist?Visibility.Visible:Visibility.Hidden) + .onClick(()=>{ this.noteName = this.contentFrist?.substring(2); - }) + }) + } Text('分组') .margin({left:15,top:15}) @@ -137,7 +139,10 @@ export struct PatientSetMsgPage { .borderRadius(4) .margin({left:15,top:10}) .onClick(()=>{ - + router.pushUrl({ + url:'pages/PatientsPage/GroupManagementPage', + params:{groupNames:this.params.model.groupType,groupUuids:this.params.model.groupUuid} + }) }) Text('描述') @@ -145,7 +150,7 @@ export struct PatientSetMsgPage { .fontSize(15).fontColor('#333333') Column() { - TextArea({ placeholder: '补充患者关键信息,方便随访患者' }) + TextArea({ placeholder: '补充患者关键信息,方便随访患者',text:this.descibe }) .fontSize(15).placeholderColor('#999999') .fontColor('#333333') .backgroundColor('#f4f4f4') diff --git a/features/patient/src/main/ets/models/ApplyModel.ets b/features/patient/src/main/ets/models/ApplyModel.ets index 366fb71..44ce5ce 100644 --- a/features/patient/src/main/ets/models/ApplyModel.ets +++ b/features/patient/src/main/ets/models/ApplyModel.ets @@ -25,6 +25,15 @@ export class applyListModel { expertUuid?:string; status?:number; content?:string; + nationName?:string; + provName?:string; + cityName?:string; + countyName?:string; + nation?:string; + note?:string + nickname?:string + groupType?:string + groupUuid?:string } export interface historyObjectModel { diff --git a/features/patient/src/main/ets/utils/Models.ets b/features/patient/src/main/ets/utils/Models.ets new file mode 100644 index 0000000..cc0ac69 --- /dev/null +++ b/features/patient/src/main/ets/utils/Models.ets @@ -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] diff --git a/features/patient/src/main/ets/utils/TextUtils.ets b/features/patient/src/main/ets/utils/TextUtils.ets new file mode 100644 index 0000000..d400e08 --- /dev/null +++ b/features/patient/src/main/ets/utils/TextUtils.ets @@ -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] \ No newline at end of file diff --git a/features/patient/src/main/ets/views/TextExpandView.ets b/features/patient/src/main/ets/views/TextExpandView.ets new file mode 100644 index 0000000..54eb0b5 --- /dev/null +++ b/features/patient/src/main/ets/views/TextExpandView.ets @@ -0,0 +1,141 @@ +/* + * 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 TextExpandView] +import { LastSpanAttribute, TextExpandModel, TextSectionAttribute } from '../utils/Models'; +import { TextUtils } from '../utils/TextUtils'; + +@Component +export struct TextExpandView { + //[StartExclude TextExpandView] + // Text chapter attribute class + @Prop @Watch('textSectionAttributeChange') textSectionAttribute: TextSectionAttribute; + // Controls the text or image properties of text folding + @Prop lastSpanAttribute: LastSpanAttribute; + // Whether to expand or not + @State expanded: boolean = false; + // Text expansion properties + @State textModifier: TextExpandModel = new TextExpandModel(); + uiContext = this.getUIContext() + + aboutToAppear(): void { + this.getIsExpanded(); + } + + //[EndExclude TextExpandView] + + // [Start TextExpandView_textSectionAttributeChange] + textSectionAttributeChange() { + this.textModifier.title = this.textSectionAttribute.title; + // this.lastSpanAttribute.content = this.lastSpanAttribute.content + // 重置展开状态 + this.expanded = false; + this.textModifier.exceedOneLine = false; + this.getIsExpanded(); + } + + // [End TextExpandView_textSectionAttributeChange] + + // [Start TextExpandView_getIsExpanded] + getIsExpanded() { + let titleSize: SizeOptions = this.uiContext.getMeasureUtils().measureTextSize({ + textContent: this.textSectionAttribute.title, //The text content is calculated + lineHeight: this.textSectionAttribute.lineHeight, + constraintWidth: this.textSectionAttribute.constraintWidth, //The text layout width is calculated + fontSize: this.textSectionAttribute.fontSize //The text font size is calculated + }); + let height = this.getUIContext().px2vp(Number(titleSize.height)); + if (height <= this.textSectionAttribute.lineHeight * 2) { + this.textModifier.needProcess = false; + this.textModifier.title = this.textSectionAttribute.title; + return; + } else { + this.textModifier.title = this.textSectionAttribute.title + this.textModifier.needProcess = true; + } + // 初始状态显示截断的文本 + this.collapseText(); + } + + // [End TextExpandView_getIsExpanded] + + build() { + Column({ space: 3 }) { + //[StartExclude TextExpandView] + Text() { + Span(this.textModifier.title) + if (this.textModifier.needProcess && !this.textModifier.exceedOneLine) { + Span(this.lastSpanAttribute.content[0]) + .fontColor(this.lastSpanAttribute.color) + } else if (this.textModifier.needProcess) { + Span(this.lastSpanAttribute.content[1]) + .fontColor(this.lastSpanAttribute.color) + } + } + .fontSize(this.lastSpanAttribute.size) + .width(this.textSectionAttribute.constraintWidth) + .lineHeight(this.textSectionAttribute.lineHeight) + + //[EndExclude TextExpandView] + } + .onClick(() => { + if (!this.textModifier.needProcess) { + return; + } + this.process(); + }) + } + + // [Start TextExpandView_process] + process(): void { + if (this.expanded) { + this.expanded = false; + this.collapseText(); + this.textModifier.exceedOneLine = false; + } else { + this.expanded = true; + this.expandText(); + this.textModifier.exceedOneLine = true; + } + } + + // [End TextExpandView_process] + + // [Start TextExpandView_expandText] + // Expand text + expandText(): void { + if (this.textModifier.needProcess) { + this.textModifier.title = this.textSectionAttribute.title; + } + } + + // [End TextExpandView_expandText] + + // [Start TextExpandView_collapseText] + // Collapse text + collapseText(): void { + if (!this.textModifier.needProcess) { + return; + } + this.textModifier.title = + TextUtils.getShortText( + this.uiContext, + this.textSectionAttribute, + this.expanded ? `${this.lastSpanAttribute.content[1]}` : `${this.lastSpanAttribute.content[0]}`); + // [End TextExpandView_collapseText] + } +} + +// [End TextExpandView] + diff --git a/features/patient/src/main/resources/base/media/course_invoice_to_details.png b/features/patient/src/main/resources/base/media/course_invoice_to_details.png new file mode 100644 index 0000000000000000000000000000000000000000..1f64e9115323e73cc97c4da2ae08be8914d39169 GIT binary patch literal 968 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 VzjI25Mdbhh002ovPDHLkV1h8kuP*=q literal 0 HcmV?d00001 diff --git a/features/patient/src/main/resources/base/media/patient_details_wuman.png b/features/patient/src/main/resources/base/media/patient_details_wuman.png new file mode 100644 index 0000000000000000000000000000000000000000..71335d92064f10b632f9cbee27fc8dd2b007e81b GIT binary patch literal 1877 zcmV-b2demqP)Px+4@pEpRA@uBntO~?XBEJI=gwnW+vO2~bxj%{#I|YTN>U}IQbh$Vk9jRl`iIp- zO0iLqL`f|#Hy{K2oMQmY-0Yd1ESmP(6gxkD(6<2s*IPs9PcB&>cruI>0> z`Qk2A{Sch3_7(w4rB?fM90#$$v{+nBi{FC2D~{7?>xeu`TV_+7RWcq}zIZpPKLM_v zc98J||3x~uQ!4iT%?zfiSGSSQJ_u~aADL#g=?DZ{q+ac@x-kc)x!eLI@GId;tFxH$ zd%%5J>h-f0eLGm8a08Ct05@A4#g~+wAitO|puQy{I$qE0&-p%F02hS65hU*uiq$Ux3zb zi<88%BEOcfdZ)#X9qjyZ>Sq=w$z_9|O1*NQ#f}|p-TEBT3@uI)%ZhB4u==pYjvcI6 zTtZ7<0MZsmv1Nq@E_Ivq_q}YfVF%0Q-UGow;0BAM1hU7_)*9*W|BuCn9n2?hnr<)f zNsFVHvWm!V+A>?Mc}F`~xtwCO@f}njm?CEwljRaMVHjbf)M~%98Z(1=2U;pEr=|N) z?X)_y$;WykWDY~?+sQyvv^^<0j%M=oUUG6*r%@q%WF0};~?2>xrn>L-ROV2D=ls1q7(D&MclxOK& z^l|CwY1s58m!2`O@dd>fC%zS`k5r9BvX&+iWO>CwOR-byi#$y;^Eo-td%}a9UpY%_!96j}6!{rMj({FUgZ*?aJTx7^ zDFf3&;TBpvjL?P1eDh`;ut93IJ(u>*__h#&t}_f>hj222%g8qA>-+cBbSDLi=FgEM zt5A6i)kTH?F5fB-(Ehf&W$)g>iyM2n{0>IPo=4->tK}6^tfyK%D$yXA*d_<_g}tW! z0@Rd5xq^?gAYYMs^^s^OM#H+X7pKMeA1i`+9MLaH7@o0#tt%}<+(7jBBuVpE50!hQ zUVUmDEXC;9?@?|~Viw^wTB+r-zwZ?rSgyDk^hb%DN6PX~#I2Mt{QJeBSSWoD=lp#x zSxW~iq*C#>`3Y_Ep_nUtANX1_&yn^3XNFf@x+iJAv%aF2wQM~z^`CqeH@ z=Gk}H#Jszf%hxk9<`2_XsYm$2eHz|dp)LO;sd#9-;*4yjZo6frbcd=d24MD|5? zN?6@y1>1*GPUP4tXHtu$Z{h^ke4&PtPh>yft5T~yWCiO%@kgIzP2>^UGMg{WGHJg1 zV`!_ExOf=w8L8EL#>_Aj3xzM@_;E6-NP7&}jbfdgWwuLi@30NbpXBGvS&WmF1W|JI z_VG7}Gth~#Obme@gx~<;{NDBIWTy^qeab`dg%EVprVOvYeiJR0Mt3ja11JkY{Zl^w z^3DJJDaHRRSu1}$@+kp7WJgd&@ToV^H&F4l?w63%VcLQ}SuUW{2D{QX)?#rU&UHY# z1DYKW_^Zr3(D~87`WL2h9jJ#*oqsl~V^QFUKjRId>W9)0qNi}d2_$ubv^zmp*I<$~ zK_alp29)|VxbL|)-^>sMDYDssW>cbv&SPT^=USxGO*%Up)45y48Myxgp5K#IK?miq P00000NkvXXu0mjfnkt^q literal 0 HcmV?d00001 diff --git a/products/expert/src/main/ets/pages/PatientsPage/GroupManagementPage.ets b/products/expert/src/main/ets/pages/PatientsPage/GroupManagementPage.ets new file mode 100644 index 0000000..13670aa --- /dev/null +++ b/products/expert/src/main/ets/pages/PatientsPage/GroupManagementPage.ets @@ -0,0 +1,14 @@ +import { GroupManagementComp } from 'patient' + +@Entry +@Component +struct GroupManagementPage { + + build() { + RelativeContainer() { + GroupManagementComp() + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/products/expert/src/main/resources/base/profile/main_pages.json b/products/expert/src/main/resources/base/profile/main_pages.json index 7347206..3cec50e 100644 --- a/products/expert/src/main/resources/base/profile/main_pages.json +++ b/products/expert/src/main/resources/base/profile/main_pages.json @@ -40,6 +40,7 @@ "pages/Netease/PreviewPhotoPage", "pages/Netease/InterrogationDetailCompPage", "pages/Netease/PatientSimplyPage", - "pages/Netease/MyOpinionPage" + "pages/Netease/MyOpinionPage", + "pages/PatientsPage/GroupManagementPage" ] } \ No newline at end of file