---
title: 日志管理
summary: 门锁相册、告警、日志三类记录的管理，以及各类日志的文案处理与相关 API 说明。
---

## 日志管理

门锁的记录有三类：相册记录、告警记录、日志记录。

### 相册记录

- 支持视频和图片抓拍的锁会有此类记录，因此记录中会包含有图片和视频，一般会在有人按门铃、有人逗留等情况产生；
- 出于安全风险考虑，涂鸦会对图片和视频进行加密处理，开发者需要使用特定的能力及方案才能正常展示。

图片处理方案请参数： [多媒体图片处理](/cn/miniapp/solution-ai/ability/doorlock-solution/media/photo)

视频处理方案请参数： [多媒体图片处理](/cn/miniapp/solution-ai/ability/doorlock-solution/media/video)

#### 告警记录

门锁告警时产生的记录，包含如：防撬、密码试错、指纹试错、逗留、劫持、低电量等告警

### 日志记录

记录类型有

- close_record 表示关锁日志
- unlock_record 表示开锁日志
- operation 操作类日志
- local_operation 设备本地操作日志
- dev_bind 设备绑定日志

### 日志文案处理

告警处理

```jsx

export const codeOnlyShowDpCodeText = [
  'doorbell',
  'unlock_offline_clear',
  'unlock_offline_clear_single',
];
const getText = (log) => {
    const text = codeOnlyShowDpCodeText.includes(log.dpCode)
        ? Strings.getDpLang(log.dpCode)
        : Strings.getDpLang(log.dpCode, log.data as string);
    if (log.isHijack) {
        // 是否劫持
        return `${Strings.getDpLang('hijack')}【${text}】`;
    }
    return text;
}
```

关锁日志

```
const text = Strings.getLang(`locked_${log.closeValue}`);

```

本地操作记录

```tsx

import {
  LocalOperateCategory,
  LocalSettingData,
  LocalUnlockMethodData,
  LogData,
} from '@ray-js/lock-sdk';

const getLocalOperationText = (log: LogData) => {
  if (!log.localRecord) {
    return Strings.getLang('unkownLocalOperation');
  }

  const { category, userId, userType, toUserType, toUserId } = log.localRecord;
  switch (category) {
    case LocalOperateCategory.DELETE_UNLOCK_METHOD: {
      const { unlockMethod, unlockId, isRemoveAll } = log.localRecord as LocalUnlockMethodData;
      if (isRemoveAll) {
        return Strings.formatValue(
          'localDeleteAllUnlockMethod',
          Strings.getLang(`localUser${userType}`),
          userId,
          Strings.getLang(`localUser${toUserType}`),
          toUserId,
          Strings.getLang(unlockMethod)
        );
      }
      return Strings.formatValue(
        'deleteUnlockMethod',
        Strings.getLang(`localUser${userType}`),
        userId,
        Strings.getLang(`localUser${toUserType}`),
        toUserId,
        Strings.getLang(unlockMethod),
        unlockId
      );
    }
    case LocalOperateCategory.ADD_UNLOCK_METHOD: {
      const { unlockMethod, unlockId } = log.localRecord as LocalUnlockMethodData;
      return Strings.formatValue(
        'localAddUnlockMethod',
        Strings.getLang(`localUser${userType}`),
        userId,
        Strings.getLang(`localUser${toUserType}`),
        toUserId,
        Strings.getLang(unlockMethod),
        unlockId
      );
    }
    case LocalOperateCategory.MODIFY_UNLOCK_METHOD: {
      const { unlockMethod, unlockId } = log.localRecord as LocalUnlockMethodData;
      return Strings.formatValue(
        'localModifyUnlockMethod',
        Strings.getLang(`localUser${userType}`),
        userId,
        Strings.getLang(`localUser${toUserType}`),
        toUserId,
        Strings.getLang(unlockMethod),
        unlockId
      );
    }
    case LocalOperateCategory.ADD_USER:
      return Strings.formatValue(
        'localAddUser',
        Strings.getLang(`localUser${userType}`),
        userId,
        Strings.getLang(`localUser${toUserType}`),
        toUserId
      );
    case LocalOperateCategory.DELETE_USER:
      return Strings.formatValue(
        'localDeleteUser',
        Strings.getLang(`localUser${userType}`),
        userId,
        Strings.getLang(`localUser${toUserType}`),
        toUserId
      );
    case LocalOperateCategory.SETTING: {
      const { type, data } = log.localRecord as LocalSettingData;
      /**
       * 配置性数据多语言 key 规则：
       * 名称 key： localSetting_{type};
       * 值 key： localSetting_{type}_{data};
       */
      if (typeof data === 'number') {
        return Strings.formatValue(
          'localSetting',
          Strings.getLang(`localUser${userType}`),
          userId,
          // @ts-expect-error
          Strings.getLang(`localSetting_${type}`),
          // @ts-expect-error
          Strings.getLang(`localSetting_${type}_${data}`)
        );
      }
      return Strings.formatValue(
        'localSetting1',
        Strings.getLang(`localUser${userType}`),
        userId,
        // @ts-expect-error
        Strings.getLang(`localSetting_${type}`)
      );
    }
    default:
      return Strings.getLang('unkownLocalOperation');
  }
};
```

操作类日志

