--- title: 前後台客服信息部分API及前端邏輯 tags: 股神 --- :::danger 每支 api,前端每個頁面,請記得做錯誤處理 ::: # 前台 H5 所需 API 們 ## 0. 共用格式 | 項目 | 值 | | ------ | ----------- | | Method | POST | | Type | FormData | | param | SessionCode | ```typescript=1 // 回傳示例 { code: 0, message: 'success', // result為下面API們的回傳範例,這裡用checkStatus做示範 result: { isRead: false, isBlacklisted: false } } ``` ## 1. 確認該 customer 狀態,ex.是否有未讀的新訊息/是否已被黑名單 | 項目 | 值 | | ----- | ------------ | | URL | /checkStatus | | table | sys_dialogue + 黑名單的table | - isRead邏輯: ==sys_dialogue==這張 table,同個**customer id**底下的==isRated = 0==, **最多**只會有 1 個 - 如果有一個,且該"話題編號"的 isRead 也是 0,則回傳 false - 其他狀況都回傳 true ex.如果該 customer id 底下,完全沒有==isRated = false==,代表完全沒有未結束的話題,所以回傳 true - isBlacklisted邏輯: 如果該customerId有被黑名單,回傳isBlacklisted = true - API 因為是被動的,無法主動知道資料有沒有被更新,所以必須每隔一段時間去 call checkStatus API - 回傳欄位 ```typescript=1 interface ICheckStatus { isRead: boolean; isBlacklisted: boolean; } // 回傳示例 { isRead: false, isBlacklisted: false } ``` ## 2. 撈取客服組別名稱 | 項目 | 值 | | ----- | -------------- | | URL | /kefuGroupName | | table | ?? | - 回傳該 customerId 對應的客服組別名稱 - 回傳欄位 ```typescript= interface IKefuGroupName { kefuGroupName: string; } // 回傳示例 { kefuGroupName: 'A公司' } ``` ## 3. 發送話題(新話題/當前話題) | 項目 | 值 | | ----- | ----------------------------------- | | URL | /postTopic | | param | 如發送欄位所示 | | table | sys_dialogue + sys_dialogue_message | - 新話題時,前端**不帶** topicId, 帶 ==groupId, groupName, message== - 當前話題時,前端帶==topicId==及==message== - ==這支 API 為前台 H5 傳送,寫入 sys_dialogue_message, type 一律為'Q'== :::info 後端邏輯 - 如果前端沒傳 topicId(話題編號) - 新話題 - 後端生成 topicId(話題編號), sys_dialogue 依照欄位寫入資訊, 因為無法預知會是哪個客服回覆,由 H5 傳送的,kefuName 可以不寫入資料 - 後端針對每個 message 生成 messageId(信息編號), sys_dialogue_message 依照欄位寫入資訊 - 如果前端有傳 topicId(話題編號) - 當前話題 - sys_dialogue 依照欄位更新資訊 ex. lastMessage 及 updateTime - 後端針對每個 message 生成 messageId(信息編號), sys_dialogue_message 依照欄位寫入資訊 ::: * 發送欄位 ```typescript= interface IPostTopic { topicId: string; // 話題編號 (唯一值) groupId: string; // 用戶的話題id text_config.js設定 groupName: string; // 用戶的話題名稱 text_config.js設定 message: string; // 使用者輸入的留言=> 防呆: 只有該topicId對應的isFinished=false,才可寫入db,否則回傳錯誤 score: 1|2|3|4|5; // 使用者的評分=> 防呆: 只有該topicId對應的isRated=false,才可寫入db,否則回傳錯誤 分數為1(最低),2,3,4,5(最高) } // 發送示例 (新增) { groupId: 'A01', groupName: '黃金', message: '請問黃金交易手續費怎麼算?' } // 發送示例 (當前話題) { topicId: '69462295-6c41-425f-a33f-fadb6310d7ba', message: '請問什麼時候可以拿到出金' } ``` - 回傳欄位 ```typescript= // 回傳示例 { code: 0, message: 'success' } ``` ## 4. 發送評分 | 項目 | 值 | | ----- | ----------------------------------- | | URL | /updateScore | | param | 如發送欄位所示 | | table | sys_dialogue + sys_dialogue_message | - 前端帶==topicId==及==score== - ==若使用者 24 小時無評分,後端必須把 sys_dialogue 對應的 topicId 的 isRated 改成 1, 以及補上 score 為 5== - 發送欄位 ```typescript= interface IUpdateScore { topicId: string; // 話題編號 (唯一值) score: 1|2|3|4|5; // 使用者的評分=> 防呆: 只有該topicId對應的isRated=false,才可寫入db,否則回傳錯誤 分數為1(最低),2,3,4,5(最高) } // 發送示例 (評分) { topicId: '69462295-6c41-425f-a33f-fadb6310d7ba', score: 5 } ``` - 回傳欄位 ```typescript= // 回傳示例 { code: 0, message: 'success' } ``` ## 5. 撈取新話題/當前話題 | 項目 | 值 | | ----- | ----------------------------------- | | URL | /getTopic | | table | sys_dialogue + sys_dialogue_message | - sys_dialogue,同個**customer id**底下的==isRated = 0==, **最多**只會有 1 個 - API 只需回傳這一個==isRated = 0==的資料給前端,若沒有,則回傳==null== - 如果有資料,回傳對應的 topicId,sys_dialogue_message 裡面的所有對話 - order by ==time==, 舊到新 - 需要確保回傳的值,只會是==null==或者==一個 object== - 回傳欄位 ```typescript=1 interface IMessage { customerName: string; // user暱稱 kefuName: string; // 客服暱稱 time: string; // 留言時間 格式: 2021-07-16 15:43 message: string; // 如果多行,請保留 \n,前端才知道什麼時候要斷行 type: 'Q' | 'A'; // Q: customer寫的, A: 客服寫的 } interface IGetTopic { history: IMessage[]; topicId: string; // 話題編號 (唯一值) topicTime: string; // 此話題編號的 update time 格式: 2021-07-16 15:43 groupId: string; // 用戶的話題id text_config.js設定 groupName: string; // 用戶的話題名稱 text_config.js設定 isFinished: boolean; // 此話題是否已結束? true:已結束 false:尚未結束 isRated: boolean; // 此話題是否已評分? true:已評分 false:尚未評分 isRead: boolean; // 此話題是否所有訊息,都已被user讀取 } // 回傳示例 { history: [ { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-16 15:43', message: '請問抽到新股,什麼時候知道結果?', type: 'Q' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-16 15:48', message: '可是我不想讓你知道結果', type: 'A' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-16 15:53', message: '你這客服怎麼可以這麼優秀', type: 'Q' } ], topicId: '69462295-6c41-425f-a33f-fadb6310d7ba', topicTime: '2021-07-16 15:53', groupId: 'A04', groupName: '其他', isFinished: false, isRated: false, isRead: true, } ``` - 示意圖 ![](https://i.imgur.com/CvlskD3.jpg) ## 6. 撈取歷史話題 | 項目 | 值 | | ----- | ----------------------------------- | | URL | /history | | param | groupId ==非必填== | | table | sys_dialogue + sys_dialogue_message | - ==groupId==未填, 則回傳所有歷史話題 - ==array 回傳排序,topicTime 新->舊 (topicTime 是 sys_dialogue 的 createTime); 但是話題裡面的 history , time 舊->新== - 在 db 裡面,所有的歷史話題,table 對應的資訊,應該都會是==isFinished = true 而且 isRated = true== ```typescript=1 interface IMessage { customerName: string; // user暱稱 kefuName: string; // 客服暱稱 time: string; // 留言時間 格式: 2021-07-16 15:53 message: string; // 如果多行,請保留 \n,前端才知道什麼時候要斷行 type: 'Q' | 'A'; // Q: customer寫的, A: 客服寫的 } interface IHistory { history: IMessage[]; topicId: string; // 話題編號 (唯一值) topicTime: string; // 此話題編號的 update time 格式: 2021-07-16 15:53 groupId: string; // 用戶的話題id text_config.js設定 groupName: string; // 用戶的話題名稱 text_config.js設定 } // API回傳的格式會是以 IGetHistory 組成的 array // 回傳示例 [ { history: [ { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-16 15:43', message: '請問抽到新股,什麼時候知道結果?', type: 'Q' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-16 15:48', message: '可是我不想讓你知道結果', type: 'A' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-16 15:53', message: '你這客服怎麼可以這麼優秀', type: 'Q' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-16 15:54', message: '不優秀要怎麼當客服', type: 'A' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-16 15:55', message: '我不知道要說什麼了', type: 'Q' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-16 15:56', message: '請問還有問題嗎?如果沒有問題我就結束話題了', type: 'A' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-16 15:58', message: '好的~掰掰', type: 'Q' } ], topicId: '23702224-febe-4443-a03f-e926a1bb0556', topicTime: '2021-07-16 15:58', groupId: 'G03', groupName: '其他' }, { history: [ { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-15 11:20', message: '您好,我是股神客服001,很高興為您服務,有任何問題請給我留言,我將盡快給你答覆!', type: 'A' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-15 11:20', message: '請問我是誰?', type: 'Q' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-15 11:25', message: '牛仔很忙,不要找我聊天', type: 'A' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-15 11:28', message: '那不吵你了', type: 'Q' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-15 11:35', message: '請問還有問題嗎?如果沒有問題我就結束話題了', type: 'A' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-15 11:58', message: '好的,掰掰', type: 'Q' }, ], topicId: '69462295-6c41-425f-a33f-fadb6310d7ba', topicTime: '2021-07-15 11:58', groupId: 'G03', groupName: '其他' }, { history: [ { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-13 08:43', message: '您好,我是股神客服001,很高興為您服務,有任何問題請給我留言,我將盡快給你答覆!', type: 'A' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-13 08:43', message: '請問抽到新股,什麼時候知道結果?', type: 'Q' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-13 08:48', message: '可是我不想讓你知道結果', type: 'A' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-13 09:03', message: '你這客服怎麼可以這麼優秀', type: 'Q' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-13 09:04', message: '不優秀要怎麼當客服', type: 'A' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-13 09:05', message: '我不知道要說什麼了', type: 'Q' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-13 09:06', message: '請問還有問題嗎?如果沒有問題我就結束話題了', type: 'A' }, { customerName: 'user暱稱', kefuName: '客服001', time: '2021-07-13 09:08', message: '好的~掰掰', type: 'Q' } ], topicId: '23892224-aabb-4443-a03f-e926a1bb0556', topicTime: '2021-07-13 09:08', groupId: 'G03', groupName: '其他' }, ]; ``` - 示意圖 ![](https://i.imgur.com/rQt47vT.jpg) # 前台 H5 邏輯 ## H5 首頁 - 在首頁且 login 後,才打 checkStatus api - 頻率: 跟==策略消息==同時撈取 - 若 checkStatus api 回傳==isRead = false==, 表示未讀,需顯示紅點 ## H5 客服留言 - 進入預設選擇==新話題/當前話題== ### 新話題/當前話題 - 剛進畫面,打 getTopic api - api 回傳==null==: 可開啟新話題 - api 回傳==object==: 依照回傳 object,顯示當前話題 - 新話題 getTopic api - 回傳 null 時顯示 - 打 template api, template='招呼模板的編號', 將撈回的模板顯示在畫面上 - 話題必選/內容必填,才可送出,若其中一個未填,顯示紅字提示 - 送出中, 請顯示送出中 - 當前話題 getTopic api - isRated = false, isFinished= false, 顯示輸入框 - isRated = false, isFinished= true, 顯示評分畫面,不會有輸入框 - 不會有其他狀況, 其他狀況代表有問題 - 內容必填,才可送出,若未填或小於 5 字,顯示紅字提示 - 送出中, 請顯示送出中 - 使用者按完送出或評分後 - 若成功, 則跳轉頁面 - 若失敗, 則停留原畫面, 並顯示原因 ### 歷史話題 - 剛進畫面,打 history api - 下拉選單預設都不選(所以撈回所有話題) - 頻率: 只有==每次點擊歷史話題按鈕==or 更改下拉選單,才打 api,不做頻繁更新 # 後台所需的 API 們 ## 0. 共用格式 | 項目 | 值 | | ------ | -------------- | | Type | JSON | | cookie | token ==必填== | ## 1. 列表頁 | 項目 | 值 | | ------ | ------------------------- | | URL | /sys/dialogue/list | | Method | GET | | params | 搜尋列的條件們+分頁條件們 | | table | sys_dialogue | - 針對前端給的 params 以及 token 拿到的 userId,可以找出 userId 對應的==客服組別==,後端對==sys_dialogue==下 query,回傳對應的結果 - 分頁以及多個 params 的串法,請參照後台其他 API - 示意圖 ![](https://i.imgur.com/Nakptoe.jpg) ## 2. 刪除某話題編號對應的所有資料 | 項目 | 值 | | ------ | ----------------------------------- | | URL | /sys/dialogue/delete | | Method | POST | | params | ==topicId== | | table | sys_dialogue + sys_dialogue_message | - 請先從 token,確定該 userId 有刪除的權限,才需要做下述事情 - 刪除 sys_dialogue_message 該 ==topicId== 底下所有資料 - 刪除 sys_dialogue 該 ==topicId==資料 ## 3. 撈取某話題編號(彈窗內的所有資料) | 項目 | 值 | | ------ | ---------------------------------------------------------------------------- | | URL | /sys/dialogue/{topicId} | | Method | GET | | params | ==topicId== | | table | sys_dialogue + sys_dialogue_message + customer_info(撈取 Mobile 及 NickName) | - 回傳==sys_dialogue==及==sys_dialogue_message==對應的==topicId==,組成以下資料 - 回傳欄位 ```json= { history: [ { customerName: "aki_test", kefuName: "超级管理员", time: "2021-08-05 11:24", message: "请问我是谁?", type: "Q" }, { customerName: "aki_test", kefuName: "超级管理员", time: "2021-08-05 13:01", message: "牛仔很忙,不要找我聊天", type: "A" }, { customerName: "aki_test", kefuName: "超级管理员", time: "2021-08-06 09:52", message: "那不吵你", type: "Q" }, { customerName: "aki_test", kefuName: "超级管理员", time: "2021-08-06 11:53", message: "请问还有问题吗?如果没有问题我就结束话题了", type: "A" }, { customerName: "aki_test", kefuName: "超级管理员", time: "2021-08-06 13:05", message: "没有了,谢谢", type: "Q" } ], topicId: "23702224-febe-4443-a03f-e926a1bb0556", topicTime: "2021-08-05 11:24", customerName: "aki_test", // customer_info NickName mobile: "19876543210", // customer_info Mobile groupId: "G03", groupName: "其他", isFinished: true } ``` - 示意圖 ![](https://i.imgur.com/NIs4ER8.jpg) ![](https://i.imgur.com/xGRMmlR.jpg) ## 4. 客服回覆/結束話題 | 項目 | 值 | | ------ | ----------------------------------- | | URL | /sys/dialogue/update | | Method | POST | | params | 如==傳送欄位==所示 | | table | sys_dialogue + sys_dialogue_message | - sys_dialogue 更新欄位資訊 - 必定更新: updateTime, isRead 要改成 0, isReplied 要改成 1 - 可能更新: ==isFinish 改成 1== 或 ==更新 lastMessage== - sys_dialogue_message 依照欄位寫入資訊 - ==這支 API 為後台客服傳送,寫入 sys_dialogue_message, type 一律為'A'== * 前端傳送欄位 ```json= // 發送示例 (回覆) { topicId: "23702224-febe-4443-a03f-e926a1bb0556", message: "请问还有问题吗?如果没有问题我就结束话题了" } // 發送示例 (結束話題) { topicId: "23702224-febe-4443-a03f-e926a1bb0556", isFinished: true } ```