删除target文件夹

This commit is contained in:
MerCry 2026-02-23 23:59:09 +08:00
parent 72d84e2622
commit 3a4d8643b0
85 changed files with 2 additions and 1850 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target/
/.idea/

View File

@ -1,49 +0,0 @@
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/wecom_robot?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: jiong1114
redis:
host: localhost
port: 6379
password:
database: 0
timeout: 10000
lettuce:
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
wecom:
corp-id: ww29e81e73b1f4c6fd
agent-id: 1000006
secret: vltAfKVAH1bqo6WjB99rJaH6iQSXDyx3uf3hbbA8F-M
token: 2wuT6pE
encoding-aes-key: l0boKM2eqcGT3xV2O03y6VXx9U5l25u0tWQsgF3aNPT
ai:
enabled: true
provider: deepseek
deepseek:
api-key: sk-6cdd32d6d49d4d399b479d99e02d1672
base-url: https://api.deepseek.com/v1
model: deepseek-chat
openai:
api-key: your_openai_api_key
base-url: https://api.openai.com/v1
model: gpt-3.5-turbo
logging:
level:
com.wecom.robot: debug
org.springframework.web: info

View File

@ -1,49 +0,0 @@
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://host.docker.internal:3316/wecom_robot?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: jiong1114
redis:
host: host.docker.internal
port: 6379
password: jiong1114
database: 0
timeout: 10000
lettuce:
pool:
max-active: 16
max-wait: -1
max-idle: 8
min-idle: 2
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
wecom:
corp-id: ww29e81e73b1f4c6fd
agent-id: 1000006
secret: vltAfKVAH1bqo6WjB99rJaH6iQSXDyx3uf3hbbA8F-M
token: 2wuT6pE
encoding-aes-key: l0boKM2eqcGT3xV2O03y6VXx9U5l25u0tWQsgF3aNPT
ai:
enabled: true
provider: deepseek
deepseek:
api-key: sk-6cdd32d6d49d4d399b479d99e02d1672
base-url: https://api.deepseek.com/v1
model: deepseek-chat
openai:
api-key: your_openai_api_key
base-url: https://api.openai.com/v1
model: gpt-3.5-turbo
logging:
level:
com.wecom.robot: info
org.springframework.web: warn

View File

@ -1,30 +0,0 @@
server:
port: 8080
spring:
application:
name: wecom-robot
profiles:
active: dev
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.wecom.robot.entity
configuration:
map-underscore-to-camel-case: true
wecom:
kf:
callback-url: /wecom/callback
transfer:
keywords:
- 人工
- 转人工
- 投诉
- 客服
- 人工客服
confidence-threshold: 0.6
max-fail-rounds: 3
max-session-duration: 1800000
max-message-rounds: 50

View File

