collabdocchat 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -111,10 +111,25 @@
111
111
 
112
112
  ### 安装步骤
113
113
 
114
+ #### 方式一:通过 npm 安装(推荐)
115
+
116
+ ```bash
117
+ # 安装包
118
+ npm install collabdocchat
119
+
120
+ # 进入安装目录
121
+ cd node_modules/collabdocchat
122
+
123
+ # 启动应用(自动打开浏览器)
124
+ npm start
125
+ ```
126
+
127
+ #### 方式二:从源码安装
128
+
114
129
  1. **克隆项目**
115
130
 
116
131
  ```bash
117
- git clone https://github.com/yourusername/collabdocchat.git
132
+ git clone https://github.com/shijinghao/collabdocchat.git
118
133
  cd collabdocchat
119
134
  ```
120
135
 
@@ -154,7 +169,10 @@ sudo systemctl start mongod
154
169
  5. **启动项目**
155
170
 
156
171
  ```bash
157
- # 开发模式(同时启动前后端)
172
+ # 一键启动(推荐)- 自动启动服务器和客户端,并打开浏览器
173
+ npm start
174
+
175
+ # 开发模式(同时启动前后端,使用 nodemon 自动重启)
158
176
  npm run dev
159
177
 
160
178
  # 或分别启动
@@ -164,7 +182,9 @@ npm run client # 前端开发服务器
164
182
 
165
183
  6. **访问应用**
166
184
 
167
- 打开浏览器访问:`http://localhost:5173`
185
+ 运行 `npm start` 后,浏览器会自动打开并访问 `http://localhost:5173`
186
+
187
+ 或手动访问:`http://localhost:5173`
168
188
 
169
189
  ---
170
190
 
package/index.html ADDED
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>CollabDocChat - 协作文档聊天平台</title>
7
+ <link rel="stylesheet" href="/src/styles/main.css">
8
+ </head>
9
+ <body>
10
+ <div id="app"></div>
11
+ <script type="module" src="/src/main.js"></script>
12
+ </body>
13
+ </html>
14
+
package/package.json CHANGED
@@ -1,15 +1,18 @@
1
1
  {
2
2
  "name": "collabdocchat",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "开源的实时协作文档聊天平台 - 集成任务管理、多人文档编辑、智能点名功能",
5
5
  "main": "./server/index.js",
6
6
  "type": "module",
7
7
  "files": [
8
8
  "server",
9
9
  "src",
10
+ "scripts",
10
11
  "README.md",
11
12
  "LICENSE",
12
- "package.json"
13
+ "package.json",
14
+ "vite.config.js",
15
+ "index.html"
13
16
  ],
14
17
  "keywords": [
15
18
  "collaboration",
@@ -40,31 +43,35 @@
40
43
  "npm": ">=7.0.0"
41
44
  },
42
45
  "scripts": {
43
- "dev": "concurrently \"npm run server\" \"npm run client\"",
46
+ "postinstall": "node scripts/postinstall.js",
47
+ "dev": "concurrently \"npm run server\" \"npm run client\" \"npm run open-browser\"",
48
+ "start": "node scripts/start-app.js",
44
49
  "server": "nodemon server/index.js",
45
50
  "client": "vite",
51
+ "open-browser": "node scripts/open-browser.js",
46
52
  "build": "vite build",
47
53
  "preview": "vite preview",
48
- "start": "node server/index.js",
49
- "prepublishOnly": "npm run build"
54
+ "serve": "node server/index.js",
55
+ "prepublishOnly": "echo 'Skipping build for source package'"
50
56
  },
51
57
  "dependencies": {
52
- "express": "^4.18.2",
53
- "ws": "^8.14.2",
54
- "mongoose": "^8.0.3",
55
- "jsonwebtoken": "^9.0.2",
56
58
  "bcryptjs": "^2.4.3",
59
+ "collabdocchat": "^1.0.0",
57
60
  "cors": "^2.8.5",
58
61
  "dotenv": "^16.3.1",
59
- "yjs": "^13.6.10",
62
+ "express": "^4.18.2",
63
+ "jsonwebtoken": "^9.0.2",
64
+ "mongoose": "^8.0.3",
65
+ "quill": "^2.0.3",
66
+ "quill-cursors": "^4.0.2",
67
+ "ws": "^8.14.2",
60
68
  "y-websocket": "^1.5.0",
61
- "quill": "^1.3.7",
62
- "quill-cursors": "^4.0.2"
69
+ "yjs": "^13.6.10"
63
70
  },
64
71
  "devDependencies": {
65
- "vite": "^5.0.8",
72
+ "concurrently": "^8.2.2",
66
73
  "nodemon": "^3.0.2",
67
- "concurrently": "^8.2.2"
74
+ "open": "^11.0.0",
75
+ "vite": "^7.3.1"
68
76
  }
69
77
  }
