login_controller.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. 'use strict';
  2. /**
  3. * 登录页面控制器
  4. *
  5. * @author CaiAoLin
  6. * @date 2017/11/15
  7. * @version
  8. */
  9. const URL = require('url');
  10. const maintainConst = require('../const/maintain');
  11. const OAuth = require('co-wechat-oauth');
  12. const office = require('../const/cld_office')
  13. module.exports = app => {
  14. class LoginController extends app.BaseController {
  15. /**
  16. * 登录页面
  17. *
  18. * @param {Object} ctx - egg全局页面
  19. * @return {void}
  20. */
  21. async index(ctx) {
  22. if (ctx.helper.isMobile(ctx.request.header['user-agent'])) {
  23. ctx.redirect('/wap');
  24. return;
  25. }
  26. let projectData = null;
  27. // 判断是否有编号且存在
  28. if (ctx.params.code) {
  29. const projectInfo = await ctx.service.project.getProjectByCode(ctx.params.code.toString().trim());
  30. if (projectInfo) {
  31. projectData = projectInfo;
  32. } else {
  33. ctx.redirect('/');
  34. return;
  35. }
  36. }
  37. const errorMessage = ctx.session.loginError;
  38. // 显示完删除
  39. ctx.session.loginError = null;
  40. // 获取系统维护信息
  41. const maintainData = await ctx.service.maintain.getDataById(1);
  42. if (!ctx.app.config.is_debug) {
  43. await ctx.service.maintain.syncMaintainData();
  44. }
  45. const renderData = {
  46. projectData,
  47. maintainData,
  48. maintainConst,
  49. errorMessage,
  50. hostUrl: ctx.protocol + '://' + ctx.host,
  51. appid: ctx.app.config.wxCode.appid,
  52. };
  53. await ctx.render('login/login.ejs', renderData);
  54. }
  55. /**
  56. * 微信扫码认证并返回
  57. *
  58. * @param {Object} ctx - egg全局页面
  59. * @return {void}
  60. */
  61. async wxAuth(ctx) {
  62. const code = ctx.query.code;
  63. try {
  64. const client = new OAuth(ctx.app.config.wxCode.appid, ctx.app.config.wxCode.appsecret);
  65. const token = await client.getAccessToken(code);
  66. // const user = await client.getUser(token.data.openid);
  67. // console.log(user);
  68. if (!token) {
  69. throw '微信扫码获取信息失败';
  70. }
  71. // 判断扫码者项目是否只有一个,是则直接跳到登录页,否则显示项目选择页
  72. const paList = await ctx.service.projectAccount.getAllDataByCondition({ where: { wx_unionid: token.data.unionid } });
  73. if (paList && paList.length === 1) {
  74. const pro = await ctx.service.project.getDataById(paList[0].project_id);
  75. let redirect_url = ctx.protocol + '://' + ctx.host;
  76. redirect_url += ctx.query.state ? ctx.query.state : '/dashboard';
  77. ctx.redirect('/wx/url2web?project=' + pro.code + '&url=' + redirect_url + '&unionid=' + token.data.unionid);
  78. } else {
  79. ctx.session.wechatLogin = token.data.unionid;
  80. ctx.redirect('/wxproject');
  81. }
  82. } catch (error) {
  83. this.log(error);
  84. ctx.session.loginError = error;
  85. ctx.redirect('/login');
  86. }
  87. }
  88. async wxProject(ctx) {
  89. try {
  90. const unionid = ctx.session.wechatLogin;
  91. if (!unionid) {
  92. throw '扫码信息已失效,请重新登录';
  93. }
  94. ctx.session.wechatLogin = null;
  95. const paList = await ctx.service.projectAccount.getAllDataByCondition({ where: { wx_unionid: unionid } });
  96. const pidList = ctx.app._.uniq(ctx.app._.map(paList, 'project_id'));
  97. const pList = [];
  98. const redirect_url = ctx.protocol + '://' + ctx.host + '/dashboard';
  99. for (const p of pidList) {
  100. const pro = await ctx.service.project.getDataById(p);
  101. pro.userMsg = ctx.app._.find(paList, { project_id: p });
  102. pList.push(pro);
  103. }
  104. // 获取系统维护信息
  105. const maintainData = await ctx.service.maintain.getDataById(1);
  106. const renderData = {
  107. maintainData,
  108. maintainConst,
  109. unionid,
  110. pList,
  111. redirect_url,
  112. };
  113. await ctx.render('login/wxproject.ejs', renderData);
  114. } catch (error) {
  115. this.log(error);
  116. ctx.session.loginError = error;
  117. ctx.redirect('/login');
  118. }
  119. }
  120. // 设置用户微信登录项目,跳转到对应wap页面
  121. async url2web(ctx) {
  122. try {
  123. if (!ctx.query.project || !ctx.query.url || !ctx.query.unionid) {
  124. throw '参数有误';
  125. }
  126. const code = ctx.query.project;
  127. // 查找项目数据
  128. const projectData = await ctx.service.project.getProjectByCode(code.toString().trim());
  129. if (projectData === null) {
  130. throw '不存在项目数据';
  131. }
  132. const pa = await ctx.service.projectAccount.getDataByCondition({ project_id: projectData.id, wx_unionid: ctx.query.unionid });
  133. if (!pa) {
  134. throw '该微信号未绑定此项目';
  135. }
  136. if (pa.enable !== 1) {
  137. // 判断是否有设置停用提示,有则展示
  138. const msg = await ctx.service.projectStopmsg.getMsg(projectData.id);
  139. throw msg;
  140. }
  141. // 设置项目和用户session记录
  142. const result = await ctx.service.projectAccount.accountLogin({ project: projectData, accountData: pa }, 3);
  143. if (!result) {
  144. throw '登录出错';
  145. }
  146. ctx.redirect(ctx.query.url);
  147. } catch (error) {
  148. const renderData = {
  149. status: 1,
  150. msg: error,
  151. };
  152. await ctx.render('wechat/tips.ejs', renderData);
  153. }
  154. }
  155. /**
  156. * 登录操作
  157. *
  158. * @param {Object} ctx - egg全局变量
  159. * @return {void}
  160. */
  161. async login(ctx) {
  162. let loginType = ctx.request.body.type;
  163. try {
  164. loginType = parseInt(loginType);
  165. const result = await ctx.service.projectAccount.accountLogin(ctx.request.body, loginType);
  166. if (!result) {
  167. throw '用户名或密码错误';
  168. }
  169. // 查找项目数据
  170. const projectData = await this.ctx.service.project.getProjectByCode(ctx.request.body.project.toString().trim());
  171. let subProject = await ctx.service.subProject.getSubProject(projectData.id, ctx.session.sessionUser.accountId, ctx.session.sessionUser.is_admin, true);
  172. if (result === 2) {
  173. // 判断是否有设置停用提示,有则展示
  174. const msg = await ctx.service.projectStopmsg.getMsg(projectData.id);
  175. throw msg;
  176. }
  177. // 调用 rotateCsrfSecret 刷新用户的 CSRF token
  178. ctx.rotateCsrfSecret();
  179. // 判断是否已经有对应用户信息,没有则跳转初始化页面
  180. const needBoot = await ctx.service.customer.isNeedBoot(ctx.request.body);
  181. // todo 登录进来暂时跳转项目列表,工作台做好了以后须改回去
  182. const url = needBoot ? '/boot' : (subProject && subProject.length === 1 ? `/sp/${subProject[0].id}/dashboard` : '/subproj');
  183. // const url = needBoot ? '/boot' : (subProject && subProject.length === 1 ? `/sp/${subProject[0].id}/dashboard` : '/dashboard');
  184. const query = URL.parse(ctx.request.header.referer, true).query;
  185. ctx.redirect(query.referer ? query.referer : url);
  186. } catch (error) {
  187. this.log(error);
  188. ctx.session.loginError = error;
  189. // if (ctx.request.body && ctx.request.body.project && parseInt(ctx.request.body.hide_code)) {
  190. // ctx.redirect('/login/' + ctx.request.body.project);
  191. // } else {
  192. ctx.redirect('/login');
  193. // }
  194. }
  195. }
  196. /**
  197. * 退出登录
  198. *
  199. * @param {Object} ctx - egg全局变量
  200. * @return {void}
  201. */
  202. async logout(ctx) {
  203. // 删除session并跳转
  204. const code = ctx.session.sessionProject && ctx.session.sessionProject.code ? ctx.session.sessionProject.code : null;
  205. ctx.session = null;
  206. if (code) {
  207. ctx.redirect('/login/' + code);
  208. } else {
  209. ctx.redirect('/');
  210. }
  211. }
  212. /**
  213. * 获取项目名
  214. *
  215. * @param {Object} ctx - egg全局context
  216. * @return {void}
  217. */
  218. async projectName(ctx) {
  219. const response = {
  220. err: 0,
  221. msg: '',
  222. };
  223. const code = ctx.query.code;
  224. try {
  225. const data = await ctx.service.project.getProjectByCode(code);
  226. if (data) {
  227. response.data = data.name;
  228. } else {
  229. throw '项目不存在';
  230. }
  231. } catch (err) {
  232. response.err = 1;
  233. response.msg = err;
  234. }
  235. ctx.body = response;
  236. }
  237. /**
  238. * 忘记密码-重置密码
  239. * @param ctx
  240. * @returns {Promise<void>}
  241. */
  242. async resetPassword(ctx) {
  243. const response = {
  244. err: 0,
  245. index: 0,
  246. msg: '',
  247. };
  248. const code = ctx.request.body.code;
  249. const name = ctx.request.body.name;
  250. try {
  251. const data = await ctx.service.project.getProjectByCode(code);
  252. if (data) {
  253. const pa = await ctx.service.projectAccount.getDataByCondition({ account: name, project_id: data.id });
  254. if (!pa) {
  255. response.index = 2;
  256. throw '登录账号不存在,请检查是否输入错误。';
  257. }
  258. if (!pa.auth_mobile) {
  259. response.index = 2;
  260. throw '登录账号还没有认证手机,请联系项目管理员。';
  261. }
  262. // 重置密码并发短信
  263. const newpwd = ctx.helper.generateRandomString(6);
  264. console.log(newpwd);
  265. const result = await ctx.service.projectAccount.resetPassword(pa.id, newpwd);
  266. if (!result) {
  267. throw '修改密码失败';
  268. }
  269. response.data = {
  270. pName: data.name,
  271. name: pa.name,
  272. mobile: pa.auth_mobile.substr(0, 3) + '****' + pa.auth_mobile.substr(7),
  273. account: pa.account,
  274. };
  275. } else {
  276. response.index = 1;
  277. throw '项目不存在,请检查是否输入有误。';
  278. }
  279. } catch (err) {
  280. response.err = 1;
  281. response.msg = err;
  282. }
  283. ctx.body = response;
  284. }
  285. /**
  286. * 接口登录页面
  287. *
  288. * @param {Object} ctx - egg全局页面
  289. * @return {void}
  290. */
  291. async port(ctx) {
  292. // 获取系统维护信息
  293. const maintainData = await ctx.service.maintain.getDataById(1);
  294. if (!ctx.app.config.is_debug) {
  295. await ctx.service.maintain.syncMaintainData();
  296. }
  297. let pa;
  298. try {
  299. if (ctx.session.loginError !== null && ctx.session.loginError !== undefined) {
  300. throw ctx.session.loginError;
  301. }
  302. if (!ctx.query.mobile) {
  303. throw '参数有误';
  304. }
  305. pa = await ctx.service.projectAccount.getDataByCondition({ mobile: ctx.query.mobile, project_id: ctx.projectData.id });
  306. if (!pa) {
  307. throw '您无权限登录系统。';
  308. }
  309. if (pa.bind === 0) {
  310. // 先绑定再登录
  311. throw '';
  312. } else {
  313. if (pa.enable !== 1) {
  314. // 判断是否有设置停用提示,有则展示
  315. const msg = await ctx.service.projectStopmsg.getMsg(ctx.projectData.id);
  316. throw msg;
  317. }
  318. const result = await ctx.service.projectAccount.accountLogin({ project: ctx.projectData, accountData: pa }, 3);
  319. if (!result) {
  320. throw '登录出错';
  321. }
  322. const returnUrl = ctx.projectData.after_login_url ? ctx.projectData.after_login_url : '/dashboard';
  323. ctx.redirect(returnUrl);
  324. }
  325. } catch (error) {
  326. // this.log(error);
  327. console.log(error);
  328. ctx.session.loginError = error;
  329. }
  330. const errorMessage = ctx.session.loginError;
  331. // 显示完删除
  332. ctx.session.loginError = null;
  333. const renderData = {
  334. maintainData,
  335. maintainConst,
  336. errorMessage,
  337. projectData: ctx.projectData,
  338. accountData: pa,
  339. };
  340. await ctx.render('login/login_port.ejs', renderData);
  341. }
  342. /**
  343. * 登录操作
  344. *
  345. * @param {Object} ctx - egg全局变量
  346. * @return {void}
  347. */
  348. async loginPort(ctx) {
  349. let loginType = ctx.request.body.type;
  350. try {
  351. loginType = parseInt(loginType);
  352. const data = await ctx.service.project.getProjectByCode(ctx.request.body.code.toString().trim());
  353. if (data === null) {
  354. throw '不存在项目数据';
  355. }
  356. if (data.custom === 0) {
  357. throw '无法通过接口登录本系统';
  358. }
  359. if (data && data.custom === 1) {
  360. const pa = await ctx.service.projectAccount.getDataById(ctx.request.body.accountId);
  361. if (!pa) {
  362. throw '您无权限登录系统。';
  363. }
  364. if (pa.enable !== 1) {
  365. // 判断是否有设置停用提示,有则展示
  366. const msg = await ctx.service.projectStopmsg.getMsg(pa.project_id);
  367. throw msg;
  368. }
  369. const updateData = {
  370. bind: 1,
  371. };
  372. await ctx.service.projectAccount.update(updateData, { id: pa.id });
  373. const result = await ctx.service.projectAccount.accountLogin({ project: data, accountData: pa }, loginType);
  374. if (!result) {
  375. throw '绑定登录出错,请使用账号密码登录';
  376. }
  377. const projectData = await this.ctx.service.project.getProjectByCode(ctx.request.body.code.toString().trim());
  378. const returnUrl = projectData.after_login_url ? projectData.after_login_url : '/dashboard';
  379. ctx.redirect(returnUrl);
  380. // ctx.redirect('/dashboard');
  381. }
  382. } catch (error) {
  383. this.log(error);
  384. ctx.session.loginError = error;
  385. if (ctx.request.body && ctx.request.body.code) {
  386. ctx.redirect('/login/' + ctx.request.body.code);
  387. } else {
  388. ctx.redirect('/login');
  389. }
  390. }
  391. }
  392. /**
  393. * (项目管理)获取账号
  394. * @param {Object} ctx - egg全局变量
  395. */
  396. async account(ctx) {
  397. const data = ctx.data;
  398. const response = {
  399. code: 0,
  400. data: 0,
  401. msg: '',
  402. };
  403. try {
  404. const project = await ctx.service.project.getProjectByCode(data.code);
  405. if (!project) throw '未找到该项目';
  406. const pa = await ctx.service.projectAccount.getAccountInfoByAccountWithPid(data.account, project.id);
  407. if (!pa ) throw '该账号不存在,请联系管理员';
  408. const manager = await ctx.service.manager.getDataById(project.manager_id)
  409. const { is_admin: isAdmin, account_group: accountGroup, ...otherObj } = pa
  410. response.data = {
  411. account: { ...otherObj, accountGroup, isAdmin},
  412. project: {
  413. code: project.code,
  414. name: project.name,
  415. categoryId: project.manager_office,
  416. category: office.list[project.manager_office],
  417. staff: manager.real_name
  418. }
  419. }
  420. } catch (error) {
  421. console.log(error);
  422. response.code = -1;
  423. response.msg = error.toString();
  424. }
  425. ctx.body = response;
  426. }
  427. /**
  428. * (项目管理)获取项目
  429. * @param {Object} ctx - egg全局变量
  430. */
  431. async project(ctx) {
  432. const data = ctx.data;
  433. const response = {
  434. code: 0,
  435. data: 0,
  436. msg: '',
  437. };
  438. try {
  439. const project = await ctx.service.project.getProjectByCode(data.code);
  440. if (!project) throw '未找到该项目';
  441. response.data = project;
  442. } catch (error) {
  443. response.code = -1;
  444. response.msg = error.toString();
  445. }
  446. ctx.body = response;
  447. }
  448. /**
  449. * (项目管理)校验项目
  450. * @param {Object} ctx - egg全局变量
  451. */
  452. async vertifyProject(ctx) {
  453. const response = {
  454. code: 0,
  455. data: 0,
  456. msg: '',
  457. };
  458. try {
  459. const code = ctx.session.sessionProject.code
  460. const accountData = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId)
  461. if (!code || !accountData) {
  462. throw new Error('参数错误')
  463. }
  464. const result = await ctx.service.project.verifyManagementProject(ctx.helper.createJWT({ code }));
  465. const token = ctx.helper.createJWT({ code, account: accountData.account })
  466. const redirect = `${app.config.managementPath}/auth?token=${token}`
  467. response.data = { ...result, is_admin: accountData.is_admin, redirect, env: app.config.env};
  468. } catch (error) {
  469. response.code = -1;
  470. response.msg = error.toString();
  471. }
  472. ctx.body = response;
  473. }
  474. /**
  475. * (项目管理)新增项目
  476. * @param {Object} ctx - egg全局变量
  477. */
  478. async addProject(ctx) {
  479. const response = {
  480. code: 0,
  481. data: {},
  482. msg: '',
  483. };
  484. try {
  485. const result = await ctx.service.project.addProjectFromManagement()
  486. if (!result) {
  487. throw new Error('请求失败')
  488. }
  489. const { code = -1, data: { token = ''} = { token: ''}, msg = '请求失败' } = result
  490. if ( code === 0 && token) {
  491. response.data = {
  492. redirect: `${app.config.managementPath}/auth?token=${token}`,
  493. }
  494. } else {
  495. throw new Error(msg)
  496. }
  497. } catch (error) {
  498. response.code = -1;
  499. response.msg = error.toString();
  500. }
  501. ctx.body = response;
  502. }
  503. /**
  504. * 项目管理授权页面
  505. *
  506. * @param {Object} ctx - egg全局页面
  507. * @return {void}
  508. */
  509. async management(ctx) {
  510. const data = ctx.data;
  511. // 获取系统维护信息
  512. const maintainData = await ctx.service.maintain.getDataById(1);
  513. if (!ctx.app.config.is_debug) {
  514. await ctx.service.maintain.syncMaintainData();
  515. }
  516. let account, project;
  517. try {
  518. if (ctx.session.loginError !== null) {
  519. throw ctx.session.loginError;
  520. }
  521. if (!data) {
  522. throw '参数有误';
  523. }
  524. project = await ctx.service.project.getDataByCondition({ code: data.code })
  525. if (!project) {
  526. throw '未找到该项目';
  527. }
  528. account = await ctx.service.projectAccount.getDataByCondition({ project_id: project.id, account: data.account });
  529. if (!account) {
  530. throw '您无权限登录系统。';
  531. }
  532. if (account.enable !== 1) {
  533. // 判断是否有设置停用提示,有则展示
  534. const msg = await ctx.service.projectStopmsg.getMsg(project.id);
  535. throw msg;
  536. }
  537. const result = await ctx.service.projectAccount.accountLogin({ project, accountData: account }, 3);
  538. if (!result) {
  539. throw '登录出错';
  540. }
  541. ctx.redirect('/dashboard');
  542. } catch (error) {
  543. // this.log(error);
  544. console.log(error);
  545. ctx.session.loginError = error;
  546. }
  547. const errorMessage = ctx.session.loginError;
  548. // 显示完删除
  549. ctx.session.loginError = null;
  550. const renderData = {
  551. maintainData,
  552. maintainConst,
  553. errorMessage,
  554. projectData: project,
  555. accountData: account,
  556. };
  557. await ctx.render('login/login_management.ejs', renderData);
  558. }
  559. /** 拉取项目下所有计量账号至项目管理 */
  560. async syncProjectAccount(ctx) {
  561. const response = {
  562. code: 0,
  563. data: [],
  564. msg: '',
  565. };
  566. try {
  567. const { code = ''} = ctx.data
  568. if (!code) throw '参数错误';
  569. const projectData = await ctx.service.project.getProjectByCode(code)
  570. if (!projectData) throw '未找到项目';
  571. const data = await ctx.service.projectAccount.getAllProjectAccountByPid(projectData.id)
  572. response.data = data || []
  573. } catch (error) {
  574. response.code = -1
  575. response.msg = error.toString()
  576. }
  577. ctx.body = response
  578. }
  579. /** (项目管理) 验证账号密码 */
  580. async syncValidAccount(ctx) {
  581. const response = {
  582. code: 0,
  583. data: {},
  584. msg: '',
  585. };
  586. try {
  587. if (!ctx.data) {
  588. throw '参数有误';
  589. }
  590. const { code, account, password} = ctx.data;
  591. if (!code || !account || !password) {
  592. throw '参数有误';
  593. }
  594. const projectData = await ctx.service.project.getProjectByCode(code)
  595. if (!projectData) throw '未找到项目';
  596. const result = await ctx.service.projectAccount.accountLogin({ project: code, project_password: password, account }, 2);
  597. if (!result) {
  598. throw '用户名或密码错误';
  599. }
  600. if (result === 2) {
  601. // 判断是否有设置停用提示,有则展示
  602. const msg = await ctx.service.projectStopmsg.getMsg(projectData.id);
  603. throw msg;
  604. }
  605. } catch (error) {
  606. response.code = -1;
  607. response.msg = error.toString();
  608. }
  609. ctx.body = response;
  610. }
  611. }
  612. return LoginController;
  613. };