476 lines
17 KiB
Plaintext
476 lines
17 KiB
Plaintext
/**
|
||||
|
|
* 家书 FamilyBook · 日程「时间轴」视图(鸿蒙端)
|
|||
|
|
*
|
|||
|
|
* 🔴 用户 2026-10-16:「**没有时间轴展示**……你这不是说让你把 SyncCalendar
|
|||
|
|
* 里面的功能搬过来吗?」
|
|||
|
|
* ⇒ 照 SyncCalendar 的 `DayTimelineView`(在 `Index.ets` 里)移植:
|
|||
|
|
* 左侧小时刻度 + 右侧**三层堆叠**渲染。
|
|||
|
|
*
|
|||
|
|
* 为什么是"三层堆叠"(照 SyncCalendar 的设计,别改):
|
|||
|
|
* · 第 1 层 **整点网格**:每小时一格、格底一条灰线;
|
|||
|
|
* · 第 2 层 **日程色块**:按冲突组分列、纵向用 `Blank` 定位;
|
|||
|
|
* · 第 3 层 **当前时间红线**:浮在最上面。
|
|||
|
|
* ⚠️ 三层尺寸与分格完全一致、上层透明 ⇒
|
|||
|
|
* **色块不会被整点线或红线"切开"**,红线也永远压在最上面。
|
|||
|
|
* 如果图省事把线直接画进日程层,一条日程就会被切成两段。
|
|||
|
|
*
|
|||
|
|
* 🔴 为什么是"组件"而不是 `@Builder`:
|
|||
|
|
* `@Builder` 的**值类型参数不参与状态观察**(见 `FbTagChip.ets` 的说明、
|
|||
|
|
* SDK 规则 `r/quick-rules/05-state.md`)—— 本项目的日程页正是因此
|
|||
|
|
* 出现"点日历下面的日程不变"。这里用 `@ComponentV2` + `@Param`,
|
|||
|
|
* `timeline` 一变整棵子树就重建。
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
import { FbColors, FbMetric } from '../common/Theme';
|
|||
|
|
import { FbCalEvent } from '../model/Types';
|
|||
|
|
import {
|
|||
|
|
FbTimelineData, FbTimeBlock, FbTimeGroup, FbTimeRow, FbTimelineUtil, FbViewRange
|
|||
|
|
} from '../common/FbTimeline';
|
|||
|
|
|
|||
|
|
/** 「当前时间红线」的颜色(照 SyncCalendar:系统红) */
|
|||
|
|
const FB_NOW_RED: string = '#FF3B30';
|
|||
|
|
|
|||
|
|
@ComponentV2
|
|||
|
|
export struct FbDayTimeline {
|
|||
|
|
/** 一天的布局(**必须由父组件按选中日期算好传进来**) */
|
|||
|
|
@Param timeline: FbTimelineData = new FbTimelineData();
|
|||
|
|
/** 是不是"今天"(决定要不要画红线) */
|
|||
|
|
@Param isToday: boolean = false;
|
|||
|
|
/** 当前时刻(当天第几分钟) */
|
|||
|
|
@Param nowMin: number = 0;
|
|||
|
|
/** 点一条日程 */
|
|||
|
|
@Event onPick: (e: FbCalEvent) => void = (e: FbCalEvent): void => {
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/** 1 小时的高度(vp) */
|
|||
|
|
private hourUnit: number = FbTimelineUtil.HOUR_UNIT;
|
|||
|
|
/** 极短色块的可读高度下限(一行"标题 + 时间") */
|
|||
|
|
private minBlockVp: number = 16;
|
|||
|
|
/** 能放下两行的高度门槛 */
|
|||
|
|
private twoLineVp: number = 30;
|
|||
|
|
/** 能放下三行的高度门槛 */
|
|||
|
|
private threeLineVp: number = 46;
|
|||
|
|
|
|||
|
|
// ---- 视窗 ----
|
|||
|
|
private range(): FbViewRange {
|
|||
|
|
return FbTimelineUtil.viewRange(this.timeline.blocks);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private viewTop(): number {
|
|||
|
|
return this.range().startHour / 24;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private viewBot(): number {
|
|||
|
|
return this.range().endHour / 24;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 视窗总高(vp) */
|
|||
|
|
private viewH(): number {
|
|||
|
|
const r: FbViewRange = this.range();
|
|||
|
|
return (r.endHour - r.startHour) * this.hourUnit;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 整日高度(vp) */
|
|||
|
|
private totalH(): number {
|
|||
|
|
return this.hourUnit * 24;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 视窗内的小时刻度 */
|
|||
|
|
private hourLabels(): number[] {
|
|||
|
|
const r: FbViewRange = this.range();
|
|||
|
|
const out: number[] = [];
|
|||
|
|
for (let h = r.startHour; h < r.endHour; h++) {
|
|||
|
|
out.push(h);
|
|||
|
|
}
|
|||
|
|
return out;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private hourText(h: number): string {
|
|||
|
|
return h < 10 ? ('0' + h.toString() + ':00') : (h.toString() + ':00');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 当前小时是否高亮(仅今天) */
|
|||
|
|
private isNowHour(h: number): boolean {
|
|||
|
|
return this.isToday && Math.floor(FbTimelineUtil.nowRatio(this.nowMin) * 24) === h;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 红线是否可见(今天 + 落在视窗内) */
|
|||
|
|
private nowVisible(): boolean {
|
|||
|
|
if (!this.isToday) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
const r: number = FbTimelineUtil.nowRatio(this.nowMin);
|
|||
|
|
return r >= this.viewTop() - 0.0001 && r <= this.viewBot() + 0.0001;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 红线距层顶的偏移(vp) */
|
|||
|
|
private nowOffsetVp(): number {
|
|||
|
|
const y: number = (FbTimelineUtil.nowRatio(this.nowMin) - this.viewTop()) * this.totalH() - 1;
|
|||
|
|
return y < 0 ? 0 : y;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ---- 行序列(空隙 + 冲突组)----
|
|||
|
|
|
|||
|
|
private groups(): FbTimeGroup[] {
|
|||
|
|
return FbTimelineUtil.groupsOf(this.timeline.blocks);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 纵向序列:只看视窗内的部分。
|
|||
|
|
* **本层只有两样东西:空隙(Blank)与冲突组行** ——
|
|||
|
|
* 整点线与红线交给另外两层,所以每条日程永远是完整连续的色块。
|
|||
|
|
*/
|
|||
|
|
private buildRows(): FbTimeRow[] {
|
|||
|
|
const rows: FbTimeRow[] = [];
|
|||
|
|
const gs: FbTimeGroup[] = this.groups();
|
|||
|
|
const top: number = this.viewTop();
|
|||
|
|
const bot: number = this.viewBot();
|
|||
|
|
const dk: string = this.range().startHour.toString() + '_' + this.range().endHour.toString();
|
|||
|
|
let cursor: number = top;
|
|||
|
|
for (const g of gs) {
|
|||
|
|
const gsx: number = g.startRatio > top ? g.startRatio : top;
|
|||
|
|
const gex: number = g.endRatio < bot ? g.endRatio : bot;
|
|||
|
|
if (gex - gsx <= 0.0002) {
|
|||
|
|
continue; // 整组都在视窗外
|
|||
|
|
}
|
|||
|
|
this.pushRow(rows, cursor, gsx, null, dk);
|
|||
|
|
this.pushRow(rows, gsx, gex, g, dk);
|
|||
|
|
cursor = gex;
|
|||
|
|
}
|
|||
|
|
this.pushRow(rows, cursor, bot, null, dk);
|
|||
|
|
return rows;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private pushRow(rows: FbTimeRow[], from: number, to: number,
|
|||
|
|
g: FbTimeGroup | null, dk: string): void {
|
|||
|
|
if (to - from <= 0.0002) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
const r: FbTimeRow = new FbTimeRow();
|
|||
|
|
r.topRatio = from;
|
|||
|
|
r.botRatio = to;
|
|||
|
|
if (g === null) {
|
|||
|
|
r.kind = 0;
|
|||
|
|
r.key = 'g_' + dk + '_' + rows.length.toString() + '_'
|
|||
|
|
+ Math.round((to - from) * 100000).toString();
|
|||
|
|
} else {
|
|||
|
|
r.kind = 1;
|
|||
|
|
r.group = g;
|
|||
|
|
let sig: string = '';
|
|||
|
|
for (const b of g.blocks) {
|
|||
|
|
sig = sig + '_' + b.key;
|
|||
|
|
}
|
|||
|
|
r.key = 'b_' + dk + '_' + rows.length.toString() + sig;
|
|||
|
|
}
|
|||
|
|
rows.push(r);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 某一列中、与本行窗口有交集的色块 */
|
|||
|
|
private laneBlocks(r: FbTimeRow, lane: FbTimeBlock[]): FbTimeBlock[] {
|
|||
|
|
const out: FbTimeBlock[] = [];
|
|||
|
|
for (const b of lane) {
|
|||
|
|
const be: number = b.topRatio + b.heightRatio;
|
|||
|
|
if (be > r.topRatio + 0.0001 && b.topRatio < r.botRatio - 0.0001) {
|
|||
|
|
out.push(b);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return out;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 列内第 index 个色块之前要空出的高度(vp) */
|
|||
|
|
private lanePadH(r: FbTimeRow, lane: FbTimeBlock[], index: number): number {
|
|||
|
|
const arr: FbTimeBlock[] = this.laneBlocks(r, lane);
|
|||
|
|
let prevEnd: number = r.topRatio;
|
|||
|
|
if (index > 0) {
|
|||
|
|
const p: FbTimeBlock = arr[index - 1];
|
|||
|
|
const pe: number = p.topRatio + p.heightRatio;
|
|||
|
|
prevEnd = pe > r.topRatio ? pe : r.topRatio;
|
|||
|
|
}
|
|||
|
|
const b: FbTimeBlock = arr[index];
|
|||
|
|
const top: number = b.topRatio > r.topRatio ? b.topRatio : r.topRatio;
|
|||
|
|
const d: number = (top - prevEnd) * this.totalH();
|
|||
|
|
return d < 0 ? 0 : d;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 色块实际渲染高度(vp):极短的尽量垫到可读高度,但不越过同列下一块 */
|
|||
|
|
private blockVp(r: FbTimeRow, lane: FbTimeBlock[], index: number): number {
|
|||
|
|
const arr: FbTimeBlock[] = this.laneBlocks(r, lane);
|
|||
|
|
const b: FbTimeBlock = arr[index];
|
|||
|
|
const real: number = b.heightRatio * this.totalH();
|
|||
|
|
if (real >= this.minBlockVp) {
|
|||
|
|
return real;
|
|||
|
|
}
|
|||
|
|
let room: number = 0;
|
|||
|
|
if (index + 1 < arr.length) {
|
|||
|
|
room = this.lanePadH(r, lane, index + 1);
|
|||
|
|
} else {
|
|||
|
|
const tail: number = (r.botRatio - (b.topRatio + b.heightRatio)) * this.totalH();
|
|||
|
|
room = tail > 0 ? tail : 0;
|
|||
|
|
}
|
|||
|
|
const h: number = real + room;
|
|||
|
|
return h > this.minBlockVp ? this.minBlockVp : h;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 色块信息行数(按渲染高度判定) */
|
|||
|
|
private blockLines(r: FbTimeRow, lane: FbTimeBlock[], index: number, b: FbTimeBlock): number {
|
|||
|
|
const h: number = this.blockVp(r, lane, index);
|
|||
|
|
if (h >= this.threeLineVp && b.place !== '') {
|
|||
|
|
return 3;
|
|||
|
|
}
|
|||
|
|
if (h >= this.twoLineVp) {
|
|||
|
|
return 2;
|
|||
|
|
}
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 两行色块的第二行:`09:00 - 10:30 · 地点` */
|
|||
|
|
private blockMeta(b: FbTimeBlock): string {
|
|||
|
|
if (b.place !== '') {
|
|||
|
|
return b.timeText + ' · ' + b.place;
|
|||
|
|
}
|
|||
|
|
return b.timeText;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 色块 key 的内容签名(内容变了必须重建,否则 ArkUI 复用旧子组件) */
|
|||
|
|
private blockSig(r: FbTimeRow, lane: FbTimeBlock[], index: number, b: FbTimeBlock): string {
|
|||
|
|
return b.title.length.toString() + '_' + b.place.length.toString() + '_'
|
|||
|
|
+ Math.round(this.blockVp(r, lane, index)).toString();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ============================================================
|
|||
|
|
// 三层
|
|||
|
|
// ============================================================
|
|||
|
|
|
|||
|
|
/** 第 1 层:整点网格(每小时一格,格底一条灰线) */
|
|||
|
|
@Builder
|
|||
|
|
gridLayer() {
|
|||
|
|
Column() {
|
|||
|
|
ForEach(this.hourLabels(), (h: number) => {
|
|||
|
|
Column()
|
|||
|
|
.width('100%')
|
|||
|
|
.height(this.hourUnit)
|
|||
|
|
.border({ width: { bottom: 0.5 }, color: { bottom: FbColors.line2 } })
|
|||
|
|
.hitTestBehavior(HitTestMode.None)
|
|||
|
|
}, (h: number): string => 'gd_' + h.toString())
|
|||
|
|
}
|
|||
|
|
.width('100%')
|
|||
|
|
.height('100%')
|
|||
|
|
.hitTestBehavior(HitTestMode.None) // 装饰层:点击穿透到色块
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 第 2 层:日程色块(冲突组分行 + 组内分列,纵向用 Blank 定位) */
|
|||
|
|
@Builder
|
|||
|
|
eventLayer() {
|
|||
|
|
Column() {
|
|||
|
|
ForEach(this.buildRows(), (r: FbTimeRow) => {
|
|||
|
|
if (r.kind === 1 && r.group !== null) {
|
|||
|
|
Row() {
|
|||
|
|
ForEach(r.group!.lanes, (lane: FbTimeBlock[], li: number) => {
|
|||
|
|
Column() {
|
|||
|
|
ForEach(this.laneBlocks(r, lane), (b: FbTimeBlock, index: number) => {
|
|||
|
|
Blank().height(this.lanePadH(r, lane, index))
|
|||
|
|
Column({ space: 1 }) {
|
|||
|
|
if (this.blockLines(r, lane, index, b) === 1) {
|
|||
|
|
// 一行:标题 · 时间(地点放不下)
|
|||
|
|
Row({ space: 4 }) {
|
|||
|
|
Text(b.title)
|
|||
|
|
.fontSize(10)
|
|||
|
|
.fontWeight(FontWeight.Medium)
|
|||
|
|
.fontColor(Color.White)
|
|||
|
|
.maxLines(1)
|
|||
|
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
|||
|
|
.constraintSize({ maxWidth: '50%' })
|
|||
|
|
Text(b.timeText)
|
|||
|
|
.fontSize(9)
|
|||
|
|
.fontColor('#E6FFFFFF')
|
|||
|
|
.maxLines(1)
|
|||
|
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
|||
|
|
.constraintSize({ maxWidth: '55%' })
|
|||
|
|
}
|
|||
|
|
.width('100%')
|
|||
|
|
.alignItems(VerticalAlign.Center)
|
|||
|
|
} else {
|
|||
|
|
// 第一行:标题
|
|||
|
|
Text(b.title)
|
|||
|
|
.fontSize(11)
|
|||
|
|
.fontWeight(FontWeight.Medium)
|
|||
|
|
.fontColor(Color.White)
|
|||
|
|
.maxLines(1)
|
|||
|
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
|||
|
|
.width('100%')
|
|||
|
|
if (this.blockLines(r, lane, index, b) >= 3) {
|
|||
|
|
Text(b.timeText)
|
|||
|
|
.fontSize(9)
|
|||
|
|
.fontColor('#E6FFFFFF')
|
|||
|
|
.maxLines(1)
|
|||
|
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
|||
|
|
.width('100%')
|
|||
|
|
Text(b.place)
|
|||
|
|
.fontSize(9)
|
|||
|
|
.fontColor('#B3FFFFFF')
|
|||
|
|
.maxLines(1)
|
|||
|
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
|||
|
|
.width('100%')
|
|||
|
|
} else {
|
|||
|
|
Text(this.blockMeta(b))
|
|||
|
|
.fontSize(9)
|
|||
|
|
.fontColor('#E6FFFFFF')
|
|||
|
|
.maxLines(1)
|
|||
|
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
|||
|
|
.width('100%')
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
.alignItems(HorizontalAlign.Start)
|
|||
|
|
.justifyContent(FlexAlign.Start)
|
|||
|
|
.padding({ left: 6, right: 3, top: 2, bottom: 2 })
|
|||
|
|
.borderRadius(6)
|
|||
|
|
.backgroundColor(b.color)
|
|||
|
|
.clip(true)
|
|||
|
|
.width('100%')
|
|||
|
|
.height(this.blockVp(r, lane, index))
|
|||
|
|
.onClick((): void => {
|
|||
|
|
if (b.ev !== null) {
|
|||
|
|
this.onPick(b.ev);
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}, (b: FbTimeBlock, index: number): string =>
|
|||
|
|
'blk_' + r.key + '_' + b.key + '_' + this.blockSig(r, lane, index, b))
|
|||
|
|
}
|
|||
|
|
.layoutWeight(1)
|
|||
|
|
.height('100%')
|
|||
|
|
.padding({ right: 2 })
|
|||
|
|
.clip(true)
|
|||
|
|
}, (lane: FbTimeBlock[], li: number): string => 'ln_' + r.key + '_' + li.toString())
|
|||
|
|
}
|
|||
|
|
.width('100%')
|
|||
|
|
.height((r.botRatio - r.topRatio) * this.totalH())
|
|||
|
|
.alignItems(VerticalAlign.Top)
|
|||
|
|
} else {
|
|||
|
|
// 空隙:纯占位
|
|||
|
|
Blank().height((r.botRatio - r.topRatio) * this.totalH())
|
|||
|
|
}
|
|||
|
|
}, (r: FbTimeRow): string => r.key)
|
|||
|
|
}
|
|||
|
|
.width('100%')
|
|||
|
|
.height('100%')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 第 3 层:当前时间红线(浮在最上层) */
|
|||
|
|
@Builder
|
|||
|
|
nowLayer() {
|
|||
|
|
if (this.nowVisible()) {
|
|||
|
|
Row() {
|
|||
|
|
// 左侧时间文字(红线那头)
|
|||
|
|
Text(FbTimelineUtil.hhmm(this.nowMin))
|
|||
|
|
.fontSize(9)
|
|||
|
|
.fontColor(FB_NOW_RED)
|
|||
|
|
.fontWeight(FontWeight.Medium)
|
|||
|
|
.textAlign(TextAlign.End)
|
|||
|
|
.width(34)
|
|||
|
|
Row()
|
|||
|
|
.layoutWeight(1)
|
|||
|
|
.height(2)
|
|||
|
|
.backgroundColor(FB_NOW_RED)
|
|||
|
|
Row()
|
|||
|
|
.width(6)
|
|||
|
|
.height(6)
|
|||
|
|
.borderRadius(3)
|
|||
|
|
.backgroundColor(FB_NOW_RED)
|
|||
|
|
}
|
|||
|
|
.width('100%')
|
|||
|
|
.alignItems(VerticalAlign.Center)
|
|||
|
|
.margin({ top: this.nowOffsetVp() })
|
|||
|
|
.hitTestBehavior(HitTestMode.None)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
build() {
|
|||
|
|
Column({ space: 0 }) {
|
|||
|
|
// ---- 全天 / 跨天:画在 0 点之前,用色块展示 ----
|
|||
|
|
if (this.timeline.allDay.length > 0) {
|
|||
|
|
Column({ space: 4 }) {
|
|||
|
|
ForEach(this.timeline.allDay, (e: FbCalEvent) => {
|
|||
|
|
Row({ space: 6 }) {
|
|||
|
|
Text('全天')
|
|||
|
|
.fontSize(9)
|
|||
|
|
.fontColor(Color.White)
|
|||
|
|
.backgroundColor('#26000000')
|
|||
|
|
.borderRadius(6)
|
|||
|
|
.padding({ left: 5, right: 5, top: 1, bottom: 1 })
|
|||
|
|
Text(e.title !== '' ? e.title : '(无标题)')
|
|||
|
|
.fontSize(12)
|
|||
|
|
.fontWeight(FontWeight.Medium)
|
|||
|
|
.fontColor(Color.White)
|
|||
|
|
.maxLines(1)
|
|||
|
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
|||
|
|
.layoutWeight(1)
|
|||
|
|
if (e.place !== '') {
|
|||
|
|
Text(e.place)
|
|||
|
|
.fontSize(10)
|
|||
|
|
.fontColor('#D9FFFFFF')
|
|||
|
|
.maxLines(1)
|
|||
|
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
|||
|
|
.constraintSize({ maxWidth: 110 })
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
.alignItems(VerticalAlign.Center)
|
|||
|
|
.width('100%')
|
|||
|
|
.height(26)
|
|||
|
|
.padding({ left: 8, right: 8 })
|
|||
|
|
.borderRadius(8)
|
|||
|
|
.backgroundColor(e.color)
|
|||
|
|
.onClick((): void => {
|
|||
|
|
this.onPick(e);
|
|||
|
|
})
|
|||
|
|
}, (e: FbCalEvent): string => 'al_' + FbTimelineUtil.keyOf(e))
|
|||
|
|
}
|
|||
|
|
.width('100%')
|
|||
|
|
.padding({ bottom: 6 })
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ---- 时间轴主体 ----
|
|||
|
|
Row() {
|
|||
|
|
// 左侧小时刻度
|
|||
|
|
Column() {
|
|||
|
|
ForEach(this.hourLabels(), (h: number) => {
|
|||
|
|
Text(this.hourText(h))
|
|||
|
|
.fontSize(10)
|
|||
|
|
.fontColor(this.isNowHour(h) ? FB_NOW_RED : FbColors.faint)
|
|||
|
|
.width(36)
|
|||
|
|
.height(this.hourUnit)
|
|||
|
|
.textAlign(TextAlign.End)
|
|||
|
|
.padding({ right: 4, top: 2 })
|
|||
|
|
.border({ width: { bottom: 0.5 }, color: { bottom: FbColors.line2 } })
|
|||
|
|
}, (h: number): string => 'h' + h.toString())
|
|||
|
|
}
|
|||
|
|
.width(36)
|
|||
|
|
|
|||
|
|
// 右侧内容区:三层堆叠
|
|||
|
|
Stack() {
|
|||
|
|
this.gridLayer()
|
|||
|
|
this.eventLayer()
|
|||
|
|
this.nowLayer()
|
|||
|
|
}
|
|||
|
|
.layoutWeight(1)
|
|||
|
|
.height(this.viewH())
|
|||
|
|
.alignContent(Alignment.TopStart)
|
|||
|
|
.border({ width: { left: 0.5 }, color: { left: FbColors.line2 } })
|
|||
|
|
}
|
|||
|
|
.width('100%')
|
|||
|
|
.alignItems(VerticalAlign.Top)
|
|||
|
|
|
|||
|
|
// ---- 当天没有带时间的日程 ----
|
|||
|
|
if (!this.timeline.hasTimed && this.timeline.allDay.length === 0) {
|
|||
|
|
Text('这天没有安排')
|
|||
|
|
.fontSize(FbMetric.fontSmall)
|
|||
|
|
.fontColor(FbColors.faint)
|
|||
|
|
.width('100%')
|
|||
|
|
.textAlign(TextAlign.Center)
|
|||
|
|
.padding({ top: 20, bottom: 20 })
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
.width('100%')
|
|||
|
|
.alignItems(HorizontalAlign.Start)
|
|||
|
|
}
|
|||
|
|
}
|