@gingkoo/base-server 0.0.1-alpha.0 → 0.0.1-alpha.10

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.
Files changed (122) hide show
  1. package/README.md +4 -0
  2. package/app.js +41 -40
  3. package/backend/common/entity.js +55 -0
  4. package/backend/common/enum.js +247 -0
  5. package/backend/common/fss/index.js +18 -0
  6. package/backend/common/fss/routers/attachment.js +45 -0
  7. package/backend/common/fss/routers/download.js +43 -0
  8. package/backend/common/fss/routers/import_export.js +113 -0
  9. package/backend/common/fss/routers/resources.js +149 -0
  10. package/backend/common/fss/routers/upload.js +81 -0
  11. package/backend/common/fss/services/import_export.js +159 -0
  12. package/backend/common/fss/services/index.js +92 -0
  13. package/backend/common/fss/utils.js +39 -0
  14. package/backend/common/ginfo/config.js +5 -0
  15. package/backend/common/ginfo/index.js +62 -0
  16. package/backend/common/index_template.html +28 -0
  17. package/backend/common/logger/index.js +96 -0
  18. package/backend/common/mapping.js +128 -0
  19. package/backend/common/middleware/auth.js +109 -0
  20. package/backend/common/middleware/cors.js +13 -0
  21. package/backend/common/middleware/response.js +25 -0
  22. package/backend/common/page_engine.js +487 -0
  23. package/backend/common/schedule.js +45 -0
  24. package/backend/common/services/dataCombine.js +67 -0
  25. package/backend/common/services/dept.js +37 -0
  26. package/backend/common/services/dict.js +488 -0
  27. package/backend/common/services/email.js +49 -0
  28. package/backend/common/services/generalConfig.js +137 -0
  29. package/backend/common/services/login.js +18 -0
  30. package/backend/common/services/notice.js +260 -0
  31. package/backend/common/services/permission.js +500 -0
  32. package/backend/common/services/roles.js +57 -0
  33. package/backend/common/services/send-notice.js +86 -0
  34. package/backend/common/services/task.js +259 -0
  35. package/backend/common/services/user.js +673 -0
  36. package/backend/common/socket.js +18 -0
  37. package/backend/common/sse/index.js +81 -0
  38. package/backend/common/sse/router.js +30 -0
  39. package/backend/common/task.js +75 -0
  40. package/backend/common/wechat/index.js +9 -0
  41. package/backend/common/wechat/routers/auth.js +238 -0
  42. package/{modules/user/frontend → backend/common/wechat/routers}/index.html +14 -7
  43. package/backend/common/wechat/services/auth.js +209 -0
  44. package/backend/common/wechat/services/notice.js +171 -0
  45. package/backend/config/index.js +61 -0
  46. package/backend/config/path.js +3 -0
  47. package/backend/router.js +100 -0
  48. package/backend/routers/app.js +222 -0
  49. package/backend/routers/automate.js +276 -0
  50. package/backend/routers/dict.js +370 -0
  51. package/backend/routers/email.js +85 -0
  52. package/backend/routers/generalConfig.js +276 -0
  53. package/backend/routers/idm.js +245 -0
  54. package/backend/routers/module.js +357 -0
  55. package/backend/routers/notice.js +138 -0
  56. package/backend/routers/pages.js +46 -0
  57. package/backend/routers/permission.js +985 -0
  58. package/backend/routers/setting.js +184 -0
  59. package/backend/routers/team/index.js +22 -0
  60. package/backend/routers/team/routers/mapping.js +29 -0
  61. package/backend/routers/team/routers/member.js +72 -0
  62. package/backend/routers/team/routers/membermanage.js +289 -0
  63. package/backend/routers/team/routers/pages.js +47 -0
  64. package/backend/routers/team/routers/roles.js +92 -0
  65. package/backend/routers/team/routers/teaminfo.js +27 -0
  66. package/backend/routers/team/routers/usergroup.js +213 -0
  67. package/backend/routers/team/services/mapping.js +101 -0
  68. package/backend/routers/team/services/member.js +206 -0
  69. package/backend/routers/team/services/roles.js +71 -0
  70. package/backend/routers/team/services/teaminfo.js +20 -0
  71. package/backend/routers/team/services/usergroup.js +128 -0
  72. package/backend/routers/user.js +436 -0
  73. package/backend/services/automate.js +60 -0
  74. package/backend/services/config.js +14 -0
  75. package/backend/services/module.js +298 -0
  76. package/backend/services/permission.js +192 -0
  77. package/backend/services/services.js +115 -0
  78. package/backend/services/setting.js +190 -0
  79. package/backend/services/token.js +42 -0
  80. package/backend/space.js +52 -0
  81. package/backend/space_mapping.js +22 -0
  82. package/backend/utils/avatar.js +48 -0
  83. package/backend/utils/color_gen_helper.js +20 -0
  84. package/backend/utils/date.js +66 -0
  85. package/backend/utils/excel.js +446 -0
  86. package/backend/utils/fs/doc.md +64 -0
  87. package/backend/utils/fs/index.js +127 -0
  88. package/backend/utils/jwt.js +54 -0
  89. package/backend/utils/modules/sequence.js +93 -0
  90. package/backend/utils/object.js +31 -0
  91. package/backend/utils/page-query-helper/index.js +61 -0
  92. package/backend/utils/path.js +123 -0
  93. package/backend/utils/run.js +25 -0
  94. package/backend/utils/tokenize.js +82 -0
  95. package/backend/utils/typeof.js +5 -0
  96. package/backend/utils/util.js +153 -0
  97. package/backend/views/api/index.js +32 -0
  98. package/backend/views/api/index.xml +49 -0
  99. package/backend/views/dict/index.js +80 -0
  100. package/backend/views/dict/index.xml +52 -0
  101. package/backend/views/index.js +32 -0
  102. package/backend/views/members_manage/index.js +68 -0
  103. package/backend/views/members_manage/index.xml +68 -0
  104. package/backend/views/roles/index.js +17 -0
  105. package/backend/views/roles/index.xml +47 -0
  106. package/backend/views/usergroup/index.js +68 -0
  107. package/backend/views/usergroup/index.xml +65 -0
  108. package/dist/base-assets/css/index-ffdb55a5.css +3 -0
  109. package/dist/base-assets/css/index-ffdb55a5.css.gz +0 -0
  110. package/dist/base-assets/js/index-b3998a47.js +762 -0
  111. package/dist/base-assets/js/index-b3998a47.js.gz +0 -0
  112. package/dist/base-assets/js/react-cropper.es-d5f06996.js +10 -0
  113. package/dist/base-assets/js/react-cropper.es-d5f06996.js.gz +0 -0
  114. package/dist/base-assets/png/u9-2348c304.png +0 -0
  115. package/dist/base-assets/woff2/materialicons-83be7b2f.woff2 +0 -0
  116. package/dist/index.html +162 -0
  117. package/package.json +62 -5
  118. package/common/router.js +0 -42
  119. package/modules/user/backend/index.js +0 -19
  120. package/modules/user/backend/routers/user.js +0 -11
  121. package/modules/user/frontend/index.js +0 -1
  122. package/serve.js +0 -9
