在这里插入图片描述
在这里插入图片描述

实例:资料征集分发台|技术:完整源码、路由接入、首页入口、运行核对

一、完整源码

import { ColumnLayoutAlgorithm, DynamicLayout, DynamicLayoutAttribute, GridLayoutAlgorithm, LayoutAlgorithm, LengthMetrics, curves } from '@kit.ArkUI';

@ComponentV2
struct CollectNoticeCard {
  @Local title: string = '批次 A 通知';
  @Local note: string = '先发给东区、北区和设备组。';

  build() {
    Column({ space: 10 }) {
      Text('征集通知').fontSize(17).fontWeight(FontWeight.Bold).fontColor('#111827')
      TextInput({ text: this.title, placeholder: '通知标题' })
        .backgroundColor('#F8FAFC')
        .borderRadius(10)
        .onChange((value: string) => this.title = value)
      TextArea({ text: this.note, placeholder: '发送范围' })
        .height(86)
        .backgroundColor('#F8FAFC')
        .borderRadius(10)
        .onChange((value: string) => this.note = value)
    }
    .width('100%')
    .padding(16)
    .backgroundColor('#FFFFFF')
    .borderRadius(18)
  }
}

@ComponentV2
struct CollectReceiveCard {
  @Local count: number = 18;
  @Local note: string = '上午已签收 12 份,下午继续补收。';

  build() {
    Column({ space: 10 }) {
      Text('签收记录').fontSize(17).fontWeight(FontWeight.Bold).fontColor('#111827')
      Row() {
        Text('已到件数').fontSize(12).fontColor('#64748B')
        Blank()
        Text(`${Math.round(this.count)}`).fontSize(14).fontWeight(FontWeight.Medium).fontColor('#0F766E')
      }.width('100%')
      Slider({ value: this.count, min: 0, max: 40, step: 1 })
        .selectedColor('#14B8A6')
        .trackColor('#CCFBF1')
        .blockColor('#0F766E')
        .onChange((value: number) => this.count = value)
      TextArea({ text: this.note, placeholder: '签收说明' })
        .height(86)
        .backgroundColor('#F8FAFC')
        .borderRadius(10)
        .onChange((value: string) => this.note = value)
    }
    .width('100%')
    .padding(16)
    .backgroundColor('#FFFFFF')
    .borderRadius(18)
  }
}

@ComponentV2
struct CollectMissingCard {
  @Local urgent: boolean = true;
  @Local note: string = '仍缺封面页、签章页和电子留档页。';

  build() {
    Column({ space: 10 }) {
      Text('缺件提醒').fontSize(17).fontWeight(FontWeight.Bold).fontColor('#111827')
      Row() {
        Text('是否加急').fontSize(12).fontColor('#64748B')
        Blank()
        Toggle({ type: ToggleType.Switch, isOn: this.urgent })
          .selectedColor('#DC2626')
          .onChange((value: boolean) => this.urgent = value)
      }.width('100%')
      TextArea({ text: this.note, placeholder: '缺件项目' })
        .height(102)
        .backgroundColor('#F8FAFC')
        .borderRadius(10)
        .onChange((value: string) => this.note = value)
    }
    .width('100%')
    .padding(16)
    .backgroundColor('#FFFFFF')
    .borderRadius(18)
  }
}

@ComponentV2
struct CollectPackageCard {
  @Local owner: string = '夏打包';
  @Local note: string = '按楼层顺序打包,便于下午统一分发。';

  build() {
    Column({ space: 10 }) {
      Text('批次打包').fontSize(17).fontWeight(FontWeight.Bold).fontColor('#111827')
      TextInput({ text: this.owner, placeholder: '打包负责人' })
        .backgroundColor('#F8FAFC')
        .borderRadius(10)
        .onChange((value: string) => this.owner = value)
      TextArea({ text: this.note, placeholder: '打包说明' })
        .height(86)
        .backgroundColor('#F8FAFC')
        .borderRadius(10)
        .onChange((value: string) => this.note = value)
    }
    .width('100%')
    .padding(16)
    .backgroundColor('#FFFFFF')
    .borderRadius(18)
  }
}

@ComponentV2
struct CollectVerifyCard {
  @Local done: boolean = false;
  @Local note: string = '回传校验前,先检查页码、顺序和签章完整度。';

  build() {
    Column({ space: 10 }) {
      Text('回传校验').fontSize(17).fontWeight(FontWeight.Bold).fontColor('#111827')
      Row() {
        Text('是否完成').fontSize(12).fontColor('#64748B')
        Blank()
        Toggle({ type: ToggleType.Switch, isOn: this.done })
          .selectedColor('#2563EB')
          .onChange((value: boolean) => this.done = value)
      }.width('100%')
      TextArea({ text: this.note, placeholder: '校验说明' })
        .height(102)
        .backgroundColor('#F8FAFC')
        .borderRadius(10)
        .onChange((value: string) => this.note = value)
    }
    .width('100%')
    .padding(16)
    .backgroundColor('#FFFFFF')
    .borderRadius(18)
  }
}

