鸿蒙项目实战 - 住户报修派单台:完整代码与运行效果
·

实例:住户报修派单台|技术:完整源码、路由接入、首页入口、运行核对
一、完整源码
import { DynamicLayout, DynamicLayoutAttribute, StackLayoutAlgorithm } from '@kit.ArkUI';
@ComponentV2
struct RepairUrgentCard {
@Local title: string = '0601 室厨房渗水';
@Local owner: string = '张派单';
@Local note: string = '先联系楼层值守,再安排水路师傅优先上门。';
build() {
Column({ space: 10 }) {
Text('加急工单').fontSize(18).fontWeight(FontWeight.Bold).fontColor('#0F172A')
TextInput({ text: this.title, placeholder: '工单标题' })
.backgroundColor('#FFF7ED')
.borderRadius(10)
.onChange((value: string) => this.title = value)
TextInput({ text: this.owner, placeholder: '派单人' })
.backgroundColor('#FFF7ED')
.borderRadius(10)
.onChange((value: string) => this.owner = value)
TextArea({ text: this.note, placeholder: '派单说明' })
.height(90)
.backgroundColor('#FFF7ED')
.borderRadius(10)
.onChange((value: string) => this.note = value)
}
.padding(18)
.backgroundColor('#FFFFFF')
.borderRadius(22)
}
}
@ComponentV2
struct RepairPlumberCard {
@Local worker: string = '王师傅';
@Local arrival: string = '14:20';
@Local note: string = '检查厨房下水、角阀和墙角返潮点。';
build() {
Column({ space: 10 }) {
Text('水路工单').fontSize(18).fontWeight(FontWeight.Bold).fontColor('#0F172A')
TextInput({ text: this.worker, placeholder: '处理师傅' })
.backgroundColor('#EFF6FF')
.borderRadius(10)
.onChange((value: string) => this.worker = value)
TextInput({ text: this.arrival, placeholder: '预计到场' })
.backgroundColor('#EFF6FF')
.borderRadius(10)
.onChange((value: string) => this.arrival = value)
TextArea({ text: this.note, placeholder: '现场要点' })
.height(84)
.backgroundColor('#EFF6FF')
.borderRadius(10)
.onChange((value: string) => this.note = value)
}
.padding(18)
.backgroundColor('#FFFFFF')
.borderRadius(22)
}
}
@ComponentV2
struct RepairPublicAreaCard {
@Local location: string = '二号楼电梯厅';
@Local ready: boolean = true;
@Local note: string = '需要先贴出短时围挡提示。';
build() {
Column({ space: 10 }) {
Text('公区报修').fontSize(18).fontWeight(FontWeight.Bold).fontColor('#0F172A')
TextInput({ text: this.location, placeholder: '位置' })
.backgroundColor('#ECFDF5')
.borderRadius(10)
.onChange((value: string) => this.location = value)
Row() {
Text('围挡准备').fontSize(12).fontColor('#64748B')
Blank()
Toggle({ type: ToggleType.Switch, isOn: this.ready })
.selectedColor('#16A34A')
.onChange((value: boolean) => this.ready = value)
}.width('100%')
TextArea({ text: this.note, placeholder: '公区说明' })
.height(74)
.backgroundColor('#ECFDF5')
.borderRadius(10)
.onChange((value: string) => this.note = value)
}
.padding(18)
.backgroundColor('#FFFFFF')
.borderRadius(22)
}
}
@ComponentV2
struct RepairReturnCard {
@Local callbackOwner: string = '李回访';
@Local satisfied: boolean = false;
@Local note: string = '回访时确认墙面是否仍有潮痕。';
build() {
Column({ space: 10 }) {
Text('回访收口').fontSize(18).fontWeight(FontWeight.Bold).fontColor('#0F172A')
TextInput({ text: this.callbackOwner, placeholder: '回访负责人' })
.backgroundColor('#F5F3FF')
.borderRadius(10)
.onChange((value: string) => this.callbackOwner = value)
Row() {
Text('住户确认').fontSize(12).fontColor('#64748B')
Blank()
Toggle({ type: ToggleType.Switch, isOn: this.satisfied })
.selectedColor('#7C3AED')
.onChange((value: boolean) => this.satisfied = value)
}.width('100%')
TextArea({ text: this.note, placeholder: '回访记录' })
.height(74)
.backgroundColor('#F5F3FF')
.borderRadius(10)
.onChange((value: string) => this.note = value)
}
.padding(18)
.backgroundColor('#FFFFFF')
.borderRadius(22)
}
}
@Entry
@ComponentV2
struct RepairDispatchPage {
@Local layoutAlgorithm: StackLayoutAlgorithm = new StackLayoutAlgorithm();
build() {
Column() {
Column({ space: 4 }) {
Text('🔧 60 住户报修派单台').fontSize(22).fontWeight(FontWeight.Bold)
Text('用 API 24 的 Stack 布局把派单卡片叠成调度视图,顶部工单不会遮掉下层输入状态。')
.fontSize(12).fontColor('#64748B').lineHeight(18)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
.padding({ left: 16, right: 16, top: 14, bottom: 12 })
Row({ space: 10 }) {
Column({ space: 4 }) {
Text('今日待派 7 单').fontSize(16).fontWeight(FontWeight.Bold).fontColor('#111827')
Text('加急 2 单,普通 5 单').fontSize(11).fontColor('#64748B')
}.layoutWeight(1)
Column({ space: 4 }) {
Text('已回访 3 单').fontSize(16).fontWeight(FontWeight.Bold).fontColor('#111827')
Text('待收口 1 单').fontSize(11).fontColor('#64748B')
}.layoutWeight(1)
}
.width('100%')
.padding({ left: 16, right: 16, bottom: 12 })
Scroll() {
Column({ space: 14 }) {
DynamicLayout(this.layoutAlgorithm) {
RepairReturnCard()
.width('74%')
.margin({ top: 128, left: 42 })
RepairPublicAreaCard()
.width('80%')
.margin({ top: 86, left: 28 })
RepairPlumberCard()
.width('86%')
.margin({ top: 42, left: 16 })
RepairUrgentCard()
.width('92%')
}
.width('100%')
.height(420)
Column({ space: 8 }) {
Text('调度说明').fontSize(15).fontWeight(FontWeight.Bold).fontColor('#111827')
Text('层叠视图适合在报修高峰期把不同阶段工单同时压在一屏内观察:顶层处理加急任务,下层保留师傅安排、公区准备和回访收口。')
.fontSize(12).fontColor('#64748B').lineHeight(20)
}
.width('100%')
.padding(16)
.backgroundColor('#FFFFFF')
.borderRadius(18)
}
.width('100%')
.padding({ left: 16, right: 16, bottom: 24 })
}
.layoutWeight(1)
.scrollBar(BarState.Off)
}
.width('100%')
.height('100%')
.backgroundColor('#F3F5F7')
}
}
二、路由接入
"pages/api24_series/RepairDispatchPage",
三、首页入口
Button('🔧 60 住户报修派单台')
.fontSize(14)
.width('80%')
.onClick(() => {
this.getUIContext().getRouter().pushUrl({ url: 'pages/api24_series/RepairDispatchPage' });
})
四、运行核对表
| 操作 | 应看到的界面表现 | 要核对的代码点 |
|---|---|---|
| 首次打开 | 四张工单按宽度和偏移叠起 | DynamicLayout 下的 width / margin |
| 编辑顶层工单 | 输入框可直接编辑,不影响下层卡 | 顶层卡片是否仍为完整组件 |
| 查看下层标题露出 | 后续阶段仍可看见顶部信息 | 偏移量是否保留阶段感 |
五、落地检查点
- 完整代码里最重要的是四张卡在
DynamicLayout下的叠层挂载顺序。 - 路由接入后,先验证页面是否能滚动,再验证叠层区底部是否被裁切。
- 如果增加新卡片层数,要同步调整叠层区容器高度。
六、本篇小结
第三篇保留完整源码,便于把这页当作 Stack 叠层模板继续派生出审批栈、任务栈或调度栈等其它页面。
更多推荐

所有评论(0)