feat(rating): 结束服务、星级评价与管理员回看统计

结束会话后可提交 1-5 星与文字评价,重复提交更新原记录;管理端回看接待人与评分。
This commit is contained in:
WangShen007 committed 2026-10-13 21:55:00 +08:00
1 parent ad90b830c4
commit 2adf288cd2
8 files changed
+3815

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
/*
Copyright 2024-2026 ChatterMate
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* Channels served by our own widget rather than an external messaging platform.
* Mirrors WIDGET_CHANNELS in backend/app/channels/constants.py — keep the two
* in step. 'shopify' is the widget embedded in a storefront: a separate label
* in the inbox, the same chat surface.
*/
const WIDGET_CHANNELS = ['web', 'shopify']
/**
* Rating is a widget-only feature. External channels (WhatsApp, Messenger,
* Instagram, Telegram, ...) render plain text and have no rating UI, so asking
* there leaves the customer a question they cannot answer. The backend applies
* the same rule to AI-ended chats.
*/
export const canRequestRating = (channel?: string | null): boolean =>
!channel || WIDGET_CHANNELS.includes(channel)
/** Closing message shown to the customer when an agent ends the chat. */
export const endChatMessage = (channel?: string | null): string =>
canRequestRating(channel)
? '感谢您的咨询。方便为我们的服务评分吗?'
: '感谢您的咨询。'
interface EndChatCandidate {
attributes?: { end_chat?: boolean } | null
}
/**
* Whether a widget message is the one that actually ends the conversation.
*
* `attributes.end_chat` is the only signal for this — message_type and the
* presence of a session_id are not. The takeover notice and form prompts are
* ordinary conversation messages that happen to carry a real session_id, and
* treating those as an end-chat closed live conversations the moment a human
* agent joined.
*/
export const isEndChatMessage = (message?: EndChatCandidate | null): boolean =>
Boolean(message?.attributes?.end_chat)