refactor: 重构项目结构和代码组织
This commit is contained in:
@@ -1,51 +0,0 @@
|
||||
# Dependencies
|
||||
node_modules/
|
||||
|
||||
# Build output
|
||||
dist/
|
||||
build/
|
||||
|
||||
# Environment files
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Logs
|
||||
logs/
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Data
|
||||
data/
|
||||
|
||||
# Git
|
||||
.git/
|
||||
.gitignore
|
||||
|
||||
# Docker
|
||||
Dockerfile
|
||||
docker-compose*.yml
|
||||
.dockerignore
|
||||
|
||||
# Documentation
|
||||
*.md
|
||||
docs/
|
||||
|
||||
# Tests
|
||||
test/
|
||||
tests/
|
||||
coverage/
|
||||
|
||||
# Misc
|
||||
*.tmp
|
||||
*.temp
|
||||
61
.gitignore
vendored
61
.gitignore
vendored
@@ -1,61 +0,0 @@
|
||||
# Dependencies
|
||||
node_modules/
|
||||
.pnp
|
||||
.pnp.js
|
||||
|
||||
# Testing
|
||||
coverage/
|
||||
*.lcov
|
||||
|
||||
# Production builds
|
||||
dist/
|
||||
build/
|
||||
server/dist/
|
||||
client/dist/
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
!.env.example
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Logs
|
||||
logs/
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Data persistence
|
||||
data/
|
||||
*.db
|
||||
*.sqlite
|
||||
|
||||
# Temporary files
|
||||
tmp/
|
||||
temp/
|
||||
*.tmp
|
||||
*.temp
|
||||
|
||||
# Docker
|
||||
docker-compose.override.yml
|
||||
|
||||
# Secrets
|
||||
*.pem
|
||||
*.key
|
||||
secrets/
|
||||
|
||||
# Shared types build output
|
||||
shared/dist/
|
||||
5
.idea/.gitignore
generated
vendored
Normal file
5
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
6
.idea/encodings.xml
generated
Normal file
6
.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/make.bat" charset="GB2312" />
|
||||
</component>
|
||||
</project>
|
||||
12
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
12
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredIdentifiers">
|
||||
<list>
|
||||
<option value="requests.models.Response.__getitem__" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/sillytavern-repalice.iml" filepath="$PROJECT_DIR$/.idea/sillytavern-repalice.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/sillytavern-repalice.iml
generated
Normal file
8
.idea/sillytavern-repalice.iml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,254 +0,0 @@
|
||||
# 项目架构检查报告
|
||||
|
||||
## ✅ 架构合理性评估
|
||||
|
||||
### **1. 整体结构评分:9/10** ⭐⭐⭐⭐⭐
|
||||
|
||||
---
|
||||
|
||||
## 📁 目录结构分析
|
||||
|
||||
### **✅ 优点**
|
||||
|
||||
#### **1. 清晰的三层架构**
|
||||
```
|
||||
project/
|
||||
├── server/ # 后端 (NestJS)
|
||||
├── client/ # 前端 (Vue3)
|
||||
├── shared/ # 共享类型系统
|
||||
├── data/ # 持久化数据
|
||||
├── docker/ # Docker 配置
|
||||
└── docs/ # 文档
|
||||
```
|
||||
- ✅ 前后端分离明确
|
||||
- ✅ 共享类型独立管理
|
||||
- ✅ 数据和配置隔离
|
||||
|
||||
#### **2. 后端模块化设计 (DDD)**
|
||||
```
|
||||
server/src/
|
||||
├── core/ # 核心基础设施层
|
||||
├── modules/ # 业务模块层
|
||||
├── shared/ # 共享工具层
|
||||
├── events/ # 事件系统
|
||||
├── queues/ # 任务队列
|
||||
└── common/ # 通用基类
|
||||
```
|
||||
- ✅ 符合领域驱动设计
|
||||
- ✅ 职责分离清晰
|
||||
- ✅ 易于扩展和维护
|
||||
|
||||
#### **3. 模块内部结构标准**
|
||||
```
|
||||
modules/{module}/
|
||||
├── controllers/ # API 控制器
|
||||
├── services/ # 业务逻辑
|
||||
├── adapters/ # 格式转换适配器
|
||||
├── dto/ # 数据传输对象
|
||||
└── interfaces/ # 接口定义
|
||||
```
|
||||
- ✅ 遵循 MVC 模式
|
||||
- ✅ 适配器模式实现良好
|
||||
- ✅ 依赖注入友好
|
||||
|
||||
#### **4. 前端分层合理**
|
||||
```
|
||||
client/src/
|
||||
├── api/ # API 客户端层
|
||||
├── components/ # UI 组件层
|
||||
├── views/ # 页面视图层
|
||||
├── composables/ # 组合式函数
|
||||
├── stores/ # 状态管理
|
||||
├── router/ # 路由配置
|
||||
├── types/ # 类型定义
|
||||
└── utils/ # 工具函数
|
||||
```
|
||||
- ✅ 符合 Vue3 最佳实践
|
||||
- ✅ 关注点分离
|
||||
- ✅ 可复用性强
|
||||
|
||||
#### **5. 共享类型系统设计**
|
||||
```
|
||||
shared/types/
|
||||
├── sillytavern/ # ST 原生格式(兼容层)
|
||||
├── extended/ # 扩展格式(增强层)
|
||||
├── adapters/ # 适配器接口
|
||||
└── index.ts # 统一导出
|
||||
```
|
||||
- ✅ 双层格式设计优秀
|
||||
- ✅ 完全兼容 SillyTavern
|
||||
- ✅ 扩展性强
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 需要改进的地方
|
||||
|
||||
### **1. 缺少配置文件**
|
||||
```
|
||||
❌ server/.env.example
|
||||
❌ client/.env.example
|
||||
❌ server/tsconfig.build.json (已有但需检查)
|
||||
```
|
||||
|
||||
**建议:**
|
||||
- 创建 `.env.example` 模板文件
|
||||
- 确保所有必要的环境变量都有文档
|
||||
|
||||
### **2. 模块完整性不一致**
|
||||
|
||||
**完整的模块:**
|
||||
- ✅ `chat/` - 有 adapters
|
||||
- ✅ `world-info/` - 有 adapters
|
||||
- ✅ `preset/` - 有 adapters
|
||||
|
||||
**不完整的模块:**
|
||||
- ⚠️ `auth/` - 缺少 adapters
|
||||
- ⚠️ `llm/` - 缺少 adapters
|
||||
- ⚠️ `workflow/` - 缺少 adapters
|
||||
- ⚠️ `data-store/` - 缺少 adapters
|
||||
- ⚠️ `file-management/` - 缺少 adapters
|
||||
- ⚠️ `import-export/` - 缺少 adapters
|
||||
|
||||
**建议:**
|
||||
为每个模块添加标准的子目录结构,即使暂时为空。
|
||||
|
||||
### **3. 前端目录有空文件夹**
|
||||
```
|
||||
client/src/
|
||||
├── composables/ # 空
|
||||
├── plugins/ # 空
|
||||
├── services/ # 空
|
||||
└── store/ # 空(应该是 stores/)
|
||||
```
|
||||
|
||||
**建议:**
|
||||
- 删除空的 `store/` 目录(已有 `stores/`)
|
||||
- 在 `composables/` 中添加基础 composable
|
||||
- 在 `plugins/` 中添加必要的插件
|
||||
|
||||
### **4. 缺少测试目录结构**
|
||||
```
|
||||
tests/ # 空
|
||||
```
|
||||
|
||||
**建议:**
|
||||
```
|
||||
tests/
|
||||
├── unit/ # 单元测试
|
||||
├── integration/ # 集成测试
|
||||
└── e2e/ # 端到端测试
|
||||
```
|
||||
|
||||
### **5. Docker 配置可以优化**
|
||||
|
||||
**当前配置:**
|
||||
- ✅ 开发环境热重载配置正确
|
||||
- ✅ 端口映射合理(23337, 23338)
|
||||
- ✅ 卷挂载正确
|
||||
|
||||
**建议改进:**
|
||||
- 添加 `.dockerignore` 文件
|
||||
- 考虑添加 Nginx 反向代理(生产环境)
|
||||
- 添加日志卷挂载
|
||||
|
||||
---
|
||||
|
||||
## 🎯 架构优势总结
|
||||
|
||||
### **1. 数据类型设计优秀** ⭐⭐⭐⭐⭐
|
||||
- 双层格式(ST + Extended)
|
||||
- 适配器模式实现完善
|
||||
- 完全向后兼容
|
||||
|
||||
### **2. 模块化程度高** ⭐⭐⭐⭐⭐
|
||||
- 每个模块独立
|
||||
- 低耦合高内聚
|
||||
- 易于团队协作
|
||||
|
||||
### **3. 技术栈选择合理** ⭐⭐⭐⭐⭐
|
||||
- NestJS + Vue3 = 现代全栈
|
||||
- TypeScript 全程类型安全
|
||||
- Docker 容器化部署
|
||||
|
||||
### **4. 可扩展性强** ⭐⭐⭐⭐⭐
|
||||
- 事件系统预留
|
||||
- 任务队列预留
|
||||
- 微服务演进可能
|
||||
|
||||
### **5. 开发体验好** ⭐⭐⭐⭐
|
||||
- 热重载支持
|
||||
- 路径别名配置
|
||||
- 类型提示完整
|
||||
|
||||
---
|
||||
|
||||
## 📋 建议的改进清单
|
||||
|
||||
### **高优先级**
|
||||
1. ✅ 创建 `.env.example` 文件
|
||||
2. ✅ 统一模块目录结构
|
||||
3. ✅ 清理空文件夹
|
||||
4. ✅ 添加 `.dockerignore`
|
||||
|
||||
### **中优先级**
|
||||
5. ⏳ 创建基础 Composables
|
||||
6. ⏳ 添加单元测试框架
|
||||
7. ⏳ 完善 Docker 配置
|
||||
8. ⏳ 添加 CI/CD 配置
|
||||
|
||||
### **低优先级**
|
||||
9. 📝 编写 API 文档
|
||||
10. 📝 添加部署指南
|
||||
11. 📝 创建贡献指南
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Docker 配置说明
|
||||
|
||||
### **端口映射**
|
||||
- 后端:`23337:3000` (宿主机 23337 → 容器 3000)
|
||||
- 前端:`23338:5173` (宿主机 23338 → 容器 5173)
|
||||
|
||||
### **热重载支持**
|
||||
```yaml
|
||||
volumes:
|
||||
- ./server:/usr/src/app # 代码挂载
|
||||
- ./shared:/usr/src/shared # 共享类型挂载
|
||||
- /usr/src/app/node_modules # 排除 node_modules
|
||||
```
|
||||
|
||||
### **数据持久化**
|
||||
```yaml
|
||||
volumes:
|
||||
- ./data:/usr/src/app/data # 数据库和文件
|
||||
- ./.env:/usr/src/app/.env:ro # 环境变量(只读)
|
||||
```
|
||||
|
||||
### **健康检查**
|
||||
```yaml
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/api"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 总体评价
|
||||
|
||||
**架构评分:9/10**
|
||||
|
||||
**优点:**
|
||||
- 设计思路清晰
|
||||
- 技术选型现代
|
||||
- 可扩展性强
|
||||
- 兼容性好
|
||||
|
||||
**待改进:**
|
||||
- 部分模块不完整
|
||||
- 缺少一些配置文件
|
||||
- 测试框架未搭建
|
||||
|
||||
**结论:**
|
||||
整体架构非常合理,具备良好的可扩展性和维护性。只需补充一些细节即可投入开发。
|
||||
@@ -1,6 +0,0 @@
|
||||
node_modules
|
||||
dist
|
||||
.env
|
||||
.git
|
||||
.idea
|
||||
.vscode
|
||||
@@ -1,37 +0,0 @@
|
||||
# =====================================================
|
||||
# API Configuration
|
||||
# =====================================================
|
||||
VITE_API_URL=http://localhost:23337/api
|
||||
VITE_WS_URL=ws://localhost:23337
|
||||
|
||||
# =====================================================
|
||||
# Application Configuration
|
||||
# =====================================================
|
||||
VITE_APP_NAME=SillyTavern Replace
|
||||
VITE_APP_VERSION=1.0.0
|
||||
|
||||
# =====================================================
|
||||
# Feature Flags
|
||||
# =====================================================
|
||||
VITE_ENABLE_WEBSOCKET=true
|
||||
VITE_ENABLE_SSE=true
|
||||
|
||||
# =====================================================
|
||||
# LLM Configuration (Public - Safe to Expose)
|
||||
# =====================================================
|
||||
VITE_DEFAULT_LLM_PROVIDER=openai
|
||||
VITE_MAX_TOKENS=4096
|
||||
VITE_DEFAULT_TEMPERATURE=0.7
|
||||
|
||||
# =====================================================
|
||||
# UI Configuration
|
||||
# =====================================================
|
||||
VITE_THEME=light
|
||||
VITE_LANGUAGE=zh-CN
|
||||
VITE_ITEMS_PER_PAGE=20
|
||||
|
||||
# =====================================================
|
||||
# Upload Configuration
|
||||
# =====================================================
|
||||
VITE_MAX_UPLOAD_SIZE=10485760
|
||||
VITE_ALLOWED_FILE_TYPES=.json,.csv,.txt,.md,.png,.jpg
|
||||
@@ -1,17 +0,0 @@
|
||||
# Development Dockerfile for Frontend (Vue3 + Vite)
|
||||
FROM node:20-alpine
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm install
|
||||
|
||||
# Expose Vite dev server port
|
||||
EXPOSE 5173
|
||||
|
||||
# Default command (will be overridden by docker-compose)
|
||||
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "5173"]
|
||||
@@ -1,42 +0,0 @@
|
||||
# client
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VS Code](https://code.visualstudio.com/) + [Vue (Official)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
|
||||
|
||||
## Recommended Browser Setup
|
||||
|
||||
- Chromium-based browsers (Chrome, Edge, Brave, etc.):
|
||||
- [Vue.js devtools](https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd)
|
||||
- [Turn on Custom Object Formatter in Chrome DevTools](http://bit.ly/object-formatters)
|
||||
- Firefox:
|
||||
- [Vue.js devtools](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/)
|
||||
- [Turn on Custom Object Formatter in Firefox DevTools](https://fxdx.dev/firefox-devtools-custom-object-formatters/)
|
||||
|
||||
## Type Support for `.vue` Imports in TS
|
||||
|
||||
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
|
||||
|
||||
## Customize configuration
|
||||
|
||||
See [Vite Configuration Reference](https://vite.dev/config/).
|
||||
|
||||
## Project Setup
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compile and Hot-Reload for Development
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Type-Check, Compile and Minify for Production
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
1
client/env.d.ts
vendored
1
client/env.d.ts
vendored
@@ -1 +0,0 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
3148
client/package-lock.json
generated
3148
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"name": "client",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check \"build-only {@}\" --",
|
||||
"preview": "vite preview",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --build"
|
||||
},
|
||||
"dependencies": {
|
||||
"pinia": "^3.0.4",
|
||||
"vue": "^3.5.32",
|
||||
"vue-router": "^5.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/node24": "^24.0.4",
|
||||
"@types/node": "^24.12.2",
|
||||
"@vitejs/plugin-vue": "^6.0.6",
|
||||
"@vitejs/plugin-vue-jsx": "^5.1.5",
|
||||
"@vue/tsconfig": "^0.9.1",
|
||||
"npm-run-all2": "^8.0.4",
|
||||
"typescript": "~6.0.0",
|
||||
"vite": "^8.0.8",
|
||||
"vite-plugin-vue-devtools": "^8.1.1",
|
||||
"vue-tsc": "^3.2.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -1,41 +0,0 @@
|
||||
<template>
|
||||
<div class="app-layout">
|
||||
<!-- 顶部工具栏 -->
|
||||
<TopToolbar />
|
||||
|
||||
<!-- 主体内容区 -->
|
||||
<div class="main-content">
|
||||
<!-- 左侧面板 -->
|
||||
<LeftPanel />
|
||||
|
||||
<!-- 中间聊天区 -->
|
||||
<CenterChat />
|
||||
|
||||
<!-- 右侧工具面板 -->
|
||||
<RightPanel />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import TopToolbar from './components/layout/TopToolbar.vue';
|
||||
import LeftPanel from './components/layout/LeftPanel.vue';
|
||||
import CenterChat from './components/layout/CenterChat.vue';
|
||||
import RightPanel from './components/layout/RightPanel.vue';
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-layout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
0
client/src/api/index.ts
Normal file
0
client/src/api/index.ts
Normal file
@@ -1,86 +0,0 @@
|
||||
/* color palette from <https://github.com/vuejs/theme> */
|
||||
:root {
|
||||
--vt-c-white: #ffffff;
|
||||
--vt-c-white-soft: #f8f8f8;
|
||||
--vt-c-white-mute: #f2f2f2;
|
||||
|
||||
--vt-c-black: #181818;
|
||||
--vt-c-black-soft: #222222;
|
||||
--vt-c-black-mute: #282828;
|
||||
|
||||
--vt-c-indigo: #2c3e50;
|
||||
|
||||
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
||||
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
||||
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
||||
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
||||
|
||||
--vt-c-text-light-1: var(--vt-c-indigo);
|
||||
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
||||
--vt-c-text-dark-1: var(--vt-c-white);
|
||||
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
||||
}
|
||||
|
||||
/* semantic color variables for this project */
|
||||
:root {
|
||||
--color-background: var(--vt-c-white);
|
||||
--color-background-soft: var(--vt-c-white-soft);
|
||||
--color-background-mute: var(--vt-c-white-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-light-2);
|
||||
--color-border-hover: var(--vt-c-divider-light-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-light-1);
|
||||
--color-text: var(--vt-c-text-light-1);
|
||||
|
||||
--section-gap: 160px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-background: var(--vt-c-black);
|
||||
--color-background-soft: var(--vt-c-black-soft);
|
||||
--color-background-mute: var(--vt-c-black-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-dark-2);
|
||||
--color-border-hover: var(--vt-c-divider-dark-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-dark-1);
|
||||
--color-text: var(--vt-c-text-dark-2);
|
||||
}
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
color: var(--color-text);
|
||||
background: var(--color-background);
|
||||
transition:
|
||||
color 0.5s,
|
||||
background-color 0.5s;
|
||||
line-height: 1.6;
|
||||
font-family:
|
||||
Inter,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
'Segoe UI',
|
||||
Roboto,
|
||||
Oxygen,
|
||||
Ubuntu,
|
||||
Cantarell,
|
||||
'Fira Sans',
|
||||
'Droid Sans',
|
||||
'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-size: 15px;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
0
client/src/assets/logo.png
Normal file
0
client/src/assets/logo.png
Normal file
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
||||
|
Before Width: | Height: | Size: 276 B |
@@ -1,35 +0,0 @@
|
||||
@import './base.css';
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a,
|
||||
.green {
|
||||
text-decoration: none;
|
||||
color: hsla(160, 100%, 37%, 1);
|
||||
transition: 0.4s;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
a:hover {
|
||||
background-color: hsla(160, 100%, 37%, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
body {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
}
|
||||
0
client/src/components/CenterPanel/CenterPanel.vue
Normal file
0
client/src/components/CenterPanel/CenterPanel.vue
Normal file
0
client/src/components/CenterPanel/center-panel.css
Normal file
0
client/src/components/CenterPanel/center-panel.css
Normal file
0
client/src/components/CenterPanel/useCenterPanel.ts
Normal file
0
client/src/components/CenterPanel/useCenterPanel.ts
Normal file
0
client/src/components/LeftPanel/LeftPanel.vue
Normal file
0
client/src/components/LeftPanel/LeftPanel.vue
Normal file
0
client/src/components/LeftPanel/left-panel.css
Normal file
0
client/src/components/LeftPanel/left-panel.css
Normal file
0
client/src/components/LeftPanel/useLeftPanel.ts
Normal file
0
client/src/components/LeftPanel/useLeftPanel.ts
Normal file
0
client/src/components/RightPanel/RightPanel.vue
Normal file
0
client/src/components/RightPanel/RightPanel.vue
Normal file
0
client/src/components/RightPanel/right-panel.css
Normal file
0
client/src/components/RightPanel/right-panel.css
Normal file
0
client/src/components/RightPanel/useRightPanel.ts
Normal file
0
client/src/components/RightPanel/useRightPanel.ts
Normal file
0
client/src/components/TopBar/TopBar.vue
Normal file
0
client/src/components/TopBar/TopBar.vue
Normal file
0
client/src/components/TopBar/top-bar.css
Normal file
0
client/src/components/TopBar/top-bar.css
Normal file
0
client/src/components/TopBar/useTopBar.ts
Normal file
0
client/src/components/TopBar/useTopBar.ts
Normal file
0
client/src/components/common/BaseIcon/BaseIcon.vue
Normal file
0
client/src/components/common/BaseIcon/BaseIcon.vue
Normal file
0
client/src/components/common/BaseIcon/base-icon.css
Normal file
0
client/src/components/common/BaseIcon/base-icon.css
Normal file
@@ -1,72 +0,0 @@
|
||||
<template>
|
||||
<div :class="['message-item', message.senderRole]">
|
||||
<div class="message-header">
|
||||
<span class="sender-name">{{ message.senderName }}</span>
|
||||
<span class="timestamp">{{ formatTime(message.timestamp) }}</span>
|
||||
</div>
|
||||
<div class="message-content">{{ message.mes }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
interface Message {
|
||||
id: string;
|
||||
senderName: string;
|
||||
senderRole: 'user' | 'assistant' | 'system';
|
||||
mes: string;
|
||||
timestamp: Date;
|
||||
}
|
||||
|
||||
defineProps<{
|
||||
message: Message;
|
||||
}>();
|
||||
|
||||
function formatTime(date: Date) {
|
||||
return new Date(date).toLocaleTimeString('zh-CN', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.message-item {
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 8px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.message-item.user {
|
||||
background: #e3f2fd;
|
||||
border-color: #bbdefb;
|
||||
margin-left: 20%;
|
||||
}
|
||||
|
||||
.message-item.assistant {
|
||||
background: #f1f8e9;
|
||||
border-color: #dcedc8;
|
||||
margin-right: 20%;
|
||||
}
|
||||
|
||||
.message-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
font-size: 12px;
|
||||
color: #7f8c8d;
|
||||
}
|
||||
|
||||
.sender-name {
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
line-height: 1.6;
|
||||
white-space: pre-wrap;
|
||||
font-size: 14px;
|
||||
color: #2c3e50;
|
||||
}
|
||||
</style>
|
||||
@@ -1,21 +0,0 @@
|
||||
<template>
|
||||
<div class="api-config-view">
|
||||
<h3>🔌 API 配置</h3>
|
||||
<p>API 配置管理界面</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.api-config-view {
|
||||
padding: 8px;
|
||||
}
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
color: #2c3e50;
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
p {
|
||||
font-size: 13px;
|
||||
color: #7f8c8d;
|
||||
}
|
||||
</style>
|
||||
@@ -1,21 +0,0 @@
|
||||
<template>
|
||||
<div class="gallery-view">
|
||||
<h3>🖼️ 画廊</h3>
|
||||
<p>LLM 生成的图片将显示在这里</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.gallery-view {
|
||||
padding: 8px;
|
||||
}
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
color: #2c3e50;
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
p {
|
||||
font-size: 13px;
|
||||
color: #7f8c8d;
|
||||
}
|
||||
</style>
|
||||
@@ -1,21 +0,0 @@
|
||||
<template>
|
||||
<div class="preset-view">
|
||||
<h3>⚙️ 预设管理</h3>
|
||||
<p>预设配置和条目展示</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.preset-view {
|
||||
padding: 8px;
|
||||
}
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
color: #2c3e50;
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
p {
|
||||
font-size: 13px;
|
||||
color: #7f8c8d;
|
||||
}
|
||||
</style>
|
||||
@@ -1,21 +0,0 @@
|
||||
<template>
|
||||
<div class="world-book-view">
|
||||
<h3>📚 世界书管理</h3>
|
||||
<p>全局世界书激活和条目管理</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.world-book-view {
|
||||
padding: 8px;
|
||||
}
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
color: #2c3e50;
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
p {
|
||||
font-size: 13px;
|
||||
color: #7f8c8d;
|
||||
}
|
||||
</style>
|
||||
@@ -1,21 +0,0 @@
|
||||
<template>
|
||||
<div class="dice-view">
|
||||
<h3>🎲 骰子工具</h3>
|
||||
<p>纯前端骰子功能</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.dice-view {
|
||||
padding: 8px;
|
||||
}
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
color: #2c3e50;
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
p {
|
||||
font-size: 13px;
|
||||
color: #7f8c8d;
|
||||
}
|
||||
</style>
|
||||
@@ -1,21 +0,0 @@
|
||||
<template>
|
||||
<div class="rag-view">
|
||||
<h3>🔍 RAG 检索</h3>
|
||||
<p>RAG 知识检索功能</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.rag-view {
|
||||
padding: 8px;
|
||||
}
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
color: #2c3e50;
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
p {
|
||||
font-size: 13px;
|
||||
color: #7f8c8d;
|
||||
}
|
||||
</style>
|
||||
@@ -1,21 +0,0 @@
|
||||
<template>
|
||||
<div class="world-book-call-view">
|
||||
<h3>📚 世界书调用</h3>
|
||||
<p>世界书条目调用记录</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.world-book-call-view {
|
||||
padding: 8px;
|
||||
}
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
color: #2c3e50;
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
p {
|
||||
font-size: 13px;
|
||||
color: #7f8c8d;
|
||||
}
|
||||
</style>
|
||||
@@ -1,175 +0,0 @@
|
||||
<template>
|
||||
<main class="center-chat">
|
||||
<!-- 消息列表 -->
|
||||
<div class="message-list">
|
||||
<CenterMessageItem
|
||||
v-for="msg in messages"
|
||||
:key="msg.id"
|
||||
:message="msg"
|
||||
/>
|
||||
</div>
|
||||
<!-- 输入区域 -->
|
||||
<div class="input-area">
|
||||
<!-- 选项框 -->
|
||||
<div class="input-options">
|
||||
<select v-model="sendOptions.role" class="option-select">
|
||||
<option value="user">用户</option>
|
||||
<option value="assistant">AI</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 输入框 -->
|
||||
<textarea
|
||||
v-model="inputMessage"
|
||||
class="message-input"
|
||||
placeholder="输入消息..."
|
||||
@keydown.enter.ctrl="sendMessage"
|
||||
></textarea>
|
||||
|
||||
<!-- 发送/停止按钮 -->
|
||||
<button
|
||||
:class="['send-btn', { sending: isSending }]"
|
||||
@click="isSending ? stopGeneration() : sendMessage()"
|
||||
>
|
||||
{{ isSending ? '⏹ 停止' : '📤 发送' }}
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import CenterMessageItem from '../features/center/MessageItem.vue';
|
||||
|
||||
interface Message {
|
||||
id: string;
|
||||
senderName: string;
|
||||
senderRole: 'user' | 'assistant' | 'system';
|
||||
mes: string;
|
||||
timestamp: Date;
|
||||
}
|
||||
|
||||
const messages = ref<Message[]>([
|
||||
{
|
||||
id: '1',
|
||||
senderName: 'Assistant',
|
||||
senderRole: 'assistant',
|
||||
mes: '你好!有什么可以帮助你的吗?',
|
||||
timestamp: new Date(),
|
||||
},
|
||||
]);
|
||||
|
||||
const inputMessage = ref('');
|
||||
const isSending = ref(false);
|
||||
const sendOptions = ref({
|
||||
role: 'user' as 'user' | 'assistant',
|
||||
});
|
||||
|
||||
function sendMessage() {
|
||||
if (!inputMessage.value.trim()) return;
|
||||
|
||||
const newMessage: Message = {
|
||||
id: Date.now().toString(),
|
||||
senderName: sendOptions.value.role === 'user' ? 'User' : 'Assistant',
|
||||
senderRole: sendOptions.value.role,
|
||||
mes: inputMessage.value,
|
||||
timestamp: new Date(),
|
||||
};
|
||||
|
||||
messages.value.push(newMessage);
|
||||
inputMessage.value = '';
|
||||
isSending.value = true;
|
||||
|
||||
// 模拟 AI 回复
|
||||
setTimeout(() => {
|
||||
isSending.value = false;
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function stopGeneration() {
|
||||
isSending.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.center-chat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
background: #ffffff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.message-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.input-area {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 8px;
|
||||
padding: 16px;
|
||||
background: #f8f9fa;
|
||||
border-top: 2px solid #dee2e6;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.input-options {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.option-select {
|
||||
padding: 8px;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 4px;
|
||||
background: white;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.message-input {
|
||||
flex: 1;
|
||||
padding: 12px;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 4px;
|
||||
resize: none;
|
||||
font-size: 14px;
|
||||
min-height: 60px;
|
||||
max-height: 200px;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.message-input:focus {
|
||||
outline: none;
|
||||
border-color: #3498db;
|
||||
}
|
||||
|
||||
.send-btn {
|
||||
padding: 12px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: #3498db;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
transition: background 0.2s;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.send-btn:hover {
|
||||
background: #2980b9;
|
||||
}
|
||||
|
||||
.send-btn.sending {
|
||||
background: #e74c3c;
|
||||
}
|
||||
|
||||
.send-btn.sending:hover {
|
||||
background: #c0392b;
|
||||
}
|
||||
</style>
|
||||
@@ -1,99 +0,0 @@
|
||||
<template>
|
||||
<aside class="left-panel">
|
||||
<!-- 左侧-顶部分页标签 -->
|
||||
<div class="panel-tabs">
|
||||
<button
|
||||
v-for="tab in tabs"
|
||||
:key="tab.id"
|
||||
:class="['tab-btn', { active: currentTab === tab.id }]"
|
||||
@click="currentTab = tab.id"
|
||||
>
|
||||
{{ tab.icon }} {{ tab.label }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 左侧-内容区域 -->
|
||||
<div class="panel-content">
|
||||
<LeftGalleryView v-if="currentTab === 'gallery'" />
|
||||
<LeftApiConfigView v-if="currentTab === 'api'" />
|
||||
<LeftPresetView v-if="currentTab === 'preset'" />
|
||||
<LeftWorldBookView v-if="currentTab === 'worldbook'" />
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import LeftGalleryView from '../features/left/GalleryView.vue';
|
||||
import LeftApiConfigView from '../features/left/ApiConfigView.vue';
|
||||
import LeftPresetView from '../features/left/PresetView.vue';
|
||||
import LeftWorldBookView from '../features/left/WorldBookView.vue';
|
||||
|
||||
const currentTab = ref('gallery');
|
||||
|
||||
const tabs = [
|
||||
{ id: 'gallery', label: '画廊', icon: '🖼️' },
|
||||
{ id: 'api', label: 'API', icon: '🔌' },
|
||||
{ id: 'preset', label: '预设', icon: '⚙️' },
|
||||
{ id: 'worldbook', label: '世界书', icon: '📚' },
|
||||
];
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.left-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 25%;
|
||||
min-width: 300px;
|
||||
max-width: 400px;
|
||||
background: #ffffff;
|
||||
border-right: 1px solid #e0e0e0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.panel-tabs {
|
||||
display: flex;
|
||||
background: #f8f9fa;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
padding: 6px 8px;
|
||||
gap: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
flex: 1;
|
||||
padding: 8px 6px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
color: #7f8c8d;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.tab-btn:hover {
|
||||
background: #ffffff;
|
||||
border-color: #e0e0e0;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.tab-btn.active {
|
||||
background: #ffffff;
|
||||
border-color: #3498db;
|
||||
color: #3498db;
|
||||
box-shadow: 0 1px 3px rgba(52, 152, 219, 0.1);
|
||||
}
|
||||
|
||||
.panel-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 16px;
|
||||
background: #fafafa;
|
||||
}
|
||||
</style>
|
||||
@@ -1,267 +0,0 @@
|
||||
<template>
|
||||
<aside class="right-panel">
|
||||
<!-- 右侧-顶部分页标签 -->
|
||||
<div class="panel-tabs">
|
||||
<button
|
||||
v-for="tool in availableToolsList"
|
||||
:key="tool.id"
|
||||
:class="['tab-btn', { active: isToolActive(tool.id) }]"
|
||||
@click="selectTool(tool.id)"
|
||||
>
|
||||
{{ tool.icon }} {{ tool.shortLabel }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 右侧-上部分区(最新使用的工具) -->
|
||||
<div class="panel-section top-section">
|
||||
<div class="section-header">
|
||||
<span class="section-title">{{ recentTools[0]?.label || '未选择工具' }}</span>
|
||||
<button class="collapse-btn" @click="toggleTop" title="折叠/展开">
|
||||
{{ isTopCollapsed ? '▼' : '▲' }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-show="!isTopCollapsed" class="section-content">
|
||||
<component :is="recentTools[0]?.component" v-if="recentTools[0]" />
|
||||
<EmptyState v-else message="点击上方标签选择工具" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧-下部分区(次新使用的工具) -->
|
||||
<div class="panel-section bottom-section">
|
||||
<div class="section-header">
|
||||
<span class="section-title">{{ recentTools[1]?.label || '未选择工具' }}</span>
|
||||
<button class="collapse-btn" @click="toggleBottom" title="折叠/展开">
|
||||
{{ isBottomCollapsed ? '▼' : '▲' }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-show="!isBottomCollapsed" class="section-content">
|
||||
<component :is="recentTools[1]?.component" v-if="recentTools[1]" />
|
||||
<EmptyState v-else message="点击上方标签选择工具" />
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import RightToolDiceView from '../features/right/DiceView.vue';
|
||||
import RightToolRagView from '../features/right/RagView.vue';
|
||||
import RightToolWorldBookCallView from '../features/right/WorldBookCallView.vue';
|
||||
import RightToolDynamicTableView from '../features/right/DynamicTableView.vue';
|
||||
import EmptyState from '../shared/EmptyState.vue';
|
||||
|
||||
interface ToolItem {
|
||||
id: string;
|
||||
label: string;
|
||||
shortLabel: string;
|
||||
icon: string;
|
||||
component: any;
|
||||
}
|
||||
|
||||
const isTopCollapsed = ref(false);
|
||||
const isBottomCollapsed = ref(false);
|
||||
const recentTools = ref<ToolItem[]>([]);
|
||||
|
||||
// 所有可用工具
|
||||
const availableTools: Record<string, ToolItem> = {
|
||||
dice: {
|
||||
id: 'dice',
|
||||
label: '🎲 骰子工具',
|
||||
shortLabel: '骰子',
|
||||
icon: '🎲',
|
||||
component: RightToolDiceView,
|
||||
},
|
||||
rag: {
|
||||
id: 'rag',
|
||||
label: '🔍 RAG 检索',
|
||||
shortLabel: 'RAG',
|
||||
icon: '🔍',
|
||||
component: RightToolRagView,
|
||||
},
|
||||
worldbook: {
|
||||
id: 'worldbook',
|
||||
label: '📚 世界书调用',
|
||||
shortLabel: '世界书',
|
||||
icon: '📚',
|
||||
component: RightToolWorldBookCallView,
|
||||
},
|
||||
table: {
|
||||
id: 'table',
|
||||
label: '📊 动态表格',
|
||||
shortLabel: '表格',
|
||||
icon: '📊',
|
||||
component: RightToolDynamicTableView,
|
||||
},
|
||||
};
|
||||
|
||||
// 获取工具列表(用于渲染标签)
|
||||
const availableToolsList = Object.values(availableTools);
|
||||
|
||||
// 判断工具是否在当前显示的两个中
|
||||
function isToolActive(toolId: string): boolean {
|
||||
return recentTools.value.some((tool) => tool.id === toolId);
|
||||
}
|
||||
|
||||
// 选择工具(添加到最近使用队列)
|
||||
function selectTool(toolId: string) {
|
||||
const tool = availableTools[toolId];
|
||||
if (!tool) return;
|
||||
|
||||
// 移除已存在的相同工具
|
||||
recentTools.value = recentTools.value.filter((t) => t.id !== toolId);
|
||||
|
||||
// 添加到最前面
|
||||
recentTools.value.unshift(tool);
|
||||
|
||||
// 只保留最近两个
|
||||
if (recentTools.value.length > 2) {
|
||||
recentTools.value = recentTools.value.slice(0, 2);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleTop() {
|
||||
isTopCollapsed.value = !isTopCollapsed.value;
|
||||
}
|
||||
|
||||
function toggleBottom() {
|
||||
isBottomCollapsed.value = !isBottomCollapsed.value;
|
||||
}
|
||||
|
||||
// 暴露方法供外部调用
|
||||
defineExpose({
|
||||
selectTool,
|
||||
});
|
||||
|
||||
// 初始化默认工具
|
||||
selectTool('dice');
|
||||
selectTool('worldbook');
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.right-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 25%;
|
||||
min-width: 300px;
|
||||
max-width: 400px;
|
||||
background: #ffffff;
|
||||
border-left: 1px solid #e0e0e0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.panel-tabs {
|
||||
display: flex;
|
||||
background: #f8f9fa;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
padding: 6px 8px;
|
||||
gap: 4px;
|
||||
flex-shrink: 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
flex: 1;
|
||||
min-width: 60px;
|
||||
padding: 8px 6px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
color: #7f8c8d;
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tab-btn:hover {
|
||||
background: #ffffff;
|
||||
border-color: #e0e0e0;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.tab-btn.active {
|
||||
background: #ffffff;
|
||||
border-color: #3498db;
|
||||
color: #3498db;
|
||||
box-shadow: 0 1px 3px rgba(52, 152, 219, 0.1);
|
||||
}
|
||||
|
||||
.panel-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.panel-section:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 16px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.collapse-btn {
|
||||
padding: 4px 8px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
color: #7f8c8d;
|
||||
transition: color 0.2s;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.collapse-btn:hover {
|
||||
color: #2c3e50;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.section-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 12px;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
/* 滚动条样式 */
|
||||
.panel-tabs::-webkit-scrollbar,
|
||||
.section-content::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.panel-tabs::-webkit-scrollbar-track,
|
||||
.section-content::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.panel-tabs::-webkit-scrollbar-thumb,
|
||||
.section-content::-webkit-scrollbar-thumb {
|
||||
background: #d0d0d0;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.panel-tabs::-webkit-scrollbar-thumb:hover,
|
||||
.section-content::-webkit-scrollbar-thumb:hover {
|
||||
background: #b0b0b0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,18 +0,0 @@
|
||||
<template>
|
||||
<div class="right-toolbar">
|
||||
<span style="color: #bdc3c7; font-size: 12px;">工具栏</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
rightPanelRef?: any;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.right-toolbar {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,125 +0,0 @@
|
||||
<template>
|
||||
<header class="top-toolbar">
|
||||
<div class="toolbar-left">
|
||||
<!-- API 配置快速切换 -->
|
||||
<div class="toolbar-item">
|
||||
<span class="label">API:</span>
|
||||
<select v-model="currentApi" class="toolbar-select">
|
||||
<option value="primary">主 API</option>
|
||||
<option value="secondary">副 API</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toolbar-center">
|
||||
<!-- 当前用户角色 -->
|
||||
<div class="toolbar-item">
|
||||
<span class="label">用户:</span>
|
||||
<span class="value">{{ currentUser }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 当前 AI 角色 -->
|
||||
<div class="toolbar-item">
|
||||
<span class="label">AI:</span>
|
||||
<span class="value">{{ currentAICharacter }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 激活的全局世界书 -->
|
||||
<div class="toolbar-item">
|
||||
<span class="label">世界书:</span>
|
||||
<span class="value">{{ activeWorldBooks.length }} 个激活</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toolbar-right">
|
||||
<!-- 设置按钮 -->
|
||||
<button class="toolbar-btn" @click="openSettings">
|
||||
⚙️ 设置
|
||||
</button>
|
||||
|
||||
<!-- 拓展按钮 -->
|
||||
<button class="toolbar-btn" @click="openExtensions">
|
||||
🧩 拓展
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
const currentApi = ref('primary');
|
||||
const currentUser = ref('User');
|
||||
const currentAICharacter = ref('Assistant');
|
||||
const activeWorldBooks = ref(['奇幻世界', '现代都市']);
|
||||
|
||||
function openSettings() {
|
||||
console.log('Open settings');
|
||||
}
|
||||
|
||||
function openExtensions() {
|
||||
console.log('Open extensions');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.top-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 16px;
|
||||
background: #2c3e50;
|
||||
color: white;
|
||||
border-bottom: 2px solid #34495e;
|
||||
height: 50px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.toolbar-left,
|
||||
.toolbar-center,
|
||||
.toolbar-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.toolbar-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 12px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.toolbar-select {
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #34495e;
|
||||
background: #34495e;
|
||||
color: white;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.toolbar-btn {
|
||||
padding: 6px 12px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: #3498db;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.toolbar-btn:hover {
|
||||
background: #2980b9;
|
||||
}
|
||||
</style>
|
||||
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
* useApi Composable
|
||||
* Provides API client with error handling and loading states
|
||||
*/
|
||||
|
||||
import { ref } from 'vue';
|
||||
import type { Ref } from 'vue';
|
||||
|
||||
interface UseApiOptions<T> {
|
||||
immediate?: boolean;
|
||||
onError?: (error: Error) => void;
|
||||
onSuccess?: (data: T) => void;
|
||||
}
|
||||
|
||||
export function useApi<T>(
|
||||
apiCall: () => Promise<T>,
|
||||
options: UseApiOptions<T> = {}
|
||||
) {
|
||||
const data: Ref<T | null> = ref(null);
|
||||
const error: Ref<Error | null> = ref(null);
|
||||
const loading: Ref<boolean> = ref(false);
|
||||
|
||||
const execute = async () => {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
|
||||
try {
|
||||
const result = await apiCall();
|
||||
data.value = result;
|
||||
options.onSuccess?.(result);
|
||||
return result;
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err : new Error(String(err));
|
||||
options.onError?.(error.value);
|
||||
throw error.value;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
if (options.immediate) {
|
||||
execute();
|
||||
}
|
||||
|
||||
return {
|
||||
data,
|
||||
error,
|
||||
loading,
|
||||
execute,
|
||||
};
|
||||
}
|
||||
0
client/src/composables/useTheme.ts
Normal file
0
client/src/composables/useTheme.ts
Normal file
0
client/src/layouts/MainLayout/MainLayout.vue
Normal file
0
client/src/layouts/MainLayout/MainLayout.vue
Normal file
0
client/src/layouts/MainLayout/main-layout.css
Normal file
0
client/src/layouts/MainLayout/main-layout.css
Normal file
@@ -1,14 +0,0 @@
|
||||
import './assets/main.css'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
0
client/src/router/index.ts
Normal file
0
client/src/router/index.ts
Normal file
0
client/src/stores/useAppStore.ts
Normal file
0
client/src/stores/useAppStore.ts
Normal file
0
client/src/styles/reset.css
Normal file
0
client/src/styles/reset.css
Normal file
0
client/src/styles/variables.css
Normal file
0
client/src/styles/variables.css
Normal file
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||
"exclude": ["src/**/__tests__/*"],
|
||||
"compilerOptions": {
|
||||
// Extra safety for array and object lookups, but may have false positives.
|
||||
"noUncheckedIndexedAccess": true,
|
||||
|
||||
// Path mapping for cleaner imports.
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"@shared/*": ["../shared/types/*"]
|
||||
},
|
||||
|
||||
// `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking.
|
||||
// Specified here to keep it out of the root directory.
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo"
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// TSConfig for modules that run in Node.js environment via either transpilation or type-stripping.
|
||||
{
|
||||
"extends": "@tsconfig/node24/tsconfig.json",
|
||||
"include": [
|
||||
"vite.config.*",
|
||||
"vitest.config.*",
|
||||
"cypress.config.*",
|
||||
"playwright.config.*",
|
||||
"eslint.config.*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
// Most tools use transpilation instead of Node.js's native type-stripping.
|
||||
// Bundler mode provides a smoother developer experience.
|
||||
"module": "preserve",
|
||||
"moduleResolution": "bundler",
|
||||
|
||||
// Include Node.js types and avoid accidentally including other `@types/*` packages.
|
||||
"types": ["node"],
|
||||
|
||||
// Disable emitting output during `vue-tsc --build`, which is used for type-checking only.
|
||||
"noEmit": true,
|
||||
|
||||
// `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking.
|
||||
// Specified here to keep it out of the root directory.
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo"
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
'@shared': fileURLToPath(new URL('../shared/types', import.meta.url))
|
||||
}
|
||||
},
|
||||
server: {
|
||||
port: 8080,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:3000',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, '')
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1,68 +0,0 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# Backend Service (NestJS)
|
||||
backend:
|
||||
build:
|
||||
context: ./server
|
||||
dockerfile: Dockerfile.dev
|
||||
container_name: sillytavern-backend
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "23337:3000" # Map to host port 23337
|
||||
volumes:
|
||||
# Mount code for hot reload (development)
|
||||
- ./server:/usr/src/app
|
||||
- ./shared:/usr/src/shared
|
||||
# Exclude node_modules to use container's version
|
||||
- /usr/src/app/node_modules
|
||||
# Persistent data
|
||||
- ./data:/usr/src/app/data
|
||||
- ./.env:/usr/src/app/.env:ro
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- PORT=3000
|
||||
- DB_DATABASE=./data/db/app.db
|
||||
- UPLOAD_DIR=./data/files
|
||||
- LOG_DIR=./data/logs
|
||||
working_dir: /usr/src/app
|
||||
command: npm run start:dev
|
||||
networks:
|
||||
- app-network
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/api"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
# Frontend Service (Vue3 + Vite)
|
||||
frontend:
|
||||
build:
|
||||
context: ./client
|
||||
dockerfile: Dockerfile.dev
|
||||
container_name: sillytavern-frontend
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "23338:5173" # Vite dev server port
|
||||
volumes:
|
||||
# Mount code for hot reload (development)
|
||||
- ./client:/usr/src/app
|
||||
- ./shared:/usr/src/shared
|
||||
# Exclude node_modules
|
||||
- /usr/src/app/node_modules
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- VITE_API_URL=http://localhost:23337
|
||||
- VITE_WS_URL=ws://localhost:23337
|
||||
working_dir: /usr/src/app
|
||||
command: npm run dev -- --host 0.0.0.0 --port 5173
|
||||
depends_on:
|
||||
backend:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- app-network
|
||||
|
||||
networks:
|
||||
app-network:
|
||||
driver: bridge
|
||||
|
||||
0
docker/backend.Dockerfile
Normal file
0
docker/backend.Dockerfile
Normal file
0
docker/frontend.Dockerfile
Normal file
0
docker/frontend.Dockerfile
Normal file
0
docker/nginx/default.conf
Normal file
0
docker/nginx/default.conf
Normal file
310
make.bat
310
make.bat
@@ -1,310 +0,0 @@
|
||||
NEW_FILE_CODE
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo =====================================================
|
||||
echo Creating Enterprise-Grade Project Architecture...
|
||||
echo Backend: NestJS with DDD + Frontend: Vue3 Composition API
|
||||
echo =====================================================
|
||||
|
||||
:: Check if we are in the right directory
|
||||
if not exist server (
|
||||
echo [ERROR] Please run this script from project root directory
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
|
||||
:: -------------------------------------------------------
|
||||
:: 1. Restructure Backend (NestJS)
|
||||
:: -------------------------------------------------------
|
||||
echo.
|
||||
echo [Backend] Creating complete directory structure...
|
||||
|
||||
cd server\src
|
||||
|
||||
:: Remove existing directories to start fresh
|
||||
if exist core rmdir /s /q core
|
||||
if exist modules rmdir /s /q modules
|
||||
if exist shared rmdir /s /q shared
|
||||
|
||||
:: === CORE LAYER ===
|
||||
echo Creating core layer...
|
||||
|
||||
mkdir core
|
||||
mkdir core\config
|
||||
mkdir core\database
|
||||
mkdir core\database\migrations
|
||||
mkdir core\database\seeds
|
||||
mkdir core\decorators
|
||||
mkdir core\filters
|
||||
mkdir core\guards
|
||||
mkdir core\interceptors
|
||||
mkdir core\pipes
|
||||
mkdir core\middleware
|
||||
|
||||
:: === MODULES LAYER ===
|
||||
echo Creating modules layer...
|
||||
|
||||
mkdir modules
|
||||
|
||||
:: Auth Module
|
||||
mkdir modules\auth
|
||||
mkdir modules\auth\controllers
|
||||
mkdir modules\auth\services
|
||||
mkdir modules\auth\strategies
|
||||
mkdir modules\auth\dto
|
||||
mkdir modules\auth\interfaces
|
||||
|
||||
:: LLM Module
|
||||
mkdir modules\llm
|
||||
mkdir modules\llm\controllers
|
||||
mkdir modules\llm\services
|
||||
mkdir modules\llm\providers
|
||||
mkdir modules\llm\dto
|
||||
mkdir modules\llm\entities
|
||||
mkdir modules\llm\interfaces
|
||||
|
||||
:: Workflow Module
|
||||
mkdir modules\workflow
|
||||
mkdir modules\workflow\controllers
|
||||
mkdir modules\workflow\services
|
||||
mkdir modules\workflow\engine
|
||||
mkdir modules\workflow\nodes
|
||||
mkdir modules\workflow\dto
|
||||
mkdir modules\workflow\entities
|
||||
mkdir modules\workflow\interfaces
|
||||
|
||||
:: Data Store Module
|
||||
mkdir modules\data-store
|
||||
mkdir modules\data-store\controllers
|
||||
mkdir modules\data-store\services
|
||||
mkdir modules\data-store\repositories
|
||||
mkdir modules\data-store\entities
|
||||
mkdir modules\data-store\schemas
|
||||
mkdir modules\data-store\dto
|
||||
mkdir modules\data-store\interfaces
|
||||
|
||||
:: Import/Export Module
|
||||
mkdir modules\import-export
|
||||
mkdir modules\import-export\controllers
|
||||
mkdir modules\import-export\services
|
||||
mkdir modules\import-export\transformers
|
||||
mkdir modules\import-export\serializers
|
||||
mkdir modules\import-export\parsers
|
||||
mkdir modules\import-export\dto
|
||||
mkdir modules\import-export\interfaces
|
||||
|
||||
:: File Management Module
|
||||
mkdir modules\file-management
|
||||
mkdir modules\file-management\controllers
|
||||
mkdir modules\file-management\services
|
||||
mkdir modules\file-management\storage
|
||||
mkdir modules\file-management\dto
|
||||
mkdir modules\file-management\entities
|
||||
|
||||
:: === SHARED LAYER ===
|
||||
echo Creating shared layer...
|
||||
|
||||
mkdir shared
|
||||
mkdir shared\interfaces
|
||||
mkdir shared\types
|
||||
mkdir shared\utils
|
||||
mkdir shared\constants
|
||||
mkdir shared\dtos
|
||||
mkdir shared\decorators
|
||||
|
||||
:: === EVENTS SYSTEM ===
|
||||
echo Creating events system...
|
||||
|
||||
mkdir events
|
||||
mkdir events\event-emitter
|
||||
mkdir events\events
|
||||
mkdir events\listeners
|
||||
|
||||
:: === QUEUES SYSTEM ===
|
||||
echo Creating queues system...
|
||||
|
||||
mkdir queues
|
||||
mkdir queues\processors
|
||||
mkdir queues\jobs
|
||||
mkdir queues\interfaces
|
||||
|
||||
:: === COMMON LAYER ===
|
||||
echo Creating common layer...
|
||||
|
||||
mkdir common
|
||||
mkdir common\base
|
||||
mkdir common\mixins
|
||||
mkdir common\exceptions
|
||||
|
||||
cd ..\..
|
||||
|
||||
echo [Backend] Directory structure created successfully!
|
||||
|
||||
:: -------------------------------------------------------
|
||||
:: 2. Restructure Frontend (Vue3)
|
||||
:: -------------------------------------------------------
|
||||
echo.
|
||||
echo [Frontend] Creating complete directory structure...
|
||||
|
||||
cd client\src
|
||||
|
||||
:: Remove existing directories to start fresh
|
||||
if exist api rmdir /s /q api
|
||||
if exist components rmdir /s /q components
|
||||
if exist views rmdir /s /q views
|
||||
if exist composables rmdir /s /q composables
|
||||
if exist stores rmdir /s /q stores
|
||||
if exist router rmdir /s /q router
|
||||
if exist types rmdir /s /q types
|
||||
if exist utils rmdir /s /q utils
|
||||
|
||||
:: === API LAYER ===
|
||||
echo Creating API layer...
|
||||
|
||||
mkdir api
|
||||
mkdir api\clients
|
||||
mkdir api\modules
|
||||
mkdir api\interceptors
|
||||
|
||||
:: === COMPONENTS LAYER ===
|
||||
echo Creating components layer...
|
||||
|
||||
mkdir components
|
||||
mkdir components\base
|
||||
mkdir components\base\buttons
|
||||
mkdir components\base\inputs
|
||||
mkdir components\base\modals
|
||||
mkdir components\base\layouts
|
||||
mkdir components\base\tables
|
||||
mkdir components\base\forms
|
||||
|
||||
mkdir components\business
|
||||
mkdir components\business\llm-chat
|
||||
mkdir components\business\workflow-canvas
|
||||
mkdir components\business\data-table
|
||||
mkdir components\business\file-uploader
|
||||
mkdir components\business\prompt-editor
|
||||
mkdir components\business\node-palette
|
||||
|
||||
mkdir components\widgets
|
||||
mkdir components\widgets\status-indicator
|
||||
mkdir components\widgets\progress-bar
|
||||
mkdir components\widgets\toast
|
||||
|
||||
:: === VIEWS LAYER ===
|
||||
echo Creating views layer...
|
||||
|
||||
mkdir views
|
||||
mkdir views\dashboard
|
||||
mkdir views\workflow-editor
|
||||
mkdir views\llm-playground
|
||||
mkdir views\data-browser
|
||||
mkdir views\settings
|
||||
mkdir views\auth
|
||||
|
||||
:: === COMPOSABLES LAYER ===
|
||||
echo Creating composables layer...
|
||||
|
||||
mkdir composables
|
||||
|
||||
:: === STORES LAYER ===
|
||||
echo Creating stores layer...
|
||||
|
||||
mkdir stores
|
||||
mkdir stores\modules
|
||||
|
||||
:: === ROUTER LAYER ===
|
||||
echo Creating router layer...
|
||||
|
||||
mkdir router
|
||||
mkdir router\routes
|
||||
|
||||
:: === TYPES LAYER ===
|
||||
echo Creating types layer...
|
||||
|
||||
mkdir types
|
||||
mkdir types\models
|
||||
mkdir types\api
|
||||
mkdir types\common
|
||||
|
||||
:: === UTILS LAYER ===
|
||||
echo Creating utils layer...
|
||||
|
||||
mkdir utils
|
||||
mkdir utils\formatters
|
||||
mkdir utils\validators
|
||||
mkdir utils\helpers
|
||||
mkdir utils\constants
|
||||
|
||||
:: === ASSETS LAYER ===
|
||||
echo Creating assets structure...
|
||||
|
||||
if not exist assets mkdir assets
|
||||
mkdir assets\styles
|
||||
mkdir assets\icons
|
||||
mkdir assets\images
|
||||
|
||||
:: === PLUGINS LAYER ===
|
||||
echo Creating plugins layer...
|
||||
|
||||
mkdir plugins
|
||||
|
||||
cd ..\..
|
||||
|
||||
echo [Frontend] Directory structure created successfully!
|
||||
|
||||
:: -------------------------------------------------------
|
||||
:: 3. Create Root Level Directories
|
||||
:: -------------------------------------------------------
|
||||
echo.
|
||||
echo [Infrastructure] Creating infrastructure directories...
|
||||
|
||||
if not exist data mkdir data
|
||||
if not exist data\db mkdir data\db
|
||||
if not exist data\files mkdir data\files
|
||||
if not exist data\logs mkdir data\logs
|
||||
if not exist data\backups mkdir data\backups
|
||||
|
||||
if not exist docker mkdir docker
|
||||
if not exist docker\nginx mkdir docker\nginx
|
||||
if not exist docker\app mkdir docker\app
|
||||
if not exist docker\certs mkdir docker\certs
|
||||
|
||||
if not exist docs mkdir docs
|
||||
if not exist scripts mkdir scripts
|
||||
if not exist tests mkdir tests
|
||||
|
||||
echo [Infrastructure] Infrastructure directories created!
|
||||
|
||||
:: -------------------------------------------------------
|
||||
:: 4. Summary
|
||||
:: -------------------------------------------------------
|
||||
echo.
|
||||
echo =====================================================
|
||||
echo Project architecture created successfully!
|
||||
echo.
|
||||
echo Backend Structure (server/src):
|
||||
echo - core/ Infrastructure layer
|
||||
echo - modules/ Business modules (DDD)
|
||||
echo - shared/ Shared utilities
|
||||
echo - events/ Event system
|
||||
echo - queues/ Task queues
|
||||
echo - common/ Base classes
|
||||
echo.
|
||||
echo Frontend Structure (client/src):
|
||||
echo - api/ API clients
|
||||
echo - components/ UI components
|
||||
echo - views/ Page views
|
||||
echo - composables/ Reusable logic
|
||||
echo - stores/ State management
|
||||
echo - types/ TypeScript types
|
||||
echo - utils/ Utility functions
|
||||
echo.
|
||||
echo Next steps:
|
||||
echo 1. cd server ^&^& npm install
|
||||
echo 2. cd ../client ^&^& npm install
|
||||
echo 3. Start implementing base classes and interfaces
|
||||
echo =====================================================
|
||||
|
||||
pause
|
||||
@@ -1,6 +0,0 @@
|
||||
node_modules
|
||||
dist
|
||||
.env
|
||||
.git
|
||||
.idea
|
||||
.vscode
|
||||
@@ -1,57 +0,0 @@
|
||||
# =====================================================
|
||||
# Server Configuration
|
||||
# =====================================================
|
||||
NODE_ENV=development
|
||||
PORT=3000
|
||||
API_PREFIX=/api
|
||||
|
||||
# =====================================================
|
||||
# Database Configuration (File-based, no DB server needed)
|
||||
# =====================================================
|
||||
DB_TYPE=better-sqlite3
|
||||
DB_DATABASE=./data/db/app.db
|
||||
|
||||
# =====================================================
|
||||
# JWT Authentication
|
||||
# =====================================================
|
||||
JWT_SECRET=change-this-to-a-random-string-at-least-32-chars
|
||||
JWT_EXPIRES_IN=7d
|
||||
JWT_REFRESH_SECRET=change-this-to-another-random-string
|
||||
JWT_REFRESH_EXPIRES_IN=30d
|
||||
|
||||
# =====================================================
|
||||
# LLM Provider API Keys (Backend Only - Secure)
|
||||
# =====================================================
|
||||
OPENAI_API_KEY=sk-your-openai-api-key-here
|
||||
ANTHROPIC_API_KEY=sk-ant-your-anthropic-api-key-here
|
||||
GOOGLE_API_KEY=your-google-api-key-here
|
||||
LOCAL_LLM_URL=http://localhost:11434
|
||||
|
||||
# =====================================================
|
||||
# File Storage
|
||||
# =====================================================
|
||||
UPLOAD_DIR=./data/files
|
||||
MAX_FILE_SIZE=10485760
|
||||
|
||||
# =====================================================
|
||||
# CORS Configuration
|
||||
# =====================================================
|
||||
CORS_ORIGIN=http://localhost:23338
|
||||
|
||||
# =====================================================
|
||||
# Rate Limiting
|
||||
# =====================================================
|
||||
RATE_LIMIT_TTL=60
|
||||
RATE_LIMIT_MAX=100
|
||||
|
||||
# =====================================================
|
||||
# Workflow Configuration
|
||||
# =====================================================
|
||||
WORKFLOW_MAX_PARALLEL=5
|
||||
WORKFLOW_TIMEOUT=300000
|
||||
|
||||
# =====================================================
|
||||
# Logging
|
||||
# =====================================================
|
||||
LOG_LEVEL=debug
|
||||
LOG_DIR=./data/logs
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user