chore(hmos): 导入生产环境鸿蒙工程
- 以 D:\SmartSenior 生产工程为源,纳入 AppScope、entry、cjagent、hvigor 及根配置 - 移除 build-profile.json5 的 signingConfigs(p12/p7b/cer 路径与加密口令)及 products.signingConfig 引用 - 不纳入本地与开发产物:local.properties、.idea、.hvigor、.codegenie、demo、backup_a2a_native、SESSION_LOG.md、build_err.txt、build/、oh_modules - .gitignore 追加 .codegenie 与密钥文件通配(*.p12/*.p7b/*.cer/*.jks/*.keystore/*.pem)
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
// 老人端 · 膳食推荐(ArkTS 严格类型,无 any)
|
||||
// 接口:GET /elderly-portal/recommendations/
|
||||
import { router } from '@kit.ArkUI';
|
||||
import { promptAction } from '@kit.ArkUI';
|
||||
import { HdsNavigation, HdsNavigationTitleMode, ScrollEffectType } from '@kit.UIDesignKit';
|
||||
import { hdsMaterial } from '@hms.hds.hdsMaterial';
|
||||
import { BusinessError } from '@kit.BasicServicesKit';
|
||||
import { normalizeError } from '../../common/ApiConstants';
|
||||
import { api, RequestError } from '../../utils/Request';
|
||||
import { FontScaleLevel, FONT_SCALE_MAP } from '../../utils/FontScale';
|
||||
|
||||
interface Recommendation {
|
||||
id: number;
|
||||
service_date: string;
|
||||
meal_period: string;
|
||||
dish_name: string;
|
||||
price: string;
|
||||
reason: string;
|
||||
}
|
||||
|
||||
interface RecommendationsResponse {
|
||||
elderly_id: number | null;
|
||||
recommendations: Array<Recommendation>;
|
||||
}
|
||||
|
||||
function periodIcon(period: string): string {
|
||||
if (period === '早餐') {
|
||||
return '🌅';
|
||||
}
|
||||
if (period === '午餐') {
|
||||
return '🍚';
|
||||
}
|
||||
return '🌙';
|
||||
}
|
||||
|
||||
function periodColor(period: string): string {
|
||||
if (period === '早餐') {
|
||||
return '#FF9500';
|
||||
}
|
||||
if (period === '午餐') {
|
||||
return '#007AFF';
|
||||
}
|
||||
return '#34C759';
|
||||
}
|
||||
|
||||
function formatDateLabel(dateStr: string): string {
|
||||
if (!dateStr || dateStr.length === 0) {
|
||||
return '';
|
||||
}
|
||||
const parts: Array<string> = dateStr.split('-');
|
||||
if (parts.length !== 3) {
|
||||
return dateStr;
|
||||
}
|
||||
const month = parseInt(parts[1], 10);
|
||||
const day = parseInt(parts[2], 10);
|
||||
return `${month}月${day}日`;
|
||||
}
|
||||
|
||||
function isToday(dateStr: string): boolean {
|
||||
if (!dateStr || dateStr.length === 0) {
|
||||
return false;
|
||||
}
|
||||
const now = new Date();
|
||||
const mm = String(now.getMonth() + 1).padStart(2, '0');
|
||||
const dd = String(now.getDate()).padStart(2, '0');
|
||||
return dateStr === `${now.getFullYear()}-${mm}-${dd}`;
|
||||
}
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct ElderlyRecommendations {
|
||||
@StorageProp('fontScale') fontScaleLevel: FontScaleLevel = 'system';
|
||||
@State recommendations: Array<Recommendation> = [];
|
||||
@State loading: boolean = true;
|
||||
|
||||
private scroller: Scroller = new Scroller();
|
||||
|
||||
private scaleFor(): number {
|
||||
return FONT_SCALE_MAP[this.fontScaleLevel] ?? 1.0;
|
||||
}
|
||||
|
||||
aboutToAppear(): void {
|
||||
this.load();
|
||||
}
|
||||
|
||||
private async load(): Promise<void> {
|
||||
this.loading = true;
|
||||
try {
|
||||
const res = await api.get<RecommendationsResponse>('/elderly-portal/recommendations/');
|
||||
this.recommendations = res.recommendations;
|
||||
} catch (err) {
|
||||
const message = err instanceof RequestError ? err.message : normalizeError(err as BusinessError | Error);
|
||||
promptAction.showToast({ message: message });
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Builder
|
||||
RecommendCard(item: Recommendation) {
|
||||
Column({ space: 8 }) {
|
||||
Row({ space: 10 }) {
|
||||
Text(periodIcon(item.meal_period))
|
||||
.fontSize(Math.round(24 * this.scaleFor()))
|
||||
Text(`${item.meal_period} · ${isToday(item.service_date) ? '今日' : formatDateLabel(item.service_date)}`)
|
||||
.fontSize(Math.round(17 * this.scaleFor()))
|
||||
.fontWeight(FontWeight.Bold)
|
||||
.fontColor($r('app.color.text_primary'))
|
||||
Blank()
|
||||
Text(`¥${item.price}`)
|
||||
.fontSize(Math.round(16 * this.scaleFor()))
|
||||
.fontWeight(FontWeight.Bold)
|
||||
.fontColor('#FF9500')
|
||||
}
|
||||
.width('100%')
|
||||
|
||||
Text(item.dish_name)
|
||||
.fontSize(Math.round(20 * this.scaleFor()))
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.fontColor(periodColor(item.meal_period))
|
||||
.width('100%')
|
||||
|
||||
if (item.reason && item.reason.length > 0) {
|
||||
Text(item.reason)
|
||||
.fontSize(Math.round(15 * this.scaleFor()))
|
||||
.fontColor($r('app.color.text_secondary'))
|
||||
.lineHeight(22)
|
||||
.width('100%')
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.padding(16)
|
||||
.backgroundColor($r('app.color.background_card'))
|
||||
.borderRadius(18)
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
}
|
||||
|
||||
build() {
|
||||
HdsNavigation() {
|
||||
Column() {
|
||||
Scroll(this.scroller) {
|
||||
Column({ space: 12 }) {
|
||||
if (this.loading) {
|
||||
Text('加载中...')
|
||||
.fontSize(Math.round(16 * this.scaleFor()))
|
||||
.fontColor($r('app.color.inactive_tab'))
|
||||
.margin({ top: 40 })
|
||||
} else if (this.recommendations.length === 0) {
|
||||
Column({ space: 8 }) {
|
||||
Text('暂无膳食推荐')
|
||||
.fontSize(Math.round(20 * this.scaleFor()))
|
||||
.fontWeight(FontWeight.Bold)
|
||||
.fontColor($r('app.color.text_primary'))
|
||||
Text('护理团队会根据您的健康状况推送个性化餐食建议')
|
||||
.fontSize(Math.round(15 * this.scaleFor()))
|
||||
.fontColor($r('app.color.text_secondary'))
|
||||
.textAlign(TextAlign.Center)
|
||||
}
|
||||
.width('100%')
|
||||
.padding(24)
|
||||
.backgroundColor($r('app.color.background_card'))
|
||||
.borderRadius(16)
|
||||
.alignItems(HorizontalAlign.Center)
|
||||
} else {
|
||||
ForEach(this.recommendations, (item: Recommendation) => {
|
||||
Column() {
|
||||
this.RecommendCard(item)
|
||||
}
|
||||
.width('100%')
|
||||
}, (item: Recommendation) => String(item.id))
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.padding({ left: 16, right: 16, top: 92, bottom: 30 })
|
||||
}
|
||||
.width('100%')
|
||||
.layoutWeight(1)
|
||||
.scrollBar(BarState.Auto)
|
||||
.edgeEffect(EdgeEffect.Spring)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
}
|
||||
.mode(NavigationMode.Stack)
|
||||
.titleBar({
|
||||
content: {
|
||||
title: {
|
||||
mainTitle: '膳食推荐',
|
||||
},
|
||||
},
|
||||
style: {
|
||||
scrollEffectOpts: {
|
||||
enableScrollEffect: false,
|
||||
scrollEffectType: ScrollEffectType.GRADIENT_BLUR,
|
||||
},
|
||||
systemMaterialEffect: {
|
||||
materialType: hdsMaterial.MaterialType.ADAPTIVE,
|
||||
materialLevel: hdsMaterial.MaterialLevel.EXQUISITE,
|
||||
},
|
||||
},
|
||||
avoidLayoutSafeArea: false,
|
||||
enableComponentSafeArea: false,
|
||||
})
|
||||
.bindToScrollable([this.scroller])
|
||||
.hideBackButton(false)
|
||||
.titleMode(HdsNavigationTitleMode.MINI)
|
||||
.ignoreLayoutSafeArea([LayoutSafeAreaType.SYSTEM], [LayoutSafeAreaEdge.TOP, LayoutSafeAreaEdge.BOTTOM])
|
||||
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
|
||||
.backgroundColor($r('app.color.background'))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user