优化快捷回复功能
This commit is contained in:
@@ -83,6 +83,7 @@ type CreateQuickReplyRequest struct {
|
||||
Title string `json:"title" binding:"required"`
|
||||
Content string `json:"content" binding:"required"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
IsGlobal bool `json:"is_global"`
|
||||
}
|
||||
|
||||
type UpdateQuickReplyRequest struct {
|
||||
|
||||
@@ -883,7 +883,11 @@ func (r *Repository) ListConversationsWithFilter(principal Principal, page, page
|
||||
|
||||
items := make([]ConversationDTO, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
items = append(items, row.toDTO(nil))
|
||||
participants, err := r.participants(row.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, row.toDTO(participants))
|
||||
}
|
||||
return &PaginatedResult{Items: items, Total: total, Page: page, PageSize: pageSize}, nil
|
||||
}
|
||||
@@ -957,8 +961,12 @@ func (r *Repository) ListQuickReplies(adminID uint64) ([]QuickReplyDTO, error) {
|
||||
|
||||
// CreateQuickReply 创建快捷回复
|
||||
func (r *Repository) CreateQuickReply(adminID uint64, req CreateQuickReplyRequest) (*QuickReplyDTO, error) {
|
||||
ownerID := adminID
|
||||
if req.IsGlobal {
|
||||
ownerID = 0
|
||||
}
|
||||
reply := model.ChatQuickReply{
|
||||
AdminUserID: adminID,
|
||||
AdminUserID: ownerID,
|
||||
Title: req.Title,
|
||||
Content: req.Content,
|
||||
SortOrder: req.SortOrder,
|
||||
@@ -972,7 +980,7 @@ func (r *Repository) CreateQuickReply(adminID uint64, req CreateQuickReplyReques
|
||||
Title: reply.Title,
|
||||
Content: reply.Content,
|
||||
SortOrder: reply.SortOrder,
|
||||
IsGlobal: false,
|
||||
IsGlobal: reply.AdminUserID == 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -161,6 +161,8 @@ func (s *Service) CreateQuickReply(adminID uint64, req CreateQuickReplyRequest)
|
||||
if s.repo == nil {
|
||||
return nil, ErrDependencyUnavailable
|
||||
}
|
||||
req.Title = strings.TrimSpace(req.Title)
|
||||
req.Content = strings.TrimSpace(req.Content)
|
||||
if req.Title == "" || req.Content == "" {
|
||||
return nil, ErrInvalidMessage
|
||||
}
|
||||
|
||||
@@ -156,11 +156,12 @@ export async function fetchQuickReplies() {
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function createQuickReply(title: string, content: string, sortOrder = 0) {
|
||||
export async function createQuickReply(title: string, content: string, sortOrder = 0, isGlobal = false) {
|
||||
const { data } = await apiClient.post<ApiResponse<QuickReply>>('/admin/chats/quick-replies', {
|
||||
title,
|
||||
content,
|
||||
sort_order: sortOrder,
|
||||
is_global: isGlobal,
|
||||
})
|
||||
return data.data
|
||||
}
|
||||
|
||||
@@ -133,12 +133,16 @@ async function handleLogout() {
|
||||
<style scoped>
|
||||
.admin-shell {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
min-height: 100vh;
|
||||
background-color: #f5f7fa;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.admin-sidebar {
|
||||
width: 220px;
|
||||
height: 100vh;
|
||||
flex: none;
|
||||
background-color: #304156;
|
||||
transition: width 0.3s ease;
|
||||
display: flex;
|
||||
@@ -199,8 +203,11 @@ async function handleLogout() {
|
||||
|
||||
.admin-menu {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
border-right: none;
|
||||
background-color: transparent;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.admin-menu:not(.el-menu--collapse) {
|
||||
@@ -222,6 +229,9 @@ async function handleLogout() {
|
||||
|
||||
.admin-workspace {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
@@ -229,6 +239,7 @@ async function handleLogout() {
|
||||
|
||||
.admin-topbar {
|
||||
height: 56px;
|
||||
flex: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
@@ -261,6 +272,7 @@ async function handleLogout() {
|
||||
|
||||
.admin-main {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
padding: 24px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@@ -450,8 +450,16 @@ function getSupportName(item: ChatConversation) {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.admin-page {
|
||||
display: grid;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
grid-template-rows: auto minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.page-head {
|
||||
display: flex;
|
||||
flex: none;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
@@ -474,7 +482,7 @@ function getSupportName(item: ChatConversation) {
|
||||
|
||||
.chat-workbench {
|
||||
display: grid;
|
||||
min-height: 640px;
|
||||
min-height: 0;
|
||||
grid-template-columns: 330px minmax(0, 1fr);
|
||||
overflow: hidden;
|
||||
border: 1px solid #e5e7eb;
|
||||
@@ -483,6 +491,7 @@ function getSupportName(item: ChatConversation) {
|
||||
}
|
||||
|
||||
.conversation-pane {
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid #e5e7eb;
|
||||
background: #f8fafc;
|
||||
@@ -567,6 +576,7 @@ function getSupportName(item: ChatConversation) {
|
||||
.message-pane {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
grid-template-rows: auto minmax(0, 1fr) auto;
|
||||
}
|
||||
|
||||
@@ -608,6 +618,7 @@ function getSupportName(item: ChatConversation) {
|
||||
}
|
||||
|
||||
.message-list {
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
padding: 18px;
|
||||
background: #f3f6fa;
|
||||
|
||||
@@ -26,6 +26,7 @@ const form = ref({
|
||||
title: '',
|
||||
content: '',
|
||||
sort_order: 0,
|
||||
is_global: false,
|
||||
})
|
||||
|
||||
watch(() => props.modelValue, (val) => {
|
||||
@@ -51,7 +52,7 @@ async function loadReplies() {
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
form.value = { title: '', content: '', sort_order: 0 }
|
||||
form.value = { title: '', content: '', sort_order: 0, is_global: false }
|
||||
editingId.value = null
|
||||
}
|
||||
|
||||
@@ -61,6 +62,7 @@ function startEdit(reply: QuickReply) {
|
||||
title: reply.title,
|
||||
content: reply.content,
|
||||
sort_order: reply.sort_order,
|
||||
is_global: reply.is_global,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +76,7 @@ async function handleSubmit() {
|
||||
await updateQuickReply(editingId.value, form.value)
|
||||
ElMessage.success('更新成功')
|
||||
} else {
|
||||
await createQuickReply(form.value.title, form.value.content, form.value.sort_order)
|
||||
await createQuickReply(form.value.title, form.value.content, form.value.sort_order, form.value.is_global)
|
||||
ElMessage.success('创建成功')
|
||||
}
|
||||
resetForm()
|
||||
@@ -126,14 +128,23 @@ function handleCancel() {
|
||||
style="margin-bottom: 8px"
|
||||
/>
|
||||
<div class="form-actions">
|
||||
<el-input-number
|
||||
v-model="form.sort_order"
|
||||
:min="0"
|
||||
:max="999"
|
||||
size="small"
|
||||
placeholder="排序"
|
||||
style="width: 120px"
|
||||
/>
|
||||
<div class="form-meta">
|
||||
<label class="sort-field">
|
||||
<span>排序</span>
|
||||
<el-input-number
|
||||
v-model="form.sort_order"
|
||||
:min="0"
|
||||
:max="999"
|
||||
size="small"
|
||||
placeholder="排序"
|
||||
style="width: 120px"
|
||||
/>
|
||||
</label>
|
||||
<el-radio-group v-model="form.is_global" size="small" :disabled="!!editingId">
|
||||
<el-radio-button :value="false">个人</el-radio-button>
|
||||
<el-radio-button :value="true">全局</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div>
|
||||
<el-button v-if="editingId" size="small" @click="handleCancel">取消</el-button>
|
||||
<el-button size="small" type="primary" @click="handleSubmit">
|
||||
@@ -196,6 +207,23 @@ function handleCancel() {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.form-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sort-field {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #6b7280;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.reply-list {
|
||||
|
||||
Reference in New Issue
Block a user