projects.controller.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. const projectsService = require('../service/projects.service');
  2. const pagesRoleService = require('../service/pagesRole.service');
  3. const pagesService = require('../service/pages.service');
  4. const menuService = require('../service/menu.service');
  5. const roleService = require('../service/roles.service');
  6. const projectUserService = require('../service/project.user.service');
  7. const templateUserService = require('../service/templates.service');
  8. const pageService = require('../service/pages.service');
  9. const publishService = require('../service/publish.service');
  10. const request = require('../utils/request');
  11. const util = require('../utils/util');
  12. const { MODEL_BASE_URL, ENABLE_MODEL_SERVICE } = require('../config');
  13. module.exports = {
  14. async getCategoryList(ctx) {
  15. const { userId } = util.decodeToken(ctx);
  16. const { pageNum, pageSize, keyword } = ctx.request.query;
  17. const { total } = await projectsService.getCategoryCount(keyword, userId);
  18. if (total == 0) {
  19. return util.success(ctx, {
  20. list: [],
  21. total: 0,
  22. pageSize: +pageSize || 12,
  23. pageNum: +pageNum || 1,
  24. });
  25. }
  26. const list = await projectsService.getCategoryList(pageNum || 1, pageSize || 12, keyword, userId);
  27. util.success(ctx, {
  28. list,
  29. total,
  30. pageSize: +pageSize,
  31. pageNum: +pageNum,
  32. });
  33. },
  34. // mars-admin 项目列表
  35. async getProjectList(ctx) {
  36. const { pageNum = 1, pageSize = 10, isTemplate, userId } = ctx.request.query;
  37. const template = util.isNumber(isTemplate) ? Number(isTemplate) : '';
  38. const uid = util.isNumber(userId) ? Number(userId) : '';
  39. const { total } = await projectsService.getProjectCount(template, uid);
  40. if (total == 0) {
  41. return util.success(ctx, {
  42. list: [],
  43. total: 0,
  44. pageSize: +pageSize,
  45. pageNum: +pageNum,
  46. });
  47. }
  48. const list = await projectsService.getProjectList(pageNum, pageSize, template, uid);
  49. util.success(ctx, {
  50. list,
  51. total,
  52. pageSize: +pageSize,
  53. pageNum: +pageNum,
  54. });
  55. },
  56. async create(ctx) {
  57. const { id, ...params } = ctx.request.body;
  58. const { userId, userName } = util.decodeToken(ctx);
  59. if (id) {
  60. if (!util.isNumber(id)) {
  61. return ctx.throw(400, '模板ID格式异常');
  62. }
  63. const project = await projectsService.getProjectByTemplateId(id);
  64. if (!project) {
  65. return ctx.throw(400, '模板不存在');
  66. }
  67. const insertRecord = await projectsService.installProject({
  68. ...project,
  69. userId,
  70. userName,
  71. name: params.name || project.name,
  72. remark: params.remark || project.remark,
  73. logo: params.logo || project.logo,
  74. });
  75. let dictMap = {};
  76. // 开启模型服务后,需要复制模型
  77. if (ENABLE_MODEL_SERVICE) {
  78. // 获取项目模型列表
  79. const res = await request
  80. .post(
  81. `${MODEL_BASE_URL}/api/model/model/copy`,
  82. JSON.stringify({
  83. oldProjectId: String(project.id),
  84. newProjectId: String(insertRecord.insertId),
  85. }),
  86. {
  87. headers: {
  88. authorization: ctx.request.headers?.authorization,
  89. },
  90. },
  91. )
  92. .catch((error) => {
  93. ctx.throw(400, '模型创建失败:' + error);
  94. });
  95. const result = JSON.parse(res.data);
  96. dictMap = result.oldNewDataDictionaryIdMap;
  97. }
  98. // 获取模板菜单列表
  99. const menusList = await menuService.getMenuByTemplateId(project.id);
  100. const originIdMap = {};
  101. let rootList = menusList.filter((menu) => !menu.parentId);
  102. // 递归创建菜单和页面
  103. while (rootList.length) {
  104. const parentIds = [];
  105. for (let menu of rootList) {
  106. // 保存父级菜单id
  107. parentIds.push(menu.id);
  108. if (menu.pageId) {
  109. // 获取菜单绑定的页面信息
  110. const page = await pagesService.getPagesById(menu.pageId);
  111. let pageRecord = { pageId: 0 };
  112. if (page) {
  113. page.pageData &&
  114. Object.keys(dictMap).forEach((key) => {
  115. page.pageData = page.pageData.replaceAll(`"dataDictionaryKey":"${key}"`, `"dataDictionaryKey":"${dictMap[key]}"`);
  116. });
  117. // 写入页面数据
  118. pageRecord = await pagesService.createPage(page.name, userId, userName, page.remark, page.pageData, insertRecord.insertId);
  119. }
  120. // 写入菜单数据
  121. const newRecord = await menuService.create({
  122. ...menu,
  123. parentId: originIdMap[menu.parentId],
  124. userId,
  125. userName,
  126. projectId: insertRecord.insertId,
  127. pageId: pageRecord.insertId,
  128. });
  129. originIdMap[menu.id] = newRecord.insertId;
  130. } else {
  131. const newRecord = await await menuService.create({
  132. ...menu,
  133. parentId: originIdMap[menu.parentId],
  134. userId,
  135. userName,
  136. projectId: insertRecord.insertId,
  137. });
  138. originIdMap[menu.id] = newRecord.insertId;
  139. }
  140. }
  141. // 获取下一级菜单
  142. rootList = menusList.filter((menu) => parentIds.find((pid) => pid === menu.parentId));
  143. }
  144. await templateUserService.updateInstallCount(id);
  145. util.success(ctx, '同步成功');
  146. } else {
  147. if (!params.name) {
  148. return ctx.throw(400, '项目名称不能为空');
  149. }
  150. if (!params.remark) {
  151. return ctx.throw(400, '项目描述不能为空');
  152. }
  153. if (!params.logo) {
  154. return ctx.throw(400, '项目logo不能为空');
  155. }
  156. await projectsService.createProject({
  157. ...params,
  158. userId,
  159. userName,
  160. });
  161. util.success(ctx);
  162. }
  163. },
  164. async delete(ctx) {
  165. const { id, type } = ctx.request.body;
  166. if (!util.isNumber(id)) {
  167. return ctx.throw(400, 'id参数不正确');
  168. }
  169. const { userId } = util.decodeToken(ctx);
  170. const [projectInfo] = await projectsService.getProjectInfoById(+id);
  171. if (!projectInfo || projectInfo.userId != userId) {
  172. return ctx.throw(400, '您暂无权限删除该项目');
  173. }
  174. // 删除项目本身
  175. const res = await projectsService.deleteProject(id, userId);
  176. // 删除项目对应开发者权限
  177. await pagesRoleService.deleteByPageId(id);
  178. // 删除项目菜单
  179. await menuService.deleteMenuByProjectId(id);
  180. // 删除项目角色
  181. await roleService.deleteByProjectId(id);
  182. // 删除项目对应访问者权限
  183. await projectUserService.deleteUserByProjectId(id);
  184. // 删除模型表
  185. await request.delete(`${MODEL_BASE_URL}/api/model/model/projectId/${id}`, {
  186. headers: {
  187. authorization: ctx.request.headers?.authorization,
  188. },
  189. });
  190. if (type == 'all') {
  191. await pagesService.deletePageByProjectId(id, userId);
  192. } else {
  193. await pagesService.updatePageForProjectId(id);
  194. }
  195. if (res.affectedRows > 0) {
  196. util.success(ctx);
  197. } else {
  198. return ctx.throw(400, '当前暂无权限');
  199. }
  200. },
  201. async update(ctx) {
  202. const { id, name, remark, logo } = ctx.request.body;
  203. if (!util.isNumber(id)) {
  204. return ctx.throw(400, 'id参数不正确');
  205. }
  206. if (!name) {
  207. return ctx.throw(400, '项目名称不能为空');
  208. }
  209. if (!remark) {
  210. return ctx.throw(400, '项目描述不能为空');
  211. }
  212. if (!logo) {
  213. return ctx.throw(400, '项目logo不能为空');
  214. }
  215. await projectsService.updateProjectInfo(ctx.request.body);
  216. util.success(ctx);
  217. },
  218. // 检查是否有项目权限
  219. async checkProjectAuth(ctx) {
  220. const { id } = ctx.request.body;
  221. if (!util.isNumber(id)) {
  222. return ctx.throw(400, '项目ID不正确');
  223. }
  224. const { userId } = util.decodeToken(ctx);
  225. const list = await projectsService.checkAuth(id);
  226. if (list.length === 0) {
  227. return util.success(ctx, '404');
  228. }
  229. if (list[0].userId !== userId && list.filter((item) => item.devUserId === userId).length === 0) {
  230. return util.success(ctx, '403');
  231. }
  232. util.success(ctx, '');
  233. },
  234. async detail(ctx) {
  235. const { id } = ctx.params;
  236. if (!util.isNumber(id)) {
  237. return ctx.throw(400, '项目ID不能为空');
  238. }
  239. const info = await projectsService.getProjectInfoById(id);
  240. if (!info?.length) {
  241. return util.fail(ctx, '当前项目不存在', 404);
  242. }
  243. util.success(ctx, info[0]);
  244. },
  245. /**
  246. * 项目下页面列表 - 一键发布
  247. */
  248. async oneClickPublishing(ctx) {
  249. const { userId, userName } = util.decodeToken(ctx);
  250. const { id } = ctx.request.body;
  251. if (!util.isNumber(id)) {
  252. return ctx.throw(400, '项目ID不能为空');
  253. }
  254. const info = await projectsService.getProjectInfoById(id);
  255. if (!info?.length) {
  256. return util.fail(ctx, '当前项目不存在', 404);
  257. }
  258. const authList = await projectsService.checkAuth(id);
  259. if (authList.length === 0) {
  260. util.success(ctx, '暂无发布权限');
  261. return false;
  262. }
  263. if (authList[0].userId !== userId && authList.filter((item) => item.devUserId === userId).length === 0) {
  264. util.success(ctx, '暂无发布权限');
  265. return false;
  266. }
  267. const ids = await pageService.getPageIdsByProjectId(Number(id));
  268. for (let { id: pageId } of ids) {
  269. // 获取菜单绑定的页面信息
  270. const page = await pagesService.getPagesById(pageId);
  271. // 只发布有数据和未发布的页面
  272. if (page && page.pageData && page.stgState != 3) {
  273. const result = await publishService.createPublish(pageId, page.name, page.pageData, userName, userId, 'stg');
  274. await pagesService.updatePageState(result.insertId, pageId, 'stg', '');
  275. }
  276. }
  277. util.success(ctx, '发布成功');
  278. },
  279. };