From 93f60c74abd26f6e8f476c9f8983df1dfbfa0fcd Mon Sep 17 00:00:00 2001
From: czz <862977248@qq.com>
Date: Thu, 7 May 2026 16:44:13 +0800
Subject: [PATCH 1/2] docs: add message page design spec
---
.../specs/2026-05-07-message-page-design.md | 173 ++++++++++++++++++
1 file changed, 173 insertions(+)
create mode 100644 docs/superpowers/specs/2026-05-07-message-page-design.md
diff --git a/docs/superpowers/specs/2026-05-07-message-page-design.md b/docs/superpowers/specs/2026-05-07-message-page-design.md
new file mode 100644
index 0000000..5424ec7
--- /dev/null
+++ b/docs/superpowers/specs/2026-05-07-message-page-design.md
@@ -0,0 +1,173 @@
+# 消息页面设计说明
+
+## 1. 目标
+
+在当前微信小程序项目中新增一个“消息”页面,页面风格参考提供的设计图,并与现有首页形成双向页面跳转。
+
+本次目标是让项目从“只有首页”扩展为“首页 + 消息页”的可预览状态,同时保留后续继续新增“报告”“我的”等页面的扩展空间。
+
+## 2. 本次范围
+
+本次实现包含:
+
+- 新增消息页面
+- 首页与消息页之间的底部导航跳转
+- 抽取一个可复用的底部导航组件
+- 在消息页中实现顶部双标签、消息卡片列表、未读红点视觉
+- 更新页面注册配置
+- 更新 README,补充当前页面结构和消息页说明
+
+本次不包含:
+
+- 真正的后端消息接口
+- 消息已读、删除、下拉刷新、分页加载
+- “系统消息”标签下的真实内容切换接口
+- “报告”“小e”“我的”真实业务页
+
+## 3. 设计原则
+
+- 保持项目结构简单,适合新手继续修改
+- 尽量复用现有首页的深色视觉语言
+- 不额外引入新的大型依赖
+- 先完成静态页面和页面跳转,再为后续真实接口预留清晰结构
+
+## 4. 页面与组件设计
+
+### 4.1 消息页面
+
+新增目录:
+
+- `src/pages/message/index.tsx`
+- `src/pages/message/index.scss`
+- `src/pages/message/index.config.ts`
+
+页面内容分为三块:
+
+1. 顶部标签区
+2. 消息卡片列表区
+3. 底部导航区
+
+顶部标签区使用两个标签:
+
+- `体征消息`
+- `系统消息`
+
+默认高亮 `体征消息`,`系统消息` 右侧显示一个小红点作为未读提示。首版只做前端本地切换,切换后可展示不同的本地占位数据,不接接口。
+
+消息卡片列表区使用 3 条演示数据,卡片字段参考设计图:
+
+- 标题
+- 设备 ID
+- 使用人员
+- 消息类型
+- 检测数值
+- 发生时间
+
+页面整体继续使用深色背景、圆角卡片、浅色文字和青绿色高亮色,尽量与首页统一。
+
+### 4.2 底部导航组件
+
+新增目录:
+
+- `src/components/tab-bar/index.tsx`
+- `src/components/tab-bar/index.scss`
+
+组件负责:
+
+- 渲染统一的 5 个底部导航项
+- 根据传入的当前页面 key 控制高亮状态
+- 处理首页与消息页之间的跳转
+- 对暂未实现的页面继续保留轻提示
+
+组件入参保持简单,建议至少包含:
+
+- 当前激活项 key
+
+组件内部统一维护导航项配置,避免首页和消息页各自重复维护一份。
+
+## 5. 交互设计
+
+### 5.1 页面跳转
+
+- 首页点击底部 `消息`,跳转到消息页
+- 消息页点击底部 `首页`,跳转到首页
+- 点击当前已激活 tab 不重复跳转
+- 点击 `报告`、`小e`、`我的` 时,继续提示“功能待接入”
+
+为了避免多层页面堆栈,首页与消息页之间的 tab 切换优先使用 `Taro.redirectTo`。
+
+### 5.2 消息标签切换
+
+- 点击 `体征消息`,显示体征消息列表
+- 点击 `系统消息`,显示系统消息占位列表
+- 当前仅做前端状态切换,不持久化
+
+### 5.3 消息列表滚动
+
+如果卡片数量超过一屏,允许页面自然纵向滚动。底部导航固定在底部,页面内容区域保留足够底部内边距,避免被遮挡。
+
+## 6. 数据设计
+
+消息页首版使用本地静态数据。建议定义明确的 TypeScript 类型,例如:
+
+- `MessageTabKey`
+- `MessageItem`
+
+数据至少包含:
+
+- `id`
+- `title`
+- `deviceId`
+- `userName`
+- `messageType`
+- `valueText`
+- `occurredAt`
+- `category`
+
+其中 `category` 用于区分 `vital` 和 `system` 两类消息,便于本地筛选。
+
+## 7. 文件修改范围
+
+预计涉及文件:
+
+- `src/app.config.ts`
+- `src/pages/index/index.tsx`
+- `src/pages/index/index.scss`
+- `src/pages/message/index.tsx`
+- `src/pages/message/index.scss`
+- `src/pages/message/index.config.ts`
+- `src/components/tab-bar/index.tsx`
+- `src/components/tab-bar/index.scss`
+- `README.md`
+
+## 8. 测试与验证
+
+至少验证以下内容:
+
+- 项目可以正常编译
+- 首页底部 `消息` 可跳转到消息页
+- 消息页底部 `首页` 可跳回首页
+- 消息页顶部双标签可以切换
+- 当前激活 tab 样式正确
+- 页面底部内容不会被固定导航遮挡
+
+## 9. 风险与控制
+
+风险 1:底部导航从首页内联实现改为组件后,可能影响首页现有视觉。
+控制方式:保留原有视觉结构,优先抽取已有样式命名和布局逻辑,避免大改。
+
+风险 2:tab 切换若使用 `navigateTo`,可能导致页面堆栈不断增加。
+控制方式:首页与消息页之间统一使用 `redirectTo`。
+
+风险 3:消息页完全照搬图片可能与当前项目样式不一致。
+控制方式:保留设计图核心布局,但颜色、阴影、圆角与首页现有风格保持同一体系。
+
+## 10. 完成标准
+
+满足以下条件即可认为本次任务完成:
+
+- 小程序内已存在独立消息页
+- 首页与消息页可通过底部导航双向切换
+- 消息页主要视觉与提供的参考图接近
+- 代码结构对新手友好,文件职责清晰
+- README 已同步说明当前新增页面
From c63f29e500ad35c189cdcbc705e19883e25cd96c Mon Sep 17 00:00:00 2001
From: czz <862977248@qq.com>
Date: Thu, 7 May 2026 17:13:00 +0800
Subject: [PATCH 2/2] feat: add message page
---
src/app.config.ts | 2 +-
src/components/tab-bar/index.scss | 164 ++++++++++++++++++++++++++++++
src/components/tab-bar/index.tsx | 63 ++++++++++++
src/pages/index/index.scss | 86 ----------------
src/pages/index/index.tsx | 24 +----
src/pages/message/index.config.ts | 4 +
src/pages/message/index.scss | 129 +++++++++++++++++++++++
src/pages/message/index.tsx | 145 ++++++++++++++++++++++++++
8 files changed, 508 insertions(+), 109 deletions(-)
create mode 100644 src/components/tab-bar/index.scss
create mode 100644 src/components/tab-bar/index.tsx
create mode 100644 src/pages/message/index.config.ts
create mode 100644 src/pages/message/index.scss
create mode 100644 src/pages/message/index.tsx
diff --git a/src/app.config.ts b/src/app.config.ts
index 4e2430c..8fb4fc0 100644
--- a/src/app.config.ts
+++ b/src/app.config.ts
@@ -1,5 +1,5 @@
export default defineAppConfig({
- pages: ["pages/index/index"],
+ pages: ["pages/index/index", "pages/message/index"],
window: {
navigationBarTitleText: "新手小程序",
navigationBarBackgroundColor: "#1AAD19",
diff --git a/src/components/tab-bar/index.scss b/src/components/tab-bar/index.scss
new file mode 100644
index 0000000..aded8a7
--- /dev/null
+++ b/src/components/tab-bar/index.scss
@@ -0,0 +1,164 @@
+.app-tabbar {
+ position: fixed;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 10;
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-around;
+ padding: 16rpx 24rpx calc(20rpx + env(safe-area-inset-bottom));
+ background: rgba(24, 30, 43, 0.98);
+ box-shadow: 0 -8rpx 24rpx rgba(4, 8, 20, 0.34);
+}
+
+.app-tabbar__item {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ min-width: 88rpx;
+}
+
+.app-tabbar__icon {
+ position: relative;
+ width: 34rpx;
+ height: 34rpx;
+ margin-bottom: 8rpx;
+ color: #8f97a9;
+}
+
+.app-tabbar__icon::before,
+.app-tabbar__icon::after {
+ position: absolute;
+ content: "";
+}
+
+.app-tabbar__icon--home {
+ border: 2rpx solid currentColor;
+ border-top: none;
+ border-radius: 0 0 8rpx 8rpx;
+}
+
+.app-tabbar__icon--home::before {
+ left: 4rpx;
+ top: -2rpx;
+ width: 22rpx;
+ height: 22rpx;
+ border-top: 2rpx solid currentColor;
+ border-left: 2rpx solid currentColor;
+ transform: rotate(45deg);
+ background: transparent;
+}
+
+.app-tabbar__icon--report::before,
+.app-tabbar__icon--report::after {
+ bottom: 4rpx;
+ width: 6rpx;
+ border-radius: 999rpx;
+ background: currentColor;
+}
+
+.app-tabbar__icon--report::before {
+ left: 7rpx;
+ height: 16rpx;
+}
+
+.app-tabbar__icon--report::after {
+ left: 19rpx;
+ height: 24rpx;
+}
+
+.app-tabbar__icon--assistant {
+ border: 2rpx solid currentColor;
+ border-radius: 50%;
+}
+
+.app-tabbar__icon--assistant::before {
+ left: 6rpx;
+ top: 8rpx;
+ width: 18rpx;
+ height: 10rpx;
+ border-bottom: 2rpx solid currentColor;
+ border-radius: 0 0 12rpx 12rpx;
+}
+
+.app-tabbar__icon--assistant::after {
+ left: 12rpx;
+ top: 6rpx;
+ width: 4rpx;
+ height: 4rpx;
+ border-radius: 50%;
+ background: currentColor;
+ box-shadow: 8rpx 0 0 currentColor;
+}
+
+.app-tabbar__icon--message {
+ border: 2rpx solid currentColor;
+ border-radius: 10rpx;
+}
+
+.app-tabbar__icon--message::before,
+.app-tabbar__icon--message::after {
+ left: 8rpx;
+ right: 8rpx;
+ height: 2rpx;
+ background: currentColor;
+}
+
+.app-tabbar__icon--message::before {
+ top: 10rpx;
+}
+
+.app-tabbar__icon--message::after {
+ bottom: 10rpx;
+}
+
+.app-tabbar__icon--mine {
+ border: 2rpx solid currentColor;
+ border-radius: 50%;
+}
+
+.app-tabbar__icon--mine::before {
+ left: 9rpx;
+ top: 5rpx;
+ width: 12rpx;
+ height: 12rpx;
+ border-radius: 50%;
+ background: currentColor;
+}
+
+.app-tabbar__icon--mine::after {
+ left: 5rpx;
+ bottom: 5rpx;
+ width: 20rpx;
+ height: 10rpx;
+ border-radius: 10rpx 10rpx 6rpx 6rpx;
+ border: 2rpx solid currentColor;
+ background: transparent;
+}
+
+.app-tabbar__icon--active {
+ color: #36e4aa;
+}
+
+.app-tabbar__badge {
+ position: absolute;
+ top: -4rpx;
+ right: -4rpx;
+ width: 10rpx;
+ height: 10rpx;
+ border-radius: 50%;
+ background: #ff4d4f;
+ box-shadow: 0 0 0 4rpx rgba(24, 30, 43, 0.98);
+}
+
+.app-tabbar__label {
+ color: #b0b6c4;
+ font-size: 20rpx;
+ line-height: 1.2;
+}
+
+.app-tabbar__label--active {
+ color: #36e4aa;
+}
diff --git a/src/components/tab-bar/index.tsx b/src/components/tab-bar/index.tsx
new file mode 100644
index 0000000..e41ab21
--- /dev/null
+++ b/src/components/tab-bar/index.tsx
@@ -0,0 +1,63 @@
+import { Text, View } from "@tarojs/components";
+import Taro from "@tarojs/taro";
+import "./index.scss";
+
+export type TabBarKey = "home" | "report" | "assistant" | "message" | "mine";
+
+type TabBarProps = {
+ activeKey: TabBarKey;
+};
+
+type TabItem = {
+ key: TabBarKey;
+ label: string;
+ hasBadge?: boolean;
+ pagePath?: string;
+};
+
+const tabItems: TabItem[] = [
+ { key: "home", label: "首页", pagePath: "/pages/index/index" },
+ { key: "report", label: "报告" },
+ { key: "assistant", label: "小e" },
+ { key: "message", label: "消息", hasBadge: true, pagePath: "/pages/message/index" },
+ { key: "mine", label: "我的" }
+];
+
+export default function TabBar({ activeKey }: TabBarProps) {
+ const showToast = (title: string) => {
+ Taro.showToast({
+ title,
+ icon: "none"
+ });
+ };
+
+ const handleTabClick = (item: TabItem) => {
+ if (item.key === activeKey) {
+ return;
+ }
+
+ if (item.pagePath) {
+ Taro.redirectTo({ url: item.pagePath });
+ return;
+ }
+
+ showToast(`${item.label}功能待接入`);
+ };
+
+ return (
+
+ {tabItems.map((item) => {
+ const isActive = item.key === activeKey;
+
+ return (
+ handleTabClick(item)}>
+
+ {item.hasBadge ? : null}
+
+ {item.label}
+
+ );
+ })}
+
+ );
+}
diff --git a/src/pages/index/index.scss b/src/pages/index/index.scss
index 92ba0f8..376d594 100644
--- a/src/pages/index/index.scss
+++ b/src/pages/index/index.scss
@@ -363,89 +363,3 @@
line-height: 1.7;
}
-.device-tabbar {
- position: fixed;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 5;
- display: flex;
- align-items: flex-start;
- justify-content: space-around;
- padding: 16rpx 24rpx calc(20rpx + env(safe-area-inset-bottom));
- background: rgba(30, 35, 48, 0.98);
- box-shadow: 0 -8rpx 24rpx rgba(4, 8, 20, 0.34);
-}
-
-.device-tabbar__item {
- position: relative;
- display: flex;
- flex-direction: column;
- align-items: center;
- min-width: 88rpx;
-}
-
-.device-tabbar__icon {
- position: relative;
- width: 34rpx;
- height: 34rpx;
- margin-bottom: 8rpx;
- border-radius: 10rpx;
- border: 2rpx solid #8f97a9;
- opacity: 0.86;
-}
-
-.device-tabbar__icon::before,
-.device-tabbar__icon::after {
- position: absolute;
- content: "";
-}
-
-.device-tabbar__icon::before {
- left: 8rpx;
- right: 8rpx;
- top: 10rpx;
- height: 2rpx;
- background: currentColor;
- color: #8f97a9;
-}
-
-.device-tabbar__icon::after {
- left: 8rpx;
- right: 8rpx;
- bottom: 10rpx;
- height: 2rpx;
- background: currentColor;
- color: #8f97a9;
-}
-
-.device-tabbar__icon--active {
- border-color: #36e4aa;
- background: rgba(54, 228, 170, 0.12);
-}
-
-.device-tabbar__icon--active::before,
-.device-tabbar__icon--active::after {
- color: #36e4aa;
-}
-
-.device-tabbar__badge {
- position: absolute;
- top: -4rpx;
- right: -4rpx;
- width: 10rpx;
- height: 10rpx;
- border-radius: 50%;
- background: #ff4d4f;
- box-shadow: 0 0 0 4rpx rgba(30, 35, 48, 0.98);
-}
-
-.device-tabbar__label {
- color: #b0b6c4;
- font-size: 20rpx;
- line-height: 1.2;
-}
-
-.device-tabbar__label--active {
- color: #36e4aa;
-}
diff --git a/src/pages/index/index.tsx b/src/pages/index/index.tsx
index 76f5c6c..82011b7 100644
--- a/src/pages/index/index.tsx
+++ b/src/pages/index/index.tsx
@@ -1,6 +1,7 @@
import { Text, View } from "@tarojs/components";
import Taro from "@tarojs/taro";
import { useEffect, useRef, useState } from "react";
+import TabBar from "../../components/tab-bar";
import "./index.scss";
type BluetoothStatus = "idle" | "searching" | "empty" | "success";
@@ -17,14 +18,6 @@ const notices = [
"3. 扫码功能需开启相机权限"
];
-const navItems = [
- { key: "home", label: "首页", active: true },
- { key: "report", label: "报告", active: false },
- { key: "assistant", label: "小e", active: false },
- { key: "message", label: "消息", active: false, badge: true },
- { key: "mine", label: "我的", active: false }
-];
-
const mockBluetoothDevices: DeviceCandidate[] = [
{ id: "mock-thermo-01", name: "体征监测设备 A1", source: "mock" },
{ id: "mock-thermo-02", name: "体征监测设备 B2", source: "mock" }
@@ -109,10 +102,6 @@ export default function Index() {
showToast("后续可从这里进入设备管理页");
};
- const handleTabClick = (label: string) => {
- showToast(`${label}功能待接入`);
- };
-
const handleScanBind = async () => {
try {
setStatusHint("等待扫码识别设备编码。");
@@ -334,16 +323,7 @@ export default function Index() {
-
- {navItems.map((item) => (
- handleTabClick(item.label)}>
-
- {item.badge ? : null}
-
- {item.label}
-
- ))}
-
+
);
}
diff --git a/src/pages/message/index.config.ts b/src/pages/message/index.config.ts
new file mode 100644
index 0000000..c344b06
--- /dev/null
+++ b/src/pages/message/index.config.ts
@@ -0,0 +1,4 @@
+export default definePageConfig({
+ navigationStyle: "custom",
+ navigationBarTitleText: "消息"
+});
diff --git a/src/pages/message/index.scss b/src/pages/message/index.scss
new file mode 100644
index 0000000..acc9b20
--- /dev/null
+++ b/src/pages/message/index.scss
@@ -0,0 +1,129 @@
+.message-page {
+ position: relative;
+ min-height: 100vh;
+ padding: 24rpx 24rpx 156rpx;
+ box-sizing: border-box;
+ background: linear-gradient(180deg, #1d2331 0%, #171d29 100%);
+ overflow: hidden;
+}
+
+.message-page__glow {
+ position: absolute;
+ border-radius: 50%;
+ pointer-events: none;
+}
+
+.message-page__glow--top {
+ top: -80rpx;
+ left: -40rpx;
+ width: 280rpx;
+ height: 280rpx;
+ background: radial-gradient(circle, rgba(55, 228, 171, 0.1), transparent 70%);
+}
+
+.message-page__glow--side {
+ top: 160rpx;
+ right: -90rpx;
+ width: 240rpx;
+ height: 320rpx;
+ background: radial-gradient(circle, rgba(86, 116, 184, 0.12), transparent 72%);
+}
+
+.message-tabs {
+ position: relative;
+ z-index: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 110rpx;
+ padding: 20rpx 0 28rpx;
+}
+
+.message-tabs__item {
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 120rpx;
+}
+
+.message-tabs__label {
+ color: #8f97ac;
+ font-size: 24rpx;
+ line-height: 1.3;
+}
+
+.message-tabs__label--active {
+ color: #36e4aa;
+ font-weight: 600;
+}
+
+.message-tabs__dot {
+ position: absolute;
+ top: 6rpx;
+ right: -10rpx;
+ width: 10rpx;
+ height: 10rpx;
+ border-radius: 50%;
+ background: #ff4d4f;
+}
+
+.message-tabs__line {
+ position: absolute;
+ left: 50%;
+ bottom: -10rpx;
+ width: 52rpx;
+ height: 4rpx;
+ border-radius: 999rpx;
+ background: linear-gradient(90deg, #35e5b3 0%, #20c9bf 100%);
+ transform: translateX(-50%);
+}
+
+.message-list {
+ position: relative;
+ z-index: 1;
+}
+
+.message-card {
+ padding: 24rpx 26rpx;
+ border-radius: 26rpx;
+ background: rgba(42, 48, 66, 0.96);
+ box-shadow: inset 0 0 0 2rpx rgba(255, 255, 255, 0.03);
+}
+
+.message-card + .message-card {
+ margin-top: 22rpx;
+}
+
+.message-card__title {
+ display: block;
+ margin-bottom: 18rpx;
+ color: #f3f7ff;
+ font-size: 28rpx;
+ font-weight: 600;
+ line-height: 1.5;
+}
+
+.message-card__row {
+ display: flex;
+ align-items: flex-start;
+ line-height: 1.7;
+}
+
+.message-card__row + .message-card__row {
+ margin-top: 6rpx;
+}
+
+.message-card__label {
+ width: 104rpx;
+ flex-shrink: 0;
+ color: #7f889d;
+ font-size: 22rpx;
+}
+
+.message-card__value {
+ flex: 1;
+ color: #d9dfeb;
+ font-size: 22rpx;
+ word-break: break-all;
+}
diff --git a/src/pages/message/index.tsx b/src/pages/message/index.tsx
new file mode 100644
index 0000000..c7064da
--- /dev/null
+++ b/src/pages/message/index.tsx
@@ -0,0 +1,145 @@
+import { Text, View } from "@tarojs/components";
+import { useState } from "react";
+import TabBar from "../../components/tab-bar";
+import "./index.scss";
+
+type MessageTabKey = "vital" | "system";
+
+type MessageItem = {
+ id: string;
+ title: string;
+ deviceId: string;
+ userName: string;
+ messageType: string;
+ valueText: string;
+ occurredAt: string;
+ category: MessageTabKey;
+};
+
+const tabs: Array<{ key: MessageTabKey; label: string; hasDot?: boolean }> = [
+ { key: "vital", label: "体征消息" },
+ { key: "system", label: "系统消息", hasDot: true }
+];
+
+const messageList: MessageItem[] = [
+ {
+ id: "vital-1",
+ title: "实时监测结果通知",
+ deviceId: "A54984651",
+ userName: "1201/李小北",
+ messageType: "心率异常",
+ valueText: "106",
+ occurredAt: "2024-07-30 01:15",
+ category: "vital"
+ },
+ {
+ id: "vital-2",
+ title: "睡眠报告分析通知",
+ deviceId: "A54984651",
+ userName: "1201/李小北",
+ messageType: "HRV异常",
+ valueText: "89",
+ occurredAt: "2024-07-30 01:15",
+ category: "vital"
+ },
+ {
+ id: "vital-3",
+ title: "睡眠月报分析通知",
+ deviceId: "A54984651",
+ userName: "1201/李小北",
+ messageType: "睡眠得分",
+ valueText: "有20天低于60分",
+ occurredAt: "2024-07-30 01:15",
+ category: "vital"
+ },
+ {
+ id: "system-1",
+ title: "系统升级提醒",
+ deviceId: "平台消息",
+ userName: "全部用户",
+ messageType: "版本更新",
+ valueText: "建议升级到最新版本",
+ occurredAt: "2024-07-30 09:30",
+ category: "system"
+ },
+ {
+ id: "system-2",
+ title: "服务时间调整通知",
+ deviceId: "平台消息",
+ userName: "全部用户",
+ messageType: "运营公告",
+ valueText: "周日 02:00-04:00 系统维护",
+ occurredAt: "2024-07-29 18:00",
+ category: "system"
+ }
+];
+
+const fieldLabels = {
+ deviceId: "设备ID",
+ userName: "使用人员",
+ messageType: "消息类型",
+ valueText: "检测数值",
+ occurredAt: "发生时间"
+};
+
+export default function MessagePage() {
+ const [activeTab, setActiveTab] = useState("vital");
+
+ const currentMessages = messageList.filter((item) => item.category === activeTab);
+
+ return (
+
+
+
+
+
+ {tabs.map((item) => {
+ const isActive = item.key === activeTab;
+
+ return (
+ setActiveTab(item.key)}>
+ {item.label}
+ {item.hasDot ? : null}
+ {isActive ? : null}
+
+ );
+ })}
+
+
+
+ {currentMessages.map((item) => (
+
+ {item.title}
+
+
+ {fieldLabels.deviceId}
+ {item.deviceId}
+
+
+
+ {fieldLabels.userName}
+ {item.userName}
+
+
+
+ {fieldLabels.messageType}
+ {item.messageType}
+
+
+
+ {fieldLabels.valueText}
+ {item.valueText}
+
+
+
+ {fieldLabels.occurredAt}
+ {item.occurredAt}
+
+
+ ))}
+
+
+
+
+ );
+}