@ -1,77 +0,0 @@
-- 创建数据库
CREATE DATABASE IF NOT EXISTS wecom_robot DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE wecom_robot;
-- 会话表
CREATE TABLE IF NOT EXISTS `session` (
`session_id` VARCHAR(128) NOT NULL COMMENT '会话ID',
`customer_id` VARCHAR(64) NOT NULL COMMENT '客户ID (external_userid)',
`kf_id` VARCHAR(64) NOT NULL COMMENT '客服账号ID (open_kfid)',
`status` VARCHAR(20) NOT NULL DEFAULT 'AI' COMMENT '状态: AI/PENDING/MANUAL/CLOSED',
`wx_service_state` INT DEFAULT 0 COMMENT '微信会话状态: 0-未处理/1-智能助手/2-待接入池/3-人工接待/4-已结束',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`manual_cs_id` VARCHAR(64) DEFAULT NULL COMMENT '人工客服ID',
`metadata` TEXT DEFAULT NULL COMMENT '扩展信息JSON',
PRIMARY KEY (`session_id`),
INDEX `idx_customer_id` (`customer_id`),
INDEX `idx_kf_id` (`kf_id`),
INDEX `idx_status` (`status`),
INDEX `idx_updated_at` (`updated_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='会话表';
-- 消息表
CREATE TABLE IF NOT EXISTS `message` (
`msg_id` VARCHAR(128) NOT NULL COMMENT '消息ID',
`session_id` VARCHAR(128) NOT NULL COMMENT '会话ID',
`sender_type` VARCHAR(20) NOT NULL COMMENT '发送者类型: customer/ai/manual',
`sender_id` VARCHAR(64) NOT NULL COMMENT '发送者标识',
`content` TEXT NOT NULL COMMENT '消息内容',
`msg_type` VARCHAR(20) NOT NULL DEFAULT 'text' COMMENT '消息类型: text/image/link等',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`raw_data` TEXT DEFAULT NULL COMMENT '原始消息数据JSON',
PRIMARY KEY (`msg_id`),
INDEX `idx_session_id` (`session_id`),
INDEX `idx_created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='消息表';
-- 客服账号表
CREATE TABLE IF NOT EXISTS `kf_account` (
`kf_id` VARCHAR(64) NOT NULL COMMENT '客服账号ID',
`name` VARCHAR(100) DEFAULT NULL COMMENT '客服昵称',
`avatar` VARCHAR(500) DEFAULT NULL COMMENT '头像URL',
`status` VARCHAR(20) NOT NULL DEFAULT 'offline' COMMENT '状态: online/offline',
`bind_manual_id` VARCHAR(64) DEFAULT NULL COMMENT '绑定的企业微信员工ID',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`kf_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='客服账号表';
-- 转人工记录表
CREATE TABLE IF NOT EXISTS `transfer_log` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`session_id` VARCHAR(128) NOT NULL COMMENT '会话ID',
`trigger_reason` VARCHAR(200) DEFAULT NULL COMMENT '触发原因',
`trigger_time` DATETIME NOT NULL COMMENT '触发时间',
`accepted_time` DATETIME DEFAULT NULL COMMENT '客服接入时间',
`accepted_cs_id` VARCHAR(64) DEFAULT NULL COMMENT '接入的客服ID',
PRIMARY KEY (`id`),
INDEX `idx_session_id` (`session_id`),
INDEX `idx_trigger_time` (`trigger_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='转人工记录表';
-- 快捷回复表 (可选)
CREATE TABLE IF NOT EXISTS `quick_reply` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`cs_id` VARCHAR(64) DEFAULT NULL COMMENT '客服ID为空表示公共',
`category` VARCHAR(50) DEFAULT NULL COMMENT '分类',
`content` VARCHAR(500) NOT NULL COMMENT '回复内容',
`sort_order` INT DEFAULT 0 COMMENT '排序',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
INDEX `idx_cs_id` (`cs_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='快捷回复表';
-- 如果表已存在,添加新字段
ALTER TABLE `session` ADD COLUMN IF NOT EXISTS `wx_service_state` INT DEFAULT 0 COMMENT '微信会话状态';

View File

@ -1,455 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>聊天记录查询</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background: #f5f5f5;
min-height: 100vh;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
}
.header {
background: #1890ff;
color: white;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
.header h1 {
font-size: 24px;
margin-bottom: 8px;
}
.header p {
opacity: 0.8;
font-size: 14px;
}
.filters {
background: white;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
display: flex;
gap: 20px;
flex-wrap: wrap;
align-items: center;
}
.filter-group {
display: flex;
align-items: center;
gap: 8px;
}
.filter-group label {
font-weight: 500;
color: #333;
}
select, input {
padding: 8px 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 14px;
min-width: 200px;
}
select:focus, input:focus {
outline: none;
border-color: #1890ff;
}
.btn {
padding: 8px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
}
.btn-primary {
background: #1890ff;
color: white;
}
.btn-primary:hover {
background: #40a9ff;
}
.btn-secondary {
background: #f0f0f0;
color: #333;
}
.btn-secondary:hover {
background: #d9d9d9;
}
.main-content {
display: grid;
grid-template-columns: 350px 1fr;
gap: 20px;
}
.session-list {
background: white;
border-radius: 8px;
overflow: hidden;
}
.session-list-header {
padding: 15px 20px;
background: #fafafa;
border-bottom: 1px solid #f0f0f0;
font-weight: 600;
}
.session-item {
padding: 15px 20px;
border-bottom: 1px solid #f0f0f0;
cursor: pointer;
transition: background 0.2s;
}
.session-item:hover {
background: #f5f5f5;
}
.session-item.active {
background: #e6f7ff;
border-left: 3px solid #1890ff;
}
.session-item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.session-customer-id {
font-weight: 500;
color: #333;
font-size: 14px;
}
.session-status {
font-size: 12px;
padding: 2px 8px;
border-radius: 10px;
}
.status-AI { background: #e6f7ff; color: #1890ff; }
.status-PENDING { background: #fff7e6; color: #fa8c16; }
.status-MANUAL { background: #f6ffed; color: #52c41a; }
.status-CLOSED { background: #f5f5f5; color: #999; }
.session-meta {
font-size: 12px;
color: #999;
}
.chat-panel {
background: white;
border-radius: 8px;
display: flex;
flex-direction: column;
min-height: 600px;
}
.chat-header {
padding: 15px 20px;
background: #fafafa;
border-bottom: 1px solid #f0f0f0;
display: flex;
justify-content: space-between;
align-items: center;
}
.chat-header-info {
font-size: 14px;
color: #666;
}
.chat-messages {
flex: 1;
padding: 20px;
overflow-y: auto;
background: #fafafa;
}
.message {
margin-bottom: 16px;
display: flex;
flex-direction: column;
}
.message.customer {
align-items: flex-start;
}
.message.ai, .message.manual {
align-items: flex-end;
}
.message-sender {
font-size: 12px;
color: #999;
margin-bottom: 4px;
}
.message-content {
max-width: 70%;
padding: 10px 15px;
border-radius: 8px;
font-size: 14px;
line-height: 1.5;
}
.message.customer .message-content {
background: white;
border: 1px solid #e8e8e8;
}
.message.ai .message-content {
background: #e6f7ff;
border: 1px solid #91d5ff;
}
.message.manual .message-content {
background: #f6ffed;
border: 1px solid #b7eb8f;
}
.message-time {
font-size: 11px;
color: #bbb;
margin-top: 4px;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
color: #999;
}
.empty-state svg {
width: 80px;
height: 80px;
margin-bottom: 16px;
opacity: 0.5;
}
.loading {
text-align: center;
padding: 20px;
color: #999;
}
.no-sessions {
text-align: center;
padding: 40px;
color: #999;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>聊天记录查询</h1>
<p>查看各客服账号的历史聊天记录</p>
</div>
<div class="filters">
<div class="filter-group">
<label>客服账号:</label>
<select id="kfAccountSelect">
<option value="">请选择客服账号</option>
</select>
</div>
<div class="filter-group">
<label>会话状态:</label>
<select id="statusSelect">
<option value="all">全部</option>
<option value="AI">AI接待中</option>
<option value="PENDING">待接入</option>
<option value="MANUAL">人工接待中</option>
<option value="CLOSED">已结束</option>
</select>
</div>
<button class="btn btn-primary" onclick="loadSessions()">查询会话</button>
<button class="btn btn-secondary" onclick="refreshKfAccounts()">刷新账号</button>
</div>
<div class="main-content">
<div class="session-list">
<div class="session-list-header">
会话列表 (<span id="sessionCount">0</span>)
</div>
<div id="sessionListContainer">
<div class="no-sessions">请选择客服账号并查询</div>
</div>
</div>
<div class="chat-panel">
<div class="chat-header">
<div class="chat-header-info" id="chatHeaderInfo">请选择会话查看聊天记录</div>
</div>
<div class="chat-messages" id="chatMessagesContainer">
<div class="empty-state">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<path d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"/>
</svg>
<p>选择左侧会话查看聊天记录</p>
</div>
</div>
</div>
</div>
</div>
<script>
let currentSessionId = null;
async function refreshKfAccounts() {
try {
const response = await fetch('/chat-history/api/kf-accounts');
const result = await response.json();
if (result.code === 0) {
const select = document.getElementById('kfAccountSelect');
select.innerHTML = '<option value="">请选择客服账号</option>';
result.data.forEach(account => {
const option = document.createElement('option');
option.value = account.openKfId;
option.textContent = account.name || account.openKfId;
select.appendChild(option);
});
if (result.data.length === 0) {
alert('未获取到客服账号,请检查配置');
}
} else {
alert('获取客服账号失败: ' + result.message);
}
} catch (error) {
console.error('获取客服账号失败:', error);
alert('获取客服账号失败,请检查网络连接');
}
}
async function loadSessions() {
const kfId = document.getElementById('kfAccountSelect').value;
const status = document.getElementById('statusSelect').value;
if (!kfId) {
alert('请选择客服账号');
return;
}
const container = document.getElementById('sessionListContainer');
container.innerHTML = '<div class="loading">加载中...</div>';
try {
const response = await fetch(`/chat-history/api/sessions?openKfId=${encodeURIComponent(kfId)}&status=${status}`);
const result = await response.json();
if (result.code === 0) {
document.getElementById('sessionCount').textContent = result.data.length;
renderSessionList(result.data);
} else {
container.innerHTML = `<div class="no-sessions">查询失败: ${result.message}</div>`;
}
} catch (error) {
console.error('加载会话列表失败:', error);
container.innerHTML = '<div class="no-sessions">加载失败,请重试</div>';
}
}
function renderSessionList(sessions) {
const container = document.getElementById('sessionListContainer');
if (sessions.length === 0) {
container.innerHTML = '<div class="no-sessions">暂无会话记录</div>';
return;
}
container.innerHTML = sessions.map(session => `
<div class="session-item" data-session-id="${session.sessionId}" onclick="selectSession('${session.sessionId}')">
<div class="session-item-header">
<span class="session-customer-id">${session.customerId.substring(0, 15)}...</span>
<span class="session-status status-${session.status}">${getStatusText(session.status)}</span>
</div>
<div class="session-meta">
消息: ${session.messageCount} 条 | ${formatTime(session.updatedAt)}
</div>
</div>
`).join('');
}
function getStatusText(status) {
const map = {
'AI': 'AI接待',
'PENDING': '待接入',
'MANUAL': '人工接待',
'CLOSED': '已结束'
};
return map[status] || status;
}
function formatTime(timeStr) {
if (!timeStr) return '-';
const date = new Date(timeStr);
return `${date.getMonth() + 1}/${date.getDate()} ${date.getHours()}:${String(date.getMinutes()).padStart(2, '0')}`;
}
async function selectSession(sessionId) {
currentSessionId = sessionId;
document.querySelectorAll('.session-item').forEach(item => {
item.classList.remove('active');
});
document.querySelector(`[data-session-id="${sessionId}"]`).classList.add('active');
const container = document.getElementById('chatMessagesContainer');
container.innerHTML = '<div class="loading">加载中...</div>';
try {
const response = await fetch(`/chat-history/api/messages?sessionId=${encodeURIComponent(sessionId)}`);
const result = await response.json();
if (result.code === 0) {
document.getElementById('chatHeaderInfo').textContent =
`会话ID: ${sessionId} | 消息数: ${result.data.length}`;
renderMessages(result.data);
} else {
container.innerHTML = `<div class="no-sessions">加载失败: ${result.message}</div>`;
}
} catch (error) {
console.error('加载消息失败:', error);
container.innerHTML = '<div class="no-sessions">加载失败,请重试</div>';
}
}
function renderMessages(messages) {
const container = document.getElementById('chatMessagesContainer');
if (messages.length === 0) {
container.innerHTML = '<div class="empty-state"><p>暂无消息记录</p></div>';
return;
}
container.innerHTML = messages.map(msg => {
const senderName = getSenderName(msg.senderType, msg.senderId);
return `
<div class="message ${msg.senderType}">
<div class="message-sender">${senderName}</div>
<div class="message-content">${escapeHtml(msg.content)}</div>
<div class="message-time">${formatTime(msg.createdAt)}</div>
</div>
`;
}).join('');
container.scrollTop = container.scrollHeight;
}
function getSenderName(senderType, senderId) {
switch (senderType) {
case 'customer': return '客户';
case 'ai': return 'AI助手';
case 'manual': return `客服(${senderId || '未知'})`;
default: return senderType;
}
}
function escapeHtml(text) {
if (!text) return '';
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML.replace(/\n/g, '<br>');
}
document.addEventListener('DOMContentLoaded', function() {
refreshKfAccounts();
});
</script>
</body>
</html>

View File

@ -1,458 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>客户模拟端</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f5f5f5;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.phone-frame {
width: 375px;
height: 700px;
background: #fff;
border-radius: 30px;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
overflow: hidden;
display: flex;
flex-direction: column;
border: 8px solid #333;
}
.phone-header {
background: #ededed;
padding: 15px;
text-align: center;
border-bottom: 1px solid #d9d9d9;
position: relative;
}
.phone-header .status-bar {
position: absolute;
top: 5px;
left: 15px;
right: 15px;
display: flex;
justify-content: space-between;
font-size: 11px;
color: #333;
}
.phone-header .title {
margin-top: 15px;
font-size: 16px;
font-weight: 500;
}
.phone-header .subtitle {
font-size: 11px;
color: #999;
margin-top: 2px;
}
.chat-area {
flex: 1;
overflow-y: auto;
padding: 15px;
background: #f5f5f5;
}
.message {
margin-bottom: 15px;
display: flex;
flex-direction: column;
}
.message.sent {
align-items: flex-end;
}
.message.received {
align-items: flex-start;
}
.message-bubble {
max-width: 75%;
padding: 10px 14px;
border-radius: 8px;
font-size: 14px;
line-height: 1.4;
position: relative;
}
.message.sent .message-bubble {
background: #95ec69;
border-radius: 8px 0 8px 8px;
}
.message.received .message-bubble {
background: #fff;
border-radius: 0 8px 8px 8px;
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
}
.message-time {
font-size: 10px;
color: #999;
margin-top: 4px;
}
.sender-name {
font-size: 11px;
color: #999;
margin-bottom: 3px;
}
.typing-indicator {
display: none;
align-items: center;
padding: 10px 14px;
background: #fff;
border-radius: 0 8px 8px 8px;
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
width: fit-content;
}
.typing-indicator.show {
display: flex;
}
.typing-indicator span {
width: 6px;
height: 6px;
background: #999;
border-radius: 50%;
margin: 0 2px;
animation: typing 1.4s infinite;
}
.typing-indicator span:nth-child(2) {
animation-delay: 0.2s;
}
.typing-indicator span:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes typing {
0%, 60%, 100% { transform: translateY(0); }
30% { transform: translateY(-4px); }
}
.input-area {
background: #f7f7f7;
padding: 10px;
border-top: 1px solid #e0e0e0;
}
.input-row {
display: flex;
align-items: flex-end;
gap: 8px;
}
.input-row textarea {
flex: 1;
padding: 10px;
border: none;
border-radius: 20px;
background: #fff;
resize: none;
height: 40px;
max-height: 100px;
font-size: 14px;
outline: none;
}
.input-row button {
width: 40px;
height: 40px;
border-radius: 50%;
border: none;
background: #07c160;
color: white;
font-size: 18px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.input-row button:hover {
background: #06ad56;
}
.input-row button:disabled {
background: #ccc;
}
.quick-actions {
display: flex;
gap: 8px;
margin-top: 8px;
}
.quick-action {
padding: 6px 12px;
background: #fff;
border: 1px solid #e0e0e0;
border-radius: 15px;
font-size: 12px;
cursor: pointer;
}
.quick-action:hover {
background: #f5f5f5;
}
.settings-panel {
position: absolute;
top: 10px;
right: 10px;
background: #fff;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
z-index: 100;
display: none;
}
.settings-panel.show {
display: block;
}
.settings-panel h4 {
margin-bottom: 10px;
font-size: 14px;
}
.settings-panel input {
width: 100%;
padding: 8px;
margin-bottom: 8px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 12px;
}
.settings-panel button {
width: 100%;
padding: 8px;
background: #07c160;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.settings-btn {
position: absolute;
top: 10px;
right: 10px;
background: #fff;
border: 1px solid #d9d9d9;
border-radius: 50%;
width: 30px;
height: 30px;
cursor: pointer;
font-size: 14px;
}
.transfer-notice {
background: #fff3cd;
border: 1px solid #ffc107;
border-radius: 8px;
padding: 10px;
margin: 10px 0;
font-size: 12px;
color: #856404;
text-align: center;
}
.system-message {
text-align: center;
font-size: 11px;
color: #999;
margin: 10px 0;
}
</style>
</head>
<body>
<div class="phone-frame">
<div class="phone-header">
<div class="status-bar">
<span id="currentTime">12:00</span>
<span>📶 🔋</span>
</div>
<div class="title">智能客服</div>
<div class="subtitle" id="statusText">AI在线</div>
</div>
<div class="chat-area" id="chatArea">
<div class="system-message">会话已开始</div>
<div class="message received">
<div class="sender-name">客服</div>
<div class="message-bubble">您好!我是智能客服,有什么可以帮您的吗?</div>
<div class="message-time">刚刚</div>
</div>
</div>
<div class="input-area">
<div class="input-row">
<textarea id="messageInput" placeholder="输入消息..." rows="1"></textarea>
<button onclick="sendMessage()" id="sendBtn"></button>
</div>
<div class="quick-actions">
<button class="quick-action" onclick="quickSend('你好')">你好</button>
<button class="quick-action" onclick="quickSend('转人工')">转人工</button>
<button class="quick-action" onclick="quickSend('投诉')">投诉</button>
</div>
</div>
<button class="settings-btn" onclick="toggleSettings()">⚙️</button>
<div class="settings-panel" id="settingsPanel">
<h4>测试设置</h4>
<input type="text" id="customerId" placeholder="客户ID" value="customer_001">
<input type="text" id="kfId" placeholder="客服账号ID" value="kf_001">
<button onclick="saveSettings()">保存设置</button>
<button onclick="clearChat()" style="margin-top: 8px; background: #ff4d4f;">清空聊天</button>
</div>
</div>
<script>
const baseUrl = window.location.origin;
let customerId = 'customer_001';
let kfId = 'kf_001';
let sessionStatus = 'AI';
function updateTime() {
const now = new Date();
document.getElementById('currentTime').textContent =
now.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
}
setInterval(updateTime, 1000);
updateTime();
function toggleSettings() {
document.getElementById('settingsPanel').classList.toggle('show');
}
function saveSettings() {
customerId = document.getElementById('customerId').value || 'customer_001';
kfId = document.getElementById('kfId').value || 'kf_001';
toggleSettings();
addSystemMessage('设置已更新');
}
function clearChat() {
document.getElementById('chatArea').innerHTML = '<div class="system-message">会话已重置</div>';
sessionStatus = 'AI';
document.getElementById('statusText').textContent = 'AI在线';
toggleSettings();
}
function addSystemMessage(text) {
const chatArea = document.getElementById('chatArea');
const msg = document.createElement('div');
msg.className = 'system-message';
msg.textContent = text;
chatArea.appendChild(msg);
chatArea.scrollTop = chatArea.scrollHeight;
}
function addMessage(content, isSent, senderName = '') {
const chatArea = document.getElementById('chatArea');
const msg = document.createElement('div');
msg.className = 'message ' + (isSent ? 'sent' : 'received');
const time = new Date().toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
msg.innerHTML = `
${senderName ? '<div class="sender-name">' + senderName + '</div>' : ''}
<div class="message-bubble">${content}</div>
<div class="message-time">${time}</div>
`;
chatArea.appendChild(msg);
chatArea.scrollTop = chatArea.scrollHeight;
}
function showTyping() {
const chatArea = document.getElementById('chatArea');
const typing = document.createElement('div');
typing.className = 'message received';
typing.id = 'typingIndicator';
typing.innerHTML = `
<div class="typing-indicator show">
<span></span><span></span><span></span>
</div>
`;
chatArea.appendChild(typing);
chatArea.scrollTop = chatArea.scrollHeight;
}
function hideTyping() {
const typing = document.getElementById('typingIndicator');
if (typing) typing.remove();
}
async function sendMessage() {
const input = document.getElementById('messageInput');
const content = input.value.trim();
if (!content) return;
addMessage(content, true);
input.value = '';
showTyping();
try {
const response = await fetch(baseUrl + '/test/send-message?' +
'customerId=' + encodeURIComponent(customerId) +
'&kfId=' + encodeURIComponent(kfId) +
'&content=' + encodeURIComponent(content), {
method: 'POST'
});
const result = await response.json();
setTimeout(() => {
hideTyping();
if (result.code === 200) {
if (content.includes('人工') || content.includes('转人工') || content.includes('投诉')) {
sessionStatus = 'PENDING';
document.getElementById('statusText').textContent = '等待人工接入...';
addTransferNotice();
}
}
}, 1000 + Math.random() * 1000);
} catch (error) {
hideTyping();
console.error('发送失败:', error);
addMessage('消息发送失败,请重试', false, '系统');
}
}
function addTransferNotice() {
const chatArea = document.getElementById('chatArea');
const notice = document.createElement('div');
notice.className = 'transfer-notice';
notice.textContent = '正在为您转接人工客服,请稍候...';
chatArea.appendChild(notice);
chatArea.scrollTop = chatArea.scrollHeight;
}
function quickSend(text) {
document.getElementById('messageInput').value = text;
sendMessage();
}
document.getElementById('messageInput').addEventListener('keypress', function(e) {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
});
document.getElementById('messageInput').addEventListener('input', function() {
this.style.height = 'auto';
this.style.height = Math.min(this.scrollHeight, 100) + 'px';
});
setInterval(async () => {
try {
const response = await fetch(baseUrl + '/api/sessions?status=MANUAL');
const result = await response.json();
if (result.code === 200) {
const mySession = result.data.find(s =>
s.customerId === customerId && s.status === 'MANUAL'
);
if (mySession && sessionStatus !== 'MANUAL') {
sessionStatus = 'MANUAL';
document.getElementById('statusText').textContent = '人工客服接待中';
addSystemMessage('人工客服已接入');
}
}
} catch (e) {}
}, 3000);
</script>
</body>
</html>

View File

@ -1,638 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>人工客服工作台</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f5f5f5;
height: 100vh;
display: flex;
}
.sidebar {
width: 300px;
background: #fff;
border-right: 1px solid #e0e0e0;
display: flex;
flex-direction: column;
}
.sidebar-header {
padding: 15px;
background: #1890ff;
color: white;
font-size: 16px;
font-weight: bold;
}
.session-tabs {
display: flex;
border-bottom: 1px solid #e0e0e0;
}
.session-tab {
flex: 1;
padding: 10px;
text-align: center;
cursor: pointer;
border-bottom: 2px solid transparent;
}
.session-tab.active {
border-bottom-color: #1890ff;
color: #1890ff;
}
.session-list {
flex: 1;
overflow-y: auto;
}
.session-item {
padding: 12px 15px;
border-bottom: 1px solid #f0f0f0;
cursor: pointer;
}
.session-item:hover {
background: #f5f5f5;
}
.session-item.active {
background: #e6f7ff;
}
.session-item .customer-id {
font-weight: bold;
margin-bottom: 5px;
}
.session-item .last-msg {
font-size: 12px;
color: #666;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.session-item .time {
font-size: 11px;
color: #999;
margin-top: 3px;
}
.status-badge {
display: inline-block;
padding: 2px 6px;
border-radius: 3px;
font-size: 11px;
margin-left: 5px;
}
.status-pending {
background: #fff7e6;
color: #fa8c16;
}
.status-manual {
background: #e6f7ff;
color: #1890ff;
}
.main-content {
flex: 1;
display: flex;
flex-direction: column;
}
.chat-header {
padding: 15px;
background: #fff;
border-bottom: 1px solid #e0e0e0;
display: flex;
justify-content: space-between;
align-items: center;
}
.chat-messages {
flex: 1;
padding: 20px;
overflow-y: auto;
background: #f9f9f9;
}
.message {
margin-bottom: 15px;
display: flex;
}
.message.customer {
justify-content: flex-start;
}
.message.ai, .message.manual {
justify-content: flex-end;
}
.message-content {
max-width: 60%;
padding: 10px 15px;
border-radius: 8px;
position: relative;
}
.message.customer .message-content {
background: #fff;
border: 1px solid #e0e0e0;
}
.message.ai .message-content {
background: #e6f7ff;
border: 1px solid #91d5ff;
}
.message.manual .message-content {
background: #f6ffed;
border: 1px solid #b7eb8f;
}
.message-sender {
font-size: 11px;
color: #999;
margin-bottom: 3px;
}
.message-time {
font-size: 10px;
color: #bbb;
margin-top: 3px;
}
.chat-input {
padding: 15px;
background: #fff;
border-top: 1px solid #e0e0e0;
display: flex;
gap: 10px;
}
.chat-input textarea {
flex: 1;
padding: 10px;
border: 1px solid #d9d9d9;
border-radius: 4px;
resize: none;
height: 60px;
}
.chat-input button {
padding: 10px 20px;
background: #1890ff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.chat-input button:hover {
background: #40a9ff;
}
.chat-input button:disabled {
background: #d9d9d9;
cursor: not-allowed;
}
.empty-state {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
color: #999;
}
.connection-status {
padding: 5px 10px;
font-size: 12px;
border-radius: 4px;
}
.connected {
background: #f6ffed;
color: #52c41a;
}
.disconnected {
background: #fff2f0;
color: #ff4d4f;
}
.actions {
display: flex;
gap: 10px;
}
.actions button {
padding: 5px 10px;
border: 1px solid #d9d9d9;
background: #fff;
border-radius: 4px;
cursor: pointer;
}
.actions button:hover {
border-color: #1890ff;
color: #1890ff;
}
.test-panel {
position: fixed;
right: 20px;
bottom: 20px;
background: #fff;
border: 1px solid #d9d9d9;
border-radius: 8px;
padding: 15px;
width: 300px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.test-panel h4 {
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid #f0f0f0;
}
.test-panel input, .test-panel textarea {
width: 100%;
padding: 8px;
margin-bottom: 10px;
border: 1px solid #d9d9d9;
border-radius: 4px;
}
.test-panel button {
width: 100%;
padding: 8px;
background: #52c41a;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.test-panel button:hover {
background: #73d13d;
}
</style>
</head>
<body>
<div class="sidebar">
<div class="sidebar-header">
客服工作台 <span id="csId">CS_001</span>
</div>
<div class="session-tabs">
<div class="session-tab active" data-status="PENDING" onclick="switchTab('PENDING')">
待接入 (<span id="pendingCount">0</span>)
</div>
<div class="session-tab" data-status="MANUAL" onclick="switchTab('MANUAL')">
进行中 (<span id="manualCount">0</span>)
</div>
</div>
<div class="session-list" id="sessionList">
</div>
</div>
<div class="main-content">
<div id="chatArea" style="display: none; height: 100%; flex-direction: column;">
<div class="chat-header">
<div>
<strong id="currentCustomer">-</strong>
<span class="status-badge" id="currentStatus">-</span>
</div>
<div class="actions">
<button onclick="acceptSession()" id="acceptBtn">接入会话</button>
<button onclick="closeSession()" id="closeBtn">结束会话</button>
</div>
</div>
<div class="chat-messages" id="chatMessages">
</div>
<div class="chat-input">
<textarea id="messageInput" placeholder="输入消息..."></textarea>
<button onclick="sendMessage()" id="sendBtn" disabled>发送</button>
</div>
</div>
<div id="emptyState" class="empty-state">
<div style="text-align: center;">
<p>请从左侧选择一个会话</p>
<p style="margin-top: 10px; font-size: 12px;">WebSocket: <span id="wsStatus" class="connection-status disconnected">未连接</span></p>
</div>
</div>
</div>
<div class="test-panel">
<h4>🧪 模拟客户消息</h4>
<input type="text" id="testCustomerId" placeholder="客户ID" value="test_customer_001">
<input type="text" id="testKfId" placeholder="客服账号ID" value="test_kf_001">
<textarea id="testContent" placeholder="消息内容"></textarea>
<button onclick="sendTestMessage()">发送测试消息</button>
<button onclick="triggerTransfer()" style="margin-top: 5px; background: #fa8c16;">触发转人工</button>
</div>
<script>
let ws = null;
let currentSessionId = null;
let currentStatus = null;
let csId = 'CS_001';
const baseUrl = window.location.origin;
function connectWebSocket() {
const wsUrl = baseUrl.replace('http', 'ws') + '/ws/cs/' + csId;
ws = new WebSocket(wsUrl);
ws.onopen = function() {
document.getElementById('wsStatus').className = 'connection-status connected';
document.getElementById('wsStatus').textContent = '已连接';
console.log('WebSocket已连接');
};
ws.onclose = function() {
document.getElementById('wsStatus').className = 'connection-status disconnected';
document.getElementById('wsStatus').textContent = '已断开';
console.log('WebSocket已断开');
setTimeout(connectWebSocket, 3000);
};
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
console.log('收到消息:', data);
handleWebSocketMessage(data);
};
ws.onerror = function(error) {
console.error('WebSocket错误:', error);
};
}
function handleWebSocketMessage(data) {
switch(data.type) {
case 'new_pending_session':
alert('有新的待接入会话!');
loadSessions();
break;
case 'new_message':
case 'customer_message':
if (currentSessionId === data.sessionId) {
addMessage('customer', data.content, data.timestamp);
}
loadSessions();
break;
case 'session_accepted':
if (currentSessionId === data.sessionId) {
currentStatus = 'MANUAL';
updateChatHeader();
document.getElementById('sendBtn').disabled = false;
document.getElementById('acceptBtn').disabled = true;
}
break;
case 'session_closed':
if (currentSessionId === data.sessionId) {
alert('会话已结束');
currentSessionId = null;
showEmptyState();
}
loadSessions();
break;
}
}
function switchTab(status) {
document.querySelectorAll('.session-tab').forEach(tab => {
tab.classList.remove('active');
if (tab.dataset.status === status) {
tab.classList.add('active');
}
});
loadSessions(status);
}
async function loadSessions(status = 'PENDING') {
try {
const response = await fetch(baseUrl + '/api/sessions?status=' + status);
const result = await response.json();
if (result.code === 200) {
renderSessionList(result.data, status);
if (status === 'PENDING') {
document.getElementById('pendingCount').textContent = result.data.length;
} else {
document.getElementById('manualCount').textContent = result.data.length;
}
}
} catch (error) {
console.error('加载会话列表失败:', error);
}
}
function renderSessionList(sessions, status) {
const list = document.getElementById('sessionList');
list.innerHTML = '';
sessions.forEach(session => {
const item = document.createElement('div');
item.className = 'session-item' + (currentSessionId === session.sessionId ? ' active' : '');
item.onclick = () => selectSession(session);
const time = session.lastMessageTime ? new Date(session.lastMessageTime).toLocaleString() : '-';
item.innerHTML = `
<div class="customer-id">
${session.customerId}
<span class="status-badge status-${session.status.toLowerCase()}">${session.status}</span>
</div>
<div class="last-msg">${session.lastMessage || '暂无消息'}</div>
<div class="time">${time}</div>
`;
list.appendChild(item);
});
if (sessions.length === 0) {
list.innerHTML = '<div style="padding: 20px; text-align: center; color: #999;">暂无会话</div>';
}
}
async function selectSession(session) {
currentSessionId = session.sessionId;
currentStatus = session.status;
document.querySelectorAll('.session-item').forEach(item => {
item.classList.remove('active');
});
event.currentTarget.classList.add('active');
document.getElementById('emptyState').style.display = 'none';
document.getElementById('chatArea').style.display = 'flex';
updateChatHeader();
await loadHistory();
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
type: 'bind_session',
sessionId: currentSessionId
}));
}
}
function updateChatHeader() {
document.getElementById('currentCustomer').textContent = currentSessionId;
const statusBadge = document.getElementById('currentStatus');
statusBadge.textContent = currentStatus;
statusBadge.className = 'status-badge status-' + currentStatus.toLowerCase();
document.getElementById('acceptBtn').disabled = currentStatus !== 'PENDING';
document.getElementById('sendBtn').disabled = currentStatus !== 'MANUAL';
document.getElementById('closeBtn').disabled = currentStatus !== 'MANUAL';
}
async function loadHistory() {
try {
const response = await fetch(baseUrl + '/api/sessions/' + currentSessionId + '/history');
const result = await response.json();
if (result.code === 200) {
const container = document.getElementById('chatMessages');
container.innerHTML = '';
result.data.forEach(msg => {
addMessage(msg.senderType, msg.content, msg.createdAt);
});
container.scrollTop = container.scrollHeight;
}
} catch (error) {
console.error('加载历史消息失败:', error);
}
}
function addMessage(senderType, content, timestamp) {
const container = document.getElementById('chatMessages');
const msg = document.createElement('div');
msg.className = 'message ' + senderType;
const senderName = senderType === 'customer' ? '客户' :
senderType === 'ai' ? 'AI客服' : '人工客服';
const time = timestamp ? new Date(timestamp).toLocaleString() : new Date().toLocaleString();
msg.innerHTML = `
<div class="message-content">
<div class="message-sender">${senderName}</div>
<div>${content}</div>
<div class="message-time">${time}</div>
</div>
`;
container.appendChild(msg);
container.scrollTop = container.scrollHeight;
}
async function acceptSession() {
if (!currentSessionId) return;
try {
const response = await fetch(baseUrl + '/api/sessions/' + currentSessionId + '/accept', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ csId: csId })
});
const result = await response.json();
if (result.code === 200) {
currentStatus = 'MANUAL';
updateChatHeader();
loadSessions('PENDING');
loadSessions('MANUAL');
} else {
alert('接入失败: ' + result.message);
}
} catch (error) {
console.error('接入会话失败:', error);
}
}
async function sendMessage() {
if (!currentSessionId || currentStatus !== 'MANUAL') return;
const content = document.getElementById('messageInput').value.trim();
if (!content) return;
try {
const response = await fetch(baseUrl + '/api/sessions/' + currentSessionId + '/message', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content: content, msgType: 'text' })
});
const result = await response.json();
if (result.code === 200) {
addMessage('manual', content);
document.getElementById('messageInput').value = '';
} else {
alert('发送失败: ' + result.message);
}
} catch (error) {
console.error('发送消息失败:', error);
}
}
async function closeSession() {
if (!currentSessionId) return;
try {
const response = await fetch(baseUrl + '/api/sessions/' + currentSessionId + '/close', {
method: 'POST'
});
const result = await response.json();
if (result.code === 200) {
currentSessionId = null;
showEmptyState();
loadSessions('PENDING');
loadSessions('MANUAL');
}
} catch (error) {
console.error('结束会话失败:', error);
}
}
function showEmptyState() {
document.getElementById('emptyState').style.display = 'flex';
document.getElementById('chatArea').style.display = 'none';
}
async function sendTestMessage() {
const customerId = document.getElementById('testCustomerId').value;
const kfId = document.getElementById('testKfId').value;
const content = document.getElementById('testContent').value;
if (!content) {
alert('请输入消息内容');
return;
}
try {
const response = await fetch(baseUrl + '/test/send-message?customerId=' + customerId + '&kfId=' + kfId + '&content=' + encodeURIComponent(content), {
method: 'POST'
});
const result = await response.json();
if (result.code === 200) {
alert('消息已发送!');
document.getElementById('testContent').value = '';
setTimeout(() => loadSessions('PENDING'), 500);
setTimeout(() => loadSessions('MANUAL'), 500);
}
} catch (error) {
console.error('发送测试消息失败:', error);
}
}
async function triggerTransfer() {
const customerId = document.getElementById('testCustomerId').value;
const kfId = document.getElementById('testKfId').value;
try {
const response = await fetch(baseUrl + '/test/trigger-transfer?customerId=' + customerId + '&kfId=' + kfId, {
method: 'POST'
});
const result = await response.json();
if (result.code === 200) {
alert('已触发转人工!');
setTimeout(() => loadSessions('PENDING'), 500);
}
} catch (error) {
console.error('触发转人工失败:', error);
}
}
document.getElementById('messageInput').addEventListener('keypress', function(e) {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
});
connectWebSocket();
loadSessions('PENDING');
loadSessions('MANUAL');
</script>
</body>
</html>

View File

@ -1,3 +0,0 @@
artifactId=wecom-robot
groupId=com.wecom
version=1.0.0

View File

@ -1,46 +0,0 @@
com\wecom\robot\dto\WxAccessToken.class
com\wecom\robot\dto\ChatCompletionResponse$Choice.class
com\wecom\robot\dto\WxCallbackMessage.class
com\wecom\robot\websocket\CsWebSocketHandler.class
com\wecom\robot\dto\AcceptSessionRequest.class
com\wecom\robot\dto\SyncMsgResponse$MsgItem.class
com\wecom\robot\dto\WxSendMessageRequest$TextContent.class
com\wecom\robot\controller\WecomCallbackController.class
com\wecom\robot\dto\WxSendMessageRequest$ImageContent.class
com\wecom\robot\config\AiConfig$DeepSeekConfig.class
com\wecom\robot\mapper\TransferLogMapper.class
com\wecom\robot\service\WecomApiService.class
com\wecom\robot\dto\SyncMsgResponse.class
com\wecom\robot\dto\SessionInfo.class
com\wecom\robot\config\WecomConfig$KfConfig.class
com\wecom\robot\dto\WxSendMessageRequest$LinkContent.class
com\wecom\robot\mapper\KfAccountMapper.class
com\wecom\robot\service\MessageProcessService.class
com\wecom\robot\dto\ApiResponse.class
com\wecom\robot\mapper\MessageMapper.class
com\wecom\robot\config\AiConfig$OpenAiConfig.class
com\wecom\robot\dto\ChatCompletionResponse$Usage.class
com\wecom\robot\dto\MessageInfo.class
com\wecom\robot\WecomRobotApplication.class
com\wecom\robot\dto\ChatCompletionResponse.class
com\wecom\robot\config\WecomConfig.class
com\wecom\robot\dto\ChatCompletionRequest.class
com\wecom\robot\dto\ChatCompletionResponse$Message.class
com\wecom\robot\service\AiService.class
com\wecom\robot\util\XmlUtil.class
com\wecom\robot\service\WebSocketService.class
com\wecom\robot\config\TransferConfig.class
com\wecom\robot\dto\ChatCompletionRequest$Message.class
com\wecom\robot\dto\SendMessageRequest.class
com\wecom\robot\service\TransferService.class
com\wecom\robot\controller\SessionController.class
com\wecom\robot\entity\Session.class
com\wecom\robot\controller\TestController.class
com\wecom\robot\entity\Message.class
com\wecom\robot\entity\TransferLog.class
com\wecom\robot\service\SessionManagerService.class
com\wecom\robot\dto\WxSendMessageRequest.class
com\wecom\robot\entity\KfAccount.class
com\wecom\robot\config\AiConfig.class
com\wecom\robot\mapper\SessionMapper.class
com\wecom\robot\config\WebSocketConfig.class

View File

@ -1,45 +0,0 @@
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\entity\Session.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\service\WebSocketService.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\controller\WecomCallbackController.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\util\PKCS7Encoder.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\util\Sample.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\config\AiConfig.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\controller\DebugController.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\dto\ApiResponse.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\util\XMLParse.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\dto\SessionInfo.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\dto\SyncMsgResponse.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\entity\TransferLog.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\dto\SendMessageRequest.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\websocket\CsWebSocketHandler.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\mapper\MessageMapper.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\mapper\SessionMapper.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\WecomRobotApplication.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\util\XmlUtil.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\dto\ChatCompletionRequest.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\dto\AcceptSessionRequest.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\controller\SessionController.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\service\SessionManagerService.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\util\AesException.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\util\WXBizMsgCrypt.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\config\WebSocketConfig.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\service\TransferService.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\dto\MessageInfo.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\service\MessageProcessService.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\dto\ChatCompletionResponse.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\service\AiService.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\util\ByteGroup.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\dto\WxCallbackMessage.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\entity\Message.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\service\WecomApiService.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\dto\ServiceStateResponse.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\config\TransferConfig.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\entity\KfAccount.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\mapper\TransferLogMapper.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\mapper\KfAccountMapper.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\controller\TestController.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\controller\ChatHistoryController.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\util\SHA1.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\config\WecomConfig.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\dto\WxAccessToken.java
E:\AiProject\wecom-robot\src\main\java\com\wecom\robot\dto\WxSendMessageRequest.java

Binary file not shown.