【05】20250416优雅草星云物联网AI智控系统从0开发鸿蒙端适配-deveco studio-增加告警中心相关卡片页面WarningCardWidget相关-增加Canvas 绘制折线图-Canvas 绘制柱状图-首页-优雅草卓伊凡
项目背景
本项目渊源已久,优雅草2025年发布,PC端已经发布,将在4月完成成品发布,目前由于考虑到鸿蒙端用户使用,毕竟新一代纯血鸿蒙harmonyos next已经不再支持安卓android,因此优雅草团队必须考虑把鸿蒙端也开发上,以下实战过程完整记录了整个开发过程,优雅草卓伊凡审核代码,记录并更新,再次感谢优雅草团队所有同事们的努力,鸿蒙端为了加速鸿蒙生态已经开源地址供查看,关于优雅草星云物联网AI智控系统可以关注优雅草官网,在本文梳理的过程中发现在后面的页面中,只需要直接写出代码并且附上注释,卓伊凡相信大家应该看得懂,针对比较复杂的部分会单独做独立解释,每一个页面都可以对应查看,基本都会截图,如果没有截图的那就是真的没截图,另外注意由于文章篇幅关系不会把所有页面都一一写,写一些重要页面发布在文档中,每次的改进,更多内容参考大家直接观看git并且下载。
项目开源代码地址
https://gitee.com/youyacao/axharmonyos