@@ -0,0 +1,81 @@
1
+ const bgTaskEnum = {
2
+ taskProgressStatus: {
3
+ dataLoading: 'DataLoading',
4
+ importIntoData: 'ImportIntoData',
5
+
6
+ exportOutData: 'ExportOutData',
7
+ fileBuilding: 'FileBuilding',
8
+
9
+ taskComplete: 'TaskComplete',
10
+ taskError: 'TaskError',
11
+ },
12
+
13
+ eventType: {
14
+ addTask: 'AddTask',
15
+ changeTaskStatus: 'ChangeTaskStatus',
16
+ overTask: 'OverTask',
17
+ },
18
+ };
19
+
20
+ class Sse {
21
+ users = {};
22
+
23
+ constructor() {}
24
+
25
+ addUser(userId, client) {
26
+ this.users[userId] = {
27
+ client,
28
+ cancelTasks: [],
29
+ };
30
+ }
31
+
32
+ removeUser(userId) {
33
+ Reflect.deleteProperty(this.users, userId);
34
+ }
35
+
36
+ getUser(userId) {
37
+ return this.users[userId]?.client || null;
38
+ }
39
+
40
+ // 发送通知
41
+ connectEs(tasks, userId) {
42
+ let cancelTasks = this.users[userId]?.cancelTasks || [];
43
+ if (cancelTasks?.includes?.(tasks?.tasks?.TASK_ID)) return false;
44
+ let client = this.getUser(userId);
45
+ if (client) {
46
+ client.write(`data: ${JSON.stringify(tasks)}\n\n`);
47
+ }
48
+ }
49
+
50
+ // 添加后台任务
51
+ addBgTasks(tasks, userId) {
52
+ if (!tasks || !userId) return false;
53
+ this.connectEs({ tasks, type: bgTaskEnum.eventType.addTask }, userId);
54
+ }
55
+
56
+ // 修改后台任务状态
57
+ changeBgTaskSatus(tasks, userId) {
58
+ if (!tasks || !userId) return false;
59
+ this.connectEs({ tasks, type: bgTaskEnum.eventType.changeTaskStatus }, userId);
60
+ }
61
+
62
+ // 结束后台任务
63
+ overBgTaskStatus(tasks, userId) {
64
+ if (!tasks || !userId) return false;
65
+ this.connectEs({ tasks, type: bgTaskEnum.eventType.overTask }, userId);
66
+ }
67
+
68
+ // 取消后台任务 不再通知前端
69
+ cancelBgTaskStatus(taskId, userId) {
70
+ if (Array.isArray(this.users[userId]?.cancelTasks)) {
71
+ this.users[userId].cancelTasks.push(taskId);
72
+ }
73
+ }
74
+ }
75
+
76
+ const sse = new Sse();
77
+
78
+ module.exports = {
79
+ sse,
80
+ bgTaskEnum,
81
+ };
@@ -0,0 +1,30 @@
1
+ var express = require('express');
2
+ var router = express.Router();
3
+ // var express_ws = require('express-ws');
4
+ const { checkLogin } = require('../middleware/auth');
5
+ const { sse } = require('./index');
6
+
7
+ // express_ws(router);
8
+
9
+ // 任务消息eventsource
10
+ router.get('/es', [checkLogin], async function (req, res) {
11
+ const userId = req.get('X-UserId');
12
+ res.writeHead(200, { 'Content-Type': 'text/event-stream' });
13
+ req.connection.on('end', function () {
14
+ if (userId) {
15
+ console.log(`⭐️ ~ ${userId} res退出`);
16
+ sse.removeUser(userId);
17
+ res.end();
18
+ }
19
+ });
20
+ res.USER_ID = userId;
21
+ sse.addUser(userId, res);
22
+
23
+ try {
24
+ res.write('data: ' + userId + '连接成功\n\n');
25
+ } catch (error) {
26
+ console.log('🚀 ~ wtite error', error);
27
+ }
28
+ });
29
+
30
+ module.exports = router;
@@ -0,0 +1,75 @@
1
+ const isPlainObject = require('lodash/isPlainObject');
2
+
3
+ class TaskFactory {
4
+ /**
5
+ * type Task = {
6
+ * getTaskName: (params: any) => string;
7
+ * begin: (useid: string; taskid: string; params: any) => void;
8
+ * }
9
+ *
10
+ * interface Tasks {
11
+ * [module: string]: {
12
+ * [task: string]: Task
13
+ * }
14
+ * }
15
+ */
16
+ tasks = {};
17
+
18
+ register(module, moduleTasks) {
19
+ if (typeof module !== 'string') return console.log('TaskFactory register 缺少参数 module');
20
+
21
+ this.tasks[module] = moduleTasks ?? {};
22
+ }
23
+
24
+ getTask(module) {
25
+ return this.tasks[module];
26
+ }
27
+
28
+ /**
29
+ * get a taskname for the specified module and task.
30
+ * @param {string} module - task module
31
+ * @param {string} event - event name
32
+ * @param {string} rest - optional
33
+ * @param {string} defaultTaskName -
34
+ *
35
+ * @returns {string} - task name
36
+ */
37
+ async getTaskName(module, event, rest, defaultTaskName = '') {
38
+ let taskName = '';
39
+ let moduleTask = this.getTask(module);
40
+
41
+ /**
42
+ * @type {Record<string, Task>}
43
+ */
44
+ if (isPlainObject(moduleTask)) {
45
+ if (event in moduleTask && typeof moduleTask[event]['getTaskName'] === 'function') {
46
+ taskName = await moduleTask[event].getTaskName(rest);
47
+ }
48
+ }
49
+
50
+ return taskName ?? defaultTaskName;
51
+ }
52
+
53
+ /**
54
+ * Runs a task for the specified module and task.
55
+ *
56
+ * @param {string} module - The module for which the task is registered.
57
+ * @param {string} event - The forward direction of the task.
58
+ * @param {string} USER_ID - The unique identifier of the user.
59
+ * @param {string} taskid - The unique identifier of the task.
60
+ * @param {any} params - The parameters required for the task.
61
+ *
62
+ * @returns {void} - This method does not return any value.
63
+ */
64
+ async run(module, event, USER_ID, taskid, params) {
65
+ let moduleTask = this.getTask(module);
66
+
67
+ if (isPlainObject(moduleTask)) {
68
+ if (event in moduleTask && typeof moduleTask[event]['begin'] === 'function') {
69
+ moduleTask[event]['begin'](USER_ID, taskid, params);
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ module.exports = new TaskFactory();
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+ var express = require('express');
3
+ const auth = require('./routers/auth');
4
+
5
+ var router = express.Router();
6
+
7
+ router.use('/auth', auth);
8
+
9
+ module.exports = router;
@@ -0,0 +1,238 @@
1
+ 'use strict';
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const express = require('express');
5
+ const config = require('../../../config/index');
6
+
7
+ const authServices = require('../services/auth');
8
+ const ginfoServices = require('../../ginfo/index');
9
+ const userService = require('../../services/user');
10
+ const deptService = require('../../services/dept');
11
+ const generalConfigService = require('../../services/generalConfig');
12
+
13
+ var router = express.Router();
14
+
15
+ router.get('/', async function (req, res) {
16
+ let redirect_uri = req.query['redirect_uri'] || config.app.redirect_uri;
17
+
18
+ res.cookie('AUTH-Redirect', redirect_uri).redirect('/wechat/auth/oauth/qywx');
19
+ });
20
+
21
+ router.get('/deptUsers', async function (req, res) {
22
+ let token = await authServices.getAccessToken();
23
+ if (!token) return res.sendErr('获取token失败');
24
+ let depts = await authServices.getIdmList(token);
25
+ if (!depts) return res.sendErr('获取部门列表失败');
26
+ let memberList = [];
27
+ let deptInfo = [];
28
+ if (Array.isArray(depts)) {
29
+ deptInfo = await Promise.all(
30
+ depts.map(async (dept) => {
31
+ let list = await authServices.getIdmUser(token, dept.id + '');
32
+ memberList = memberList.concat(list);
33
+ let leader = dept?.['department_leader']?.[0] || list?.[0]?.['userid'];
34
+ let leaderInfo = await ginfoServices.getUserInfo(leader);
35
+ let deptNo = leaderInfo?.['GROUP_ID'] || null;
36
+ return {
37
+ ...dept,
38
+ LEADER_USER_ID: dept?.['department_leader']?.[0] ? leaderInfo?.['USER_NAME'] : null,
39
+ LEADER_USER_NAME: dept?.['department_leader']?.[0] ? leaderInfo?.['STAFF_NAME'] : null,
40
+ DEPT_NO: deptNo,
41
+ };
42
+ }),
43
+ );
44
+ }
45
+ memberList = await Promise.all(
46
+ memberList
47
+ .filter((user) => user)
48
+ .map(async (user) => {
49
+ let userinfo = await ginfoServices.getUserInfo(user.userid);
50
+ return {
51
+ ...user,
52
+ USER_ID: userinfo['USER_NAME'],
53
+ USER_NAME: userinfo['STAFF_NAME'],
54
+ DEPT_NO: userinfo['GROUP_ID'],
55
+ };
56
+ }),
57
+ );
58
+
59
+ if (memberList.length != 204) {
60
+ return res.sendErr('查询错误:' + memberList.length);
61
+ }
62
+
63
+ let teamUsers = await userService.getUsers({ USER_STATUS: 'normal' });
64
+ let teamDepts = await userService.getDeptData();
65
+ if (!Array.isArray(teamUsers)) {
66
+ return res.sendErr('查询失败');
67
+ }
68
+ let teamUserIds = teamUsers.map((user) => user.USER_ID);
69
+ teamDepts = teamDepts?.map((dept) => dept.DEPT_NO) || [];
70
+ let addDepts = deptInfo.reduce((mo, dept) => {
71
+ if (dept.DEPT_NO && !teamDepts.includes(dept.DEPT_NO)) {
72
+ mo.push({
73
+ DEPT_NO: dept.DEPT_NO,
74
+ DEPT_NAME: dept.name,
75
+ DEPT_LEADER: dept.LEADER_USER_ID,
76
+ ORG_ID: global.orgid,
77
+ });
78
+ }
79
+ return mo;
80
+ }, []);
81
+ let addUsers = memberList.reduce((mo, user) => {
82
+ if (user?.USER_ID && !teamUserIds.includes(user.USER_ID)) {
83
+ mo.push({
84
+ ORG_ID: global.orgid,
85
+ USER_ID: user.USER_ID,
86
+ USER_NAME: user.USER_NAME,
87
+ DEPT_NO: user['DEPT_NO'],
88
+ STATUS: '00',
89
+ USER_STATUS: 'normal',
90
+ });
91
+ }
92
+ return mo;
93
+ }, []);
94
+
95
+ let orgUserObj = memberList.reduce((mo, user) => {
96
+ mo[user.USER_ID] = user.DEPT_NO;
97
+ return mo;
98
+ }, {});
99
+ let delUsers = teamUserIds
100
+ .filter((v) => !orgUserObj[v])
101
+ .map((v) => {
102
+ return {
103
+ USER_ID: v,
104
+ USER_STATUS: 'leave',
105
+ };
106
+ });
107
+
108
+ let updUsers = teamUsers
109
+ .filter((user) => user.DEPT_NO !== orgUserObj[user.USER_ID])
110
+ .map((user) => {
111
+ return {
112
+ DEPT_NO: orgUserObj[user.USER_ID],
113
+ USER_ID: user.USER_ID,
114
+ };
115
+ });
116
+
117
+ await Promise.all(
118
+ addDepts.map(async (dept) => {
119
+ return await deptService.createDept(dept);
120
+ }),
121
+ );
122
+ await Promise.all(
123
+ addUsers.map(async (user) => {
124
+ return await userService.syncUserInfo(user.USER_ID, user); //添加
125
+ // return userService.operTeamMember(user.USER_ID, user); //修改
126
+ }),
127
+ );
128
+
129
+ await Promise.all(
130
+ delUsers.map(async (user) => {
131
+ return userService.operTeamMember(user.USER_ID, user); //修改
132
+ }),
133
+ );
134
+
135
+ await Promise.all(
136
+ updUsers.map(async (user) => {
137
+ return userService.operTeamMember(user.USER_ID, user); //修改
138
+ }),
139
+ );
140
+
141
+ return res.sendOk({
142
+ message: '更新成功',
143
+ addDepts: addDepts.length,
144
+ addUsers: addUsers.length,
145
+ delUsers: delUsers.length,
146
+ updUsers,
147
+ });
148
+ });
149
+
150
+ router.get('/oauth/qywx', async (req, res) => {
151
+ let userAgent = req.get('User-Agent');
152
+ let qywxUrl = await authServices.getRedirectUrl(userAgent);
153
+ res.redirect(qywxUrl);
154
+ });
155
+
156
+ router.get('/oauth/qywx/callback', async function (req, res) {
157
+ let code = req.query['code'];
158
+ if (!code) {
159
+ res.sendErr('认证失败');
160
+ return;
161
+ }
162
+
163
+ let [err, result] = await authServices.code2token(code);
164
+ if (err) {
165
+ return res.sendErr(err?.message || '');
166
+ }
167
+ let { token, userinfo, qywxuserid } = result;
168
+ let params = {
169
+ USER_ID: userinfo['USER_NAME'],
170
+ USER_NAME: userinfo['STAFF_NAME'],
171
+ DEPT_NO: userinfo['GROUP_ID'],
172
+ STATUS: 'normal',
173
+ };
174
+ let oauth = {
175
+ USER_ID: userinfo['USER_NAME'],
176
+ OAUTH_VENDOR: 'workwx',
177
+ VENDOR_USER_ID: qywxuserid,
178
+ };
179
+
180
+ await userService.syncUserInfo(params.USER_ID, params);
181
+ await userService.syncUserOAuth(params.USER_ID, oauth);
182
+
183
+ let redirect_uri = req?.cookies?.['AUTH-Redirect'] || config.app.redirect_uri;
184
+
185
+ let expires = new Date();
186
+ expires.setDate(expires.getDate() + 3);
187
+
188
+ res.cookie('X-Token', token, { expires }).redirect(301, redirect_uri);
189
+ });
190
+
191
+ router.get('/gettoken', async function (req, res) {
192
+ let code = req.query['code'];
193
+
194
+ let [err, result] = await authServices.code2token(code);
195
+ if (err) {
196
+ res.type('text/html; charset=UTF-8');
197
+ return res.send(err?.message || '');
198
+ }
199
+ let { token, userinfo, qywxuserid } = result;
200
+
201
+ let params = {
202
+ USER_ID: userinfo['USER_NAME'],
203
+ USER_NAME: userinfo['STAFF_NAME'],
204
+ DEPT_NO: userinfo['GROUP_ID'],
205
+ STATUS: 'normal',
206
+ };
207
+ let oauth = {
208
+ USER_ID: userinfo['USER_NAME'],
209
+ OAUTH_VENDOR: 'workwx',
210
+ VENDOR_USER_ID: qywxuserid,
211
+ };
212
+
213
+ await userService.syncUserInfo(params.USER_ID, params);
214
+ await userService.syncUserOAuth(params.USER_ID, oauth);
215
+
216
+ let htmlContent = fs.readFileSync(path.join(__dirname, `./index.html`), 'utf8');
217
+
218
+ htmlContent = htmlContent.replace('{{token}}', token);
219
+
220
+ res.type('text/html; charset=UTF-8');
221
+
222
+ res.send(htmlContent);
223
+ });
224
+
225
+ router.get('/config', async function (req, res) {
226
+ let data = await generalConfigService.getFromConfig({ GROUP_ID: 'qywx' });
227
+
228
+ if (!data) {
229
+ return res.sendErr('获取配置失败');
230
+ }
231
+ res.sendOk({
232
+ appid: data.qywx_APPID,
233
+ agentid: data.qywx_AgentID,
234
+ redirect_uri: data.qywx_REDIRECT,
235
+ });
236
+ });
237
+
238
+ module.exports = router;
@@ -1,20 +1,27 @@
1
- <!doctype html>
2
- <html lang="zh">
1
+ <!DOCTYPE html>
2
+ <html>
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
+ <title></title>
5
6
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
7
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
7
8
  <meta name="renderer" content="webkit" />
8
9
  <meta name="force-rendering" content="webkit" />
9
10
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
10
- <title>金丘科技 - 团队协作平台</title>
11
- <link rel="shortcut icon" type="images/x-icon" href="/static/favicon.ico" />
12
- <link rel="stylesheet" type="text/css" href="/static/css/index.css" />
13
11
  </head>
14
12
 
15
13
  <body>
16
- <div id="root" class="app-wrapper">你好</div>
14
+ <div></div>
17
15
 
18
- <script src="./index.js"></script>
16
+ <script>
17
+ window.parent.postMessage(
18
+ {
19
+ msgType: 'login',
20
+ action: 'setToken',
21
+ data: '{{token}}',
22
+ },
23
+ '*',
24
+ );
25
+ </script>
19
26
  </body>
20
27
  </html>
@@ -0,0 +1,209 @@
1
+ var httpclient = require('node-httpclient');
2
+ var util = require('../../../utils/util');
3
+ const jwt = require('../../../utils/jwt');
4
+ const { logger } = require('../../logger');
5
+ const userService = require('../../services/user');
6
+ const configService = require('../../services/generalConfig');
7
+ const ginfoServices = require('../../ginfo/index');
8
+
9
+ /**
10
+ * 获取企业微信登录方式
11
+ * 方式一、企业微信内部自动登录
12
+ * 方式二、企业微信外部扫码登录
13
+ * @param {string} userAgent 当前登录用户设备信息 (包含wxwork 代表是 企业微信内部)
14
+ * @returns auth_redirect_url as string
15
+ */
16
+ const getRedirectUrl = async (userAgent) => {
17
+ let auth_redirect_url = '';
18
+ let data = await configService.getFromConfig({ GROUP_ID: 'qywx' });
19
+ let { qywx_AgentID, qywx_APPID, qywx_REDIRECT } = data;
20
+ // qywx_REDIRECT = http://gingkoo.com/teams
21
+ let redirect_uri = `${qywx_REDIRECT}/wechat/auth/oauth/qywx/callback`;
22
+
23
+ if (userAgent.indexOf('wxwork/') > -1) {
24
+ params = {
25
+ appid: qywx_APPID,
26
+ redirect_uri,
27
+ response_type: 'code',
28
+ scope: 'snsapi_base',
29
+ state: Date.now(),
30
+ };
31
+ auth_redirect_url =
32
+ 'https://open.weixin.qq.com/connect/oauth2/authorize?' +
33
+ util.urlencodeObject(params) +
34
+ '#wechat_redirect';
35
+ } else {
36
+ params = {
37
+ appid: qywx_APPID,
38
+ agentid: qywx_AgentID,
39
+ redirect_uri,
40
+ state: Date.now(),
41
+ };
42
+ auth_redirect_url =
43
+ 'https://open.work.weixin.qq.com/wwopen/sso/qrConnect?' + util.urlencodeObject(params);
44
+ }
45
+
46
+ return auth_redirect_url;
47
+ };
48
+
49
+ /**
50
+ * 登录code 换 useId
51
+ * @param {string} code 企业微信登录code
52
+ * @returns
53
+ */
54
+ const getUserId = async (code) => {
55
+ let accessToken = await getAccessToken();
56
+ let url = 'https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token={0}&code={1}'.format(
57
+ accessToken,
58
+ code,
59
+ );
60
+ logger.info(url);
61
+ resp = await httpclient.get(url);
62
+ json_data = resp.data;
63
+ console.dir(json_data);
64
+ if (json_data['errcode'] != 0) {
65
+ logger.info('error:{0}'.format(json_data['errmsg']));
66
+ return null;
67
+ }
68
+
69
+ if (json_data['UserId']) {
70
+ return json_data['UserId'];
71
+ }
72
+
73
+ logger.info('error:{0}'.format(json_data['errmsg']));
74
+ return null;
75
+ };
76
+
77
+ /**
78
+ * 获取企业微信 token
79
+ * @returns accessToken as string
80
+ */
81
+ const getAccessToken = async (corpsecret = '') => {
82
+ let data = await configService.getFromConfig({ GROUP_ID: 'qywx' });
83
+ let { qywx_APPID, qywx_APPKEY } = data;
84
+
85
+ params = {
86
+ corp_id: qywx_APPID,
87
+ corpsecret: corpsecret || qywx_APPKEY,
88
+ };
89
+
90
+ url =
91
+ 'https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corp_id}&corpsecret={corpsecret}'.format(
92
+ params,
93
+ );
94
+
95
+ console.log(url);
96
+ resp = await httpclient.get(url);
97
+ console.dir(resp.data);
98
+ json_data = resp.data;
99
+
100
+ if (json_data['errcode'] != 0) {
101
+ console.log('error:{0}'.format(json_data['errmsg']));
102
+ return null;
103
+ }
104
+
105
+ accessToken = json_data['access_token'];
106
+
107
+ return accessToken;
108
+ };
109
+
110
+ const updateUser = async () => {
111
+ let wxworkUser = [];
112
+ let wxWorkUserid = [];
113
+ let accessToken = await getAccessToken();
114
+ let department = await getIdmList(accessToken);
115
+ if (!department) return null;
116
+
117
+ for (let i = 0; i < department.length; i++) {
118
+ const { id } = department[i];
119
+ let data = await getIdmUser(accessToken, id);
120
+ if (data) {
121
+ wxworkUser = wxworkUser.concat(data);
122
+ }
123
+ }
124
+ // 获取第三方认证用户
125
+ let data = await userService.getIdmUserOauth();
126
+ if (!data) return;
127
+ data.map((v) => {
128
+ const { VENDOR_USER_ID, USER_ID } = v;
129
+ let filter = wxworkUser.find((v) => v.userid == VENDOR_USER_ID);
130
+ if (!filter) {
131
+ wxWorkUserid.push(USER_ID);
132
+ }
133
+ });
134
+ await userService.updateUser(wxWorkUserid);
135
+ };
136
+ // 根据部门id获取部门成员
137
+ const getIdmUser = async (access_token, department_id) => {
138
+ let url =
139
+ 'https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?access_token={0}&department_id={1}'.format(
140
+ access_token,
141
+ department_id,
142
+ );
143
+ let resp = await httpclient.get(url);
144
+ let json_data = resp.data;
145
+ if (json_data['errcode'] !== 0) {
146
+ return null;
147
+ }
148
+ if (json_data['userlist']) {
149
+ return json_data['userlist'];
150
+ }
151
+ return null;
152
+ };
153
+
154
+ // 获取部门列表
155
+ async function getIdmList(access_token) {
156
+ let url = 'https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token={0}'.format(
157
+ access_token,
158
+ );
159
+ let resp = await httpclient.get(url);
160
+ let json_data = resp.data;
161
+ if (json_data['errcode'] !== 0) {
162
+ return null;
163
+ }
164
+ if (json_data['department']) {
165
+ return json_data['department'];
166
+ }
167
+ return null;
168
+ }
169
+
170
+ const code2token = async (code) => {
171
+ if (!code) {
172
+ return [{ message: '认证失败' }];
173
+ }
174
+ logger.info('企业微信授权登录 code:', code);
175
+
176
+ let qywxuserid = await getUserId(code);
177
+ if (qywxuserid == null) {
178
+ return [{ message: '获取企业微信认证信息失败' }];
179
+ }
180
+
181
+ let userinfo = await ginfoServices.getUserInfo(qywxuserid);
182
+ if (userinfo == null) {
183
+ return [{ message: '获取用户认证信息失败' }];
184
+ }
185
+
186
+ let userid = userinfo['USER_NAME'];
187
+ let token = jwt.generateToken({
188
+ userid: userid,
189
+ });
190
+
191
+ return [
192
+ false,
193
+ {
194
+ token,
195
+ userinfo,
196
+ qywxuserid,
197
+ },
198
+ ];
199
+ };
200
+
201
+ module.exports = {
202
+ getAccessToken,
203
+ getUserId,
204
+ getRedirectUrl,
205
+ updateUser,
206
+ getIdmList,
207
+ getIdmUser,
208
+ code2token,
209
+ };