feat: 首页开发
This commit is contained in:
@@ -103,12 +103,18 @@ function buildEnv(exeDir) {
|
||||
}
|
||||
|
||||
function getExePath() {
|
||||
// 开发模式:__dirname = .vite/build,往上两级到项目根
|
||||
// 打包模式:用 process.resourcesPath
|
||||
// 根据平台和架构确定可执行文件名及目录
|
||||
const isWin = process.platform === 'win32';
|
||||
const exeName = isWin ? 'opencode.exe' : 'opencode';
|
||||
|
||||
if (app.isPackaged) {
|
||||
return path.join(process.resourcesPath, 'opencode.exe');
|
||||
return path.join(process.resourcesPath, exeName);
|
||||
}
|
||||
return path.join(__dirname, '..', '..', 'resources', 'windows', 'x64', 'opencode.exe');
|
||||
|
||||
// 开发模式:__dirname = .vite/build,往上两级到项目根
|
||||
const platformDir = process.platform === 'darwin' ? 'darwin' : 'windows';
|
||||
const archDir = process.arch === 'arm64' ? 'arm64' : 'x64';
|
||||
return path.join(__dirname, '..', '..', 'resources', platformDir, archDir, exeName);
|
||||
}
|
||||
|
||||
async function startOpencode() {
|
||||
@@ -121,11 +127,16 @@ async function startOpencode() {
|
||||
const exeDir = path.dirname(exePath);
|
||||
await fs.promises.access(exePath, fs.constants.F_OK);
|
||||
|
||||
// macOS/Linux 需要确保可执行权限
|
||||
if (process.platform !== 'win32') {
|
||||
await fs.promises.chmod(exePath, 0o755);
|
||||
}
|
||||
|
||||
opencodePort = await resolvePort();
|
||||
opencodeProcess = spawn(exePath, ['serve', '--port', String(opencodePort)], {
|
||||
cwd: exeDir,
|
||||
windowsHide: true,
|
||||
env: buildEnv(exeDir),
|
||||
...(process.platform === 'win32' ? { windowsHide: true } : {}),
|
||||
});
|
||||
|
||||
opencodeProcess.stdout?.on('data', (d) => console.log(`[opencode] ${d.toString().trim()}`));
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
appStore.collapsed ? 'justify-center px-0 py-3 mx-auto w-11 rounded-xl' : 'w-[216px] h-[37px] rounded-[10px] pl-3 pr-[146px] py-0 mx-auto',
|
||||
$route.path === item.index ? 'bg-[#DEE0E4] text-gray-900' : 'text-gray-500 hover:bg-gray-50 hover:text-gray-700',
|
||||
]"
|
||||
@click="router.push(item.index)"
|
||||
@click="handleMenuClick(item)"
|
||||
>
|
||||
<!-- 图标 -->
|
||||
<div
|
||||
@@ -34,7 +34,7 @@
|
||||
<el-divider></el-divider>
|
||||
<div class="w-54 h-8 text-sm mx-3 py-4 flex items-center" style="color: #8a9097">历史记录</div>
|
||||
<div
|
||||
v-for="(item, index) in historyItems"
|
||||
v-for="(item, index) in historyStore.historyItems"
|
||||
:key="index"
|
||||
class="flex items-center w-[216px] h-[37px] justify-between rounded-[10px] pl-3 pr-3 mx-auto text-gray-500 hover:bg-gray-50 hover:text-gray-700 cursor-pointer transition-all duration-200"
|
||||
@click="onHistoryClick(item)"
|
||||
@@ -91,12 +91,14 @@
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useAppStore } from '@/stores/app';
|
||||
import { useHistoryStore } from '@/stores/history';
|
||||
import { House, Monitor, Expand, Fold, ChatDotRound, Search, Collection, Clock } from '@element-plus/icons-vue';
|
||||
import router from '@/router';
|
||||
import axios from 'axios';
|
||||
|
||||
const route = useRoute();
|
||||
const appStore = useAppStore();
|
||||
const historyStore = useHistoryStore();
|
||||
|
||||
const menus = ref([
|
||||
{ name: '新对话', index: '/', icon: 'plus' },
|
||||
@@ -105,32 +107,19 @@ const menus = ref([
|
||||
{ name: '发现设备', index: '/bonjour', icon: 'server' },
|
||||
]);
|
||||
|
||||
const historyItems = ref([]);
|
||||
// 处理菜单点击
|
||||
function handleMenuClick(item) {
|
||||
if (item.index) {
|
||||
router.push(item.index);
|
||||
}
|
||||
}
|
||||
|
||||
const isServiceRunning = ref(false);
|
||||
let checkInterval = null;
|
||||
|
||||
// 查询历史会话列表
|
||||
async function loadHistorySessions() {
|
||||
console.log('[loadHistorySessions] 开始加载历史会话...');
|
||||
try {
|
||||
const baseUrl = window.__opencodeBaseUrl || 'http://127.0.0.1:4096';
|
||||
console.log('[loadHistorySessions] baseUrl:', baseUrl);
|
||||
const response = await axios.get(`${baseUrl}/session`);
|
||||
console.log('[loadHistorySessions] 响应数据:', response.data);
|
||||
const sessions = response.data || [];
|
||||
console.log('[loadHistorySessions] 会话数量:', sessions.length);
|
||||
// 将会话列表转换为历史记录格式
|
||||
historyItems.value = sessions.map((session) => ({
|
||||
id: session.id,
|
||||
name: session.title || `会话 ${session.slug || session.id.slice(0, 8)}...`,
|
||||
slug: session.slug,
|
||||
created: session.time?.created,
|
||||
updated: session.time?.updated,
|
||||
}));
|
||||
console.log('[loadHistorySessions] 转换后的历史记录:', historyItems.value);
|
||||
} catch (err) {
|
||||
console.error('[loadHistorySessions] 加载历史会话失败:', err);
|
||||
}
|
||||
await historyStore.loadHistorySessions();
|
||||
}
|
||||
|
||||
// 点击历史会话,跳转到对话页面并加载该会话
|
||||
@@ -167,7 +156,7 @@ async function stopService() {
|
||||
try {
|
||||
await window.opencode.stop();
|
||||
isServiceRunning.value = false;
|
||||
historyItems.value = [];
|
||||
historyStore.clearHistory();
|
||||
} catch (err) {
|
||||
console.error('停止服务失败:', err);
|
||||
}
|
||||
@@ -188,17 +177,17 @@ async function checkServiceStatus() {
|
||||
window.__opencodeBaseUrl = info.url;
|
||||
}
|
||||
// 如果历史记录为空,则加载
|
||||
if (historyItems.value.length === 0) {
|
||||
if (historyStore.historyItems.length === 0) {
|
||||
loadHistorySessions();
|
||||
}
|
||||
} else {
|
||||
// 服务未运行,清空历史记录
|
||||
historyItems.value = [];
|
||||
historyStore.clearHistory();
|
||||
}
|
||||
} catch (err) {
|
||||
// 获取状态失败,视为服务断开
|
||||
isServiceRunning.value = false;
|
||||
historyItems.value = [];
|
||||
historyStore.clearHistory();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,13 @@
|
||||
<!-- 底部:输入框 -->
|
||||
<div class="input-section">
|
||||
<div class="input-wrapper">
|
||||
<textarea class="input-textarea" placeholder="描述任务,/ 调用技能与工具,@调用知识库"></textarea>
|
||||
<textarea
|
||||
v-model="inputText"
|
||||
class="input-textarea"
|
||||
placeholder="描述任务,/ 调用技能与工具,@调用知识库"
|
||||
:disabled="isCreating"
|
||||
@keydown="handleKeydown"
|
||||
></textarea>
|
||||
<div class="input-toolbar">
|
||||
<div class="toolbar-left">
|
||||
<button class="toolbar-btn file-btn">
|
||||
@@ -53,7 +59,7 @@
|
||||
<button class="toolbar-btn symbol-btn">@</button>
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
<button class="send-btn">
|
||||
<button class="send-btn" :disabled="!inputText.trim() || isCreating" @click="handleSend">
|
||||
<el-icon><Promotion /></el-icon>
|
||||
</button>
|
||||
</div>
|
||||
@@ -64,7 +70,50 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useHistoryStore } from '@/stores/history';
|
||||
import { Document, Plus, Promotion } from '@element-plus/icons-vue';
|
||||
|
||||
const router = useRouter();
|
||||
const historyStore = useHistoryStore();
|
||||
const inputText = ref('');
|
||||
const isCreating = ref(false);
|
||||
|
||||
// 处理发送消息
|
||||
async function handleSend() {
|
||||
const text = inputText.value.trim();
|
||||
if (!text || isCreating.value) return;
|
||||
|
||||
isCreating.value = true;
|
||||
try {
|
||||
// 创建会话,title 使用用户输入的文本
|
||||
const session = await historyStore.createSession(text);
|
||||
console.log('创建会话成功:', session);
|
||||
|
||||
// 清空输入框
|
||||
inputText.value = '';
|
||||
|
||||
// 跳转到对话页面
|
||||
router.push({
|
||||
path: '/chat',
|
||||
query: { sessionId: session.id },
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('创建会话失败:', err);
|
||||
} finally {
|
||||
isCreating.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理键盘事件
|
||||
function handleKeydown(e) {
|
||||
// Enter 发送,Shift+Enter 换行
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
handleSend();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user