358 lines
9.8 KiB
Vue
358 lines
9.8 KiB
Vue
<!--
|
||
Copyright 2024-2026 ReplyPier
|
||
|
||
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.
|
||
-->
|
||
|
||
<script setup lang="ts">
|
||
import type { Agent } from '@/types/agent'
|
||
import { useAgentCreate } from '@/composables/useAgentCreate'
|
||
|
||
const {
|
||
agentName,
|
||
useWorkflow,
|
||
isCreating,
|
||
error,
|
||
createAgent
|
||
} = useAgentCreate()
|
||
|
||
const emit = defineEmits<{
|
||
(e: 'close'): void
|
||
(e: 'created', agent: Agent): void
|
||
(e: 'openWorkflowBuilder', agent: Agent): void
|
||
}>()
|
||
|
||
const handleCreateAgent = async () => {
|
||
const newAgent = await createAgent()
|
||
if (newAgent) {
|
||
emit('created', newAgent)
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<div class="modal-overlay">
|
||
<div class="modal-content" role="dialog" aria-modal="true" aria-labelledby="create-agent-title">
|
||
<div class="modal-header">
|
||
<h3 id="create-agent-title">创建客服</h3>
|
||
<button type="button" class="close-button" aria-label="关闭" @click="$emit('close')">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form @submit.prevent="handleCreateAgent">
|
||
<div class="form-group">
|
||
<label for="agent-name">客服名称</label>
|
||
<input
|
||
id="agent-name"
|
||
type="text"
|
||
v-model="agentName"
|
||
placeholder="例如:客户支持客服"
|
||
:disabled="isCreating"
|
||
required
|
||
>
|
||
<div class="help-text">
|
||
为客服起个名字,访客会看到这个名称。
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group mode-selection">
|
||
<label>客服模式</label>
|
||
<div class="mode-options">
|
||
<div
|
||
class="mode-option"
|
||
:class="{ 'selected': !useWorkflow }"
|
||
@click="useWorkflow = false"
|
||
>
|
||
<div class="mode-icon">
|
||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M12 3l1.9 4.6L18.5 9l-4.6 1.4L12 15l-1.9-4.6L5.5 9l4.6-1.4z"/>
|
||
<path d="M19 14l.7 1.8L21.5 16.5l-1.8.7L19 19l-.7-1.8L16.5 16.5l1.8-.7z"/>
|
||
</svg>
|
||
</div>
|
||
<div class="mode-details">
|
||
<h4>AI 自动模式</h4>
|
||
<p>让 AI 依据指令自然应答</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div
|
||
class="mode-option"
|
||
:class="{ 'selected': useWorkflow }"
|
||
@click="useWorkflow = true"
|
||
>
|
||
<div class="mode-icon">
|
||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="6" cy="6" r="2.4"/>
|
||
<circle cx="6" cy="18" r="2.4"/>
|
||
<circle cx="18" cy="9" r="2.4"/>
|
||
<path d="M8.4 6H13a3 3 0 0 1 3 3M6 8.4v7.2"/>
|
||
</svg>
|
||
</div>
|
||
<div class="mode-details">
|
||
<h4>工作流编排</h4>
|
||
<p>拖拽搭建自定义对话流程</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-if="error" class="error-message">
|
||
{{ error }}
|
||
</div>
|
||
|
||
<div class="form-actions">
|
||
<button
|
||
type="button"
|
||
class="cancel-button"
|
||
@click="$emit('close')"
|
||
:disabled="isCreating"
|
||
>
|
||
取消
|
||
</button>
|
||
<button
|
||
type="submit"
|
||
class="create-button"
|
||
:disabled="isCreating"
|
||
>
|
||
{{ isCreating ? '创建中…' : '创建客服' }}
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.modal-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(255, 255, 255, 0.5);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.modal-content {
|
||
background: var(--surface);
|
||
border: 1px solid var(--o10);
|
||
border-radius: 24px;
|
||
width: 90%;
|
||
max-width: 600px;
|
||
max-height: 90vh;
|
||
overflow-y: auto;
|
||
box-shadow: 0 12px 48px rgba(0, 0, 0, 0.2);
|
||
animation: modal-appear 0.3s ease-out;
|
||
}
|
||
|
||
@keyframes modal-appear {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(20px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
.modal-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: var(--space-lg) var(--space-lg) var(--space-md);
|
||
border-bottom: 1px solid var(--border-color);
|
||
}
|
||
|
||
.modal-header h3 {
|
||
margin: 0;
|
||
font-size: 1.5rem;
|
||
color: var(--text-color);
|
||
font-weight: 600;
|
||
}
|
||
|
||
.close-button {
|
||
background: none;
|
||
border: none;
|
||
font-size: 1.5rem;
|
||
cursor: pointer;
|
||
color: var(--text-muted);
|
||
line-height: 1;
|
||
padding: 0;
|
||
margin: 0;
|
||
}
|
||
|
||
.close-button:hover {
|
||
color: var(--text-color);
|
||
}
|
||
|
||
.modal-body {
|
||
padding: var(--space-lg);
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: var(--space-lg);
|
||
}
|
||
|
||
label {
|
||
display: block;
|
||
margin-bottom: var(--space-xs);
|
||
font-weight: 500;
|
||
color: var(--text-color);
|
||
}
|
||
|
||
input {
|
||
width: 100%;
|
||
padding: var(--space-md);
|
||
border: 1px solid var(--border-color);
|
||
border-radius: var(--radius-md);
|
||
background: var(--background-soft);
|
||
color: var(--text-color);
|
||
font-size: 1rem;
|
||
transition: border-color 0.2s ease;
|
||
}
|
||
|
||
input:focus {
|
||
outline: none;
|
||
border-color: var(--primary-color);
|
||
box-shadow: 0 0 0 2px var(--primary-soft);
|
||
}
|
||
|
||
.help-text {
|
||
font-size: 0.875rem;
|
||
color: var(--text-muted);
|
||
margin-top: var(--space-xs);
|
||
}
|
||
|
||
.error-message {
|
||
background-color: var(--error-soft);
|
||
color: var(--error-color);
|
||
padding: var(--space-md);
|
||
border-radius: var(--radius-md);
|
||
margin-bottom: var(--space-lg);
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
.mode-options {
|
||
display: flex;
|
||
gap: var(--space-md);
|
||
flex-direction: column;
|
||
}
|
||
|
||
.mode-option {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-md);
|
||
padding: var(--space-md);
|
||
border: 2px solid var(--border-color);
|
||
border-radius: var(--radius-lg);
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.mode-option.selected {
|
||
border-color: var(--primary-color);
|
||
background-color: var(--primary-soft);
|
||
}
|
||
|
||
.mode-icon {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 44px;
|
||
height: 44px;
|
||
flex-shrink: 0;
|
||
border-radius: var(--radius-md);
|
||
background: var(--o05);
|
||
border: 1px solid var(--o10);
|
||
color: var(--muted);
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.mode-option.selected .mode-icon {
|
||
background: var(--accent-bg-08);
|
||
border-color: var(--accent-border);
|
||
color: var(--accent-ink);
|
||
}
|
||
|
||
.mode-details {
|
||
flex: 1;
|
||
}
|
||
|
||
.mode-details h4 {
|
||
margin: 0 0 var(--space-xs);
|
||
font-size: 1.1rem;
|
||
}
|
||
|
||
.mode-details p {
|
||
margin: 0;
|
||
color: var(--text-muted);
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
.form-actions {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: var(--space-md);
|
||
margin-top: var(--space-xl);
|
||
}
|
||
|
||
.cancel-button {
|
||
padding: var(--space-md) var(--space-lg);
|
||
border: 1px solid var(--border-color);
|
||
border-radius: var(--radius-md);
|
||
background: var(--background-soft);
|
||
color: var(--text-color);
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.cancel-button:hover {
|
||
background: var(--background-muted);
|
||
}
|
||
|
||
.create-button {
|
||
padding: var(--space-md) var(--space-lg);
|
||
border: none;
|
||
border-radius: var(--radius-md);
|
||
background: var(--accent-solid);
|
||
color: var(--on-accent-solid);
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.create-button:hover {
|
||
background: var(--primary-dark);
|
||
}
|
||
|
||
.create-button:disabled,
|
||
.cancel-button:disabled {
|
||
opacity: 0.6;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
@media (min-width: 768px) {
|
||
.mode-options {
|
||
flex-direction: row;
|
||
}
|
||
|
||
.mode-option {
|
||
flex: 1;
|
||
}
|
||
}
|
||
</style> |