鸿蒙端运行环境
deveco 5.0.4版本
实战过程
很多天没来帮忙注释文档以及 发布 过程了, 拆卸每个页面,由于实在工作太忙
Fast-forwardentry/src/main/ets/pages/Index.ets | 2 +-entry/src/main/ets/pages/LoginView.ets | 58 ++++++-entry/src/main/ets/pages/Welcome.ets | 10 +-entry/src/main/module.json5 | 5 +lib/CommonConstLibrary/Index.ets | 3 +…/src/main/ets/common/common.ets | 15 ++…/src/main/ets/enum/ApiErrorCode.ets | 15 ++…/src/main/ets/enum/SeverityLevel.ets | 9 ++…/src/main/ets/model/ApiModel.ets | 45 ++++++…/main/ets/components/common/LoadingWidget.ets | 24 +++…/ets/components/common/StatisticsWidget.ets | 18 ++-…/main/ets/components/home/TopologyMapWidget.ets | 118 ++++++++++++++…/ets/components/settings/SettingInputWidget.ets | 7 +-…/components/settings/SettingSelectWidget.ets | 3 +-…/ets/components/settings/SettingSettingItem.ets | 2 +-…/components/warning/WarningMessageWidget.ets | 27 +++-…/ets/components/warning/WarningSearchWidget.ets | 12 +-…/src/main/ets/view/HomeView.ets | 21 ++-…/src/main/ets/view/WarningCenterView.ets | 121 ++++++++———-…/main/resources/base/media/ic_topology_map.png | Bin 0 -> 3079030 byteslib/UtilsLibrary/Index.ets | 5 +-…/src/main/ets/lazyForEach/ApiDataSource.ets | 7 +lib/UtilsLibrary/src/main/ets/utils/Request.ets | 170 +++++++++++++++++++++23 files changed, 607 insertions(+), 90 deletions(-)create mode 100644 lib/CommonConstLibrary/src/main/ets/enum/ApiErrorCode.etscreate mode 100644 lib/CommonConstLibrary/src/main/ets/enum/SeverityLevel.etscreate mode 100644 lib/CommonConstLibrary/src/main/ets/model/ApiModel.etscreate mode 100644 lib/ComponentLibrary/src/main/ets/components/common/LoadingWidget.etscreate mode 100644 lib/ComponentLibrary/src/main/ets/components/home/TopologyMapWidget.etscreate mode 100644 lib/ComponentLibrary/src/main/resources/base/media/ic_topology_map.pngcreate mode 100644 lib/UtilsLibrary/src/main/ets/lazyForEach/ApiDataSource.etscreate mode 100644 lib/UtilsLibrary/src/main/ets/utils/Request.ets
今天拉了一下发现代码已经开始 写到 对接接口部分的了。
lib/ComponentLibrary/src/main/ets/components/common/BarChartNewWidget.ets
/*
* Copyright (c) 2025.成都市一颗优雅草科技有限公司
* author:卓伊凡-优雅草技术总监
* project:优雅草星云物联网智控AI系统
*/
import { BarChartDateModel, commonColor, CommonConst } from "@wcmzllx/common-const-library";
import { getRandomIntInclusive } from "@wcmzllx/utils-library";
import { vp2 } from "../../common/NewVp";
// 定义图表的上边距
const MARGIN_TOP = 20;
// 定义图表的下边距
const MARGIN_BOTTOM = 20;
// 定义图表的右边距
const MARGIN_RIGHT = 30;
// 定义柱子之间的间距
const BAR_GAP = 45; // 柱子间距
// 定义字体大小
const FONT_SIZE = 10; // 修改字体大小
// 定义柱子的颜色
const BAR_COLOR = "#16CA46";
// 定义一个结构体用于绘制柱状图
@ComponentV2
export struct BarChartNewWidget {
// 定义柱状图的数据源
@Param data: BarChartDateModel[] = [
{ xAxis: '设备1', value: getRandomIntInclusive(0, 100) },
{ xAxis: '设备2', value: getRandomIntInclusive(0, 100) },
{ xAxis: '设备3', value: getRandomIntInclusive(0, 100) },
{ xAxis: '设备4', value: getRandomIntInclusive(0, 100) },
{ xAxis: '设备5', value: getRandomIntInclusive(0, 100) },
];
// 初始化渲染上下文设置
private settings: RenderingContextSettings = new RenderingContextSettings(true)
// 创建用于绘制网格的2D渲染上下文
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
// 创建用于绘制柱子的2D渲染上下文
private context1: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
// 定义图表的宽度
@Local chartWidth: number = 0;
// 定义图表的高度
@Local chartHeight: number = 0;
// 转换字体大小为像素值
private FONT_SIZE: number = vp2px(vp2.vp2(FONT_SIZE));
// 定义Y轴单位
@Param yUnit: string = ""
// 定义图表的左边距
private MARGIN_LEFT = 30;
// 监听数据变化,当数据长度变化时调用以下方法
@Monitor("data.length")
onDataChange() {
// 调用绘制网格的方法
this.onDrawGrid();
// 调用绘制柱子的方法
this.onDrawBars();
}
// 在组件即将出现时调用,根据Y轴单位调整左边距
aboutToAppear(): void {
for (let i = 0; i < this.yUnit.length; i++) {
this.MARGIN_LEFT += 5;
}
}
// 构建组件布局
build() {
Column() {
Stack() {
// 创建用于绘制网格的Canvas
Canvas(this.context)
.onReady(() => this.onDrawGrid())
.width(CommonConst.GLOBAL_FULL_SCREEN)
.height(CommonConst.GLOBAL_FULL_SCREEN)
// 创建用于绘制柱子的Canvas
Canvas(this.context1)
.onReady(() => this.onDrawBars())
.width(CommonConst.GLOBAL_FULL_SCREEN)
.height(CommonConst.GLOBAL_FULL_SCREEN)
}
// 当组件大小变化时,更新图表宽度和高度
.onSizeChange((_, newValue) => {
this.chartWidth = newValue.width as number;
this.chartHeight = newValue.height as number;
})
}
}
// 绘制网格的方法
onDrawGrid() {
if (!this.chartWidth || !this.chartHeight) return;
// 清除画布
this.context.clearRect(0, 0, this.chartWidth, this.chartHeight);
// Y轴计算
const maxValue = Math.max(...this.data.map(d => d.value));
const maxYValue = Math.ceil(maxValue / 10) * 10 || 10;
// 样式设置
this.context.strokeStyle = 'rgba(255, 255, 255, 0.1)'// 'rgba(235, 235, 235, 0.6)';
this.context.lineWidth = 1;
this.context.fillStyle = '#FF90ACE9';
this.context.font = `${this.FONT_SIZE}px sans-serif`; // 修改字体大小
const plotHeight = this.chartHeight - MARGIN_TOP - MARGIN_BOTTOM;
// 绘制Y轴网格
const ySteps = 4;
for (let i = 0; i <= ySteps; i++) {
const y = MARGIN_TOP + plotHeight * (1 - i/ySteps);
this.context.beginPath();
this.context.moveTo(this.MARGIN_LEFT, y);
this.context.lineTo(this.chartWidth - MARGIN_RIGHT, y);
this.context.stroke();
// Y轴标签
this.context.textAlign = 'right';
this.context.textBaseline = 'middle';
this.context.fillText(
`${Math.round(maxYValue * (i/ySteps))}` + this.yUnit,
this.MARGIN_LEFT - 10,
y
);
}
// 绘制X轴标签
this.context.fillStyle = '#FF90ACE9';
this.context.textAlign = 'center';
this.context.textBaseline = 'top';
const xAxisY = this.chartHeight - MARGIN_BOTTOM + 6;
this.data.forEach((item, index) => {
const barWidth = this.getBarWidth();
const x = this.MARGIN_LEFT + index * (barWidth + BAR_GAP) + barWidth/2;
// 处理最后一个标签溢出
const textWidth = this.context.measureText(item.xAxis).width;
const maxX = this.chartWidth - MARGIN_RIGHT - textWidth/2;
const finalX = x > maxX && index === this.data.length-1 ? maxX : x;
this.context.fillText(item.xAxis, finalX, xAxisY);
});
}
// 绘制柱子的方法
onDrawBars() {
if (!this.chartWidth || !this.chartHeight) return;
// 清除画布
this.context1.clearRect(0, 0, this.chartWidth, this.chartHeight);
// 计算最大值和Y轴的最大值
const maxValue = Math.max(...this.data.map(d => d.value));
const maxYValue = Math.ceil(maxValue / 10) * 10 || 10;
const plotHeight = this.chartHeight - MARGIN_TOP - MARGIN_BOTTOM;
// 遍历数据源,绘制柱子
this.data.forEach((item, index) => {
const barWidth = this.getBarWidth();
const x = this.MARGIN_LEFT + index * (barWidth + BAR_GAP);
const height = (item.value / maxYValue) * plotHeight;
// 绘制柱子
this.context1.fillStyle = BAR_COLOR;
this.context1.fillRect(
x,
MARGIN_TOP + plotHeight - height,
barWidth,
height
);
});
}
// 计算柱子宽度的方法
private getBarWidth(): number {
const totalBars = this.data.length;
const availableWidth = this.chartWidth - this.MARGIN_LEFT - MARGIN_RIGHT;
return (availableWidth - (totalBars - 1) * BAR_GAP) / totalBars;
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
lib/ComponentLibrary/src/main/ets/view/HomeView.ets 首页
/*
* Copyright (c) 2025.成都市一颗优雅草科技有限公司
* author:卓伊凡-优雅草技术总监
* project:优雅草星云物联网智控AI系统
*/
import { BarChartDateModel, commonColor, CommonConst } from "@wcmzllx/common-const-library"
import { uiWindows } from "../common/UIWindows"
import { vp2 } from "../common/NewVp"
import { BarChartWidget } from "../components/common/BarChartWidget"
import { HomeCardWidget } from "../components/home/HomeCardWidget"
import { getRandomIntInclusive, navStackUtils } from '@wcmzllx/utils-library';
import { BarChartNewWidget } from "../components/common/BarChartNewWidget"
import { LineChartWidget } from "../components/common/LineChartWidget"
import { TopologyMapWidget } from "../components/home/TopologyMapWidget"
// 定义文本样式的方法,使文本样式统一且易于管理
@Extend(Text)
function textStyles(size: number, color: ResourceColor, weight: FontWeight, lineHeight = 11) {
.fontSize(vp2.vp2(size))
.fontColor(color)
.fontWeight(weight)
.lineHeight(vp2.vp2(lineHeight))
}
// 首页视图组件,包含多个子组件和数据展示
@Preview
@ComponentV2
export struct HomeView {
// 导航栈,用于页面跳转
private indexNavStack: NavPathStack = navStackUtils.getIndexStack();
// 本地数据,用于展示在首页的不同卡片中
@Local data: string[][] = [
["CPU TOP5", "%"],
["风扇状态", "Rpm"],
["内存 TOP5", "%"],
["接口量 TOP5", "%"],
["风扇状态", "℃"],
["丢包率 TOP5", ""],
["光功率", "mw"]
]
// 柱状图数据模型数组,用于展示告警趋势
@Local lineData: BarChartDateModel[] = [
{ xAxis: '9月12日', value: getRandomIntInclusive(0, 100) },
{ xAxis: '9月13日', value: getRandomIntInclusive(0, 100) },
{ xAxis: '9月14日', value: getRandomIntInclusive(0, 100) },
{ xAxis: '9月15日', value: getRandomIntInclusive(0, 100) },
{ xAxis: '9月16日', value: getRandomIntInclusive(0, 100) },
];
// 构建首页视图
build() {
Column() {
// 首页的标题与其它都不同,单独写
this.titleBuilder()
Column() {
Scroll() {
Column({ space: vp2.vp2(15) }) {
Column({ space: 15 }) {
Row({ space: vp2.vp2(19.5) }) {
Stack() {
Image($r("app.media.ic_btn_unselect"))
.width(CommonConst.GLOBAL_FULL_SCREEN)
.height(CommonConst.GLOBAL_FULL_SCREEN)
Text("拓扑图")
.textStyles(14, commonColor.WHITE_COLOR, FontWeight.Normal, 11)
}
.padding(vp2.vp2(6))
.width(vp2.vp2(75))
.height(vp2.vp2(38))
.onClick(() => {
this.indexNavStack.pushPathByName("NetworkTopologyView", undefined)
})
Stack() {
Image($r("app.media.ic_btn_unselect"))
.width(CommonConst.GLOBAL_FULL_SCREEN)
.height(CommonConst.GLOBAL_FULL_SCREEN)
Text("机房图")
.textStyles(14, commonColor.WHITE_COLOR, FontWeight.Bold, 11)
}
.padding(vp2.vp2(6))
.width(vp2.vp2(75))
.height(vp2.vp2(38))
}
.height(vp2.vp2(38))
Row() {
// Image($r("app.media.ic_home"))
// .width(CommonConst.GLOBAL_FULL_SCREEN)
// .height(CommonConst.GLOBAL_FULL_SCREEN)
// .onClick(()=>{
// this.indexNavStack.pushPathByName("NetworkTopologyView", undefined)
// })
// .autoResize(true)
// .syncLoad(true)
TopologyMapWidget()
}
.width(CommonConst.GLOBAL_FULL_SCREEN)
.layoutWeight(1)
}
.margin({ top: vp2.vp2(12) })
.padding(vp2.vp2(10))
.width(CommonConst.GLOBAL_FULL_SCREEN)
.height(vp2.vp2(290))
.borderRadius(vp2.vp2(5))
.backgroundColor("#FF102042")
HomeCardWidget({
title: "设备类别",
contentView: this.contentBuilder,
buttonContent: "查看详情"
})
HomeCardWidget({
title: "平均响应",
contentView: this.contentBuilder,
buttonContent: "查看详情"
})
HomeCardWidget({
title: "告警趋势",
contentView: this.lineContentBuilder
})
HomeCardWidget({
title: "核心设备情况",
contentView: this.meterContentBuilder
})
ForEach(this.data, (item: string[]) => {
HomeCardWidget({
title: item[0],
contentView: () => {
this.barContentBuilder(item[1])
}
})
})
}
.width(CommonConst.GLOBAL_FULL_SCREEN)
.padding({
left: vp2.vp2(15),
right: vp2.vp2(15),
bottom: vp2.vp2(uiWindows.getNavigationHeight())
})
}
}
.layoutWeight(1)
}
.backgroundColor("#FF000B11")
}
// 展示核心设备情况的内容构建器
@LocalBuilder
meterContentBuilder() {
Row() {
Column() {
Image($r("app.media.ic_meter"))
.width(vp2.vp2(118))
.aspectRatio(1)
Text("入口流量")
.textStyles(13, "#FFADC0E6", FontWeight.Regular, 8)
}
Blank()
Column() {
Image($r("app.media.ic_meter"))
.width(vp2.vp2(118))
.aspectRatio(1)
Text("出口流量")
.textStyles(13, "#FFADC0E6", FontWeight.Regular, 8)
}
}
.padding({ left: vp2.vp2(51.5), right: vp2.vp2(51.5) })
.width(CommonConst.GLOBAL_FULL_SCREEN)
.height(vp2.vp2(160))
}
// 展示告警趋势的内容构建器
@LocalBuilder
lineContentBuilder() {
Row() {
LineChartWidget({
data: this.lineData,
})
}
.padding({ bottom: vp2.vp2(6) })
}
// 通用内容构建器,用于展示设备类别和平均响应
@Builder
contentBuilder() {
BarChartNewWidget()
.width(CommonConst.GLOBAL_FULL_SCREEN)
.height(vp2.vp2(160))
}
// 柱状图内容构建器,根据传入的单位展示不同的数据
@Builder
barContentBuilder(yUnit: string) {
BarChartNewWidget({ yUnit: yUnit })
.width(CommonConst.GLOBAL_FULL_SCREEN)
.height(vp2.vp2(160))
}
// 标题构建器,用于展示首页的标题和品牌信息
@Builder
titleBuilder() {
Column() {
Blank().height(vp2.vp2(59))
Stack({ alignContent: Alignment.End }) {
Image($r("app.media.ic_home_top"))
.width(CommonConst.GLOBAL_FULL_SCREEN)
.height(vp2.vp2(60.5))
.offset({
y: vp2.vp2(10)
})
Row() {
Row() {
Image($r("app.media.ic_brand_icon"))
.width(vp2.vp2(70))
.height(vp2.vp2(35))
Text("优雅草星云物联网AI智控系统").fontSize(vp2.vp2(17)).fontColor(commonColor.WHITE_COLOR)
}
.width(vp2.vp2(262))
.height(vp2.vp2(35))
.offset({ x: vp2.vp2(-15) })
}
.width(CommonConst.GLOBAL_FULL_SCREEN)
.justifyContent(FlexAlign.Center)
}
.width(CommonConst.GLOBAL_FULL_SCREEN)
.height(vp2.vp2(44))
}
//.backgroundColor("#FF091429")
.width(CommonConst.GLOBAL_FULL_SCREEN)
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
- 229.
- 230.
- 231.
- 232.
- 233.
- 234.
- 235.
- 236.
- 237.
- 238.
- 239.
- 240.
- 241.
- 242.
- 243.
- 244.
- 245.
- 246.
lib/ComponentLibrary/src/main/ets/components/warning/WarningChartCardWidget.ets 告警中心 卡片页
lib/CommonConstLibrary/src/main/ets/model/DateModel.ets 日期数据模型定义 下方还有格外几个页面
这里发现我们已经开始定义数据模型,因此是CommonConstLibrary目录下,这里是扩展知识
1. 数据模型定义
- 业务实体建模:
model
目录里的文件很可能用于定义应用中的数据模型。比如,在一个电商应用中,可能会有定义商品信息的 ProductModel.ts
(假设使用 ArkTS 语言)文件,在该文件中通过类或者接口来描述商品的数据结构,像商品的 ID、名称、价格、描述、图片路径等属性。
- 数据交互结构:除了业务实体,还可能定义与服务器交互时使用的数据结构模型。例如,定义服务器响应数据格式或者请求参数格式的模型。如果服务器返回用户信息,可能有
UserResponseModel.ts
文件来定义响应数据结构。
2. 常量与枚举定义
- 通用常量:如果
CommonConstLibrary
是用于存放通用的常量库,model
目录下可能存放与数据模型相关的常量。比如,定义用户角色类型的常量。
- 枚举类型:用于定义一些固定取值集合的数据类型。例如,在一个任务管理应用中,定义任务状态的枚举。
3. 数据处理与转换逻辑
- 模型转换函数:可能包含将一种数据格式转换为另一种数据格式的函数。比如,将服务器返回的原始数据转换为符合应用内数据模型的格式。假设服务器返回的商品数据中有一些额外的字段不需要在应用内使用,就可以在
model
目录下的文件中定义转换函数。
4. 数据验证逻辑
- 模型验证:为了确保数据的正确性和完整性,
model
目录下可能包含验证数据是否符合模型定义的逻辑。例如,验证一个用户注册数据是否符合 UserModel
的要求,检查用户名长度、邮箱格式等。
lib/CommonConstLibrary/src/main/ets/model/BarChartDateModel.ets 图表数据模型
lib/CommonConstLibrary/src/main/ets/model/ApiModel.ets 数据模型api
lib/CommonConstLibrary/src/main/ets/model/InputDataModel.ets 输入数据模型
lib/CommonConstLibrary/src/main/ets/model/SettingsItemModel.ets 设置数据模型
lib/ComponentLibrary/src/main/ets/components/warning/WarningDeviceInfoWidget.ets 告警设备详细信息
/*
* Copyright (c) 2025.成都市一颗优雅草科技有限公司
* author:卓伊凡-优雅草技术总监
* project:优雅草星云物联网智控AI系统
*/
import { commonColor, CommonConst } from "@wcmzllx/common-const-library"
import { vp2 } from "../../common/NewVp"
/**
* 扩展Text组件的样式配置函数
* 用于统一设置文本的字体大小、颜色、权重、对齐方式、宽度和行高
*
* @param size 文本字体大小
* @param color 文本颜色
* @param weight 字体权重
* @param lineHeight 行高,默认为11
*/
@Extend(Text)
function textStyles(size: number, color: ResourceColor, weight: FontWeight, lineHeight = 11) {
.fontSize(vp2.vp2(size))
.fontColor(color)
.fontWeight(weight)
.textAlign(TextAlign.Start)
.width(CommonConst.GLOBAL_FULL_SCREEN)
.lineHeight(lineHeight)
}
/**
* 设备信息警告组件
* 显示设备的CPU、内存利用率,响应时间和端口使用率等信息
*/
@ComponentV2
export struct WarningDeviceInfoWidget {
build() {
// 布局主体结构,包含两列设备信息
Row(){
Column({ space: vp2.vp2(15) }) {
// 第一列:CPU和内存利用率
Row({ space: vp2.vp2(6.5) }) {
this.deviceInfoBuilder($r("app.media.ic_cpu"), "设备平均CPU利用率", "0%", "rgba(0, 141, 240, 0.06)")
this.deviceInfoBuilder($r("app.media.ic_memory"), "设备平均内存利用率", "0%", "rgba(240, 164, 0, 0.06)")
}
.width(CommonConst.GLOBAL_FULL_SCREEN)
// 第二列:响应时间和端口使用率
Row({ space: vp2.vp2(6.5) }) {
this.deviceInfoBuilder($r("app.media.ic_cpu"), "响应时间", "0%", "rgba(22, 202, 70, 0.06)")
this.deviceInfoBuilder($r("app.media.ic_com_port"), "端口使用率", "0%", "rgba(17, 195, 207, 0.06)")
}
.width(CommonConst.GLOBAL_FULL_SCREEN)
}
.borderRadius(5)
.backgroundColor(commonColor.WHITE_COLOR)
.padding({top: vp2.vp2(10.5), bottom: vp2.vp2(10.5), left: vp2.vp2(11), right: vp2.vp2(11)})
}
.padding({left: vp2.vp2(15), right: vp2.vp2(15)})
}
/**
* 构建单个设备信息项
*
* @param icon 设备信息项的图标
* @param title 设备信息项的标题
* @param content 设备信息项的内容
* @param color 背景颜色
*/
@Builder
deviceInfoBuilder(icon: ResourceStr, title: string, content: string, color: ResourceColor) {
Row({ space: vp2.vp2(5) }) {
// 设备信息项的图标
Stack() {
Image(icon)
.width(vp2.vp2(19.35))
.aspectRatio(1)
}
.backgroundColor(color)
.width(vp2.vp2(40))
.aspectRatio(1)
.borderRadius(vp2.vp2(2.58))
// 设备信息项的标题和内容
Column({ space: vp2.vp2(3.5) }) {
Text(content)
.textStyles(17, commonColor.BLACK_COLOR, FontWeight.Regular, 19.92)
Text(title)
.textStyles(13, commonColor.FONT_9999_COLOR, FontWeight.Regular, 15.23)
}
}
.layoutWeight(1)
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
lib/ComponentLibrary/src/main/ets/components/warning/WarningSearchWidget.ets 告警设备检索
lib/UtilsLibrary/src/main/ets/utils/DateUtils.ets 数据计入
以上内容就是以下几个页面,并且这几个页面都还未包含完整的内容:
首页 ,其实由于卓伊凡今天才来更新,但是今天其实已经有数据对接了

首页图表的部分

告警中心的部分

更多代码 请查看我们的gitee