70
-
@@ -0,0 +1,37 @@
1
+ import { exec } from 'child_process';
2
+ import { platform } from 'os';
3
+
4
+ const url = 'http://localhost:5173';
5
+ const delay = 3000; // 等待 3 秒让服务器启动
6
+
7
+ // 根据操作系统选择打开命令
8
+ function openBrowser(url) {
9
+ const platformName = platform();
10
+ let command;
11
+
12
+ switch (platformName) {
13
+ case 'win32':
14
+ command = `start ${url}`;
15
+ break;
16
+ case 'darwin':
17
+ command = `open ${url}`;
18
+ break;
19
+ default:
20
+ command = `xdg-open ${url}`;
21
+ }
22
+
23
+ exec(command, (error) => {
24
+ if (error) {
25
+ console.error(`无法打开浏览器: ${error.message}`);
26
+ console.log(`\n请手动访问: ${url}`);
27
+ } else {
28
+ console.log(`\n🌐 正在打开浏览器: ${url}`);
29
+ }
30
+ });
31
+ }
32
+
33
+ // 延迟打开,确保服务器已启动
34
+ setTimeout(() => {
35
+ openBrowser(url);
36
+ }, delay);
37
+
@@ -0,0 +1,159 @@
1
+ import { spawn } from 'child_process';
2
+ import { platform } from 'os';
3
+ import { fileURLToPath } from 'url';
4
+ import { dirname, join } from 'path';
5
+ import http from 'http';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+ const rootDir = join(__dirname, '..');
10
+
11
+ const PORT = process.env.PORT || 3000;
12
+ const CLIENT_PORT = 5173;
13
+ const CLIENT_URL = `http://localhost:${CLIENT_PORT}`;
14
+
15
+ // 打开浏览器的函数
16
+ function openBrowser(url) {
17
+ const platformName = platform();
18
+ let command;
19
+ let args;
20
+
21
+ switch (platformName) {
22
+ case 'win32':
23
+ command = 'cmd';
24
+ args = ['/c', 'start', url];
25
+ break;
26
+ case 'darwin':
27
+ command = 'open';
28
+ args = [url];
29
+ break;
30
+ default:
31
+ command = 'xdg-open';
32
+ args = [url];
33
+ }
34
+
35
+ const browser = spawn(command, args, { stdio: 'ignore', detached: true });
36
+ browser.unref();
37
+ }
38
+
39
+ // 检查服务器是否就绪
40
+ function waitForServer(url, maxAttempts = 30, delay = 1000) {
41
+ return new Promise((resolve, reject) => {
42
+ let attempts = 0;
43
+ const urlObj = new URL(url);
44
+
45
+ const check = () => {
46
+ attempts++;
47
+
48
+ const req = http.get({
49
+ hostname: urlObj.hostname,
50
+ port: urlObj.port,
51
+ path: urlObj.pathname,
52
+ timeout: 1000
53
+ }, (res) => {
54
+ if (res.statusCode === 200) {
55
+ resolve();
56
+ return;
57
+ }
58
+ if (attempts < maxAttempts) {
59
+ setTimeout(check, delay);
60
+ } else {
61
+ reject(new Error('服务器启动超时'));
62
+ }
63
+ });
64
+
65
+ req.on('error', () => {
66
+ if (attempts < maxAttempts) {
67
+ setTimeout(check, delay);
68
+ } else {
69
+ reject(new Error('服务器启动超时'));
70
+ }
71
+ });
72
+
73
+ req.on('timeout', () => {
74
+ req.destroy();
75
+ if (attempts < maxAttempts) {
76
+ setTimeout(check, delay);
77
+ } else {
78
+ reject(new Error('服务器启动超时'));
79
+ }
80
+ });
81
+ };
82
+
83
+ check();
84
+ });
85
+ }
86
+
87
+ // 启动服务器
88
+ function startServer() {
89
+ console.log('\n🚀 正在启动 CollabDocChat 服务器...');
90
+ const server = spawn('node', ['server/index.js'], {
91
+ cwd: rootDir,
92
+ stdio: 'inherit',
93
+ shell: true,
94
+ detached: true
95
+ });
96
+
97
+ server.unref();
98
+ return server;
99
+ }
100
+
101
+ // 启动客户端
102
+ function startClient() {
103
+ console.log('🎨 正在启动客户端...');
104
+ const client = spawn('npm', ['run', 'client'], {
105
+ cwd: rootDir,
106
+ stdio: 'inherit',
107
+ shell: true,
108
+ detached: true
109
+ });
110
+
111
+ client.unref();
112
+ return client;
113
+ }
114
+
115
+ // 主函数
116
+ async function main() {
117
+ console.log('\n📦 CollabDocChat 安装完成!');
118
+ console.log('🚀 正在自动启动应用...\n');
119
+
120
+ // 启动服务器
121
+ const server = startServer();
122
+
123
+ // 等待服务器就绪
124
+ try {
125
+ await waitForServer(`http://localhost:${PORT}/health`, 30, 1000);
126
+ console.log(`✅ 服务器已就绪: http://localhost:${PORT}\n`);
127
+ } catch (error) {
128
+ console.error('❌ 服务器启动失败:', error.message);
129
+ console.log('\n💡 请确保:');
130
+ console.log(' 1. MongoDB 已启动');
131
+ console.log(' 2. 端口 3000 和 5173 未被占用');
132
+ console.log(' 3. 运行 npm start 手动启动');
133
+ process.exit(0);
134
+ return;
135
+ }
136
+
137
+ // 启动客户端
138
+ const client = startClient();
139
+
140
+ // 等待客户端就绪后打开浏览器
141
+ setTimeout(async () => {
142
+ try {
143
+ await waitForServer(CLIENT_URL, 20, 500);
144
+ console.log(`\n🌐 正在打开浏览器: ${CLIENT_URL}`);
145
+ openBrowser(CLIENT_URL);
146
+ console.log('\n✅ 应用已启动!浏览器应该已经自动打开。');
147
+ console.log('\n💡 提示:按 Ctrl+C 可以停止服务器');
148
+ } catch (error) {
149
+ console.log(`\n⚠️ 客户端可能还在启动中,请手动访问: ${CLIENT_URL}`);
150
+ openBrowser(CLIENT_URL);
151
+ }
152
+ }, 2000);
153
+ }
154
+
155
+ main().catch(error => {
156
+ console.error('❌ 启动失败:', error.message);
157
+ console.log('\n💡 可以运行 npm start 手动启动应用');
158
+ });
159
+
@@ -0,0 +1,164 @@
1
+ import { spawn } from 'child_process';
2
+ import { platform } from 'os';
3
+ import { fileURLToPath } from 'url';
4
+ import { dirname, join } from 'path';
5
+ import http from 'http';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+ const rootDir = join(__dirname, '..');
10
+
11
+ const PORT = process.env.PORT || 3000;
12
+ const CLIENT_PORT = 5173;
13
+ const CLIENT_URL = `http://localhost:${CLIENT_PORT}`;
14
+
15
+ // 打开浏览器的函数
16
+ function openBrowser(url) {
17
+ const platformName = platform();
18
+ let command;
19
+ let args;
20
+
21
+ switch (platformName) {
22
+ case 'win32':
23
+ command = 'cmd';
24
+ args = ['/c', 'start', url];
25
+ break;
26
+ case 'darwin':
27
+ command = 'open';
28
+ args = [url];
29
+ break;
30
+ default:
31
+ command = 'xdg-open';
32
+ args = [url];
33
+ }
34
+
35
+ const browser = spawn(command, args, { stdio: 'ignore', detached: true });
36
+ browser.unref();
37
+ }
38
+
39
+ // 检查服务器是否就绪
40
+ function waitForServer(url, maxAttempts = 30, delay = 1000) {
41
+ return new Promise((resolve, reject) => {
42
+ let attempts = 0;
43
+ const urlObj = new URL(url);
44
+
45
+ const check = () => {
46
+ attempts++;
47
+
48
+ const req = http.get({
49
+ hostname: urlObj.hostname,
50
+ port: urlObj.port,
51
+ path: urlObj.pathname,
52
+ timeout: 1000
53
+ }, (res) => {
54
+ if (res.statusCode === 200) {
55
+ resolve();
56
+ return;
57
+ }
58
+ // 继续等待
59
+ if (attempts < maxAttempts) {
60
+ setTimeout(check, delay);
61
+ } else {
62
+ reject(new Error('服务器启动超时'));
63
+ }
64
+ });
65
+
66
+ req.on('error', () => {
67
+ // 服务器未就绪,继续等待
68
+ if (attempts < maxAttempts) {
69
+ setTimeout(check, delay);
70
+ } else {
71
+ reject(new Error('服务器启动超时'));
72
+ }
73
+ });
74
+
75
+ req.on('timeout', () => {
76
+ req.destroy();
77
+ if (attempts < maxAttempts) {
78
+ setTimeout(check, delay);
79
+ } else {
80
+ reject(new Error('服务器启动超时'));
81
+ }
82
+ });
83
+ };
84
+
85
+ check();
86
+ });
87
+ }
88
+
89
+ // 启动服务器
90
+ function startServer() {
91
+ console.log('🚀 正在启动服务器...');
92
+ const server = spawn('node', ['server/index.js'], {
93
+ cwd: rootDir,
94
+ stdio: 'inherit',
95
+ shell: true
96
+ });
97
+
98
+ return server;
99
+ }
100
+
101
+ // 启动客户端(如果使用 Vite)
102
+ function startClient() {
103
+ console.log('🎨 正在启动客户端...');
104
+ const client = spawn('npm', ['run', 'client'], {
105
+ cwd: rootDir,
106
+ stdio: 'inherit',
107
+ shell: true
108
+ });
109
+
110
+ return client;
111
+ }
112
+
113
+ // 主函数
114
+ async function main() {
115
+ console.log('📦 CollabDocChat 正在启动...\n');
116
+
117
+ // 启动服务器
118
+ const server = startServer();
119
+
120
+ // 等待服务器就绪
121
+ try {
122
+ await waitForServer(`http://localhost:${PORT}/health`, 30, 1000);
123
+ console.log(`✅ 服务器已就绪: http://localhost:${PORT}\n`);
124
+ } catch (error) {
125
+ console.error('❌ 服务器启动失败:', error.message);
126
+ process.exit(1);
127
+ }
128
+
129
+ // 启动客户端
130
+ const client = startClient();
131
+
132
+ // 等待客户端就绪后打开浏览器
133
+ setTimeout(async () => {
134
+ try {
135
+ await waitForServer(CLIENT_URL, 20, 500);
136
+ console.log(`\n🌐 正在打开浏览器: ${CLIENT_URL}`);
137
+ openBrowser(CLIENT_URL);
138
+ } catch (error) {
139
+ console.log(`\n⚠️ 客户端可能还在启动中,请手动访问: ${CLIENT_URL}`);
140
+ // 即使检查失败也尝试打开浏览器
141
+ openBrowser(CLIENT_URL);
142
+ }
143
+ }, 2000);
144
+
145
+ // 处理退出信号
146
+ process.on('SIGINT', () => {
147
+ console.log('\n\n🛑 正在关闭服务器...');
148
+ server.kill();
149
+ client.kill();
150
+ process.exit(0);
151
+ });
152
+
153
+ process.on('SIGTERM', () => {
154
+ server.kill();
155
+ client.kill();
156
+ process.exit(0);
157
+ });
158
+ }
159
+
160
+ main().catch(error => {
161
+ console.error('❌ 启动失败:', error);
162
+ process.exit(1);
163
+ });
164
+
package/vite.config.js ADDED
@@ -0,0 +1,21 @@
1
+ import { defineConfig } from 'vite';
2
+
3
+ export default defineConfig({
4
+ server: {
5
+ port: 5173,
6
+ open: true, // 自动打开浏览器
7
+ proxy: {
8
+ '/api': {
9
+ target: 'http://localhost:3000',
10
+ changeOrigin: true
11
+ }
12
+ }
13
+ },
14
+ build: {
15
+ rollupOptions: {
16
+ external: ['emoji-picker-element'] // 外部化依赖
17
+ }
18
+ }
19
+ });
20
+
21
+