Files
meeting-room/frontend/node_modules/.cache/default-development/7.pack

4166 lines
265 KiB
Plaintext
Raw Normal View History

wpcD%<10>webpack/lib/cache/PackFileCacheStrategy<67>PackContentItems <10>tFlagDependencyExportsPlugin|/home/node/.openclaw/workspace/flying-hero/projects/meeting-room/frontend/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[1].oneOf[3]!/home/node/.openclaw/workspace/flying-hero/projects/meeting-room/frontend/node_modules/source-map-loader/dist/cjs.js!/home/node/.openclaw/workspace/flying-hero/projects/meeting-room/frontend/src/App.jsxCompilation/codeGeneration|/home/node/.openclaw/workspace/flying-hero/projects/meeting-room/frontend/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[1].oneOf[3]!/home/node/.openclaw/workspace/flying-hero/projects/meeting-room/frontend/node_modules/source-map-loader/dist/cjs.js!/home/node/.openclaw/workspace/flying-hero/projects/meeting-room/frontend/src/App.js|main<10>webpack/lib/ModuleGraph<70>RestoreProvidedData<10><10><05>name<6D>provided<65>canMangleProvide<64>terminalBinding<6E>exportsInfo<17>default
<04>sources<65>runtimeRequirements<74>data<74>hash<01>javascript<10>webpack/lib/util/registerExternalSerializer<65>webpack-sources/CachedSource Cs<10>webpack/lib/util/registerExternalSerializer<65>webpack-sources/ConcatSource<10><10>webpack/lib/util/registerExternalSerializer<65>webpack-sources/RawSourceL__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-router-dom */ "./node_modules/react-router-dom/dist/index.js");
/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-router-dom */ "./node_modules/react-router/dist/index.js");
/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! axios */ "./node_modules/axios/lib/axios.js");
/* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js");
/* provided dependency */ var __react_refresh_utils__ = __webpack_require__(/*! ./node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js */ "./node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js");
<10>webpack/lib/util/registerExternalSerializer<65>webpack-sources/ReplaceSource<10>webpack/lib/util/registerExternalSerializer<65>webpack-sources/SourceMapSource<15>__webpack_require__.$Refresh$.runtime = require('/home/node/.openclaw/workspace/flying-hero/projects/meeting-room/frontend/node_modules/react-refresh/runtime.js');
var _jsxFileName = "/home/node/.openclaw/workspace/flying-hero/projects/meeting-room/frontend/src/App.js",
_s = $RefreshSig$(),
_s2 = $RefreshSig$(),
_s3 = $RefreshSig$();
import React, { useState, useEffect } from 'react';
import { BrowserRouter as Router, Routes, Route, Link, useNavigate, useParams } from 'react-router-dom';
import axios from 'axios';
import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";
const API_BASE = 'http://localhost:8000/api/v1';
axios.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
});
// ============ 登录页面 ============
function LoginPage() {
_s();
const [username, setUsername] = useState('test');
const [password, setPassword] = useState('test123');
const [mode, setMode] = useState('solo');
const [agents, setAgents] = useState([]);
const [selectedAgents, setSelectedAgents] = useState([]);
const navigate = useNavigate();
// 扫描本机龙虾
useEffect(() => {
if (username) {
scanAgents();
}
}, [username]);
const scanAgents = async () => {
try {
// 传递 username 参数,获取绑定的龙虾信息
const res = await axios.get(`${API_BASE}/user/scan-local-agents/?username=${username}`);
setAgents(res.data.agents || []);
} catch (error) {
console.error('扫描龙虾失败:', error);
}
};
const handleLogin = async e => {
e.preventDefault();
try {
const payload = {
username,
password,
mode
};
if (mode !== 'solo' && selectedAgents.length > 0) {
payload.agent_ids = selectedAgents;
}
const res = await axios.post(`${API_BASE}/auth/login/`, payload);
localStorage.setItem('token', res.data.token);
localStorage.setItem('user', JSON.stringify(res.data.user));
localStorage.setItem('sessions', JSON.stringify(res.data.sessions));
localStorage.setItem('mode', res.data.mode);
navigate('/meetings');
} catch (error) {
var _error$response, _error$response$data, _error$response2, _error$response2$data;
alert('登录失败:' + (((_error$response = error.response) === null || _error$response === void 0 ? void 0 : (_error$response$data = _error$response.data) === null || _error$response$data === void 0 ? void 0 : _error$response$data.detail) || ((_error$response2 = error.response) === null || _error$response2 === void 0 ? void 0 : (_error$response2$data = _error$response2.data) === null || _error$response2$data === void 0 ? void 0 : _error$response2$data.error) || error.message));
}
};
const toggleAgent = agentId => {
setSelectedAgents(prev => prev.includes(agentId) ? prev.filter(id => id !== agentId) : [...prev, agentId]);
};
return /*#__PURE__*/_jsxDEV("div", {
style: styles.center,
children: /*#__PURE__*/_jsxDEV("div", {
style: styles.card,
children: [/*#__PURE__*/_jsxDEV("h1", {
style: styles.title,
children: "\uD83C\uDFDB\uFE0F \u9F99\u867E\u8BAE\u4E8B\u5385"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 74,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("form", {
onSubmit: handleLogin,
style: {
...styles.form,
flexDirection: 'column'
},
children: [/*#__PURE__*/_jsxDEV("input", {
type: "text",
placeholder: "\u7528\u6237\u540D",
value: username,
onChange: e => setUsername(e.target.value),
style: styles.input,
required: true
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 76,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("input", {
type: "password",
placeholder: "\u5BC6\u7801",
value: password,
onChange: e => setPassword(e.target.value),
style: styles.input,
required: true
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 77,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("div", {
style: {
margin: '15px 0'
},
children: [/*#__PURE__*/_jsxDEV("label", {
style: {
display: 'block',
marginBottom: '10px',
fontWeight: '600'
},
children: "\uD83C\uDFAF \u51FA\u6218\u6A21\u5F0F\uFF1A"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 81,
columnNumber: 13
}, this), /*#__PURE__*/_jsxDEV("label", {
style: {
display: 'block',
marginBottom: '12px',
cursor: 'pointer',
padding: '10px',
background: mode === 'solo' ? '#e7f3ff' : 'white',
borderRadius: '8px',
border: '1px solid #2196f3'
},
children: [/*#__PURE__*/_jsxDEV("input", {
type: "radio",
name: "mode",
value: "solo",
checked: mode === 'solo',
onChange: e => setMode(e.target.value)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 83,
columnNumber: 15
}, this), ' ', "\uD83E\uDD77 ", /*#__PURE__*/_jsxDEV("strong", {
children: "\u5355\u67AA\u5339\u9A6C"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 90,
columnNumber: 23
}, this), "\uFF08\u4EBA\u7C7B\u5355\u72EC\u51FA\u6218\uFF0C\u4E0D\u5E26\u9F99\u867E\uFF09"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 82,
columnNumber: 13
}, this), /*#__PURE__*/_jsxDEV("label", {
style: {
display: 'block',
marginBottom: '12px',
cursor: 'pointer',
padding: '10px',
background: mode === 'team' ? '#e7f3ff' : 'white',
borderRadius: '8px',
border: '1px solid #2196f3'
},
children: [/*#__PURE__*/_jsxDEV("input", {
type: "radio",
name: "mode",
value: "team",
checked: mode === 'team',
onChange: e => setMode(e.target.value)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 93,
columnNumber: 15
}, this), ' ', "\uD83D\uDEE1\uFE0F ", /*#__PURE__*/_jsxDEV("strong", {
children: "\u7EC4\u961F\u56E2\u6218"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 100,
columnNumber: 24
}, this), "\uFF08\u4EBA\u7C7B + N \u53EA\u9F99\u867E\u4E00\u8D77\u51FA\u6218\uFF09"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 92,
columnNumber: 13
}, this), /*#__PURE__*/_jsxDEV("label", {
style: {
display: 'block',
marginBottom: '12px',
cursor: 'pointer',
padding: '10px',
background: mode === 'agent_only' ? '#e7f3ff' : 'white',
borderRadius: '8px',
border: '1px solid #2196f3'
},
children: [/*#__PURE__*/_jsxDEV("input", {
type: "radio",
name: "mode",
value: "agent_only",
checked: mode === 'agent_only',
onChange: e => setMode(e.target.value)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 103,
columnNumber: 15
}, this), ' ', "\u2694\uFE0F ", /*#__PURE__*/_jsxDEV("strong", {
children: "\u72EC\u5F53\u4E00\u9762"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 110,
columnNumber: 23
}, this), "\uFF08\u9F99\u867E\u5355\u72EC\u51FA\u5F81\uFF0C\u4EBA\u7C7B\u4E0D\u4E0A\u573A\uFF09"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 102,
columnNumber: 13
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 80,
columnNumber: 11
}, this), mode !== 'solo' && /*#__PURE__*/_jsxDEV("div", {
style: {
margin: '15px 0',
padding: '15px',
background: '#f9f9f9',
borderRadius: '8px'
},
children: [/*#__PURE__*/_jsxDEV("label", {
style: {
display: 'block',
marginBottom: '10px',
fontWeight: '600'
},
children: "\uD83E\uDD90 \u9009\u62E9\u9F99\u867E\u961F\u53CB\uFF1A"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 117,
columnNumber: 15
}, this), agents.length === 0 ? /*#__PURE__*/_jsxDEV("p", {
style: {
color: '#999',
fontSize: '14px'
},
children: "\u672A\u627E\u5230\u53EF\u7528\u9F99\u867E"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 119,
columnNumber: 17
}, this) : agents.map(a => /*#__PURE__*/_jsxDEV("label", {
style: {
display: 'flex',
alignItems: 'center',
marginBottom: '8px',
cursor: 'pointer'
},
children: [/*#__PURE__*/_jsxDEV("input", {
type: "checkbox",
checked: selectedAgents.includes(a.agent_id),
onChange: () => toggleAgent(a.agent_id),
style: {
marginRight: '10px'
}
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 123,
columnNumber: 21
}, this), /*#__PURE__*/_jsxDEV("span", {
style: {
fontSize: '16px',
marginRight: '8px'
},
children: a.agent_emoji || '🤖'
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 129,
columnNumber: 21
}, this), /*#__PURE__*/_jsxDEV("span", {
children: a.agent_id
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 130,
columnNumber: 21
}, this), /*#__PURE__*/_jsxDEV("span", {
style: {
color: '#999',
fontSize: '12px',
marginLeft: '8px'
},
children: ["(", a.instance_name, ")"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 131,
columnNumber: 21
}, this)]
}, a.agent_id, true, {
fileName: _jsxFileName,
lineNumber: 122,
columnNumber: 19
}, this)), selectedAgents.length > 0 && /*#__PURE__*/_jsxDEV("p", {
style: {
marginTop: '10px',
color: '#2196f3',
fontWeight: '600'
},
children: ["\u5DF2\u9009 ", selectedAgents.length, " \u53EA\u9F99\u867E\u961F\u53CB \uD83E\uDDB8"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 136,
columnNumber: 17
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 116,
columnNumber: 13
}, this), /*#__PURE__*/_jsxDEV("button", {
type: "submit",
style: styles.btn,
children: "\uD83D\uDE80 \u767B\u5F55\u51FA\u5F81"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 143,
columnNumber: 11
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 75,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 73,
columnNumber: 7
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 72,
columnNumber: 5
}, this);
}
// ============ 会议列表 ============
_s(LoginPage, "fZ8UTwO2MCkNd6X4nAqytpuamXM=", false, function () {
return [useNavigate];
});
_c = LoginPage;
function MeetingList() {
_s2();
const [meetings, setMeetings] = useState([]);
const [topic, setTopic] = useState('');
const [autoAddAgents, setAutoAddAgents] = useState(true);
const navigate = useNavigate();
const token = localStorage.getItem('token');
useEffect(() => {
if (!token) {
navigate('/login');
return;
}
fetchMeetings();
}, []);
const fetchMeetings = async () => {
try {
const res = await axios.get(`${API_BASE}/meetings/`);
setMeetings(res.data);
} catch (error) {
console.error(error);
}
};
const createMeeting = async e => {
e.preventDefault();
try {
// 获取当前登录的龙虾
const sessions = JSON.parse(localStorage.getItem('sessions') || '[]');
const agentIds = sessions.filter(s => s.session_type === 'agent').map(s => s.agent_id);
const res = await axios.post(`${API_BASE}/meetings/`, {
topic,
auto_add_virtual_agents: agentIds.length === 0,
// 只有没有龙虾时才添加虚拟的
host_agent_id: agentIds.length > 0 ? agentIds[0] : null,
// 第一只作为主持龙虾
agent_ids: agentIds // 传递所有龙虾
});
navigate(`/meeting/${res.data.id}`);
} catch (error) {
var _error$response3, _error$response3$data;
alert('创建失败:' + (((_error$response3 = error.response) === null || _error$response3 === void 0 ? void 0 : (_error$response3$data = _error$response3.data) === null || _error$response3$data === void 0 ? void 0 : _error$response3$data.detail) || error.message));
}
};
const logout = () => {
localStorage.removeItem('token');
navigate('/login');
};
return /*#__PURE__*/_jsxDEV("div", {
style: styles.container,
children: [/*#__PURE__*/_jsxDEV("div", {
style: styles.header,
children: [/*#__PURE__*/_jsxDEV("h1", {
children: "\uD83D\uDCCB \u6211\u7684\u4F1A\u8BAE\u5BA4"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 194,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("button", {
onClick: logout,
style: styles.smallBtn,
children: "\u9000\u51FA"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 195,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 193,
columnNumber: 7
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.card,
children: [/*#__PURE__*/_jsxDEV("h2", {
children: "\u521B\u5EFA\u4F1A\u8BAE"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 198,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("form", {
onSubmit: createMeeting,
style: styles.form,
children: [/*#__PURE__*/_jsxDEV("input", {
type: "text",
placeholder: "\u4F1A\u8BAE\u4E3B\u9898",
value: topic,
onChange: e => setTopic(e.target.value),
style: styles.input,
required: true
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 200,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("label", {
style: {
display: 'flex',
alignItems: 'center',
gap: '5px',
whiteSpace: 'nowrap'
},
children: [/*#__PURE__*/_jsxDEV("input", {
type: "checkbox",
checked: autoAddAgents,
onChange: e => setAutoAddAgents(e.target.checked)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 202,
columnNumber: 13
}, this), "\u6DFB\u52A0\u865A\u62DF\u5750\u5E2D"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 201,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("button", {
type: "submit",
style: styles.btn,
children: "\u521B\u5EFA"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 209,
columnNumber: 11
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 199,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("p", {
style: {
fontSize: '12px',
color: '#666',
marginTop: '10px'
},
children: "\uD83D\uDCA1 \u52FE\u9009\"\u6DFB\u52A0\u865A\u62DF\u5750\u5E2D\"\u4F1A\u81EA\u52A8\u521B\u5EFA 2 \u4E2A\u865A\u62DF\u9F99\u867E\u53C2\u4F1A\u8005\uFF0C\u65B9\u4FBF\u6D4B\u8BD5 @ \u529F\u80FD"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 211,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 197,
columnNumber: 7
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.list,
children: meetings.map(m => /*#__PURE__*/_jsxDEV("div", {
style: styles.item,
children: [/*#__PURE__*/_jsxDEV("div", {
children: [/*#__PURE__*/_jsxDEV("h3", {
children: m.topic
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 219,
columnNumber: 15
}, this), /*#__PURE__*/_jsxDEV("p", {
children: ["\u72B6\u6001\uFF1A", m.status, " | \u9080\u8BF7\u7801\uFF1A", m.invite_code]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 220,
columnNumber: 15
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 218,
columnNumber: 13
}, this), /*#__PURE__*/_jsxDEV("button", {
onClick: () => navigate(`/meeting/${m.id}`),
style: styles.smallBtn,
children: "\u8FDB\u5165"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 222,
columnNumber: 13
}, this)]
}, m.id, true, {
fileName: _jsxFileName,
lineNumber: 217,
columnNumber: 11
}, this))
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 215,
columnNumber: 7
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 192,
columnNumber: 5
}, this);
}
// ============ 会议室 ============
_s2(MeetingList, "uNteAZxXgR2pMaYhX5ze9khr1nw=", false, function () {
return [useNavigate];
});
_c2 = MeetingList;
function MeetingRoom() {
_s3();
const {
id
} = useParams();
const [messages, setMessages] = useState([]);
const [content, setContent] = useState('');
const [participants, setParticipants] = useState([]);
const [meeting, setMeeting] = useState(null);
const [hoveredSeat, setHoveredSeat] = useState(null);
const token = localStorage.getItem('token');
useEffect(() => {
if (!token) return;
fetchMeeting();
fetchParticipants();
fetchMessages();
const interval = setInterval(fetchMessages, 1000);
return () => clearInterval(interval);
}, [id]);
const fetchMeeting = async () => {
try {
const res = await axios.get(`${API_BASE}/meetings/${id}/`);
setMeeting(res.data);
} catch (error) {
console.error(error);
}
};
const fetchParticipants = async () => {
try {
const res = await axios.get(`${API_BASE}/meetings/${id}/participants/`);
setParticipants(res.data);
} catch (error) {
console.error(error);
}
};
const fetchMessages = async () => {
try {
const res = await axios.get(`${API_BASE}/meetings/${id}/messages/?last_id=0`);
setMessages(res.data.messages || []);
} catch (error) {
console.error(error);
}
};
const sendMessage = async e => {
e.preventDefault();
if (!content.trim()) return;
try {
await axios.post(`${API_BASE}/meetings/${id}/send_message/`, {
content
});
setContent('');
fetchMessages();
} catch (error) {
var _error$response4, _error$response4$data;
alert('发送失败:' + (((_error$response4 = error.response) === null || _error$response4 === void 0 ? void 0 : (_error$response4$data = _error$response4.data) === null || _error$response4$data === void 0 ? void 0 : _error$response4$data.detail) || error.message));
}
};
const mentionAgent = async (targetAgentId, agentName) => {
const target = targetAgentId || prompt('@哪个 Agent输入 agent_id:');
if (!target || !content.trim()) return;
const name = agentName || target;
try {
await axios.post(`${API_BASE}/meetings/${id}/mention_agent/`, {
target_agent_id: target,
content,
sender_name: localStorage.getItem('user') ? JSON.parse(localStorage.getItem('user')).username : 'User'
});
setContent('');
fetchMessages();
alert(`✅ 已 @${name}`);
} catch (error) {
var _error$response5, _error$response5$data;
alert('发送失败:' + (((_error$response5 = error.response) === null || _error$response5 === void 0 ? void 0 : (_error$response5$data = _error$response5.data) === null || _error$response5$data === void 0 ? void 0 : _error$response5$data.error) || error.message));
}
};
const startMeeting = async () => {
try {
await axios.post(`${API_BASE}/meetings/${id}/start/`);
fetchMeeting();
alert('✅ 会议已开始');
} catch (error) {
var _error$response6, _error$response6$data;
alert('开始失败:' + (((_error$response6 = error.response) === null || _error$response6 === void 0 ? void 0 : (_error$response6$data = _error$response6.data) === null || _error$response6$data === void 0 ? void 0 : _error$response6$data.error) || error.message));
}
};
const endMeeting = async () => {
if (!confirm('确定结束会议?')) return;
try {
await axios.post(`${API_BASE}/meetings/${id}/end/`);
fetchMeeting();
alert('✅ 会议已结束');
} catch (error) {
var _error$response7, _error$response7$data;
alert('结束失败:' + (((_error$response7 = error.response) === null || _error$response7 === void 0 ? void 0 : (_error$response7$data = _error$response7.data) === null || _error$response7$data === void 0 ? void 0 : _error$response7$data.error) || error.message));
}
};
const generateMinutes = async () => {
try {
const res = await axios.get(`${API_BASE}/meetings/${id}/minutes/?output=markdown`);
const blob = new Blob([res.data.markdown], {
type: 'text/markdown'
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `meeting-${id.slice(0, 8)}.md`;
a.click();
URL.revokeObjectURL(url);
alert('✅ 纪要已导出');
} catch (error) {
alert('导出失败:' + error.message);
}
};
return /*#__PURE__*/_jsxDEV("div", {
style: styles.container,
children: [/*#__PURE__*/_jsxDEV("div", {
style: styles.header,
children: [/*#__PURE__*/_jsxDEV(Link, {
to: "/meetings",
style: styles.link,
children: "\u2190 \u8FD4\u56DE"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 339,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("h1", {
children: (meeting === null || meeting === void 0 ? void 0 : meeting.topic) || '会议室'
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 340,
columnNumber: 9
}, this), meeting && /*#__PURE__*/_jsxDEV("span", {
style: styles.badge,
children: meeting.status
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 341,
columnNumber: 21
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 338,
columnNumber: 7
}, this), meeting && /*#__PURE__*/_jsxDEV("div", {
style: styles.infoCard,
children: [/*#__PURE__*/_jsxDEV("p", {
children: [/*#__PURE__*/_jsxDEV("strong", {
children: "ID:"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 346,
columnNumber: 14
}, this), " ", meeting.id]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 346,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("p", {
children: [/*#__PURE__*/_jsxDEV("strong", {
children: "\u9080\u8BF7\u7801:"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 347,
columnNumber: 14
}, this), " ", meeting.invite_code]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 347,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.btnGroup,
children: [/*#__PURE__*/_jsxDEV("button", {
onClick: startMeeting,
style: styles.btnGreen,
children: "\u25B6\uFE0F \u5F00\u59CB"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 349,
columnNumber: 13
}, this), /*#__PURE__*/_jsxDEV("button", {
onClick: endMeeting,
style: styles.btnRed,
children: "\u23F9\uFE0F \u7ED3\u675F"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 350,
columnNumber: 13
}, this), /*#__PURE__*/_jsxDEV("button", {
onClick: generateMinutes,
style: styles.btnBlue,
children: "\uD83D\uDCCB \u7EAA\u8981"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 351,
columnNumber: 13
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 348,
columnNumber: 11
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 345,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.card,
children: [/*#__PURE__*/_jsxDEV("h2", {
children: ["\uD83E\uDE91 \u5EA7\u4F4D\u56FE ", /*#__PURE__*/_jsxDEV("span", {
style: styles.badge,
children: participants.length
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 358,
columnNumber: 20
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 358,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.seats,
children: participants.map(p => /*#__PURE__*/_jsxDEV("div", {
style: {
...styles.seat,
...(hoveredSeat === p.id ? styles.seatHover : {})
},
onClick: () => {
if (p.agent_id) {
var _document$querySelect;
setContent(`@${p.nickname} `);
(_document$querySelect = document.querySelector('input[placeholder="输入消息..."]')) === null || _document$querySelect === void 0 ? void 0 : _document$querySelect.focus();
}
},
onMouseEnter: () => setHoveredSeat(p.id),
onMouseLeave: () => setHoveredSeat(null),
title: p.agent_id ? '点击 @ 此人' : '',
children: [/*#__PURE__*/_jsxDEV("div", {
style: styles.seatEmoji,
children: p.agent_emoji || '👤'
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 374,
columnNumber: 15
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.seatName,
children: p.nickname
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 375,
columnNumber: 15
}, this), p.is_host && /*#__PURE__*/_jsxDEV("div", {
style: styles.hostBadge,
children: "\uD83D\uDC51"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 376,
columnNumber: 29
}, this)]
}, p.id, true, {
fileName: _jsxFileName,
lineNumber: 361,
columnNumber: 13
}, this))
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 359,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 357,
columnNumber: 7
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.card,
children: [/*#__PURE__*/_jsxDEV("h2", {
children: ["\uD83D\uDCAC \u804A\u5929 ", /*#__PURE__*/_jsxDEV("span", {
style: styles.badge,
children: messages.length
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 384,
columnNumber: 19
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 384,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.messages,
children: messages.map(msg => /*#__PURE__*/_jsxDEV("div", {
style: styles.msg,
children: [/*#__PURE__*/_jsxDEV("div", {
style: styles.msgHeader,
children: [/*#__PURE__*/_jsxDEV("strong", {
children: [msg.sender_emoji, " ", msg.sender_name]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 389,
columnNumber: 17
}, this), /*#__PURE__*/_jsxDEV("span", {
style: styles.msgTime,
children: new Date(msg.created_at).toLocaleTimeString()
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 390,
columnNumber: 17
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 388,
columnNumber: 15
}, this), /*#__PURE__*/_jsxDEV("p", {
style: styles.msgContent,
children: msg.content
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 392,
columnNumber: 15
}, this), msg.in_reply_to && /*#__PURE__*/_jsxDEV("div", {
style: styles.replyTag,
children: ["\u21A9\uFE0F \u56DE\u590D #", msg.in_reply_to]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 393,
columnNumber: 35
}, this)]
}, msg.id, true, {
fileName: _jsxFileName,
lineNumber: 387,
columnNumber: 13
}, this))
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 385,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("form", {
onSubmit: sendMessage,
style: styles.form,
children: [/*#__PURE__*/_jsxDEV("input", {
type: "text",
placeholder: "\u8F93\u5165\u6D88\u606F...",
value: content,
onChange: e => setContent(e.target.value),
style: styles.input
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 398,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("button", {
type: "submit",
style: styles.btn,
children: "\u53D1\u9001"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 399,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("button", {
type: "button",
onClick: mentionAgent,
style: styles.btnPink,
children: "\uD83D\uDCCD @Agent"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 400,
columnNumber: 11
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 397,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 383,
columnNumber: 7
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 337,
columnNumber: 5
}, this);
}
// ============ App ============
_s3(MeetingRoom, "fh+UC+M8I83D9S4VTUsmF3cRwwg=", false, function () {
return [useParams];
});
_c3 = MeetingRoom;
function App() {
return /*#__PURE__*/_jsxDEV(Router, {
children: /*#__PURE__*/_jsxDEV(Routes, {
children: [/*#__PURE__*/_jsxDEV(Route, {
path: "/login",
element: /*#__PURE__*/_jsxDEV(LoginPage, {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 412,
columnNumber: 39
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 412,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV(Route, {
path: "/meetings",
element: /*#__PURE__*/_jsxDEV(MeetingList, {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 413,
columnNumber: 42
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 413,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV(Route, {
path: "/meeting/:id",
element: /*#__PURE__*/_jsxDEV(MeetingRoom, {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 414,
columnNumber: 45
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 414,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV(Route, {
path: "/",
element: /*#__PURE__*/_jsxDEV(LoginPage, {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 415,
columnNumber: 34
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 415,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 411,
columnNumber: 7
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 410,
columnNumber: 5
}, this);
}
// ============ 样式 ============
_c4 = App;
const styles = {
center: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: '100vh',
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'
},
container: {
maxWidth: '900px',
margin: '0 auto',
padding: '20px',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
},
header: {
display: 'flex',
alignItems: 'center',
gap: '15px',
marginBottom: '20px'
},
card: {
background: 'white',
borderRadius: '12px',
padding: '20px',
marginBottom: '20px',
boxShadow: '0 4px 6px rgba(0,0,0,0.1)'
},
infoCard: {
background: '#e7f3ff',
border: '1px solid #2196f3',
borderRadius: '12px',
padding: '15px',
marginBottom: '20px'
},
title: {
margin: '0 0 20px',
color: '#1a365d',
textAlign: 'center'
},
form: {
display: 'flex',
gap: '10px'
},
input: {
flex: 1,
padding: '12px',
border: '2px solid #e2e8f0',
borderRadius: '8px',
fontSize: '14px'
},
btn: {
padding: '12px 20px',
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
fontWeight: '600'
},
btnGreen: {
padding: '8px 16px',
background: 'linear-gradient(135deg, #11998e 0%, #38ef7d 100%)',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
marginRight: '8px'
},
btnRed: {
padding: '8px 16px',
background: 'linear-gradient(135deg, #eb3349 0%, #f45c43 100%)',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
marginRight: '8px'
},
btnBlue: {
padding: '8px 16px',
background: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer'
},
btnPink: {
padding: '8px 16px',
background: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer'
},
smallBtn: {
padding: '8px 16px',
background: '#edf2f7',
border: 'none',
borderRadius: '6px',
cursor: 'pointer'
},
list: {
display: 'flex',
flexDirection: 'column',
gap: '15px'
},
item: {
background: 'white',
borderRadius: '12px',
padding: '20px',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
boxShadow: '0 4px 6px rgba(0,0,0,0.1)'
},
link: {
color: '#4299e1',
textDecoration: 'none',
fontSize: '16px'
},
badge: {
background: '#667eea',
color: 'white',
padding: '4px 10px',
borderRadius: '20px',
fontSize: '12px',
fontWeight: '600'
},
btnGroup: {
display: 'flex',
marginTop: '10px'
},
seats: {
display: 'flex',
flexWrap: 'wrap',
gap: '15px',
justifyContent: 'center'
},
seat: {
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
padding: '15px',
borderRadius: '50%',
width: '90px',
height: '90px',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
textAlign: 'center',
cursor: 'pointer',
transition: 'transform 0.2s',
':hover': {
transform: 'scale(1.1)'
}
},
seatHover: {
transform: 'scale(1.05)'
},
seatEmoji: {
fontSize: '28px',
marginBottom: '5px'
},
seatName: {
fontSize: '12px',
fontWeight: '600'
},
hostBadge: {
fontSize: '10px',
opacity: '0.8'
},
messages: {
maxHeight: '400px',
overflowY: 'auto',
marginBottom: '15px'
},
msg: {
padding: '12px',
background: '#f7fafc',
borderRadius: '8px',
marginBottom: '10px'
},
msgHeader: {
display: 'flex',
justifyContent: 'space-between',
marginBottom: '5px'
},
msgContent: {
margin: '5px 0',
color: '#4a5568'
},
msgTime: {
fontSize: '12px',
color: '#a0aec0'
},
replyTag: {
fontSize: '11px',
color: '#a0aec0',
marginTop: '5px'
}
};
export default App;
var _c, _c2, _c3, _c4;
$RefreshReg$(_c, "LoginPage");
$RefreshReg$(_c2, "MeetingList");
$RefreshReg$(_c3, "MeetingRoom");
$RefreshReg$(_c4, "App");
const $ReactRefreshModuleId$ = __webpack_require__.$Refresh$.moduleId;
const $ReactRefreshCurrentExports$ = __react_refresh_utils__.getModuleExports(
$ReactRefreshModuleId$
);
function $ReactRefreshModuleRuntime$(exports) {
if (module.hot) {
let errorOverlay;
if (typeof __react_refresh_error_overlay__ !== 'undefined') {
errorOverlay = __react_refresh_error_overlay__;
}
let testMode;
if (typeof __react_refresh_test__ !== 'undefined') {
testMode = __react_refresh_test__;
}
return __react_refresh_utils__.executeRuntime(
exports,
$ReactRefreshModuleId$,
module.hot,
errorOverlay,
testMode
);
}
}
if (typeof Promise !== 'undefined' && $ReactRefreshCurrentExports$ instanceof Promise) {
$ReactRefreshCurrentExports$.then($ReactRefreshModuleRuntime$);
} else {
$ReactRefreshModuleRuntime$($ReactRefreshCurrentExports$);
}<1E>webpack://./node_modules/babel-loader/lib/index.js??ruleSet[1].rules[1].oneOf[3]!./node_modules/source-map-loader/dist/cjs.js!./src/App.js<1F><>{"version":3,"sources":["webpack://./src/App.js"],"names":["React","useState","useEffect","BrowserRouter","Router","Routes","Route","Link","useNavigate","useParams","axios","jsxDEV","_jsxDEV","API_BASE","interceptors","request","use","config","token","localStorage","getItem","headers","Authorization","LoginPage","_s","username","setUsername","password","setPassword","mode","setMode","agents","setAgents","selectedAgents","setSelectedAgents","navigate","scanAgents","res","get","data","error","console","handleLogin","e","preventDefault","payload","length","agent_ids","post","setItem","JSON","stringify","user","sessions","_error$response","_error$response$data","_error$response2","_error$response2$data","alert","response","detail","message","toggleAgent","agentId","prev","includes","filter","id","style","styles","center","children","card","title","fileName","_jsxFileName","lineNumber","columnNumber","onSubmit","form","flexDirection","type","placeholder","value","onChange","target","input","required","margin","display","marginBottom","fontWeight","cursor","padding","background","borderRadius","border","name","checked","color","fontSize","map","a","alignItems","agent_id","marginRight","agent_emoji","marginLeft","instance_name","marginTop","btn","_c","MeetingList","_s2","meetings","setMeetings","topic","setTopic","autoAddAgents","setAutoAddAgents","fetchMeetings","createMeeting","parse","agentIds","s","session_type","auto_add_virtual_agents","host_agent_id","_error$response3","_error$response3$data","logout","removeItem","container","header","onClick","smallBtn","gap","whiteSpace","list","m","item","status","invite_code","_c2","MeetingRoom","_s3","messages","setMessages","content","setContent","participants","setParticipants","meeting","setMeeting","hoveredSeat","setHoveredSeat","fetchMeeting","fetchParticipants","fetchMessages","interval","setInterval","clearInterval","sendMessage","trim","_error$response4","_error$response4$data","mentionAgent","targetAgentId","agentName","prompt","target_agent_id","sender_name","_error$response5","_error$response5$data","startMeeting","_error$response6","_error$response6$data","endMeeting","confirm","_error$response7","_error$response7$data","generateMinutes","blob","Blob","markdown","url","URL","createObjectURL","document","createElement","href","download","slice","click","revokeObjectURL","to","link","badge","infoCard","btnGroup","btnGreen","btnRed","btnBlue","seats","p","seat","seatHover","_document$querySelect","nickname","querySelector","focus","onMouseEnter","onMouseLeave","seatEmoji","seatName","is_host","hostBadge","msg","msgHeader","sender_emoji","msgTime","Date","created_at","toLocaleTimeString","msgContent","in_reply_to","replyTag","btnPink","_c3","App","path","element","_c4","justifyContent","minHeight","maxWidth","fontFamily","boxShadow","textAlign","flex","textDecoration","flexWrap","width","height","transition","transform","opacity","maxHeight","overflowY","$RefreshReg$"],"mappings":";;;;;;AAAA,OAAOA,KAAK,IAAIC,QAAQ,EAAEC,SAAS,QAAQ,OAAO;AAClD,SAASC,aAAa,IAAIC,MAAM,EAAEC,MAAM,EAAEC,KAAK,EAAEC,IAAI,EAAEC,WAAW,EAAEC,SAAS,QAAQ,kBAAkB;AACvG,OAAOC,KAAK,MAAM,OAAO;AAAC,SAAAC,MAAA,IAAAC,OAAA;AAE1B,MAAMC,QAAQ,GAAG,8BAA8B;AAE/CH,KAAK,CAACI,YAAY,CAACC,OAAO,CAACC,GAAG,CAACC,MAAM,IAAI;EACvC,MAAMC,KAAK,GAAGC,YAAY,CAACC,OAAO,CAAC,OAAO,CAAC;EAC3C,IAAIF,KAAK,EAAED,MAAM,CAACI,OAAO,CAACC,aAAa,GAAG,UAAUJ,KAAK,EAAE;EAC3D,OAAOD,MAAM;AACf,CAAC,CAAC;;AAEF;AACA,SAASM,SAASA,CAAA,EAAG;EAAAC,EAAA;EACnB,MAAM,CAACC,QAAQ,EAAEC,WAAW,CAAC,GAAGzB,QAAQ,CAAC,MAAM,CAAC;EAChD,MAAM,CAAC0B,QAAQ,EAAEC,WAAW,CAAC,GAAG3B,QAAQ,CAAC,SAAS,CAAC;EACnD,MAAM,CAAC4B,IAAI,EAAEC,OAAO,CAAC,GAAG7B,QAAQ,CAAC,MAAM,CAAC;EACxC,MAAM,CAAC8B,MAAM,EAAEC,SAAS,CAAC,GAAG/B,QAAQ,CAAC,EAAE,CAAC;EACxC,MAAM,CAACgC,cAAc,EAAEC,iBAAiB,CAAC,GAAGjC,QAAQ,CAAC,EAAE,CAAC;EACxD,MAAMkC,QAAQ,GAAG3B,WAAW,CAAC,CAAC;;EAE9B;EACAN,SAAS,CAAC,MAAM;IACd,IAAIuB,QAAQ,EAAE;MACZW,UAAU,CAAC,CAAC;IACd;EACF,CAAC,EAAE,CAACX,QA
88<00>8<00>8H:N:<00>:<00>:V;\;<00>;<00>;9=?=> ><00>?<00>?^A_dA<00>C<00>CDDMDSD<00>D<00>DKEQE<00>F<00>F<00>I<00>IJ JGJNJuJ|J<00>J<00>J<00>J<00>JKKTK\KtLxLCM_GM N$N8O<ORR<00>T<00>T<00>V<00>V<00>X<00>X<00>Z<00>Z[[[[a[c[f[P\V\P]V]<00>^<00>^<00>^<00>^ _&_m`_s`<00>`<00>`bbSbYbmcsc<00>d<00>d<00>f<00>f<00>f<00>f'g-g<00>h<00>h<00>h<00>h<00>k<00>k<00>l<00>l<00>m<00>m<00>o<00>oApGp<00>p_<>p<00>q<00>qUr[r<00>r<00>r<00>rs<00>st<00>u<00>u<00>v<00>v<00>x<00>x9y?y<00>z<00>z<00>{<00>{~<00>~<00>~<00>~<00>~<00>~<00>~<00>~<00>~]&,.2ms<00><><00><><00><><00><>Ѐր<00><><00><><00><><00><>8<>><3E>S<>Y<>[<5B>_<><00><><00><>ԕ<00><>ԕ<00><><00><> м<>@U<><55>
<EFBFBD><1E>)<29>@<40>K<>b<>m<><00><><00><><00><><00><>d<>m<><00><><00><>ؗ<00><>w<><00><>ɘҘ<00>__webpack_require__<15><18>/*! ./node_modules/react-refresh/runtime.js */ "./node_modules/react-refresh/runtime.js"<18>__webpack_require__.$Refresh$.signature<15><15><18><18><18><18><18>axios__WEBPACK_IMPORTED_MODULE_3__["default"]<18>(0,react__WEBPACK_IMPORTED_MODULE_0__.useState)<15><15><15><15><18>(0,react_router_dom__WEBPACK_IMPORTED_MODULE_2__.useNavigate)<18>(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)<15><15><18>(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)<15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><18>react_router_dom__WEBPACK_IMPORTED_MODULE_2__.useNavigate<15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><18>(0,react_router_dom__WEBPACK_IMPORTED_MODULE_2__.useParams)<15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><18>react_router_dom__WEBPACK_IMPORTED_MODULE_1__.Link<15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><15><18>react_router_dom__WEBPACK_IMPORTED_MODULE_2__.useParams<15><18>react_router_dom__WEBPACK_IMPORTED_MODULE_1__.BrowserRouter<15><18>react_router_dom__WEBPACK_IMPORTED_MODULE_2__.Routes<15><18>react_router_dom__WEBPACK_IMPORTED_MODULE_2__.Route<15><15><15><15><15><15><15><15><15><15><18>/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (<18><18>);<18>__webpack_require__.$Refresh$.register<15><15><15><15><18>__react_refresh_utils__<18>true<15><18>false<15><18>module.hot<05>buffer<65>source<63>size<7A>maps<15><12>__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-router-dom */ "./node_modules/react-router-dom/dist/index.js");
/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-router-dom */ "./node_modules/react-router/dist/index.js");
/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! axios */ "./node_modules/axios/lib/axios.js");
/* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js");
/* provided dependency */ var __react_refresh_utils__ = __webpack_require__(/*! ./node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js */ "./node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js");
__webpack_require__.$Refresh$.runtime = __webpack_require__(/*! ./node_modules/react-refresh/runtime.js */ "./node_modules/react-refresh/runtime.js");
var _jsxFileName = "/home/node/.openclaw/workspace/flying-hero/projects/meeting-room/frontend/src/App.js",
_s = __webpack_require__.$Refresh$.signature(),
_s2 = __webpack_require__.$Refresh$.signature(),
_s3 = __webpack_require__.$Refresh$.signature();
const API_BASE = 'http://localhost:8000/api/v1';
axios__WEBPACK_IMPORTED_MODULE_3__["default"].interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
});
// ============ 登录页面 ============
function LoginPage() {
_s();
const [username, setUsername] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('test');
const [password, setPassword] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('test123');
const [mode, setMode] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('solo');
const [agents, setAgents] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);
const [selectedAgents, setSelectedAgents] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);
const navigate = (0,react_router_dom__WEBPACK_IMPORTED_MODULE_2__.useNavigate)();
// 扫描本机龙虾
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
if (username) {
scanAgents();
}
}, [username]);
const scanAgents = async () => {
try {
// 传递 username 参数,获取绑定的龙虾信息
const res = await axios__WEBPACK_IMPORTED_MODULE_3__["default"].get(`${API_BASE}/user/scan-local-agents/?username=${username}`);
setAgents(res.data.agents || []);
} catch (error) {
console.error('扫描龙虾失败:', error);
}
};
const handleLogin = async e => {
e.preventDefault();
try {
const payload = {
username,
password,
mode
};
if (mode !== 'solo' && selectedAgents.length > 0) {
payload.agent_ids = selectedAgents;
}
const res = await axios__WEBPACK_IMPORTED_MODULE_3__["default"].post(`${API_BASE}/auth/login/`, payload);
localStorage.setItem('token', res.data.token);
localStorage.setItem('user', JSON.stringify(res.data.user));
localStorage.setItem('sessions', JSON.stringify(res.data.sessions));
localStorage.setItem('mode', res.data.mode);
navigate('/meetings');
} catch (error) {
var _error$response, _error$response$data, _error$response2, _error$response2$data;
alert('登录失败:' + (((_error$response = error.response) === null || _error$response === void 0 ? void 0 : (_error$response$data = _error$response.data) === null || _error$response$data === void 0 ? void 0 : _error$response$data.detail) || ((_error$response2 = error.response) === null || _error$response2 === void 0 ? void 0 : (_error$response2$data = _error$response2.data) === null || _error$response2$data === void 0 ? void 0 : _error$response2$data.error) || error.message));
}
};
const toggleAgent = agentId => {
setSelectedAgents(prev => prev.includes(agentId) ? prev.filter(id => id !== agentId) : [...prev, agentId]);
};
return /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.center,
children: /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.card,
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("h1", {
style: styles.title,
children: "\uD83C\uDFDB\uFE0F \u9F99\u867E\u8BAE\u4E8B\u5385"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 74,
columnNumber: 9
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("form", {
onSubmit: handleLogin,
style: {
...styles.form,
flexDirection: 'column'
},
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("input", {
type: "text",
placeholder: "\u7528\u6237\u540D",
value: username,
onChange: e => setUsername(e.target.value),
style: styles.input,
required: true
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 76,
columnNumber: 11
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("input", {
type: "password",
placeholder: "\u5BC6\u7801",
value: password,
onChange: e => setPassword(e.target.value),
style: styles.input,
required: true
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 77,
columnNumber: 11
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: {
margin: '15px 0'
},
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", {
style: {
display: 'block',
marginBottom: '10px',
fontWeight: '600'
},
children: "\uD83C\uDFAF \u51FA\u6218\u6A21\u5F0F\uFF1A"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 81,
columnNumber: 13
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", {
style: {
display: 'block',
marginBottom: '12px',
cursor: 'pointer',
padding: '10px',
background: mode === 'solo' ? '#e7f3ff' : 'white',
borderRadius: '8px',
border: '1px solid #2196f3'
},
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("input", {
type: "radio",
name: "mode",
value: "solo",
checked: mode === 'solo',
onChange: e => setMode(e.target.value)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 83,
columnNumber: 15
}, this), ' ', "\uD83E\uDD77 ", /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("strong", {
children: "\u5355\u67AA\u5339\u9A6C"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 90,
columnNumber: 23
}, this), "\uFF08\u4EBA\u7C7B\u5355\u72EC\u51FA\u6218\uFF0C\u4E0D\u5E26\u9F99\u867E\uFF09"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 82,
columnNumber: 13
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", {
style: {
display: 'block',
marginBottom: '12px',
cursor: 'pointer',
padding: '10px',
background: mode === 'team' ? '#e7f3ff' : 'white',
borderRadius: '8px',
border: '1px solid #2196f3'
},
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("input", {
type: "radio",
name: "mode",
value: "team",
checked: mode === 'team',
onChange: e => setMode(e.target.value)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 93,
columnNumber: 15
}, this), ' ', "\uD83D\uDEE1\uFE0F ", /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("strong", {
children: "\u7EC4\u961F\u56E2\u6218"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 100,
columnNumber: 24
}, this), "\uFF08\u4EBA\u7C7B + N \u53EA\u9F99\u867E\u4E00\u8D77\u51FA\u6218\uFF09"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 92,
columnNumber: 13
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", {
style: {
display: 'block',
marginBottom: '12px',
cursor: 'pointer',
padding: '10px',
background: mode === 'agent_only' ? '#e7f3ff' : 'white',
borderRadius: '8px',
border: '1px solid #2196f3'
},
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("input", {
type: "radio",
name: "mode",
value: "agent_only",
checked: mode === 'agent_only',
onChange: e => setMode(e.target.value)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 103,
columnNumber: 15
}, this), ' ', "\u2694\uFE0F ", /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("strong", {
children: "\u72EC\u5F53\u4E00\u9762"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 110,
columnNumber: 23
}, this), "\uFF08\u9F99\u867E\u5355\u72EC\u51FA\u5F81\uFF0C\u4EBA\u7C7B\u4E0D\u4E0A\u573A\uFF09"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 102,
columnNumber: 13
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 80,
columnNumber: 11
}, this), mode !== 'solo' && /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: {
margin: '15px 0',
padding: '15px',
background: '#f9f9f9',
borderRadius: '8px'
},
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", {
style: {
display: 'block',
marginBottom: '10px',
fontWeight: '600'
},
children: "\uD83E\uDD90 \u9009\u62E9\u9F99\u867E\u961F\u53CB\uFF1A"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 117,
columnNumber: 15
}, this), agents.length === 0 ? /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", {
style: {
color: '#999',
fontSize: '14px'
},
children: "\u672A\u627E\u5230\u53EF\u7528\u9F99\u867E"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 119,
columnNumber: 17
}, this) : agents.map(a => /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", {
style: {
display: 'flex',
alignItems: 'center',
marginBottom: '8px',
cursor: 'pointer'
},
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("input", {
type: "checkbox",
checked: selectedAgents.includes(a.agent_id),
onChange: () => toggleAgent(a.agent_id),
style: {
marginRight: '10px'
}
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 123,
columnNumber: 21
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", {
style: {
fontSize: '16px',
marginRight: '8px'
},
children: a.agent_emoji || '🤖'
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 129,
columnNumber: 21
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", {
children: a.agent_id
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 130,
columnNumber: 21
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", {
style: {
color: '#999',
fontSize: '12px',
marginLeft: '8px'
},
children: ["(", a.instance_name, ")"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 131,
columnNumber: 21
}, this)]
}, a.agent_id, true, {
fileName: _jsxFileName,
lineNumber: 122,
columnNumber: 19
}, this)), selectedAgents.length > 0 && /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", {
style: {
marginTop: '10px',
color: '#2196f3',
fontWeight: '600'
},
children: ["\u5DF2\u9009 ", selectedAgents.length, " \u53EA\u9F99\u867E\u961F\u53CB \uD83E\uDDB8"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 136,
columnNumber: 17
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 116,
columnNumber: 13
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", {
type: "submit",
style: styles.btn,
children: "\uD83D\uDE80 \u767B\u5F55\u51FA\u5F81"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 143,
columnNumber: 11
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 75,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 73,
columnNumber: 7
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 72,
columnNumber: 5
}, this);
}
// ============ 会议列表 ============
_s(LoginPage, "fZ8UTwO2MCkNd6X4nAqytpuamXM=", false, function () {
return [react_router_dom__WEBPACK_IMPORTED_MODULE_2__.useNavigate];
});
_c = LoginPage;
function MeetingList() {
_s2();
const [meetings, setMeetings] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);
const [topic, setTopic] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
const [autoAddAgents, setAutoAddAgents] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(true);
const navigate = (0,react_router_dom__WEBPACK_IMPORTED_MODULE_2__.useNavigate)();
const token = localStorage.getItem('token');
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
if (!token) {
navigate('/login');
return;
}
fetchMeetings();
}, []);
const fetchMeetings = async () => {
try {
const res = await axios__WEBPACK_IMPORTED_MODULE_3__["default"].get(`${API_BASE}/meetings/`);
setMeetings(res.data);
} catch (error) {
console.error(error);
}
};
const createMeeting = async e => {
e.preventDefault();
try {
// 获取当前登录的龙虾
const sessions = JSON.parse(localStorage.getItem('sessions') || '[]');
const agentIds = sessions.filter(s => s.session_type === 'agent').map(s => s.agent_id);
const res = await axios__WEBPACK_IMPORTED_MODULE_3__["default"].post(`${API_BASE}/meetings/`, {
topic,
auto_add_virtual_agents: agentIds.length === 0,
// 只有没有龙虾时才添加虚拟的
host_agent_id: agentIds.length > 0 ? agentIds[0] : null,
// 第一只作为主持龙虾
agent_ids: agentIds // 传递所有龙虾
});
navigate(`/meeting/${res.data.id}`);
} catch (error) {
var _error$response3, _error$response3$data;
alert('创建失败:' + (((_error$response3 = error.response) === null || _error$response3 === void 0 ? void 0 : (_error$response3$data = _error$response3.data) === null || _error$response3$data === void 0 ? void 0 : _error$response3$data.detail) || error.message));
}
};
const logout = () => {
localStorage.removeItem('token');
navigate('/login');
};
return /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.container,
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.header,
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("h1", {
children: "\uD83D\uDCCB \u6211\u7684\u4F1A\u8BAE\u5BA4"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 194,
columnNumber: 9
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", {
onClick: logout,
style: styles.smallBtn,
children: "\u9000\u51FA"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 195,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 193,
columnNumber: 7
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.card,
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("h2", {
children: "\u521B\u5EFA\u4F1A\u8BAE"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 198,
columnNumber: 9
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("form", {
onSubmit: createMeeting,
style: styles.form,
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("input", {
type: "text",
placeholder: "\u4F1A\u8BAE\u4E3B\u9898",
value: topic,
onChange: e => setTopic(e.target.value),
style: styles.input,
required: true
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 200,
columnNumber: 11
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", {
style: {
display: 'flex',
alignItems: 'center',
gap: '5px',
whiteSpace: 'nowrap'
},
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("input", {
type: "checkbox",
checked: autoAddAgents,
onChange: e => setAutoAddAgents(e.target.checked)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 202,
columnNumber: 13
}, this), "\u6DFB\u52A0\u865A\u62DF\u5750\u5E2D"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 201,
columnNumber: 11
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", {
type: "submit",
style: styles.btn,
children: "\u521B\u5EFA"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 209,
columnNumber: 11
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 199,
columnNumber: 9
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", {
style: {
fontSize: '12px',
color: '#666',
marginTop: '10px'
},
children: "\uD83D\uDCA1 \u52FE\u9009\"\u6DFB\u52A0\u865A\u62DF\u5750\u5E2D\"\u4F1A\u81EA\u52A8\u521B\u5EFA 2 \u4E2A\u865A\u62DF\u9F99\u867E\u53C2\u4F1A\u8005\uFF0C\u65B9\u4FBF\u6D4B\u8BD5 @ \u529F\u80FD"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 211,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 197,
columnNumber: 7
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.list,
children: meetings.map(m => /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.item,
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("h3", {
children: m.topic
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 219,
columnNumber: 15
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", {
children: ["\u72B6\u6001\uFF1A", m.status, " | \u9080\u8BF7\u7801\uFF1A", m.invite_code]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 220,
columnNumber: 15
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 218,
columnNumber: 13
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", {
onClick: () => navigate(`/meeting/${m.id}`),
style: styles.smallBtn,
children: "\u8FDB\u5165"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 222,
columnNumber: 13
}, this)]
}, m.id, true, {
fileName: _jsxFileName,
lineNumber: 217,
columnNumber: 11
}, this))
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 215,
columnNumber: 7
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 192,
columnNumber: 5
}, this);
}
// ============ 会议室 ============
_s2(MeetingList, "uNteAZxXgR2pMaYhX5ze9khr1nw=", false, function () {
return [react_router_dom__WEBPACK_IMPORTED_MODULE_2__.useNavigate];
});
_c2 = MeetingList;
function MeetingRoom() {
_s3();
const {
id
} = (0,react_router_dom__WEBPACK_IMPORTED_MODULE_2__.useParams)();
const [messages, setMessages] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);
const [content, setContent] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
const [participants, setParticipants] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);
const [meeting, setMeeting] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
const [hoveredSeat, setHoveredSeat] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
const token = localStorage.getItem('token');
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
if (!token) return;
fetchMeeting();
fetchParticipants();
fetchMessages();
const interval = setInterval(fetchMessages, 1000);
return () => clearInterval(interval);
}, [id]);
const fetchMeeting = async () => {
try {
const res = await axios__WEBPACK_IMPORTED_MODULE_3__["default"].get(`${API_BASE}/meetings/${id}/`);
setMeeting(res.data);
} catch (error) {
console.error(error);
}
};
const fetchParticipants = async () => {
try {
const res = await axios__WEBPACK_IMPORTED_MODULE_3__["default"].get(`${API_BASE}/meetings/${id}/participants/`);
setParticipants(res.data);
} catch (error) {
console.error(error);
}
};
const fetchMessages = async () => {
try {
const res = await axios__WEBPACK_IMPORTED_MODULE_3__["default"].get(`${API_BASE}/meetings/${id}/messages/?last_id=0`);
setMessages(res.data.messages || []);
} catch (error) {
console.error(error);
}
};
const sendMessage = async e => {
e.preventDefault();
if (!content.trim()) return;
try {
await axios__WEBPACK_IMPORTED_MODULE_3__["default"].post(`${API_BASE}/meetings/${id}/send_message/`, {
content
});
setContent('');
fetchMessages();
} catch (error) {
var _error$response4, _error$response4$data;
alert('发送失败:' + (((_error$response4 = error.response) === null || _error$response4 === void 0 ? void 0 : (_error$response4$data = _error$response4.data) === null || _error$response4$data === void 0 ? void 0 : _error$response4$data.detail) || error.message));
}
};
const mentionAgent = async (targetAgentId, agentName) => {
const target = targetAgentId || prompt('@哪个 Agent输入 agent_id:');
if (!target || !content.trim()) return;
const name = agentName || target;
try {
await axios__WEBPACK_IMPORTED_MODULE_3__["default"].post(`${API_BASE}/meetings/${id}/mention_agent/`, {
target_agent_id: target,
content,
sender_name: localStorage.getItem('user') ? JSON.parse(localStorage.getItem('user')).username : 'User'
});
setContent('');
fetchMessages();
alert(`✅ 已 @${name}`);
} catch (error) {
var _error$response5, _error$response5$data;
alert('发送失败:' + (((_error$response5 = error.response) === null || _error$response5 === void 0 ? void 0 : (_error$response5$data = _error$response5.data) === null || _error$response5$data === void 0 ? void 0 : _error$response5$data.error) || error.message));
}
};
const startMeeting = async () => {
try {
await axios__WEBPACK_IMPORTED_MODULE_3__["default"].post(`${API_BASE}/meetings/${id}/start/`);
fetchMeeting();
alert('✅ 会议已开始');
} catch (error) {
var _error$response6, _error$response6$data;
alert('开始失败:' + (((_error$response6 = error.response) === null || _error$response6 === void 0 ? void 0 : (_error$response6$data = _error$response6.data) === null || _error$response6$data === void 0 ? void 0 : _error$response6$data.error) || error.message));
}
};
const endMeeting = async () => {
if (!confirm('确定结束会议?')) return;
try {
await axios__WEBPACK_IMPORTED_MODULE_3__["default"].post(`${API_BASE}/meetings/${id}/end/`);
fetchMeeting();
alert('✅ 会议已结束');
} catch (error) {
var _error$response7, _error$response7$data;
alert('结束失败:' + (((_error$response7 = error.response) === null || _error$response7 === void 0 ? void 0 : (_error$response7$data = _error$response7.data) === null || _error$response7$data === void 0 ? void 0 : _error$response7$data.error) || error.message));
}
};
const generateMinutes = async () => {
try {
const res = await axios__WEBPACK_IMPORTED_MODULE_3__["default"].get(`${API_BASE}/meetings/${id}/minutes/?output=markdown`);
const blob = new Blob([res.data.markdown], {
type: 'text/markdown'
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `meeting-${id.slice(0, 8)}.md`;
a.click();
URL.revokeObjectURL(url);
alert('✅ 纪要已导出');
} catch (error) {
alert('导出失败:' + error.message);
}
};
return /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.container,
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.header,
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_router_dom__WEBPACK_IMPORTED_MODULE_1__.Link, {
to: "/meetings",
style: styles.link,
children: "\u2190 \u8FD4\u56DE"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 339,
columnNumber: 9
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("h1", {
children: (meeting === null || meeting === void 0 ? void 0 : meeting.topic) || '会议室'
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 340,
columnNumber: 9
}, this), meeting && /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", {
style: styles.badge,
children: meeting.status
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 341,
columnNumber: 21
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 338,
columnNumber: 7
}, this), meeting && /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.infoCard,
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", {
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("strong", {
children: "ID:"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 346,
columnNumber: 14
}, this), " ", meeting.id]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 346,
columnNumber: 11
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", {
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("strong", {
children: "\u9080\u8BF7\u7801:"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 347,
columnNumber: 14
}, this), " ", meeting.invite_code]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 347,
columnNumber: 11
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.btnGroup,
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", {
onClick: startMeeting,
style: styles.btnGreen,
children: "\u25B6\uFE0F \u5F00\u59CB"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 349,
columnNumber: 13
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", {
onClick: endMeeting,
style: styles.btnRed,
children: "\u23F9\uFE0F \u7ED3\u675F"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 350,
columnNumber: 13
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", {
onClick: generateMinutes,
style: styles.btnBlue,
children: "\uD83D\uDCCB \u7EAA\u8981"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 351,
columnNumber: 13
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 348,
columnNumber: 11
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 345,
columnNumber: 9
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.card,
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("h2", {
children: ["\uD83E\uDE91 \u5EA7\u4F4D\u56FE ", /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", {
style: styles.badge,
children: participants.length
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 358,
columnNumber: 20
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 358,
columnNumber: 9
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.seats,
children: participants.map(p => /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: {
...styles.seat,
...(hoveredSeat === p.id ? styles.seatHover : {})
},
onClick: () => {
if (p.agent_id) {
var _document$querySelect;
setContent(`@${p.nickname} `);
(_document$querySelect = document.querySelector('input[placeholder="输入消息..."]')) === null || _document$querySelect === void 0 ? void 0 : _document$querySelect.focus();
}
},
onMouseEnter: () => setHoveredSeat(p.id),
onMouseLeave: () => setHoveredSeat(null),
title: p.agent_id ? '点击 @ 此人' : '',
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.seatEmoji,
children: p.agent_emoji || '👤'
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 374,
columnNumber: 15
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.seatName,
children: p.nickname
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 375,
columnNumber: 15
}, this), p.is_host && /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.hostBadge,
children: "\uD83D\uDC51"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 376,
columnNumber: 29
}, this)]
}, p.id, true, {
fileName: _jsxFileName,
lineNumber: 361,
columnNumber: 13
}, this))
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 359,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 357,
columnNumber: 7
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.card,
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("h2", {
children: ["\uD83D\uDCAC \u804A\u5929 ", /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", {
style: styles.badge,
children: messages.length
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 384,
columnNumber: 19
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 384,
columnNumber: 9
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.messages,
children: messages.map(msg => /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.msg,
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.msgHeader,
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("strong", {
children: [msg.sender_emoji, " ", msg.sender_name]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 389,
columnNumber: 17
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", {
style: styles.msgTime,
children: new Date(msg.created_at).toLocaleTimeString()
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 390,
columnNumber: 17
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 388,
columnNumber: 15
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", {
style: styles.msgContent,
children: msg.content
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 392,
columnNumber: 15
}, this), msg.in_reply_to && /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
style: styles.replyTag,
children: ["\u21A9\uFE0F \u56DE\u590D #", msg.in_reply_to]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 393,
columnNumber: 35
}, this)]
}, msg.id, true, {
fileName: _jsxFileName,
lineNumber: 387,
columnNumber: 13
}, this))
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 385,
columnNumber: 9
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("form", {
onSubmit: sendMessage,
style: styles.form,
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("input", {
type: "text",
placeholder: "\u8F93\u5165\u6D88\u606F...",
value: content,
onChange: e => setContent(e.target.value),
style: styles.input
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 398,
columnNumber: 11
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", {
type: "submit",
style: styles.btn,
children: "\u53D1\u9001"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 399,
columnNumber: 11
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", {
type: "button",
onClick: mentionAgent,
style: styles.btnPink,
children: "\uD83D\uDCCD @Agent"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 400,
columnNumber: 11
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 397,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 383,
columnNumber: 7
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 337,
columnNumber: 5
}, this);
}
// ============ App ============
_s3(MeetingRoom, "fh+UC+M8I83D9S4VTUsmF3cRwwg=", false, function () {
return [react_router_dom__WEBPACK_IMPORTED_MODULE_2__.useParams];
});
_c3 = MeetingRoom;
function App() {
return /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_router_dom__WEBPACK_IMPORTED_MODULE_1__.BrowserRouter, {
children: /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_router_dom__WEBPACK_IMPORTED_MODULE_2__.Routes, {
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_router_dom__WEBPACK_IMPORTED_MODULE_2__.Route, {
path: "/login",
element: /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(LoginPage, {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 412,
columnNumber: 39
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 412,
columnNumber: 9
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_router_dom__WEBPACK_IMPORTED_MODULE_2__.Route, {
path: "/meetings",
element: /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(MeetingList, {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 413,
columnNumber: 42
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 413,
columnNumber: 9
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_router_dom__WEBPACK_IMPORTED_MODULE_2__.Route, {
path: "/meeting/:id",
element: /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(MeetingRoom, {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 414,
columnNumber: 45
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 414,
columnNumber: 9
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_router_dom__WEBPACK_IMPORTED_MODULE_2__.Route, {
path: "/",
element: /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(LoginPage, {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 415,
columnNumber: 34
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 415,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 411,
columnNumber: 7
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 410,
columnNumber: 5
}, this);
}
// ============ 样式 ============
_c4 = App;
const styles = {
center: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: '100vh',
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'
},
container: {
maxWidth: '900px',
margin: '0 auto',
padding: '20px',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
},
header: {
display: 'flex',
alignItems: 'center',
gap: '15px',
marginBottom: '20px'
},
card: {
background: 'white',
borderRadius: '12px',
padding: '20px',
marginBottom: '20px',
boxShadow: '0 4px 6px rgba(0,0,0,0.1)'
},
infoCard: {
background: '#e7f3ff',
border: '1px solid #2196f3',
borderRadius: '12px',
padding: '15px',
marginBottom: '20px'
},
title: {
margin: '0 0 20px',
color: '#1a365d',
textAlign: 'center'
},
form: {
display: 'flex',
gap: '10px'
},
input: {
flex: 1,
padding: '12px',
border: '2px solid #e2e8f0',
borderRadius: '8px',
fontSize: '14px'
},
btn: {
padding: '12px 20px',
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
fontWeight: '600'
},
btnGreen: {
padding: '8px 16px',
background: 'linear-gradient(135deg, #11998e 0%, #38ef7d 100%)',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
marginRight: '8px'
},
btnRed: {
padding: '8px 16px',
background: 'linear-gradient(135deg, #eb3349 0%, #f45c43 100%)',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
marginRight: '8px'
},
btnBlue: {
padding: '8px 16px',
background: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer'
},
btnPink: {
padding: '8px 16px',
background: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer'
},
smallBtn: {
padding: '8px 16px',
background: '#edf2f7',
border: 'none',
borderRadius: '6px',
cursor: 'pointer'
},
list: {
display: 'flex',
flexDirection: 'column',
gap: '15px'
},
item: {
background: 'white',
borderRadius: '12px',
padding: '20px',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
boxShadow: '0 4px 6px rgba(0,0,0,0.1)'
},
link: {
color: '#4299e1',
textDecoration: 'none',
fontSize: '16px'
},
badge: {
background: '#667eea',
color: 'white',
padding: '4px 10px',
borderRadius: '20px',
fontSize: '12px',
fontWeight: '600'
},
btnGroup: {
display: 'flex',
marginTop: '10px'
},
seats: {
display: 'flex',
flexWrap: 'wrap',
gap: '15px',
justifyContent: 'center'
},
seat: {
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
padding: '15px',
borderRadius: '50%',
width: '90px',
height: '90px',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
textAlign: 'center',
cursor: 'pointer',
transition: 'transform 0.2s',
':hover': {
transform: 'scale(1.1)'
}
},
seatHover: {
transform: 'scale(1.05)'
},
seatEmoji: {
fontSize: '28px',
marginBottom: '5px'
},
seatName: {
fontSize: '12px',
fontWeight: '600'
},
hostBadge: {
fontSize: '10px',
opacity: '0.8'
},
messages: {
maxHeight: '400px',
overflowY: 'auto',
marginBottom: '15px'
},
msg: {
padding: '12px',
background: '#f7fafc',
borderRadius: '8px',
marginBottom: '10px'
},
msgHeader: {
display: 'flex',
justifyContent: 'space-between',
marginBottom: '5px'
},
msgContent: {
margin: '5px 0',
color: '#4a5568'
},
msgTime: {
fontSize: '12px',
color: '#a0aec0'
},
replyTag: {
fontSize: '11px',
color: '#a0aec0',
marginTop: '5px'
}
};
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (App);
var _c, _c2, _c3, _c4;
__webpack_require__.$Refresh$.register(_c, "LoginPage");
__webpack_require__.$Refresh$.register(_c2, "MeetingList");
__webpack_require__.$Refresh$.register(_c3, "MeetingRoom");
__webpack_require__.$Refresh$.register(_c4, "App");
const $ReactRefreshModuleId$ = __webpack_require__.$Refresh$.moduleId;
const $ReactRefreshCurrentExports$ = __react_refresh_utils__.getModuleExports(
$ReactRefreshModuleId$
);
function $ReactRefreshModuleRuntime$(exports) {
if (true) {
let errorOverlay;
if (true) {
errorOverlay = false;
}
let testMode;
if (typeof __react_refresh_test__ !== 'undefined') {
testMode = __react_refresh_test__;
}
return __react_refresh_utils__.executeRuntime(
exports,
$ReactRefreshModuleId$,
module.hot,
errorOverlay,
testMode
);
}
}
if (typeof Promise !== 'undefined' && $ReactRefreshCurrentExports$ instanceof Promise) {
$ReactRefreshCurrentExports$.then($ReactRefreshModuleRuntime$);
} else {
$ReactRefreshModuleRuntime$($ReactRefreshCurrentExports$);
} <01>{"module":true,"columns":false,"finalSource":true}<02>map<61>bufferedMap<06>version<6F>file<6C>mappings<15><>sourcesContent<6E>names<03>x
;;;;;;;;;;;;;;;;;AAAmD;AACqD;AAC9E;AAAA;AAE1B;AAEA,6CAAK;AACH;AACA;AACA;AACF;;AAEA;AACA;AAAqB;AACnB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,kDAAS;AACP;AACE;AACF;AACF;AAEA;AACE;AACE;AACA;AACA;AACF;AACE;AACF;AACF;AAEA;AACE;AACA;AACE;AACE;AACA;AACA;AACF;AAEA;AACE;AACF;AAEA;AACA;AACA;AACA;AACA;AACA;AACF;AAAgB;AACd;AACF;AACF;AAEA;AACE;AAKF;AAEA;AACO;AAAqB;AACnB;AAAmB;AAClB;AAAoB;AAAU;AAAA;AAAA;AAAA;AAAA;AAC5B;AAAuB;AAAQ;AAAgB;AAAuB;AAAE;AACrE;AAAY;AAAkB;AAAiB;AAA4C;AAAqB;AAAQ;AAAA;AAAA;AAAA;AAAA;AACxH;AAAgB;AAAiB;AAAiB;AAA4C;AAAqB;AAAQ;AAAA;AAAA;AAAA;AAAA;AAG7H;AAAQ;AAAgB;AAAE;AACtB;AAAQ;AAAkB;AAAsB;AAAiB;AAAE;AAAS;AAAA;AAAA;AAAA;AAAA;AAC5E;AAAQ;AAAkB;AAAsB;AAAmB;AAAiB;AAAmD;AAAqB;AAA2B;AAAE;AAE5L;AACA;AACA;AACA;AACA;AAAuC;AAAA;AAAA;AAAA;AAAA;AAEjC;AAAY;AAAA;AAAA;AAAA;AAAA;AACtB;AAAA;AAAA;AAAA;AAAA;AACO;AAAQ;AAAkB;AAAsB;AAAmB;AAAiB;AAAmD;AAAqB;AAA2B;AAAE;AAE5L;AACA;AACA;AACA;AACA;AAAuC;AAAA;AAAA;AAAA;AAAA;AAEhC;AAAY;AAAA;AAAA;AAAA;AAAA;AACvB;AAAA;AAAA;AAAA;AAAA;AACO;AAAQ;AAAkB;AAAsB;AAAmB;AAAiB;AAAyD;AAAqB;AAA2B;AAAE;AAElM;AACA;AACA;AACA;AACA;AAAuC;AAAA;AAAA;AAAA;AAAA;AAEjC;AAAY;AAAA;AAAA;AAAA;AAAA;AACtB;AAAA;AAAA;AAAA;AAAA;AAAQ;AAAA;AAAA;AAAA;AAAA;AAKH;AAAQ;AAAkB;AAAiB;AAAuB;AAAmB;AAAE;AACnF;AAAQ;AAAkB;AAAsB;AAAiB;AAAE;AAAW;AAAA;AAAA;AAAA;AAAA;AAEhF;AAAQ;AAAe;AAAgB;AAAE;AAAQ;AAAA;AAAA;AAAA;AAAA;AAG1B;AAAQ;AAAiB;AAAsB;AAAqB;AAAiB;AAAE;AAE3G;AACA;AACA;AACA;AAAQ;AAAmB;AAAE;AAAA;AAAA;AAAA;AAAA;AAEzB;AAAQ;AAAkB;AAAkB;AAAE;AAAuB;AAAA;AAAA;AAAA;AAAA;AAC3E;AAAiB;AAAA;AAAA;AAAA;AAAA;AACX;AAAQ;AAAe;AAAkB;AAAiB;AAAE;AAAoB;AAAA;AAAA;AAAA;AAAA;AAAO;AATzE;AAAA;AAAA;AAAA;AAcrB;AAAQ;AAAmB;AAAkB;AAAiB;AAAE;AAEnE;AAAA;AAAA;AAAA;AAAA;AACD;AAAA;AAAA;AAAA;AAAA;AAIG;AAAc;AAAkB;AAAQ;AAAA;AAAA;AAAA;AAAA;AAAS;AAAA;AAAA;AAAA;AAAA;AACpD;AAAA;AAAA;AAAA;AAAA;AACH;AAAA;AAAA;AAAA;AAAA;AAGZ;;AAEA;AAAA;AAxIkB;AAMY;AAAA;AAmI9B;AAAuB;AACrB;AACA;AACA;AACA;AACA;AAEA,kDAAS;AACP;AAAc;AAAoB;AAAQ;AAC1C;AACF;AAEA;AACE;AACE;AACA;AACF;AAAkB;AAAsB;AAC1C;AAEA;AACE;AACA;AACE;AACA;AACA;AAEA;AACE;AACA;AAAgD;AAChD;AAA0D;AAC1D;AACF;AACA;AACF;AAAgB;AACd;AACF;AACF;AAEA;AAAuB;AAAkC;AAAoB;AAE7E;AACO;AAAwB;AACtB;AAAqB;AACxB;AAAY;AAAA;AAAA;AAAA;AAAA;AACJ;AAAiB;AAAuB;AAAG;AAAA;AAAA;AAAA;AAAA;AAAS;AAAA;AAAA;AAAA;AAAA;AAEzD;AAAmB;AACtB;AAAQ;AAAA;AAAA;AAAA;AAAA;AACF;AAAyB;AAAmB;AACzC;AAAY;AAAmB;AAAc;AAAyC;AAAqB;AAAQ;AAAA;AAAA;AAAA;AAAA;AACnH;AAAQ;AAAiB;AAAsB;AAAY;AAAoB;AAAE;AAEpF;AACA;AACA;AAAkD;AAAA;AAAA;AAAA;AAAA;AAGtD;AAAA;AAAA;AAAA;AAAA;AACQ;AAAc;AAAkB;AAAG;AAAA;AAAA;AAAA;AAAA;AAAS;AAAA;AAAA;AAAA;AAAA;AAEnD;AAAQ;AAAkB;AAAe;AAAiB;AAAE;AAE/D;AAAA;AAAA;AAAA;AAAA;AAAI;AAAA;AAAA;AAAA;AAAA;AAED;AAAmB;AAEJ;AAAmB;AACjC;AACE;AAAY;AAAA;AAAA;AAAA;AAAA;AACZ;AAAqC;AAAA;AAAA;AAAA;AAAA;AAAK;AAAA;AAAA;AAAA;AAAA;AAEpC;AAA6C;AAAuB;AAAG;AAAA;AAAA;AAAA;AAAA;AAAS;AAL5E;AAAA;AAAA;AAAA;AAOd;AAAA;AAAA;AAAA;AAAA;AACE;AAAA;AAAA;AAAA;AAAA;AAGZ;;AAEA;AAAA;AA/EoB;AAIU;AAAA;AA4E9B;AAAuB;AACrB;AAAQ;AAAG;AACX;AACA;AACA;AACA;AACA;AACA;AAEA,kDAAS;AACP;AACA;AACA;AACA;AACA;AACA;AACF;AAEA;AACE;AACE;AACA;AACF;AAAkB;AAAsB;AAC1C;AAEA;AACE;AACE;AACA;AACF;AAAkB;AAAsB;AAC1C;AAEA;AACE;AACE;AACA;AACF;AAAkB;AAAsB;AAC1C;AAEA;AACE;AACA;AACA;AACE;AAA+D;AAAQ;AACvE;AACA;AACF;AAAgB;AACd;AACF;AACF;AAEA;AACE;AACA;AACA;AACA;AACE;AACE;AAAyB;AACzB;AACF;AACA;AACA;AACA;AACF;AAAgB;AACd;AACF;AACF;AAEA;AACE;AACE;AACA;AACA;AACF;AAAgB;AACd;AACF;AACF;AAEA;AACE;AACA;AACE;AACA;AACA;AACF;AAAgB;AACd;AACF;AACF;AAEA;AACE;AACE;AACA;AAA6C;AAAsB;AACnE;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AACE;AACF;AACF;AAEA;AACO;AAAwB;AACtB;AAAqB;AAClB;AAAe;AAAmB;AAAK;AAAA;AAAA;AAAA;AAAA;AAC7C;AAA4B;AAAA;AAAA;AAAA;AAAA;AACV;AAAoB;AAAgB;AAAA;AAAA;AAAA;AAAA;AAAQ;AAAA;AAAA;AAAA;AAAA;AAIzD;AAAuB;AAC1B;AAAG;AAAW;AAAA;AAAA;AAAA;AAAA;AAAqB;AAAA;AAAA;AAAA;AAAA;AACnC;AAAG;AAAY;AAAA;AAAA;AAAA;AAAA;AAA8B;AAAA;AAAA;AAAA;AAAA;AACxC;AAAuB;AAClB;AAAuB;AAAuB;AAAM;AAAA;AAAA;AAAA;AAAA;AACpD;AAAqB;AAAqB;AAAM;AAAA;AAAA;AAAA;AAAA;AAChD;AAA0B;AAAsB;AAAM;AAAA;AAAA;AAAA;AAAA;AAAS;AAAA;AAAA;AAAA;AAAA;AACnE;AAAA;AAAA;AAAA;AAAA;AAKL;AAAmB;AACtB;AAAiB;AAAoB;AAAqB;AAAA;AAAA;AAAA;AAAA;AAAQ;AAAA;AAAA;AAAA;AAAA;AAC7D;AAAoB;AAInB;AAAQ;AAAgB;AAAiD;AACzE;AACE;AAAgB;AACd;AACA;AACF;AACF;AACA;AACA;AACA;AAAmC;
import { BrowserRouter as Router, Routes, Route, Link, useNavigate, useParams } from 'react-router-dom';
import axios from 'axios';
const API_BASE = 'http://localhost:8000/api/v1';
axios.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
});
// ============ 登录页面 ============
function LoginPage() {
const [username, setUsername] = useState('test');
const [password, setPassword] = useState('test123');
const [mode, setMode] = useState('solo');
const [agents, setAgents] = useState([]);
const [selectedAgents, setSelectedAgents] = useState([]);
const navigate = useNavigate();
// 扫描本机龙虾
useEffect(() => {
if (username) {
scanAgents();
}
}, [username]);
const scanAgents = async () => {
try {
// 传递 username 参数,获取绑定的龙虾信息
const res = await axios.get(`${API_BASE}/user/scan-local-agents/?username=${username}`);
setAgents(res.data.agents || []);
} catch (error) {
console.error('扫描龙虾失败:', error);
}
};
const handleLogin = async (e) => {
e.preventDefault();
try {
const payload = {
username,
password,
mode
};
if (mode !== 'solo' && selectedAgents.length > 0) {
payload.agent_ids = selectedAgents;
}
const res = await axios.post(`${API_BASE}/auth/login/`, payload);
localStorage.setItem('token', res.data.token);
localStorage.setItem('user', JSON.stringify(res.data.user));
localStorage.setItem('sessions', JSON.stringify(res.data.sessions));
localStorage.setItem('mode', res.data.mode);
navigate('/meetings');
} catch (error) {
alert('登录失败:' + (error.response?.data?.detail || error.response?.data?.error || error.message));
}
};
const toggleAgent = (agentId) => {
setSelectedAgents(prev =>
prev.includes(agentId)
? prev.filter(id => id !== agentId)
: [...prev, agentId]
);
};
return (
<div style={styles.center}>
<div style={styles.card}>
<h1 style={styles.title}>🏛️ 龙虾议事厅</h1>
<form onSubmit={handleLogin} style={{...styles.form, flexDirection: 'column'}}>
<input type="text" placeholder="用户名" value={username} onChange={e => setUsername(e.target.value)} style={styles.input} required />
<input type="password" placeholder="密码" value={password} onChange={e => setPassword(e.target.value)} style={styles.input} required />
{/* 出战模式选择 */}
<div style={{margin: '15px 0'}}>
<label style={{display: 'block', marginBottom: '10px', fontWeight: '600'}}>🎯 出战模式:</label>
<label style={{display: 'block', marginBottom: '12px', cursor: 'pointer', padding: '10px', background: mode === 'solo' ? '#e7f3ff' : 'white', borderRadius: '8px', border: '1px solid #2196f3'}}>
<input
type="radio"
name="mode"
value="solo"
checked={mode === 'solo'}
onChange={e => setMode(e.target.value)}
/>
{' '}🥷 <strong>单枪匹马</strong>(人类单独出战,不带龙虾)
</label>
<label style={{display: 'block', marginBottom: '12px', cursor: 'pointer', padding: '10px', background: mode === 'team' ? '#e7f3ff' : 'white', borderRadius: '8px', border: '1px solid #2196f3'}}>
<input
type="radio"
name="mode"
value="team"
checked={mode === 'team'}
onChange={e => setMode(e.target.value)}
/>
{' '}🛡️ <strong>组队团战</strong>(人类 + N 只龙虾一起出战)
</label>
<label style={{display: 'block', marginBottom: '12px', cursor: 'pointer', padding: '10px', background: mode === 'agent_only' ? '#e7f3ff' : 'white', borderRadius: '8px', border: '1px solid #2196f3'}}>
<input
type="radio"
name="mode"
value="agent_only"
checked={mode === 'agent_only'}
onChange={e => setMode(e.target.value)}
/>
{' '}⚔️ <strong>独当一面</strong>(龙虾单独出征,人类不上场)
</label>
</div>
{/* 龙虾选择(组队或独当一面) */}
{mode !== 'solo' && (
<div style={{margin: '15px 0', padding: '15px', background: '#f9f9f9', borderRadius: '8px'}}>
<label style={{display: 'block', marginBottom: '10px', fontWeight: '600'}}>🦐 选择龙虾队友:</label>
{agents.length === 0 ? (
<p style={{color: '#999', fontSize: '14px'}}>未找到可用龙虾</p>
) : (
agents.map(a => (
<label key={a.agent_id} style={{display: 'flex', alignItems: 'center', marginBottom: '8px', cursor: 'pointer'}}>
<input
type="checkbox"
checked={selectedAgents.includes(a.agent_id)}
onChange={() => toggleAgent(a.agent_id)}
style={{marginRight: '10px'}}
/>
<span style={{fontSize: '16px', marginRight: '8px'}}>{a.agent_emoji || '🤖'}</span>
<span>{a.agent_id}</span>
<span style={{color: '#999', fontSize: '12px', marginLeft: '8px'}}>({a.instance_name})</span>
</label>
))
)}
{selectedAgents.length > 0 && (
<p style={{marginTop: '10px', color: '#2196f3', fontWeight: '600'}}>
已选 {selectedAgents.length} 只龙虾队友 🦸
</p>
)}
</div>
)}
<button type="submit" style={styles.btn}>🚀 登录出征</button>
</form>
</div>
</div>
);
}
// ============ 会议列表 ============
function MeetingList() {
const [meetings, setMeetings] = useState([]);
const [topic, setTopic] = useState('');
const [autoAddAgents, setAutoAddAgents] = useState(true);
const navigate = useNavigate();
const token = localStorage.getItem('token');
useEffect(() => {
if (!token) { navigate('/login'); return; }
fetchMeetings();
}, []);
const fetchMeetings = async () => {
try {
const res = await axios.get(`${API_BASE}/meetings/`);
setMeetings(res.data);
} catch (error) { console.error(error); }
};
const createMeeting = async (e) => {
e.preventDefault();
try {
// 获取当前登录的龙虾
const sessions = JSON.parse(localStorage.getItem('sessions') || '[]');
const agentIds = sessions.filter(s => s.session_type === 'agent').map(s => s.agent_id);
const res = await axios.post(`${API_BASE}/meetings/`, {
topic,
auto_add_virtual_agents: agentIds.length === 0, // 只有没有龙虾时才添加虚拟的
host_agent_id: agentIds.length > 0 ? agentIds[0] : null, // 第一只作为主持龙虾
agent_ids: agentIds // 传递所有龙虾
});
navigate(`/meeting/${res.data.id}`);
} catch (error) {
alert('创建失败:' + (error.response?.data?.detail || error.message));
}
};
const logout = () => { localStorage.removeItem('token'); navigate('/login'); };
return (
<div style={styles.container}>
<div style={styles.header}>
<h1>📋 我的会议室</h1>
<button onClick={logout} style={styles.smallBtn}>退出</button>
</div>
<div style={styles.card}>
<h2>创建会议</h2>
<form onSubmit={createMeeting} style={styles.form}>
<input type="text" placeholder="会议主题" value={topic} onChange={e => setTopic(e.target.value)} style={styles.input} required />
<label style={{display: 'flex', alignItems: 'center', gap: '5px', whiteSpace: 'nowrap'}}>
<input
type="checkbox"
checked={autoAddAgents}
onChange={e => setAutoAddAgents(e.target.checked)}
/>
添加虚拟坐席
</label>
<button type="submit" style={styles.btn}>创建</button>
</form>
<p style={{fontSize: '12px', color: '#666', marginTop: '10px'}}>
💡 勾选"添加虚拟坐席"会自动创建 2 个虚拟龙虾参会者,方便测试 @ 功能
</p>
</div>
<div style={styles.list}>
{meetings.map(m => (
<div key={m.id} style={styles.item}>
<div>
<h3>{m.topic}</h3>
<p>状态:{m.status} | 邀请码:{m.invite_code}</p>
</div>
<button onClick={() => navigate(`/meeting/${m.id}`)} style={styles.smallBtn}>进入</button>
</div>
))}
</div>
</div>
);
}
// ============ 会议室 ============
function MeetingRoom() {
const { id } = useParams();
const [messages, setMessages] = useState([]);
const [content, setContent] = useState('');
const [participants, setParticipants] = useState([]);
const [meeting, setMeeting] = useState(null);
const [hoveredSeat, setHoveredSeat] = useState(null);
const token = localStorage.getItem('token');
useEffect(() => {
if (!token) return;
fetchMeeting();
fetchParticipants();
fetchMessages();
const interval = setInterval(fetchMessages, 1000);
return () => clearInterval(interval);
}, [id]);
const fetchMeeting = async () => {
try {
const res = await axios.get(`${API_BASE}/meetings/${id}/`);
setMeeting(res.data);
} catch (error) { console.error(error); }
};
const fetchParticipants = async () => {
try {
const res = await axios.get(`${API_BASE}/meetings/${id}/participants/`);
setParticipants(res.data);
} catch (error) { console.error(error); }
};
const fetchMessages = async () => {
try {
const res = await axios.get(`${API_BASE}/meetings/${id}/messages/?last_id=0`);
setMessages(res.data.messages || []);
} catch (error) { console.error(error); }
};
const sendMessage = async (e) => {
e.preventDefault();
if (!content.trim()) return;
try {
await axios.post(`${API_BASE}/meetings/${id}/send_message/`, { content });
setContent('');
fetchMessages();
} catch (error) {
alert('发送失败:' + (error.response?.data?.detail || error.message));
}
};
const mentionAgent = async (targetAgentId, agentName) => {
const target = targetAgentId || prompt('@哪个 Agent输入 agent_id:');
if (!target || !content.trim()) return;
const name = agentName || target;
try {
await axios.post(`${API_BASE}/meetings/${id}/mention_agent/`, {
target_agent_id: target, content,
sender_name: localStorage.getItem('user') ? JSON.parse(localStorage.getItem('user')).username : 'User'
});
setContent('');
fetchMessages();
alert(`✅ 已 @${name}`);
} catch (error) {
alert('发送失败:' + (error.response?.data?.error || error.message));
}
};
const startMeeting = async () => {
try {
await axios.post(`${API_BASE}/meetings/${id}/start/`);
fetchMeeting();
alert('✅ 会议已开始');
} catch (error) {
alert('开始失败:' + (error.response?.data?.error || error.message));
}
};
const endMeeting = async () => {
if (!confirm('确定结束会议?')) return;
try {
await axios.post(`${API_BASE}/meetings/${id}/end/`);
fetchMeeting();
alert('✅ 会议已结束');
} catch (error) {
alert('结束失败:' + (error.response?.data?.error || error.message));
}
};
const generateMinutes = async () => {
try {
const res = await axios.get(`${API_BASE}/meetings/${id}/minutes/?output=markdown`);
const blob = new Blob([res.data.markdown], { type: 'text/markdown' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `meeting-${id.slice(0, 8)}.md`;
a.click();
URL.revokeObjectURL(url);
alert('✅ 纪要已导出');
} catch (error) {
alert('导出失败:' + error.message);
}
};
return (
<div style={styles.container}>
<div style={styles.header}>
<Link to="/meetings" style={styles.link}>← 返回</Link>
<h1>{meeting?.topic || '会议室'}</h1>
{meeting && <span style={styles.badge}>{meeting.status}</span>}
</div>
{meeting && (
<div style={styles.infoCard}>
<p><strong>ID:</strong> {meeting.id}</p>
<p><strong>邀请码:</strong> {meeting.invite_code}</p>
<div style={styles.btnGroup}>
<button onClick={startMeeting} style={styles.btnGreen}>▶️ 开始</button>
<button onClick={endMeeting} style={styles.btnRed}>⏹️ 结束</button>
<button onClick={generateMinutes} style={styles.btnBlue}>📋 纪要</button>
</div>
</div>
)}
{/* 座位图 */}
<div style={styles.card}>
<h2>🪑 座位图 <span style={styles.badge}>{participants.length}</span></h2>
<div style={styles.seats}>
{participants.map(p => (
<div
key={p.id}
style={{...styles.seat, ...(hoveredSeat === p.id ? styles.seatHover : {})}}
onClick={() => {
if (p.agent_id) {
setContent(`@${p.nickname} `);
document.querySelector('input[placeholder="输入消息..."]')?.focus();
}
}}
onMouseEnter={() => setHoveredSeat(p.id)}
onMouseLeave={() => setHoveredSeat(null)}
title={p.agent_id ? '点击 @ 此人' : ''}
>
<div style={styles.seatEmoji}>{p.agent_emoji || '👤'}</div>
<div style={styles.seatName}>{p.nickname}</div>
{p.is_host && <div style={styles.hostBadge}>👑</div>}
</div>
))}
</div>
</div>
{/* 聊天 */}
<div style={styles.card}>
<h2>💬 聊天 <span style={styles.badge}>{messages.length}</span></h2>
<div style={styles.messages}>
{messages.map(msg => (
<div key={msg.id} style={styles.msg}>
<div style={styles.msgHeader}>
<strong>{msg.sender_emoji} {msg.sender_name}</strong>
<span style={styles.msgTime}>{new Date(msg.created_at).toLocaleTimeString()}</span>
</div>
<p style={styles.msgContent}>{msg.content}</p>
{msg.in_reply_to && <div style={styles.replyTag}>↩️ 回复 #{msg.in_reply_to}</div>}
</div>
))}
</div>
<form onSubmit={sendMessage} style={styles.form}>
<input type="text" placeholder="输入消息..." value={content} onChange={e => setContent(e.target.value)} style={styles.input} />
<button type="submit" style={styles.btn}>发送</button>
<button type="button" onClick={mentionAgent} style={styles.btnPink}>📍 @Agent</button>
</form>
</div>
</div>
);
}
// ============ App ============
function App() {
return (
<Router>
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/meetings" element={<MeetingList />} />
<Route path="/meeting/:id" element={<MeetingRoom />} />
<Route path="/" element={<LoginPage />} />
</Routes>
</Router>
);
}
// ============ 样式 ============
const styles = {
center: { display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '100vh', background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' },
container: { maxWidth: '900px', margin: '0 auto', padding: '20px', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' },
header: { display: 'flex', alignItems: 'center', gap: '15px', marginBottom: '20px' },
card: { background: 'white', borderRadius: '12px', padding: '20px', marginBottom: '20px', boxShadow: '0 4px 6px rgba(0,0,0,0.1)' },
infoCard: { background: '#e7f3ff', border: '1px solid #2196f3', borderRadius: '12px', padding: '15px', marginBottom: '20px' },
title: { margin: '0 0 20px', color: '#1a365d', textAlign: 'center' },
form: { display: 'flex', gap: '10px' },
input: { flex: 1, padding: '12px', border: '2px solid #e2e8f0', borderRadius: '8px', fontSize: '14px' },
btn: { padding: '12px 20px', background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', color: 'white', border: 'none', borderRadius: '8px', cursor: 'pointer', fontWeight: '600' },
btnGreen: { padding: '8px 16px', background: 'linear-gradient(135deg, #11998e 0%, #38ef7d 100%)', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer', marginRight: '8px' },
btnRed: { padding: '8px 16px', background: 'linear-gradient(135deg, #eb3349 0%, #f45c43 100%)', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer', marginRight: '8px' },
btnBlue: { padding: '8px 16px', background: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer' },
btnPink: { padding: '8px 16px', background: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer' },
smallBtn: { padding: '8px 16px', background: '#edf2f7', border: 'none', borderRadius: '6px', cursor: 'pointer' },
list: { display: 'flex', flexDirection: 'column', gap: '15px' },
item: { background: 'white', borderRadius: '12px', padding: '20px', display: 'flex', justifyContent: 'space-between', alignItems: 'center', boxShadow: '0 4px 6px rgba(0,0,0,0.1)' },
link: { color: '#4299e1', textDecoration: 'none', fontSize: '16px' },
badge: { background: '#667eea', color: 'white', padding: '4px 10px', borderRadius: '20px', fontSize: '12px', fontWeight: '600' },
btnGroup: { display: 'flex', marginTop: '10px' },
seats: { display: 'flex', flexWrap: 'wrap', gap: '15px', justifyContent: 'center' },
seat: { background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', color: 'white', padding: '15px', borderRadius: '50%', width: '90px', height: '90px', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', textAlign: 'center', cursor: 'pointer', transition: 'transform 0.2s', ':hover': { transform: 'scale(1.1)' } },
seatHover: { transform: 'scale(1.05)' },
seatEmoji: { fontSize: '28px', marginBottom: '5px' },
seatName: { fontSize: '12px', fontWeight: '600' },
hostBadge: { fontSize: '10px', opacity: '0.8' },
messages: { maxHeight: '400px', overflowY: 'auto', marginBottom: '15px' },
msg: { padding: '12px', background: '#f7fafc', borderRadius: '8px', marginBottom: '10px' },
msgHeader: { display: 'flex', justifyContent: 'space-between', marginBottom: '5px' },
msgContent: { margin: '5px 0', color: '#4a5568' },
msgTime: { fontSize: '12px', color: '#a0aec0' },
replyTag: { fontSize: '11px', color: '#a0aec0', marginTop: '5px' }
};
export default App;
ConcatSourceRawSourceL__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-router-dom */ "./node_modules/react-router-dom/dist/index.js");
/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-router-dom */ "./node_modules/react-router/dist/index.js");
/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! axios */ "./node_modules/axios/lib/axios.js");
/* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js");
/* provided dependency */ var __react_refresh_utils__ = __webpack_require__(/*! ./node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js */ "./node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js");
ReplaceSourceSourceMapSource<15>__webpack_require__.$Refresh$.runtime = require('/home/node/.openclaw/workspace/flying-hero/projects/meeting-room/frontend/node_modules/react-refresh/runtime.js');
var _jsxFileName = "/home/node/.openclaw/workspace/flying-hero/projects/meeting-room/frontend/src/App.js",
_s = $RefreshSig$(),
_s2 = $RefreshSig$(),
_s3 = $RefreshSig$();
import React, { useState, useEffect } from 'react';
import { BrowserRouter as Router, Routes, Route, Link, useNavigate, useParams } from 'react-router-dom';
import axios from 'axios';
import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";
const API_BASE = 'http://localhost:8000/api/v1';
axios.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
});
// ============ 登录页面 ============
function LoginPage() {
_s();
const [username, setUsername] = useState('test');
const [password, setPassword] = useState('test123');
const [mode, setMode] = useState('solo');
const [agents, setAgents] = useState([]);
const [selectedAgents, setSelectedAgents] = useState([]);
const navigate = useNavigate();
// 扫描本机龙虾
useEffect(() => {
if (username) {
scanAgents();
}
}, [username]);
const scanAgents = async () => {
try {
// 传递 username 参数,获取绑定的龙虾信息
const res = await axios.get(`${API_BASE}/user/scan-local-agents/?username=${username}`);
setAgents(res.data.agents || []);
} catch (error) {
console.error('扫描龙虾失败:', error);
}
};
const handleLogin = async e => {
e.preventDefault();
try {
const payload = {
username,
password,
mode
};
if (mode !== 'solo' && selectedAgents.length > 0) {
payload.agent_ids = selectedAgents;
}
const res = await axios.post(`${API_BASE}/auth/login/`, payload);
localStorage.setItem('token', res.data.token);
localStorage.setItem('user', JSON.stringify(res.data.user));
localStorage.setItem('sessions', JSON.stringify(res.data.sessions));
localStorage.setItem('mode', res.data.mode);
navigate('/meetings');
} catch (error) {
var _error$response, _error$response$data, _error$response2, _error$response2$data;
alert('登录失败:' + (((_error$response = error.response) === null || _error$response === void 0 ? void 0 : (_error$response$data = _error$response.data) === null || _error$response$data === void 0 ? void 0 : _error$response$data.detail) || ((_error$response2 = error.response) === null || _error$response2 === void 0 ? void 0 : (_error$response2$data = _error$response2.data) === null || _error$response2$data === void 0 ? void 0 : _error$response2$data.error) || error.message));
}
};
const toggleAgent = agentId => {
setSelectedAgents(prev => prev.includes(agentId) ? prev.filter(id => id !== agentId) : [...prev, agentId]);
};
return /*#__PURE__*/_jsxDEV("div", {
style: styles.center,
children: /*#__PURE__*/_jsxDEV("div", {
style: styles.card,
children: [/*#__PURE__*/_jsxDEV("h1", {
style: styles.title,
children: "\uD83C\uDFDB\uFE0F \u9F99\u867E\u8BAE\u4E8B\u5385"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 74,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("form", {
onSubmit: handleLogin,
style: {
...styles.form,
flexDirection: 'column'
},
children: [/*#__PURE__*/_jsxDEV("input", {
type: "text",
placeholder: "\u7528\u6237\u540D",
value: username,
onChange: e => setUsername(e.target.value),
style: styles.input,
required: true
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 76,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("input", {
type: "password",
placeholder: "\u5BC6\u7801",
value: password,
onChange: e => setPassword(e.target.value),
style: styles.input,
required: true
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 77,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("div", {
style: {
margin: '15px 0'
},
children: [/*#__PURE__*/_jsxDEV("label", {
style: {
display: 'block',
marginBottom: '10px',
fontWeight: '600'
},
children: "\uD83C\uDFAF \u51FA\u6218\u6A21\u5F0F\uFF1A"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 81,
columnNumber: 13
}, this), /*#__PURE__*/_jsxDEV("label", {
style: {
display: 'block',
marginBottom: '12px',
cursor: 'pointer',
padding: '10px',
background: mode === 'solo' ? '#e7f3ff' : 'white',
borderRadius: '8px',
border: '1px solid #2196f3'
},
children: [/*#__PURE__*/_jsxDEV("input", {
type: "radio",
name: "mode",
value: "solo",
checked: mode === 'solo',
onChange: e => setMode(e.target.value)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 83,
columnNumber: 15
}, this), ' ', "\uD83E\uDD77 ", /*#__PURE__*/_jsxDEV("strong", {
children: "\u5355\u67AA\u5339\u9A6C"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 90,
columnNumber: 23
}, this), "\uFF08\u4EBA\u7C7B\u5355\u72EC\u51FA\u6218\uFF0C\u4E0D\u5E26\u9F99\u867E\uFF09"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 82,
columnNumber: 13
}, this), /*#__PURE__*/_jsxDEV("label", {
style: {
display: 'block',
marginBottom: '12px',
cursor: 'pointer',
padding: '10px',
background: mode === 'team' ? '#e7f3ff' : 'white',
borderRadius: '8px',
border: '1px solid #2196f3'
},
children: [/*#__PURE__*/_jsxDEV("input", {
type: "radio",
name: "mode",
value: "team",
checked: mode === 'team',
onChange: e => setMode(e.target.value)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 93,
columnNumber: 15
}, this), ' ', "\uD83D\uDEE1\uFE0F ", /*#__PURE__*/_jsxDEV("strong", {
children: "\u7EC4\u961F\u56E2\u6218"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 100,
columnNumber: 24
}, this), "\uFF08\u4EBA\u7C7B + N \u53EA\u9F99\u867E\u4E00\u8D77\u51FA\u6218\uFF09"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 92,
columnNumber: 13
}, this), /*#__PURE__*/_jsxDEV("label", {
style: {
display: 'block',
marginBottom: '12px',
cursor: 'pointer',
padding: '10px',
background: mode === 'agent_only' ? '#e7f3ff' : 'white',
borderRadius: '8px',
border: '1px solid #2196f3'
},
children: [/*#__PURE__*/_jsxDEV("input", {
type: "radio",
name: "mode",
value: "agent_only",
checked: mode === 'agent_only',
onChange: e => setMode(e.target.value)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 103,
columnNumber: 15
}, this), ' ', "\u2694\uFE0F ", /*#__PURE__*/_jsxDEV("strong", {
children: "\u72EC\u5F53\u4E00\u9762"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 110,
columnNumber: 23
}, this), "\uFF08\u9F99\u867E\u5355\u72EC\u51FA\u5F81\uFF0C\u4EBA\u7C7B\u4E0D\u4E0A\u573A\uFF09"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 102,
columnNumber: 13
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 80,
columnNumber: 11
}, this), mode !== 'solo' && /*#__PURE__*/_jsxDEV("div", {
style: {
margin: '15px 0',
padding: '15px',
background: '#f9f9f9',
borderRadius: '8px'
},
children: [/*#__PURE__*/_jsxDEV("label", {
style: {
display: 'block',
marginBottom: '10px',
fontWeight: '600'
},
children: "\uD83E\uDD90 \u9009\u62E9\u9F99\u867E\u961F\u53CB\uFF1A"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 117,
columnNumber: 15
}, this), agents.length === 0 ? /*#__PURE__*/_jsxDEV("p", {
style: {
color: '#999',
fontSize: '14px'
},
children: "\u672A\u627E\u5230\u53EF\u7528\u9F99\u867E"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 119,
columnNumber: 17
}, this) : agents.map(a => /*#__PURE__*/_jsxDEV("label", {
style: {
display: 'flex',
alignItems: 'center',
marginBottom: '8px',
cursor: 'pointer'
},
children: [/*#__PURE__*/_jsxDEV("input", {
type: "checkbox",
checked: selectedAgents.includes(a.agent_id),
onChange: () => toggleAgent(a.agent_id),
style: {
marginRight: '10px'
}
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 123,
columnNumber: 21
}, this), /*#__PURE__*/_jsxDEV("span", {
style: {
fontSize: '16px',
marginRight: '8px'
},
children: a.agent_emoji || '🤖'
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 129,
columnNumber: 21
}, this), /*#__PURE__*/_jsxDEV("span", {
children: a.agent_id
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 130,
columnNumber: 21
}, this), /*#__PURE__*/_jsxDEV("span", {
style: {
color: '#999',
fontSize: '12px',
marginLeft: '8px'
},
children: ["(", a.instance_name, ")"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 131,
columnNumber: 21
}, this)]
}, a.agent_id, true, {
fileName: _jsxFileName,
lineNumber: 122,
columnNumber: 19
}, this)), selectedAgents.length > 0 && /*#__PURE__*/_jsxDEV("p", {
style: {
marginTop: '10px',
color: '#2196f3',
fontWeight: '600'
},
children: ["\u5DF2\u9009 ", selectedAgents.length, " \u53EA\u9F99\u867E\u961F\u53CB \uD83E\uDDB8"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 136,
columnNumber: 17
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 116,
columnNumber: 13
}, this), /*#__PURE__*/_jsxDEV("button", {
type: "submit",
style: styles.btn,
children: "\uD83D\uDE80 \u767B\u5F55\u51FA\u5F81"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 143,
columnNumber: 11
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 75,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 73,
columnNumber: 7
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 72,
columnNumber: 5
}, this);
}
// ============ 会议列表 ============
_s(LoginPage, "fZ8UTwO2MCkNd6X4nAqytpuamXM=", false, function () {
return [useNavigate];
});
_c = LoginPage;
function MeetingList() {
_s2();
const [meetings, setMeetings] = useState([]);
const [topic, setTopic] = useState('');
const [autoAddAgents, setAutoAddAgents] = useState(true);
const navigate = useNavigate();
const token = localStorage.getItem('token');
useEffect(() => {
if (!token) {
navigate('/login');
return;
}
fetchMeetings();
}, []);
const fetchMeetings = async () => {
try {
const res = await axios.get(`${API_BASE}/meetings/`);
setMeetings(res.data);
} catch (error) {
console.error(error);
}
};
const createMeeting = async e => {
e.preventDefault();
try {
// 获取当前登录的龙虾
const sessions = JSON.parse(localStorage.getItem('sessions') || '[]');
const agentIds = sessions.filter(s => s.session_type === 'agent').map(s => s.agent_id);
const res = await axios.post(`${API_BASE}/meetings/`, {
topic,
auto_add_virtual_agents: agentIds.length === 0,
// 只有没有龙虾时才添加虚拟的
host_agent_id: agentIds.length > 0 ? agentIds[0] : null,
// 第一只作为主持龙虾
agent_ids: agentIds // 传递所有龙虾
});
navigate(`/meeting/${res.data.id}`);
} catch (error) {
var _error$response3, _error$response3$data;
alert('创建失败:' + (((_error$response3 = error.response) === null || _error$response3 === void 0 ? void 0 : (_error$response3$data = _error$response3.data) === null || _error$response3$data === void 0 ? void 0 : _error$response3$data.detail) || error.message));
}
};
const logout = () => {
localStorage.removeItem('token');
navigate('/login');
};
return /*#__PURE__*/_jsxDEV("div", {
style: styles.container,
children: [/*#__PURE__*/_jsxDEV("div", {
style: styles.header,
children: [/*#__PURE__*/_jsxDEV("h1", {
children: "\uD83D\uDCCB \u6211\u7684\u4F1A\u8BAE\u5BA4"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 194,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("button", {
onClick: logout,
style: styles.smallBtn,
children: "\u9000\u51FA"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 195,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 193,
columnNumber: 7
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.card,
children: [/*#__PURE__*/_jsxDEV("h2", {
children: "\u521B\u5EFA\u4F1A\u8BAE"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 198,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("form", {
onSubmit: createMeeting,
style: styles.form,
children: [/*#__PURE__*/_jsxDEV("input", {
type: "text",
placeholder: "\u4F1A\u8BAE\u4E3B\u9898",
value: topic,
onChange: e => setTopic(e.target.value),
style: styles.input,
required: true
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 200,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("label", {
style: {
display: 'flex',
alignItems: 'center',
gap: '5px',
whiteSpace: 'nowrap'
},
children: [/*#__PURE__*/_jsxDEV("input", {
type: "checkbox",
checked: autoAddAgents,
onChange: e => setAutoAddAgents(e.target.checked)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 202,
columnNumber: 13
}, this), "\u6DFB\u52A0\u865A\u62DF\u5750\u5E2D"]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 201,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("button", {
type: "submit",
style: styles.btn,
children: "\u521B\u5EFA"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 209,
columnNumber: 11
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 199,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("p", {
style: {
fontSize: '12px',
color: '#666',
marginTop: '10px'
},
children: "\uD83D\uDCA1 \u52FE\u9009\"\u6DFB\u52A0\u865A\u62DF\u5750\u5E2D\"\u4F1A\u81EA\u52A8\u521B\u5EFA 2 \u4E2A\u865A\u62DF\u9F99\u867E\u53C2\u4F1A\u8005\uFF0C\u65B9\u4FBF\u6D4B\u8BD5 @ \u529F\u80FD"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 211,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 197,
columnNumber: 7
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.list,
children: meetings.map(m => /*#__PURE__*/_jsxDEV("div", {
style: styles.item,
children: [/*#__PURE__*/_jsxDEV("div", {
children: [/*#__PURE__*/_jsxDEV("h3", {
children: m.topic
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 219,
columnNumber: 15
}, this), /*#__PURE__*/_jsxDEV("p", {
children: ["\u72B6\u6001\uFF1A", m.status, " | \u9080\u8BF7\u7801\uFF1A", m.invite_code]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 220,
columnNumber: 15
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 218,
columnNumber: 13
}, this), /*#__PURE__*/_jsxDEV("button", {
onClick: () => navigate(`/meeting/${m.id}`),
style: styles.smallBtn,
children: "\u8FDB\u5165"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 222,
columnNumber: 13
}, this)]
}, m.id, true, {
fileName: _jsxFileName,
lineNumber: 217,
columnNumber: 11
}, this))
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 215,
columnNumber: 7
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 192,
columnNumber: 5
}, this);
}
// ============ 会议室 ============
_s2(MeetingList, "uNteAZxXgR2pMaYhX5ze9khr1nw=", false, function () {
return [useNavigate];
});
_c2 = MeetingList;
function MeetingRoom() {
_s3();
const {
id
} = useParams();
const [messages, setMessages] = useState([]);
const [content, setContent] = useState('');
const [participants, setParticipants] = useState([]);
const [meeting, setMeeting] = useState(null);
const [hoveredSeat, setHoveredSeat] = useState(null);
const token = localStorage.getItem('token');
useEffect(() => {
if (!token) return;
fetchMeeting();
fetchParticipants();
fetchMessages();
const interval = setInterval(fetchMessages, 1000);
return () => clearInterval(interval);
}, [id]);
const fetchMeeting = async () => {
try {
const res = await axios.get(`${API_BASE}/meetings/${id}/`);
setMeeting(res.data);
} catch (error) {
console.error(error);
}
};
const fetchParticipants = async () => {
try {
const res = await axios.get(`${API_BASE}/meetings/${id}/participants/`);
setParticipants(res.data);
} catch (error) {
console.error(error);
}
};
const fetchMessages = async () => {
try {
const res = await axios.get(`${API_BASE}/meetings/${id}/messages/?last_id=0`);
setMessages(res.data.messages || []);
} catch (error) {
console.error(error);
}
};
const sendMessage = async e => {
e.preventDefault();
if (!content.trim()) return;
try {
await axios.post(`${API_BASE}/meetings/${id}/send_message/`, {
content
});
setContent('');
fetchMessages();
} catch (error) {
var _error$response4, _error$response4$data;
alert('发送失败:' + (((_error$response4 = error.response) === null || _error$response4 === void 0 ? void 0 : (_error$response4$data = _error$response4.data) === null || _error$response4$data === void 0 ? void 0 : _error$response4$data.detail) || error.message));
}
};
const mentionAgent = async (targetAgentId, agentName) => {
const target = targetAgentId || prompt('@哪个 Agent输入 agent_id:');
if (!target || !content.trim()) return;
const name = agentName || target;
try {
await axios.post(`${API_BASE}/meetings/${id}/mention_agent/`, {
target_agent_id: target,
content,
sender_name: localStorage.getItem('user') ? JSON.parse(localStorage.getItem('user')).username : 'User'
});
setContent('');
fetchMessages();
alert(`✅ 已 @${name}`);
} catch (error) {
var _error$response5, _error$response5$data;
alert('发送失败:' + (((_error$response5 = error.response) === null || _error$response5 === void 0 ? void 0 : (_error$response5$data = _error$response5.data) === null || _error$response5$data === void 0 ? void 0 : _error$response5$data.error) || error.message));
}
};
const startMeeting = async () => {
try {
await axios.post(`${API_BASE}/meetings/${id}/start/`);
fetchMeeting();
alert('✅ 会议已开始');
} catch (error) {
var _error$response6, _error$response6$data;
alert('开始失败:' + (((_error$response6 = error.response) === null || _error$response6 === void 0 ? void 0 : (_error$response6$data = _error$response6.data) === null || _error$response6$data === void 0 ? void 0 : _error$response6$data.error) || error.message));
}
};
const endMeeting = async () => {
if (!confirm('确定结束会议?')) return;
try {
await axios.post(`${API_BASE}/meetings/${id}/end/`);
fetchMeeting();
alert('✅ 会议已结束');
} catch (error) {
var _error$response7, _error$response7$data;
alert('结束失败:' + (((_error$response7 = error.response) === null || _error$response7 === void 0 ? void 0 : (_error$response7$data = _error$response7.data) === null || _error$response7$data === void 0 ? void 0 : _error$response7$data.error) || error.message));
}
};
const generateMinutes = async () => {
try {
const res = await axios.get(`${API_BASE}/meetings/${id}/minutes/?output=markdown`);
const blob = new Blob([res.data.markdown], {
type: 'text/markdown'
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `meeting-${id.slice(0, 8)}.md`;
a.click();
URL.revokeObjectURL(url);
alert('✅ 纪要已导出');
} catch (error) {
alert('导出失败:' + error.message);
}
};
return /*#__PURE__*/_jsxDEV("div", {
style: styles.container,
children: [/*#__PURE__*/_jsxDEV("div", {
style: styles.header,
children: [/*#__PURE__*/_jsxDEV(Link, {
to: "/meetings",
style: styles.link,
children: "\u2190 \u8FD4\u56DE"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 339,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("h1", {
children: (meeting === null || meeting === void 0 ? void 0 : meeting.topic) || '会议室'
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 340,
columnNumber: 9
}, this), meeting && /*#__PURE__*/_jsxDEV("span", {
style: styles.badge,
children: meeting.status
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 341,
columnNumber: 21
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 338,
columnNumber: 7
}, this), meeting && /*#__PURE__*/_jsxDEV("div", {
style: styles.infoCard,
children: [/*#__PURE__*/_jsxDEV("p", {
children: [/*#__PURE__*/_jsxDEV("strong", {
children: "ID:"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 346,
columnNumber: 14
}, this), " ", meeting.id]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 346,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("p", {
children: [/*#__PURE__*/_jsxDEV("strong", {
children: "\u9080\u8BF7\u7801:"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 347,
columnNumber: 14
}, this), " ", meeting.invite_code]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 347,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.btnGroup,
children: [/*#__PURE__*/_jsxDEV("button", {
onClick: startMeeting,
style: styles.btnGreen,
children: "\u25B6\uFE0F \u5F00\u59CB"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 349,
columnNumber: 13
}, this), /*#__PURE__*/_jsxDEV("button", {
onClick: endMeeting,
style: styles.btnRed,
children: "\u23F9\uFE0F \u7ED3\u675F"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 350,
columnNumber: 13
}, this), /*#__PURE__*/_jsxDEV("button", {
onClick: generateMinutes,
style: styles.btnBlue,
children: "\uD83D\uDCCB \u7EAA\u8981"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 351,
columnNumber: 13
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 348,
columnNumber: 11
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 345,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.card,
children: [/*#__PURE__*/_jsxDEV("h2", {
children: ["\uD83E\uDE91 \u5EA7\u4F4D\u56FE ", /*#__PURE__*/_jsxDEV("span", {
style: styles.badge,
children: participants.length
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 358,
columnNumber: 20
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 358,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.seats,
children: participants.map(p => /*#__PURE__*/_jsxDEV("div", {
style: {
...styles.seat,
...(hoveredSeat === p.id ? styles.seatHover : {})
},
onClick: () => {
if (p.agent_id) {
var _document$querySelect;
setContent(`@${p.nickname} `);
(_document$querySelect = document.querySelector('input[placeholder="输入消息..."]')) === null || _document$querySelect === void 0 ? void 0 : _document$querySelect.focus();
}
},
onMouseEnter: () => setHoveredSeat(p.id),
onMouseLeave: () => setHoveredSeat(null),
title: p.agent_id ? '点击 @ 此人' : '',
children: [/*#__PURE__*/_jsxDEV("div", {
style: styles.seatEmoji,
children: p.agent_emoji || '👤'
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 374,
columnNumber: 15
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.seatName,
children: p.nickname
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 375,
columnNumber: 15
}, this), p.is_host && /*#__PURE__*/_jsxDEV("div", {
style: styles.hostBadge,
children: "\uD83D\uDC51"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 376,
columnNumber: 29
}, this)]
}, p.id, true, {
fileName: _jsxFileName,
lineNumber: 361,
columnNumber: 13
}, this))
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 359,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 357,
columnNumber: 7
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.card,
children: [/*#__PURE__*/_jsxDEV("h2", {
children: ["\uD83D\uDCAC \u804A\u5929 ", /*#__PURE__*/_jsxDEV("span", {
style: styles.badge,
children: messages.length
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 384,
columnNumber: 19
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 384,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("div", {
style: styles.messages,
children: messages.map(msg => /*#__PURE__*/_jsxDEV("div", {
style: styles.msg,
children: [/*#__PURE__*/_jsxDEV("div", {
style: styles.msgHeader,
children: [/*#__PURE__*/_jsxDEV("strong", {
children: [msg.sender_emoji, " ", msg.sender_name]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 389,
columnNumber: 17
}, this), /*#__PURE__*/_jsxDEV("span", {
style: styles.msgTime,
children: new Date(msg.created_at).toLocaleTimeString()
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 390,
columnNumber: 17
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 388,
columnNumber: 15
}, this), /*#__PURE__*/_jsxDEV("p", {
style: styles.msgContent,
children: msg.content
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 392,
columnNumber: 15
}, this), msg.in_reply_to && /*#__PURE__*/_jsxDEV("div", {
style: styles.replyTag,
children: ["\u21A9\uFE0F \u56DE\u590D #", msg.in_reply_to]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 393,
columnNumber: 35
}, this)]
}, msg.id, true, {
fileName: _jsxFileName,
lineNumber: 387,
columnNumber: 13
}, this))
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 385,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV("form", {
onSubmit: sendMessage,
style: styles.form,
children: [/*#__PURE__*/_jsxDEV("input", {
type: "text",
placeholder: "\u8F93\u5165\u6D88\u606F...",
value: content,
onChange: e => setContent(e.target.value),
style: styles.input
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 398,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("button", {
type: "submit",
style: styles.btn,
children: "\u53D1\u9001"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 399,
columnNumber: 11
}, this), /*#__PURE__*/_jsxDEV("button", {
type: "button",
onClick: mentionAgent,
style: styles.btnPink,
children: "\uD83D\uDCCD @Agent"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 400,
columnNumber: 11
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 397,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 383,
columnNumber: 7
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 337,
columnNumber: 5
}, this);
}
// ============ App ============
_s3(MeetingRoom, "fh+UC+M8I83D9S4VTUsmF3cRwwg=", false, function () {
return [useParams];
});
_c3 = MeetingRoom;
function App() {
return /*#__PURE__*/_jsxDEV(Router, {
children: /*#__PURE__*/_jsxDEV(Routes, {
children: [/*#__PURE__*/_jsxDEV(Route, {
path: "/login",
element: /*#__PURE__*/_jsxDEV(LoginPage, {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 412,
columnNumber: 39
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 412,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV(Route, {
path: "/meetings",
element: /*#__PURE__*/_jsxDEV(MeetingList, {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 413,
columnNumber: 42
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 413,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV(Route, {
path: "/meeting/:id",
element: /*#__PURE__*/_jsxDEV(MeetingRoom, {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 414,
columnNumber: 45
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 414,
columnNumber: 9
}, this), /*#__PURE__*/_jsxDEV(Route, {
path: "/",
element: /*#__PURE__*/_jsxDEV(LoginPage, {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 415,
columnNumber: 34
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 415,
columnNumber: 9
}, this)]
}, void 0, true, {
fileName: _jsxFileName,
lineNumber: 411,
columnNumber: 7
}, this)
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 410,
columnNumber: 5
}, this);
}
// ============ 样式 ============
_c4 = App;
const styles = {
center: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: '100vh',
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'
},
container: {
maxWidth: '900px',
margin: '0 auto',
padding: '20px',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
},
header: {
display: 'flex',
alignItems: 'center',
gap: '15px',
marginBottom: '20px'
},
card: {
background: 'white',
borderRadius: '12px',
padding: '20px',
marginBottom: '20px',
boxShadow: '0 4px 6px rgba(0,0,0,0.1)'
},
infoCard: {
background: '#e7f3ff',
border: '1px solid #2196f3',
borderRadius: '12px',
padding: '15px',
marginBottom: '20px'
},
title: {
margin: '0 0 20px',
color: '#1a365d',
textAlign: 'center'
},
form: {
display: 'flex',
gap: '10px'
},
input: {
flex: 1,
padding: '12px',
border: '2px solid #e2e8f0',
borderRadius: '8px',
fontSize: '14px'
},
btn: {
padding: '12px 20px',
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
fontWeight: '600'
},
btnGreen: {
padding: '8px 16px',
background: 'linear-gradient(135deg, #11998e 0%, #38ef7d 100%)',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
marginRight: '8px'
},
btnRed: {
padding: '8px 16px',
background: 'linear-gradient(135deg, #eb3349 0%, #f45c43 100%)',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
marginRight: '8px'
},
btnBlue: {
padding: '8px 16px',
background: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer'
},
btnPink: {
padding: '8px 16px',
background: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer'
},
smallBtn: {
padding: '8px 16px',
background: '#edf2f7',
border: 'none',
borderRadius: '6px',
cursor: 'pointer'
},
list: {
display: 'flex',
flexDirection: 'column',
gap: '15px'
},
item: {
background: 'white',
borderRadius: '12px',
padding: '20px',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
boxShadow: '0 4px 6px rgba(0,0,0,0.1)'
},
link: {
color: '#4299e1',
textDecoration: 'none',
fontSize: '16px'
},
badge: {
background: '#667eea',
color: 'white',
padding: '4px 10px',
borderRadius: '20px',
fontSize: '12px',
fontWeight: '600'
},
btnGroup: {
display: 'flex',
marginTop: '10px'
},
seats: {
display: 'flex',
flexWrap: 'wrap',
gap: '15px',
justifyContent: 'center'
},
seat: {
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
padding: '15px',
borderRadius: '50%',
width: '90px',
height: '90px',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
textAlign: 'center',
cursor: 'pointer',
transition: 'transform 0.2s',
':hover': {
transform: 'scale(1.1)'
}
},
seatHover: {
transform: 'scale(1.05)'
},
seatEmoji: {
fontSize: '28px',
marginBottom: '5px'
},
seatName: {
fontSize: '12px',
fontWeight: '600'
},
hostBadge: {
fontSize: '10px',
opacity: '0.8'
},
messages: {
maxHeight: '400px',
overflowY: 'auto',
marginBottom: '15px'
},
msg: {
padding: '12px',
background: '#f7fafc',
borderRadius: '8px',
marginBottom: '10px'
},
msgHeader: {
display: 'flex',
justifyContent: 'space-between',
marginBottom: '5px'
},
msgContent: {
margin: '5px 0',
color: '#4a5568'
},
msgTime: {
fontSize: '12px',
color: '#a0aec0'
},
replyTag: {
fontSize: '11px',
color: '#a0aec0',
marginTop: '5px'
}
};
export default App;
var _c, _c2, _c3, _c4;
$RefreshReg$(_c, "LoginPage");
$RefreshReg$(_c2, "MeetingList");
$RefreshReg$(_c3, "MeetingRoom");
$RefreshReg$(_c4, "App");
const $ReactRefreshModuleId$ = __webpack_require__.$Refresh$.moduleId;
const $ReactRefreshCurrentExports$ = __react_refresh_utils__.getModuleExports(
$ReactRefreshModuleId$
);
function $ReactRefreshModuleRuntime$(exports) {
if (module.hot) {
let errorOverlay;
if (typeof __react_refresh_error_overlay__ !== 'undefined') {
errorOverlay = __react_refresh_error_overlay__;
}
let testMode;
if (typeof __react_refresh_test__ !== 'undefined') {
testMode = __react_refresh_test__;
}
return __react_refresh_utils__.executeRuntime(
exports,
$ReactRefreshModuleId$,
module.hot,
errorOverlay,
testMode
);
}
}
if (typeof Promise !== 'undefined' && $ReactRefreshCurrentExports$ instanceof Promise) {
$ReactRefreshCurrentExports$.then($ReactRefreshModuleRuntime$);
} else {
$ReactRefreshModuleRuntime$($ReactRefreshCurrentExports$);
}<1F><>{"version":3,"sources":["webpack://./src/App.js"],"names":["React","useState","useEffect","BrowserRouter","Router","Routes","Route","Link","useNavigate","useParams","axios","jsxDEV","_jsxDEV","API_BASE","interceptors","request","use","config","token","localStorage","getItem","headers","Authorization","LoginPage","_s","username","setUsername","password","setPassword","mode","setMode","agents","setAgents","selectedAgents","setSelectedAgents","navigate","scanAgents","res","get","data","error","console","handleLogin","e","preventDefault","payload","length","agent_ids","post","setItem","JSON","stringify","user","sessions","_error$response","_error$response$data","_error$response2","_error$response2$data","alert","response","detail","message","toggleAgent","agentId","prev","includes","filter","id","style","styles","center","children","card","title","fileName","_jsxFileName","lineNumber","columnNumber","onSubmit","form","flexDirection","type","placeholder","value","onChange","target","input","required","margin","display","marginBottom","fontWeight","cursor","padding","background","borderRadius","border","name","checked","color","fontSize","map","a","alignItems","agent_id","marginRight","agent_emoji","marginLeft","instance_name","marginTop","btn","_c","MeetingList","_s2","meetings","setMeetings","topic","setTopic","autoAddAgents","setAutoAddAgents","fetchMeetings","createMeeting","parse","agentIds","s","session_type","auto_add_virtual_agents","host_agent_id","_error$response3","_error$response3$data","logout","removeItem","container","header","onClick","smallBtn","gap","whiteSpace","list","m","item","status","invite_code","_c2","MeetingRoom","_s3","messages","setMessages","content","setContent","participants","setParticipants","meeting","setMeeting","hoveredSeat","setHoveredSeat","fetchMeeting","fetchParticipants","fetchMessages","interval","setInterval","clearInterval","sendMessage","trim","_error$response4","_error$response4$data","mentionAgent","targetAgentId","agentName","prompt","target_agent_id","sender_name","_error$response5","_error$response5$data","startMeeting","_error$response6","_error$response6$data","endMeeting","confirm","_error$response7","_error$response7$data","generateMinutes","blob","Blob","markdown","url","URL","createObjectURL","document","createElement","href","download","slice","click","revokeObjectURL","to","link","badge","infoCard","btnGroup","btnGreen","btnRed","btnBlue","seats","p","seat","seatHover","_document$querySelect","nickname","querySelector","focus","onMouseEnter","onMouseLeave","seatEmoji","seatName","is_host","hostBadge","msg","msgHeader","sender_emoji","msgTime","Date","created_at","toLocaleTimeString","msgContent","in_reply_to","replyTag","btnPink","_c3","App","path","element","_c4","justifyContent","minHeight","maxWidth","fontFamily","boxShadow","textAlign","flex","textDecoration","flexWrap","width","height","transition","transform","opacity","maxHeight","overflowY","$RefreshReg$"],"mappings":";;;;;;AAAA,OAAOA,KAAK,IAAIC,QAAQ,EAAEC,SAAS,QAAQ,OAAO;AAClD,SAASC,aAAa,IAAIC,MAAM,EAAEC,MAAM,EAAEC,KAAK,EAAEC,IAAI,EAAEC,WAAW,EAAEC,SAAS,QAAQ,kBAAkB;AACvG,OAAOC,KAAK,MAAM,OAAO;AAAC,SAAAC,MAAA,IAAAC,OAAA;AAE1B,MAAMC,QAAQ,GAAG,8BAA8B;AAE/CH,KAAK,CAACI,YAAY,CAACC,OAAO,CAACC,GAAG,CAACC,MAAM,IAAI;EACvC,MAAMC,KAAK,GAAGC,YAAY,CAACC,OAAO,CAAC,OAAO,CAAC;EAC3C,IAAIF,KAAK,EAAED,MAAM,CAACI,OAAO,CAACC,aAAa,GAAG,UAAUJ,KAAK,EAAE;EAC3D,OAAOD,MAAM;AACf,CAAC,CAAC;;AAEF;AACA,SAASM,SAASA,CAAA,EAAG;EAAAC,EAAA;EACnB,MAAM,CAACC,QAAQ,EAAEC,WAAW,CAAC,GAAGzB,QAAQ,CAAC,MAAM,CAAC;EAChD,MAAM,CAAC0B,QAAQ,EAAEC,WAAW,CAAC,GAAG3B,QAAQ,CAAC,SAAS,CAAC;EACnD,MAAM,CAAC4B,IAAI,EAAEC,OAAO,CAAC,GAAG7B,QAAQ,CAAC,MAAM,CAAC;EACxC,MAAM,CAAC8B,MAAM,EAAEC,SAAS,CAAC,GAAG/B,QAAQ,CAAC,EAAE,CAAC;EACxC,MAAM,CAACgC,cAAc,EAAEC,iBAAiB,CAAC,GAAGjC,QAAQ,CAAC,EAAE,CAAC;EACxD,MAAMkC,QAAQ,GAAG3B,WAAW,CAAC,CAAC;;EAE9B;EACAN,SAAS,CAAC,MAAM;IACd,IAAIuB,QAAQ,EAAE;MACZW,UAAU,CAAC,CAAC;IACd;EACF,CAAC,EAAE,CAACX,QAAQ,CAAC,CAAC;EAEd,MAAMW,UAAU,GAAG,MAAAA,CAAA,KAAY;IAC7B,IAAI;MACF;MACA,MAAMC,GAAG,GAAG,MAAM3B,KAAK,CAAC4B,GAAG,CAAC,GAAGzB,QAAQ,qCAAqCY,QAAQ,EA