@Entry
@ComponentV2
struct CollectionDeskPage {
  @Local currentMode: string = '双列';
  @Local layoutAlgorithm: LayoutAlgorithm = new GridLayoutAlgorithm({
    columnsTemplate: '1fr 1fr',
    rowsGap: LengthMetrics.vp(12),
    columnsGap: LengthMetrics.vp(12)
  });

  private switchToSingle(): void {
    this.getUIContext()?.animateTo({ curve: curves.springMotion(0.45, 0.82) }, () => {
      this.layoutAlgorithm = new ColumnLayoutAlgorithm({
        space: LengthMetrics.vp(12)
      });
      this.currentMode = '单列';
    });
  }

  private switchToDouble(): void {
    this.getUIContext()?.animateTo({ curve: curves.springMotion(0.45, 0.82) }, () => {
      this.layoutAlgorithm = new GridLayoutAlgorithm({
        columnsTemplate: '1fr 1fr',
        rowsGap: LengthMetrics.vp(12),
        columnsGap: LengthMetrics.vp(12)
      });
      this.currentMode = '双列';
    });
  }

  private switchToTriple(): void {
    this.getUIContext()?.animateTo({ curve: curves.springMotion(0.45, 0.82) }, () => {
      this.layoutAlgorithm = new GridLayoutAlgorithm({
        columnsTemplate: '1fr 1fr 1fr',
        rowsGap: LengthMetrics.vp(10),
        columnsGap: LengthMetrics.vp(10)
      });
      this.currentMode = '三列';
    });
  }

  build() {
    Column() {
      Column({ space: 4 }) {
        Text('🗃️ 62 资料征集分发台').fontSize(22).fontWeight(FontWeight.Bold)
        Text('同一组资料卡片可在单列、双列、三列三种 DynamicLayout 模式之间切换,适合不同阶段的收件与分发视图。')
          .fontSize(12).fontColor('#64748B').lineHeight(18)
      }
      .width('100%')
      .alignItems(HorizontalAlign.Start)
      .padding({ left: 16, right: 16, top: 14, bottom: 10 })

      Row({ space: 8 }) {
        Button('单列').height(36).backgroundColor(this.currentMode === '单列' ? '#111827' : '#E5E7EB')
          .fontColor(this.currentMode === '单列' ? '#FFFFFF' : '#334155')
          .onClick(() => this.switchToSingle())
        Button('双列').height(36).backgroundColor(this.currentMode === '双列' ? '#111827' : '#E5E7EB')
          .fontColor(this.currentMode === '双列' ? '#FFFFFF' : '#334155')
          .onClick(() => this.switchToDouble())
        Button('三列').height(36).backgroundColor(this.currentMode === '三列' ? '#111827' : '#E5E7EB')
          .fontColor(this.currentMode === '三列' ? '#FFFFFF' : '#334155')
          .onClick(() => this.switchToTriple())
      }
      .width('100%')
      .padding({ left: 16, right: 16, bottom: 10 })

      Scroll() {
        DynamicLayout(this.layoutAlgorithm) {
          CollectNoticeCard()
          CollectReceiveCard()
          CollectMissingCard()
          CollectPackageCard()
          CollectVerifyCard()
        }
        .width('100%')
        .padding({ left: 16, right: 16, bottom: 24 })
      }
      .layoutWeight(1)
      .scrollBar(BarState.Off)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F4F6F8')
  }
}

二、路由接入

"pages/api24_series/CollectionDeskPage",

三、首页入口

Button('🗃️ 62 资料征集分发台')
  .fontSize(14)
  .width('80%')
  .onClick(() => {
    this.getUIContext().getRouter().pushUrl({ url: 'pages/api24_series/CollectionDeskPage' });
  })

四、运行核对表

操作 应看到的界面表现 要核对的代码点
切单列 卡片纵向展开,更适合逐项录入 switchToSingle() 是否替换成列算法
切双列 卡片并排展示,输入状态保留 switchToDouble() 是否恢复双列模板
切三列 卡片密度更高,仍可继续编辑 switchToTriple() 是否使用三列模板

五、落地检查点

  1. 完整源码里最关键的是三个切换函数与 DynamicLayout 的关系。
  2. 路由接入后,至少手动切一次单列、双列、三列,验证模式按钮和内容区同步。
  3. 增加资料卡数量后,继续检查滚动区和三列模式下的最小可编辑宽度。

六、本篇小结

第三篇保留完整源码,方便把这一页当成多视图资料页模板继续扩展到回收、分发、校验等相近场景。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