feat: 首页开发

This commit is contained in:
2026-04-12 10:34:33 +08:00
parent a2a3bd2bee
commit 9a91093325
3 changed files with 83 additions and 34 deletions

View File

@@ -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()}`));

View File

@@ -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();
}
}

View File

@@ -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>