```tsx
const {
    property: { type, scale, unit },
} = dpSchema[log.dpCode] || {};
switch (type) {
case 'value':
    return Strings.formatValue(
    'settingRecord',
    Strings.getDpLang(log.dpCode),
    `${utils.scaleNumber(scale, log.data as number)}${Strings.getDpLang(
        log.dpCode,
        'unit'
    )}`
    );
case 'enum':
    return Strings.formatValue(
    'settingRecord',
    Strings.getDpLang(log.dpCode),
    Strings.getDpLang(log.dpCode, log.data as string)
    );
case 'bool':
    return Strings.formatValue(
    'settingRecord',
    Strings.getDpLang(log.dpCode),
    Strings.getDpLang(log.dpCode, log.data as boolean)
    );
default:
    return Strings.getDpLang(log.dpCode);
}
```

开锁日志

```tsx

import {
  getCurrentUserSync,
  LocalOperateCategory,
  LocalSettingData,
  LocalUnlockMethodData,
  LogData,
  unlockDp2Type,
} from '@ray-js/lock-sdk';

const getUnlockText = (log: LogData) => {
  const user = getCurrentUserSync();
  // 是否为组合开锁
  if (log.unionUnlockInfo?.length) {
    const logText = log.unionUnlockInfo
      .map(item => {
        let { userName } = item;
        if (item.userId === user?.userId) {
          userName = Strings.getLang('you');
        }
        return Strings.formatValue(
          'unlockFormat',
          userName,
          item.unlockName ? item.unlockName : Strings.getLang(item.type)
        );
      })
      .join('、');
    return Strings.formatValue('unionUnlock', logText);
  }
  if (log.userName && log.unlockName) {
    // 如果存在用户和解锁名称，表示是用户操作
    return Strings.formatValue(
      'unlockFormat',
      log.userId === user?.userId ? Strings.getLang('you') : log.userName,
      log.unlockName
    );
  }
  // 有名称时
  if (log.unlockName) {
    return Strings.formatValue('unlockFormat1', log.unlockName);
  }

  // 以下为无名称情况处理
  // 临时或离线密码处理
  if ([69, 89].indexOf(log.dpId) !== -1) {
    // 临时或离线密码处理
    return Strings.getDpLang(log.dpCode);
  }
  // 一些特殊的解锁
  if (codeOnlyShowDpCodeText.includes(log.dpCode)) {
    return Strings.getDpLang(log.dpCode);
  }

  // 解锁方式处理
  if (unlockDp2Type[log.dpCode]) {
    return Strings.formatValue(
      'unlockFormat2',
      Strings.getLang(unlockDp2Type[log.dpCode]),
      log.data
    );
  }

  return Strings.getDpLang(log.dpCode);
};
```

### API

#### 获取最近 2 条记录

- 含义：获取最近 2条记录，包括告警、开锁、关锁、操作日志等
- 详细：[查看文档](/cn/miniapp/develop/ray/api/doorlock/log/getLatestLogs)

#### 获取日志记录

- 含义：获取日志记录，包括开锁、关锁、操作、本地操作等日志
- 详细：[查看文档](/cn/miniapp/develop/ray/api/doorlock/log/getLogs)

#### 获取告警列表

- 含义：获取告警记录列表
- 详细：[查看文档](/cn/miniapp/develop/ray/api/doorlock/log/getAlarms)

#### 获取相册日志

- 含义：获取相册日志
- 详细：[查看文档](/cn/miniapp/develop/ray/api/doorlock/log/getAlbums)

#### 注册通知可刷新日志事件

- 含义：当收到相关的记录 DP 上报时，会触发此事件
- 详细：[查看文档](/cn/miniapp/develop/ray/api/doorlock/log/onLogsRefresh)

#### 注销通知可刷新日志事件

- 含义：注销通过 `onLogsRefresh` 注册的事件
- 详细：[查看文档](/cn/miniapp/develop/ray/api/doorlock/log/offLogsRefresh)

## 常见问题

### Q1: 如何区分不同类型的日志？

**A:** 通过 `type` 字段区分：

- `unlock_record`: 开门记录
- `close_record`: 关锁记录
- `alarm_record`: 告警记录
- `dev_bind`: 设备绑定记录
- `local_operation`: 本地操作记录

### Q2: 如何判断日志是否可绑定到成员？

**A:** 通过 `bindable` 字段判断，如果为 `true`，表示该日志中的开锁方式可以绑定到成员。

### Q3: 如何获取日志中的媒体文件？

**A:** 日志对象中的 `mediaInfo` 字段包含媒体信息，使用 `getMediaUrl` API 获取实际播放地址：

```typescript
const mediaUrl = await getMediaUrl({
  mediaPath: log.mediaInfo[0].mediaPath,
  mediaBucket: log.mediaInfo[0].mediaBucket
});
```

### Q4: 联合开锁信息是什么？

**A:** `unionUnlockInfo` 表示多人联合开锁的信息，包含参与开锁的用户和开锁方式信息。

### Q5: 如何实现日志的实时更新？

**A:** 使用 `onLogsRefresh` 监听日志更新事件：

```typescript
onLogsRefresh(() => {
  // 重新获取日志列表
  fetchLogs();
});
```

### Q6: 相册记录支持哪些设备？

**A:** 相册记录仅支持视对讲设备（带摄像头的门锁设备）。

### Q7: 如何获取未读日志数量？

**A:** 使用 `getLatestLogs` API，返回结果中的 `unreadCount` 字段表示未读数量。
