---
tags: NeutecLife App
---
# 4.通知 API
:::info
目錄:
<a href="https://hackmd.io/FStSBTFdRhac3tsDr8OyiA">0.登入功能相關 API 文件</a>
<a href="https://hackmd.io/coOyibBDRYqJpluQIQFYmg">1.首頁功能相關 API 文件</a>
<a href="https://hackmd.io/-A3kGYJ8SHyjegBROlwJow">2-1.分類列表:分類列表頁、借書&歸還 API 文件</a>
<a href="https://hackmd.io/boCGrFpsR0CciLYEXS-kxw">2-2.分類列表:借物 API 文件</a>
<a href="https://hackmd.io/jBWDb0OaT_KV-_ducdzqsQ">2-3.分類列表:會議室&英文課 API 文件</a>
<a href="https://hackmd.io/FhZ89ZDxSbOK8oYslEXuCA">3.最新消息 API 文件</a>
<a href="https://hackmd.io/SSAxobFGQEC8lyHiu485iQ">4.通知 API 文件</a>
<a href="https://hackmd.io/Fz8d0LtbS2iwhuI3QmmzYQ">5.我的 API 文件</a>
> [time=Jan 4, 2024]
* `更新` Document init
> [time=Aug 8, 2024]
* `更新` 圖片路徑將不帶入domain,App端將預設domain帶入
* `更新` 欄位名稱修改:contentImgUrl -> contentImgUrl
> [time=Nov 4, 2024]
* `新增` 所有websocket API皆可額外帶入timeout參數
> [time=Feb 20, 2025]
* `更新` notificationPage.toastify與NotificationPage.dialogify中的title(上標)與content(下標)更名為category(上標)與title(下標)。
* `更新` noticePage response使用urlScheme作為導向頁面參數
> [time=Mar 5, 2025]
* `更新` badge module更名為unread,格式修改為陣列已儲存noticeIds
> [time=May 14, 2025]
* `新增` noticeDetailPage,從 noticePage 拆分出來
* `更新` noticePage 移除 content, contentImgUrl & urlScheme三個欄位
> [time=May 29, 2025]
* `更新` noticeDetailPage.noticeContent中的datetime(用於最後更新時間顯示的欄位),不顯示秒。ex:2025/5/29 13:30
> [time=Jul 18, 2025]
* `更新` Pushy推播payload變更,在meta中增加noticeId與group欄位
> [time=Feb 10, 2026]
* `更新`
----
:::
<a href="https://docs.google.com/spreadsheets/d/1qHcAhYWDky5LdZGumX5ite7Y9Tfuw07jwjZcDAs81qg/edit?gid=1129370366#gid=1129370366" target="_blank">‼️通知發送時機與文案</a>
#### Remark
```
所有websocket API皆可額外帶入timeout參數做測試用途:
參數名稱:timeout
值:0-9 代表延遲回應的秒數,可模擬網路不穩回應變慢的情況
99 代表Server端出現未知的錯誤,可模擬Server端某功能出現異常的情況
```
## 4. 通知 API
### ❇️noticePage
URL: `wss://{domain name}/`
Method: `wss`
Descirption: `通知列表頁資訊`
<img src='https://hackmd.io/_uploads/Syow5xlaJx.png' width='320' />
#### Remark
```
1. 從首頁點選右上角「鈴鐺」icon進入本頁。
2. 每個module皆可被單獨呼叫。
3. 若有異動將會主動通知僅被異動的資料。
```
**Request**
| Parameter | Type | Require | Description |
| ----------- | -------- | ------- | ----------- |
| requestId | string | Y | 對話id |
| page | string | Y | 手機畫面名稱 |
| module | string | Y | 功能區塊名稱 |
| type | string | Y | 資料處理型態 |
| data | object | Y | 資料參數 |
```json=
{
"requestId": "64d94767-c926-6156-44a5-8bf08a3691d4",
"page": "noticePage",
"module": "all",
"type": "select",
"data": {}
}
```
**Response**
| Parameter | Type | Require | Description |
| --------- | ------ | ------- | ----------- |
| requestId | string | Y | 對話id |
| status | string | Y | [狀態代碼](#狀態代碼)|
| page | string | Y | 手機畫面名稱 |
| info | array | Y | 手機畫面資訊 |
| module | string | Y | 手機畫面區塊名稱 |
| status | number | Y | [狀態代碼](#狀態代碼) |
| errorMsg | string | | 錯誤訊息 |
| type | string | Y | 資料處理型態 |
| num | string | Y | 資料筆數 |
| data | array | Y | 資料內容 |
<br>
**Response unread 公告未讀的編號module**
```
unread這個module每次都傳送「完整未讀」的清單,發送的時機點為:
1. App端要求noticePage module為all時
2. 一筆公告被新增至app中(發出)
3. 一筆公告被移除於app
4. 一筆公告被已讀
5. 一整個大類的所有公告被已讀
```
| Parameter | Type | Require | Description |
| --------- | ------ | ------- | ----------- |
| important | array | Y | 重要公告的未讀的noticeIds |
| event | array | Y | 活動快訊的未讀的noticeIds |
| personal | array | Y | 個人通知的未讀的noticeIds |
```
App端收到unread後,需要加總import, event與personal三個陣列的數值,並置入到badge中,使得App Icon的角標數字與之同步。
```
<br>
**Response importantCategory 重要公告-子分類名稱module**
| Parameter | Type | Require | Description |
| --------- | ------ | ------- | ----------- |
| name | string | Y | 重要公告-子分類名稱 |
<br>
**Response eventCategory 活動快訊-子分類名稱module**
| Parameter | Type | Require | Description |
| --------- | -------- | ------- | ----------- |
| name | string | Y | 重要公告-子分類名稱 |
<br>
**Response personalCategory 個人公告-子分類名稱module**
| Parameter | Type | Require | Description |
| --------- | -------- | ------- | ----------- |
| name | string | Y | 重要公告-子分類名稱 |
<br>
**Response importantNotice 重要公告-列表內容資訊module**
| Parameter | Type | Require | Description |
| --------- | -------- | ------- | ----------- |
| noticeId | int | Y | 公告id |
| iconUrl | string | Y | 列表左側icon圖片url |
| title | string | Y | 公告標題 |
| group | string | Y | 公告分類 (important / event / personal) |
| category | string | Y | 公告分類的子分類 (ex:大樓公告) |
| isNew | bool | Y | 是否為新公告(false:舊公告 true:7日內上架的新公告) |
| isClosedOnHomePage | bool | Y | 是否已關閉於首頁最上方區域<br>(false:開啟 true:已關閉)<br><br>執行關閉動作條件有二(任一成立即執行<a href='https://hackmd.io/coOyibBDRYqJpluQIQFYmg?both#homePage-importantNoticeIsClosed' target='_blank'>homePage-importantNoticeIsClosed</a>):<br>1.現在時間於start_time與end_time區間外<br>2.當使用者按下「X」按鈕<br><br><font color='red'>只有importantNotice才有此欄位</font> |
| closeInSeconds | int | Y | 公告將於幾秒後結束<br>Duration.between(now, endTime).getSeconds()<br><br><b>範圍值(0-28800)</b><br><br><font color='red'>只有importantNotice才有此欄位</font> |
| datetime | string | Y | 此公告最後更新時間 |
<br>
**Response eventNotice 活動公告-列表內容資訊module**
| Parameter | Type | Require | Description |
| --------- | -------- | ------- | ----------- |
| noticeId | int | Y | 公告id |
| iconUrl | string | Y | 列表左側icon圖片url |
| title | string | Y | 公告標題 |
| group | string | Y | 公告分類 (important / event / personal) |
| category | string | Y | 公告分類的子分類 (ex:新書上架) |
| isNew | bool | Y | 是否為新公告(false:舊公告 true:7日內上架的新公告) |
| datetime | string | Y | 此通知最後更新時間 |
<br>
**Response personalNotice 個人公告-列表內容資訊module**
| Parameter | Type | Require | Description |
| --------- | -------- | ------- | ----------- |
| noticeId | int | Y | 公告id |
| iconUrl | string | Y | 列表左側icon圖片url |
| title | string | Y | 公告標題 |
| group | string | Y | 通知大類 (important / event / personal) |
| category | string | Y | 通知大類的子分類 (ex:個人郵件) |
| isNew | bool | Y | 是否為新公告(false:舊公告 true:7日內上架的新公告) |
| datetime | string | Y | 此通知最後更新時間 |
```json=
{
"requestId":"64d94767-c926-6156-44a5-8bf08a3691d4",
"status": 200,
"page": "noticePage",
"info": [
{
"module": "unread",
"status": 200,
"type": "list",
"num": 3,
"data": [
{
"important": [],
"event": [2],
"personal": [3,4]
}
],
"datetime": "2024/12/30 11:02:28"
},
{
"module": "importantCategory",
"status": 200,
"type": "list",
"num": 4,
"data": [
{
"name": "大樓公告",
},
{
"name": "外報訪客通知",
},
{
"name": "公司重要活動",
},
{
"name": "其他",
},
],
"datetime": "2024/12/30 11:02:28"
},
{
"module": "eventCategory",
"status": 200,
"type": "list",
"num": 2,
"data": [
{
"name": "分類列表",
},
{
"name": "最新消息",
},
],
"datetime": "2024/12/30 11:02:28"
},
{
"module": "personalCategory",
"status": 200,
"type": "list",
"num": 3,
"data": [
{
"name": "快遞郵件",
},
{
"name": "分類列表",
},
{
"name": "最新消息",
},
],
"datetime": "2024/12/30 11:02:28"
},
{
"module": "importantNotice",
"status": 200,
"type": "list",
"num": 1,
"data": [
{
"noticeId": 1,
"iconUrl": "/images/notice/icon_important.png",
"title": "今日中午餐廳備有萬聖節大餐,敬請共襄盛舉!",
"group": "important",
"category": "重要公告",
"isNew": true,
"isClosedOnHomePage": false,
"closeInSeconds": 2198,
"datetime": "2023/11/1 07:10:13"
}
],
"datetime": "2024/12/30 11:02:28"
},
{
"module": "eventNotice",
"status": 200,
"type": "list",
"num": 1,
"data": [
{
"noticeId": 2,
"iconUrl": "/images/notice/icon_event.png",
"title": "新上架書籍,歡迎借閱。",
"group": "event",
"category": "新書上架",
"isNew": true,
"datetime": "2023/11/1 07:10:13"
}
],
"datetime": "2024/12/30 11:02:28"
},
{
"module": "personalNotice",
"status": 200,
"type": "list",
"num": 2,
"data": [
{
"noticeId": 3,
"iconUrl": "/images/notice/icon_personal.png",
"title": "您的快遞郵物已送至公司,請至櫃台領取。",
"group": "personal",
"category": "快遞郵件",
"isNew": true,
"datetime": "2023/11/1 07:10:13"
},
{
"noticeId": 4,
"iconUrl": "/images/notice/icon_personal.png",
"title": "您借閱的 [原子習慣] 將在一週後 (3/28) 到期",
"group": "personal",
"category": "書籍歸還提醒",
"isNew": true,
"datetime": "2023/11/1 07:10:13"
},
],
"datetime": "2024/12/30 11:02:28"
}
],
"datetime": "2024/12/30 11:02:28"
}
```
</br>
### ❇️noticeDetailPage
URL: `wss://{domain name}/`
Method: `wss`
Descirption: `通知內容頁`
<img src='https://hackmd.io/_uploads/HyOyITbWxg.png' width='320' />
**Request**
| Parameter | Type | Require | Description |
| ----------- | -------- | ------- | ----------- |
| requestId | string | Y | 對話id |
| page | string | Y | 手機畫面名稱 |
| module | string | Y | 功能區塊名稱 |
| type | string | Y | 資料處理型態 |
| data | object | Y | 資料參數 |
| noticeId | int | Y | 通知id |
```json=
{
"requestId": "64d94767-c926-6156-44a5-8bf08a3691d4",
"page": "noticeDetailPage",
"module": "all",
"type": "select",
"data": {
"noticeId":4
}
}
```
<br>
**Response for noticeContent module**
| Parameter | Type | Require | Description |
| --------- | -------- | ------- | ----------- |
| noticeId | int | Y | 公告id |
| title | string | Y | 公告標題 |
| content | string | Y | 公告內容 |
| contentImgUrl| string| | 公告內頁圖片連結<br><font color=red>(沒有值就不出現整個欄位)</font> |
| category | string | Y | 公告分類的子分類 (ex:大樓公告)<br>用於Navigation Title |
| urlScheme | string | | 前往路徑(與<a href='https://hackmd.io/-A3kGYJ8SHyjegBROlwJow?both#bookDetailPage' target='_blank'>歸還QRCode的urlScheme</a>相同結構)<br><br>格式:<a href='https://docs.google.com/presentation/d/1YXL1x9r8xbFr3ebq_SUL7N3xycFaYrD00-bGg2HdYbo/edit#slide=id.g33a0ba89a3b_0_163' target='_blank'>各頁面導向文件說明</a><br>neuteclife://[page_name]/[module_name]/[type_name]/[param_1_name]=[param_1_value]&[param_1_name]=[param_1_value]#anchor<br><br>Ex:前往itemPage<br>neuteclife://itemPage/all/select/?functionId=3&categoryId=0&sort=1<br> |
| datetime | string | Y | 此公告最後更新時間<br>用於畫面中『最後更新時間』的值<br><font color=red>不顯示秒,ex:2025/5/29 15:30</font> |
<br>
```json=
{
"requestId":"64d94767-c926-6156-44a5-8bf08a3691d4",
"status": 200,
"page": "noticeDetailPage",
"info": [
{
"module": "noticeContent",
"status": 200,
"type": "list",
"num": 1,
"data": [
{
"noticeId": 4,
"contentImgUrl": "/images/notice/content_img.png",
"title": "2025 日新家庭旅遊日,即將在 11/1 ~ 11/2 (六日) 隆重登場!",
"content": "親愛的同仁們......很多很多字",
"category": "公司重要活動",
"urlScheme": "neuteclife://browser/all/select/?url=https%3A%2F%2Fuat-neulife.neutec.com.tw%2Fadmin%2Fbackend%2Fitem%2Fitem%2FitemPageBase.jsp%3Fid%3D670%26action%3Dedit%26currentPage%3D1%26count%3D",
"datetime": "2025/11/1 07:10"
}
],
"datetime": "2025/11/1 06:02:28"
}
],
"datetime": "2024/12/30 11:02:28"
}
```
<br>
#### Response for 失敗(通知被刪除或下架)
| Parameter | Type | Require | Description |
| ----------| -------| ------- | ----------- |
| requestId | string | Y | 對話id |
| status | int | Y | [狀態代碼](#狀態代碼) |
| page | string | Y | 手機畫面名稱 |
| errorMsg | string | Y | 錯誤訊息 |
| datetime | string | Y | 資料回應時間 |
<img src="https://hackmd.io/_uploads/BkGqYWOXel.png" width="250" />
```
當使用者停留在通知列表頁,在App尚未刷新的情況下有某通知被下架,App再點選此通知時將會得到1041。
```
```json=
{
"requestId": "1fb7d801-4a05-0b1d-ea16-de1d32c97d6c",
"status": 200,
"page": "noticeDetailPage",
"info": [
{
"module": "noticeContent",
"status": 1041,
"errorMsg": "查無此通知",
"detetime": "2025/8/26 12:38:11"
}
],
"datetime": "2025/8/26 12:38:11"
}
```
</br>
### ❇️noticePage-setRead
URL: `wss://{domain name}/`
Method: `wss`
Descirption: `通知頁-設定整個大類(group)為已讀動作`
#### Remark
```
Server端作Response時,只需回覆unread module。
```
**Request for 按下「全部已讀」按鈕情況**
| Parameter | Type | Require | Description |
| ----------| -------- | ------- | ----------- |
| requestId | string | Y | 對話id |
| page | string | Y | 手機畫面名稱 |
| module | string | Y | 功能區塊名稱 |
| type | string | Y | 資料處理型態 |
| data | object | Y | 資料參數 |
| group | string | Y | 大類名稱(important/event/personal) |
```json=
{
"requestId": "64d94767-c926-6156-44a5-8bf08a3691d4",
"page": "noticePage",
"module": "setRead",
"type": "update",
"data": {
"group":"important"
}
}
```
**Response for 按下「全部已讀」按鈕情況**
| Parameter | Type | Require | Description |
| --------- | ------ | ------- | ----------- |
| requestId | string | Y | 對話id |
| status | int | Y | [狀態代碼](#狀態代碼) |
| page | string | Y | 手機畫面名稱 |
| info | array | Y | 手機畫面資訊 |
| module | string | Y |手機畫面區塊名稱 |
| status | int | Y | [狀態代碼](#狀態代碼) |
| type | string | Y | 資料處理型態 |
| num | int | Y | 資料筆數 |
| data | array | Y | 資料內容陣列 |
| important | array | Y | 重要公告的未讀的noticeIds |
| event | array | Y | 活動快訊的未讀的noticeIds |
| personal | array | Y | 個人通知的未讀的noticeIds |
```json=
{
"requestId": "64d94767-c926-6156-44a5-8bf08a3691d4",
"status": 200,
"page": "noticePage",
"num": 1,
"info": [
{
"module": "unread",
"status": 200,
"type": "list",
"num": 3,
"data": [
{
"important": [],
"event": [8,6],
"personal": [5,4,3,2]
}
],
"datetime": "2024/12/30 11:02:28"
}
],
"datetime": "2023/11/1 12:38:11"
}
```
</br>
### ❇️noticeDetailPage-setRead
URL: `wss://{domain name}/`
Method: `wss`
Descirption: `通知內容頁-設定單則通知已讀動作`
#### Remark
```
Server端作Response時,只需回覆unread module。
```
</br>
**Request for 單則通知已讀 情況**
| Parameter | Type | Require | Description |
| ----------| -------- | ------- | ----------- |
| requestId | string | Y | 對話id |
| page | string | Y | 手機畫面名稱 |
| module | string | Y | 功能區塊名稱 |
| type | string | Y | 資料處理型態 |
| data | object | Y | 資料參數 |
| noticeId | int | Y | 通知id |
```json=
{
"requestId": "64d94767-c926-6156-44a5-8bf08a3691d4",
"page": "noticeDetailPage",
"module": "setRead",
"type": "update",
"data": {
"noticeId":10
}
}
```
**Response for 單則通知已讀 情況**
| Parameter | Type | Require | Description |
| --------- | ------ | ------- | ----------- |
| requestId | string | Y | 對話id |
| status | int | Y | [狀態代碼](#狀態代碼) |
| page | string | Y | 手機畫面名稱 |
| info | array | Y | 手機畫面資訊 |
| module | string | Y |手機畫面區塊名稱 |
| status | int | Y | [狀態代碼](#狀態代碼) |
| type | string | Y | 資料處理型態 |
| num | int | Y | 資料筆數 |
| data | array | Y | 資料內容陣列 |
| important | array | Y | 重要公告的未讀的noticeIds |
| event | array | Y | 活動快訊的未讀的noticeIds |
| personal | array | Y | 個人通知的未讀的noticeIds |
```json=
{
"requestId": "64d94767-c926-6156-44a5-8bf08a3691d4",
"status": 200,
"page": "noticePage",
"num": 1,
"info": [
{
"module": "unread",
"status": 200,
"type": "list",
"num": 3,
"data": [
{
"important": [9,7],
"event": [8,6],
"personal": [5,4,3,2]
}
],
"datetime": "2024/12/30 11:02:28"
}
],
"datetime": "2023/11/1 12:38:11"
}
```
</br>
</br>
### noticePage-新增公告的主動通知
URL: `wss://{domain name}/`
Method: `wss`
Descirption: `通知頁-當後台新增一筆通知時,Server端將主動發出`
**Response**
| Parameter | Type | Require | Description |
| --------- | -------- | ------- | ----------- |
| noticeId | int | Y | 公告id |
| iconUrl | string | Y | 列表左側icon圖片url |
| title | string | Y | 公告標題 |
| group | string | Y | 公告分類 (important / event / personal) |
| category | string | Y | 公告分類的子分類 (ex:大樓公告) |
| isNew | bool | Y | 是否為新公告(false:舊公告 true:7日內上架的新公告) |
| isClosedOnHomePage | bool | | 是否已關閉於首頁最上方區域<br>(false:開啟 true:已關閉)<br><br>執行關閉動作條件有二(任一成立即執行<a href='https://hackmd.io/coOyibBDRYqJpluQIQFYmg?both#homePage-importantNoticeIsClosed' target='_blank'>homePage-importantNoticeIsClosed</a>):<br>1.現在時間於start_time與end_time區間外<br>2.當使用者按下「X」按鈕<br><br><font color='red'>只有importantNotice才有此欄位</font> |
| closeInSeconds | int | | 公告將於幾秒後結束<br>Duration.between(now, endTime).getSeconds()<br><br><b>範圍值(0-28800)</b><br><br><font color='red'>只有importantNotice才有此欄位</font> |
| datetime | string | Y | 此公告最後更新時間 |
#### Remark
```
案例:當後台人員新增一筆「個人郵件」通知給A員,此時A員的noticePage將立即收到noticePage.personalNotice與noticePage.unread
1. 新增時,response type請採用add
2. 大部分的通知,都會伴隨快顯通知(notificationPage)的出現,因此也會同步主動發出notificationPage
```
```json=
{
"requestId": "1fb7d801-4a05-0b1d-ea16-de1d32c97d6c",
"status": 200,
"page": "noticePage",
"info": [
{
"module": "personalNotice",
"status": 200,
"type": "add",
"num": 1,
"data": [
{
"noticeId": 5,
"iconUrl": "/images/notice/icon_personal.png",
"title": "您的快遞郵物已送至公司,請至櫃台領取。",
"group": "personal",
"category": "個人郵件",
"isNew": true,
"datetime": "2023/11/1 09:17:33"
}
],
"datetime": "2024/12/30 11:02:28"
},
{
"module": "unread",
"status": 200,
"type": "list",
"num": 3,
"data": [
{
"important": [],
"event": [],
"personal": [4,5]
}
],
"datetime": "2024/12/30 11:02:28"
}
],
"datetime": "2024/12/30 11:02:29"
}
//以下為同步發出notificationPage的案例
{
"requestId": "og4rw9a2-5br1-4eds-wqh39-nw3w68q92so1",
"status": 200,
"page": "notificationPage",
"info": [
{
"module": "toastify",
"status": 200,
"type": "list",
"num": 1,
"data": [
{
"category":"個人郵件",
"title":"您的快遞郵物已送至公司,請至櫃台領取。"
}
],
"datetime":"2024/12/30 11:02:29"
}
],
"datetime": "2024/12/30 11:02:29"
}
```
</br>
### noticePage-修改公告的主動通知
URL: `wss://{domain name}/`
Method: `wss`
Descirption: `通知頁-當後台修改某一筆通知時,Server端將主動發出`
**Response**
| Parameter | Type | Require | Description |
| --------- | -------- | ------- | ----------- |
| noticeId | int | Y | 公告id |
| iconUrl | string | Y | 列表左側icon圖片url |
| title | string | Y | 公告標題 |
| group | string | Y | 公告分類 (important / event / personal) |
| category | string | Y | 公告分類的子分類 (ex:大樓公告) |
| isNew | bool | Y | 是否為新公告(false:舊公告 true:7日內上架的新公告) |
| isClosedOnHomePage | bool | | 是否已關閉於首頁最上方區域<br>(false:開啟 true:已關閉)<br><br>執行關閉動作條件有二(任一成立即執行<a href='https://hackmd.io/coOyibBDRYqJpluQIQFYmg?both#homePage-importantNoticeIsClosed' target='_blank'>homePage-importantNoticeIsClosed</a>):<br>1.現在時間於start_time與end_time區間外<br>2.當使用者按下「X」按鈕<br><br><font color='red'>只有importantNotice才有此欄位</font> |
| closeInSeconds | int | | 公告將於幾秒後結束<br>Duration.between(now, endTime).getSeconds()<br><br><b>範圍值(0-28800)</b><br><br><font color='red'>只有importantNotice才有此欄位</font> |
| datetime | string | Y | 此公告最後更新時間 |
#### Remark
```
案例:當後台人員修改某一筆「重要公告」通知給A員,此時A員的noticePage將立即收到noticePage.importantNotice與noticePage.unread
1. 修改時,response type請採用modify
2. 修改資料,已讀狀態不變
```
```json=
{
"requestId": "1fb7d801-4a05-0b1d-ea16-de1d32c97d6c",
"status": 200,
"page": "noticePage",
"info": [
{
"module": "importantNotice",
"status": 200,
"type": "modify",
"num": 1,
"data": [
{
"noticeId": 1,
"iconUrl": "/images/notice/icon_important.png",
"title": "今日中午餐廳備有萬聖節大餐,敬請共襄盛舉!",
"group": "important",
"category": "重要公告",
"isNew": true,
"isClosedOnHomePage": false,
"closeInSeconds": 2198,
"datetime": "2024/12/30 11:02:28"
}
],
"datetime": "2024/12/30 11:02:28"
},
{
"module": "unread",
"status": 200,
"type": "list",
"num": 3,
"data": [
{
"important": [],
"event": [],
"personal": [4,5]
}
],
"datetime": "2024/12/30 11:02:28"
}
],
"datetime": "2024/12/30 11:02:29"
}
```
</br>
### noticePage-刪除公告的主動通知
URL: `wss://{domain name}/`
Method: `wss`
Descirption: `通知頁-當後台刪除某一筆通知時,Server端將主動發出`
**Response**
| Parameter | Type | Require | Description |
| --------- | -------- | ------- | ----------- |
| noticeId | int | Y | 公告id |
#### Remark
```
案例:當後台人員刪除某一筆「重要公告」通知給A員,此時A員的noticePage將立即收到noticePage.importantNotice與noticePage.unread
刪除時,response type請採用remove,data內只放noticeId
```
```json=
{
"requestId": "1fb7d801-4a05-0b1d-ea16-de1d32c97d6c",
"status": 200,
"page": "noticePage",
"info": [
{
"module": "importantNotice",
"status": 200,
"type": "remove",
"num": 1,
"data": [
{
"noticeId": 1
}
],
"datetime": "2024/12/30 11:02:28"
},
{
"module": "unread",
"status": 200,
"type": "list",
"num": 3,
"data": [
{
"important": [],
"event": [],
"personal": [4,5]
}
],
"datetime": "2024/12/30 11:02:28"
}
],
"datetime": "2024/12/30 11:02:29"
}
```
</br>
### ❇️notificationPage
URL: `wss://{domain name}/`
Method: `wss`
Descirption: `快顯通知頁`
#### Remark
```
1. Server端需依照以下『通知規則文件』所列出的對應事件做送出通知。
例如:合併訊息規則、App內/外推播規則...等等。
2. 通知區分兩種通道,本區是websocket通道的部分。
(1) websocket通道:App於前景狀態時使用。
(2) pushy通道:「App於背景狀態」或「App未開啟狀態」時使用。
3.『通知規則文件』中標明「App內接收」者,就需要走websocket通道。
4. notificationPage的畫面可以在任何Page中出現,並且覆蓋在最上方。
5. notificationPage只有單向傳輸,由Server端主動傳送給App端,Server端亦同時發送給Pushy API。
6. module區分兩種,toastify 與 dialogify。
7. Server端需注意:相同類型的通知會需要合併
Ex:
(1)書籍案例:若使用者同一天借用兩本書,兩本書的歸還時間勢必亦相同。
在歸還日前一天時將發送一則「您有2本書將於明日歸還」通知,而非各別發兩則書本的歸還通知。
(2)物品案例:物品則是依照「所屬單位」來計算。
若使用者同一天借用露營社5項物品,歸還日前一天時將發送一則「您有5項露營社物品將於明日歸還」通知,而非各別發五則物品歸還通知。
```
<p>
<a href='https://docs.google.com/spreadsheets/d/1qHcAhYWDky5LdZGumX5ite7Y9Tfuw07jwjZcDAs81qg/edit?gid=1129370366#gid=1129370366' target='_blank'>➤ 通知規則文件 (Server端)</a>
<a href='https://pushy.me/docs/api' target='_blank'>➤ Pushy API Reference 文件</a>
[➤ 查看pushy通道內容 (pushy推播)](#pushy推播)
</p>
<br>
**Request**
```
App端只能接收,無需傳送任何請求對話。
```
<br>
**Response for toastify**
<img src="https://hackmd.io/_uploads/ryP4I6bqke.png" alt="圖片說明" width="400"/>
| Parameter | Type | Require | Description |
| ----------- | -------- | ------- | ----------- |
| requestId | string | Y | 對話id |
| status | number | Y | [狀態代碼](#狀態代碼) |
| page | string | Y | 手機畫面名稱 |
| info | string | Y | 手機畫面資訊 |
| module | string | Y |手機畫面區塊名稱 |
| status | number | Y | [狀態代碼](#狀態代碼) |
| type | string | Y | 資料處理型態 |
| num | int | Y | 資料筆數 |
| data | array | Y | 資料內容陣列 |
| category | string | Y | 通知類別 |
| title | string | Y | 通知標題<br><font color=red>(toastify在App端只有一行,超過以...取代之)</font> |
| urlScheme | string | Y | 前往路徑(與<a href='https://hackmd.io/-A3kGYJ8SHyjegBROlwJow?both#bookDetailPage' target='_blank'>歸還QRCode的urlScheme</a>相同)<br><br>格式:<a href='https://docs.google.com/presentation/d/1YXL1x9r8xbFr3ebq_SUL7N3xycFaYrD00-bGg2HdYbo/edit#slide=id.g33a0ba89a3b_0_163' target='_blank'>各頁面導向文件說明</a><br>neuteclife://[page_name]/[module_name]/[type_name]/[param_1_name]=[param_1_value]&[param_1_name]=[param_1_value]...<br><br>前往noticePage的<u>個人通知</u><br>neuteclife://noticePage/all/select/#personal |
```json=
{
"requestId": "1fb7d801-4a05-0b1d-ea16-de1d32c97d6c",
"status": 200,
"page": "notificationPage",
"info": [
{
"module": "toastify",
"status": 200,
"type": "list",
"num": 2,
"data": [
{
"category":"書籍歸還提醒",
"title":"您借閱的 [原子習慣] 將在明天 (2/13) 到期",
"urlScheme":"neuteclife://noticePage/all/select#=personal"
},
{
"category":"書籍歸還提醒",
"title":"您借閱的 [如何在果凍上蓋城市?:從工法、材料到歷史,由地底到空中,頂尖結構工程師帶你解開建物的構造奧祕,了解建築究竟是怎麼一回事] 已逾期 1 天,請儘速歸還!",
"urlScheme":"neuteclife://noticePage/all/select/#personal"
}
],
"datetime":"2024/11/13 09:00:02"
}
],
"datetime": "2024/11/13 09:00:02"
}
```
</br>
**Response for dialogify**
<img src="https://hackmd.io/_uploads/rJCUtxiKyg.png" alt="圖片說明" width="250"/>
| Parameter | Type | Require | Description |
| ----------- | -------- | ------- | ----------- |
| requestId | string | Y | 對話id |
| status | number | Y | [狀態代碼](#狀態代碼) |
| page | string | Y | 手機畫面名稱 |
| info | string | Y | 手機畫面資訊 |
| module | string | Y |手機畫面區塊名稱 |
| status | number | Y | [狀態代碼](#狀態代碼) |
| type | string | Y | 資料處理型態 |
| num | int | Y | 資料筆數 |
| data | array | Y | 資料內容陣列 |
| category | string | Y | 通知類別 |
| title | string | Y | 通知標題<br><font color=red>(dialogify所有的字都要進入App畫面中,因此高度將隨字數多寡調整)</font> |
| urlScheme | string | Y | 前往路徑(與<a href='https://hackmd.io/-A3kGYJ8SHyjegBROlwJow?both#bookDetailPage' target='_blank'>歸還QRCode的urlScheme</a>相同)<br><br>格式:<a href='https://docs.google.com/presentation/d/1YXL1x9r8xbFr3ebq_SUL7N3xycFaYrD00-bGg2HdYbo/edit#slide=id.g33a0ba89a3b_0_45' target='_blank'>各頁面導向文件說明</a><br>neuteclife://[page_name]/[module_name]/[type_name]/[param_1_name]=[param_1_value]&[param_1_name]=[param_1_value]...<br><br>前往bookDetailPage<br>neuteclife://noticePage/all/select/#personal |
```json=
{
"requestId": "1fb7d801-4a05-0b1d-ea16-de1d32c97d6c",
"status": 200,
"page": "notificationPage",
"info": [
{
"module": "dialogify",
"status": 200,
"type": "list",
"num": 1,
"data": [
{
"category":"會議調整通知",
"title":"今日 14:00 新人教育訓練 [Rapa Nui] 已取消",
"urlScheme":"neuteclife://noticePage/all/select/#personal"
}
],
"datetime":"2024/11/13 09:00:02"
}
],
"datetime": "2024/11/13 09:00:02"
}
```
</br>
### ❇️pushy推播
URL: `wss://{domain name}/`
Method: `Pushy (APNs & FCM)`
Descirption: `透過第三方pushy送出推播訊息`
#### Remark
```
1. Server端需依照以下『通知規則文件』所列出的對應事件做送出通知。
例如:合併訊息規則、App內/外推播規則...等等。
2. 通知區分兩種通道,本區是pushy通道的部分。
(1) websocket通道:App於前景狀態時使用。(內容描述在notificationPage中)
(2) pushy通道:「App於背景狀態」或「App未開啟狀態」時使用。
3.『通知規則文件』中標明「App外接收」者,就需要走pushy通道。
4. Server端建議透過 Pushy SDK 發送資料,可參考Pushy Java Backend Sample 文件。
5. ‼️Server端需注意,帳號登出狀態下,不可收到推播通知。
以下列出一些情境及其對應的行為:
情境1:A帳號登入後關閉App或待機,需要收到推播。
情境2:A帳號登出,不可收到任何推播。
情境3:A帳號登出,改換B帳號登入,此時Server端會得到相同的Pushy Token,因為推播機制是只認裝置的,所以需將此Pushy Token記錄在B帳號下,A帳號則刪除該Pushy Token。
(可以把Pushy Token想像成一種DeviceId)
情境4:A帳號開啟App但不允許開啟推播功能,此時手機端將無法獲得Pushy Token。
因此並非所有登入的裝置都一定有Pushy Token。
```
<p>
<a href='https://docs.google.com/spreadsheets/d/1qHcAhYWDky5LdZGumX5ite7Y9Tfuw07jwjZcDAs81qg/edit?gid=1129370366#gid=1129370366' target='_blank'>➤ 通知規則文件 (Server端)</a>
<a href='https://pushy.me/docs/api' target='_blank'>➤ Pushy API Reference 文件</a>
[➤ Pushy Java Backend Sample 文件](https://pushy.me/docs/resources/java-backend-sample)
[➤ 查看websocket通道內容 (notificationPage)](#notificationPage)
</p>
<br>
**Request**
```
App端只能接收,無需傳送任何請求對話。
```
<br>
**Response for pushy推播**
<img src="https://hackmd.io/_uploads/H1Btvk8Jxl.png" alt="圖片說明" width="300"/>
| Parameter | Type | Require | Description |
| ----------- | -------- | ------- | ----------- |
| urlScheme | string | Y | 開啟App後前往路徑(與<a href='https://hackmd.io/-A3kGYJ8SHyjegBROlwJow?both#bookDetailPage' target='_blank'>歸還QRCode的urlScheme</a>相同)<br><br>格式:<a href='https://docs.google.com/presentation/d/1YXL1x9r8xbFr3ebq_SUL7N3xycFaYrD00-bGg2HdYbo/edit#slide=id.g33a0ba89a3b_0_163' target='_blank'>各頁面導向文件說明</a><br>neuteclife://[page_name]/[module_name]/[type_name]/[param_1_name]=[param_1_value]&[param_1_name]=[param_1_value]...<br><br>前往noticePage的<u>個人通知</u><br>neuteclife://noticePage/all/select/#personal |
| title | string | Y | 通知子類別 <font color=red>(Android專用)</font> |
| body | string | Y | 通知標題 <font color=red>(Android專用)</font><br>書名或品名若超過6個字,後續以「...」取代之,如上圖所示。 |
| meta | string | Y | 其他描述 |
| datetime | string | Y | 通知<u>實際</u>發送時間 |
| endtime | string | Y | 通知<u>預計</u>結束時間 |
| noticeId | int | Y | 該則通知的noticeId<br><font color=red>(Android專用)</font> |
| group | string | Y | 公告分類 (important / event / personal)<br><font color=red>(Android專用)</font> |
| aps | string | Y | iOS背景專用內容<br>(iOS專用) |
| title | string | Y | 通知子類別 (iOS專用) |
| body | string | Y | 通知標題 (iOS專用) |
| badge | int | Y | AppIcon右上角的數字小標 (iOS專用)<br><b>由Server端給予通知未讀數量</b> |
| sound | string | Y | 通知音效檔案 (iOS專用) |
<br/>
Server端將透過 pushy SDK 發送資料,請參酌 <a href='https://pushy.me/docs/api' target='_blank'>Pushy API Reference 文件</a>。
```json=
//以下 json 為 iOS 會看見的資料,aps 內的資料屬於 OS 層處理
//Pushy SDK 不會給予 json raw data,而是轉成 dictionary 格式輸出
{
"urlScheme": "neuteclife://noticePage/all/select/#personal",
"title": "NEU Life",
"body": "本月新書已上架,歡迎借閱!",
"meta": {
"datetime": "2025/4/23 11:03:25",
"endtime": "2025/4/23 11:03:35",
"noticeId": 25,
"group": "event"
},
"aps": {
"alert": {
"title": "NEU Life",
"body": "本月新書已上架,歡迎借閱!"
},
"badge": 5,
"sound": "ping.aiff"
}
}
```
```json=
//以下 json 為 Android 會看見的資料
//Pushy SDK 不會給予 json raw data,而是轉成 map 格式輸出
{
"urlScheme": "neuteclife://noticePage/all/select/#personal",
"title": "NEU Life",
"body": "本月新書已上架,歡迎借閱!",
"meta": {
"datetime": "2025/4/23 11:03:25",
"endtime": "2025/4/23 11:03:35",
"noticeId": 25,
"group": "event"
}
}
```
</br>
---
</br>
### 狀態代碼
<iframe src="https://hackmd.io/zqx1OcNuTKSHCI89YIHMOw?view" width="100%" height="500"></iframe>
<!--
### 狀態代碼
| status | description |
| ----- |-------------|
| 200 | Success |
| 1001 | Not found this page or module. |
| 1003 | Not found this DATA. |
| 1004 | DATA parameter error. |
| 1005 | Data processing error. |
| 1006 | 您輸入的帳號或密碼錯誤,請重新輸入 |
| 1008 | Your account has been logged in another device. |
| 1009 | Touch too fast. |
| 1010 | Unknow error. |
| 1011 | 身份驗證失敗,請重新登入 |
| 1012 | Blacklist. |
| 1013 | Not found this lastId. |
| 1014 | 已超過書籍借用2本上限 |
| 1015 | 此書籍正在借閱中,借閱失敗 |
| 1016 | 書籍有人排隊預約,展延失敗 |
| 1017 | 時段衝突,此時段已有人預約 |
| 1018 | 物品已進入借用狀態,無法取消 |
| 1030 | 已有他人在此時段預約\r請重新選擇起訖時間 |
| 1031 | 會議時段衝突\r請重新選擇循環時段 |
<br>
### socket對話資料處理型態
| type | description |
| ----- |-------------|
| select | App端請求「顯示用」資料。<br>ex:需要顯示書籍列表時。 |
| insert | App端請求「新增」動作。<br>ex:使用者按下借用按鈕時。 |
| update | App端請求「更新」動作。<br>ex:使用者更換快速入口項目時。 |
| delete | App端請求「刪除」動作。<br>ex:使用者按下取消收藏按鈕時。 |
| list | Server端請求刷新整個區塊資料,或僅告知事件已處理完成。<br>ex:需要顯示書籍列表時。 |
| add | Server端請求新增資料到區塊中。<br>ex:當後台新增了一筆通知時。 |
| modify | Server端請求更新畫面中的某筆資料。<br>ex:當後台修改了某一筆已發出通知的錯字時。 |
| remove | App端請求「刪除」動作。<br>ex:大樓消防演練通知會在演練結束後自動在App端移除消失。 |
-->