login_controller.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  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. const url = needBoot ? '/boot' : (subProject && subProject.length === 1 ? `/sp/${subProject[0].id}/dashboard` : '/dashboard');
  182. const query = URL.parse(ctx.request.header.referer, true).query;
  183. ctx.redirect(query.referer ? query.referer : url);
  184. } catch (error) {
  185. this.log(error);
  186. ctx.session.loginError = error;
  187. // if (ctx.request.body && ctx.request.body.project && parseInt(ctx.request.body.hide_code)) {
  188. // ctx.redirect('/login/' + ctx.request.body.project);
  189. // } else {
  190. ctx.redirect('/login');
  191. // }
  192. }
  193. }
  194. /**
  195. * 退出登录
  196. *
  197. * @param {Object} ctx - egg全局变量
  198. * @return {void}
  199. */
  200. async logout(ctx) {
  201. // 删除session并跳转
  202. const code = ctx.session.sessionProject && ctx.session.sessionProject.code ? ctx.session.sessionProject.code : null;
  203. ctx.session = null;
  204. if (code) {
  205. ctx.redirect('/login/' + code);
  206. } else {
  207. ctx.redirect('/');
  208. }
  209. }
  210. /**
  211. * 获取项目名
  212. *
  213. * @param {Object} ctx - egg全局context
  214. * @return {void}
  215. */
  216. async projectName(ctx) {
  217. const response = {
  218. err: 0,
  219. msg: '',
  220. };
  221. const code = ctx.query.code;
  222. try {
  223. const data = await ctx.service.project.getProjectByCode(code);
  224. if (data) {
  225. response.data = data.name;
  226. } else {
  227. throw '项目不存在';
  228. }
  229. } catch (err) {
  230. response.err = 1;
  231. response.msg = err;
  232. }
  233. ctx.body = response;
  234. }
  235. /**
  236. * 忘记密码-重置密码
  237. * @param ctx
  238. * @returns {Promise<void>}
  239. */
  240. async resetPassword(ctx) {
  241. const response = {
  242. err: 0,
  243. index: 0,
  244. msg: '',
  245. };
  246. const code = ctx.request.body.code;
  247. const name = ctx.request.body.name;
  248. try {
  249. const data = await ctx.service.project.getProjectByCode(code);
  250. if (data) {
  251. const pa = await ctx.service.projectAccount.getDataByCondition({ account: name, project_id: data.id });
  252. if (!pa) {
  253. response.index = 2;
  254. throw '登录账号不存在,请检查是否输入错误。';
  255. }
  256. if (!pa.auth_mobile) {
  257. response.index = 2;
  258. throw '登录账号还没有认证手机,请联系项目管理员。';
  259. }
  260. // 重置密码并发短信
  261. const newpwd = ctx.helper.generateRandomString(6);
  262. console.log(newpwd);
  263. const result = await ctx.service.projectAccount.resetPassword(pa.id, newpwd);
  264. if (!result) {
  265. throw '修改密码失败';
  266. }
  267. response.data = {
  268. pName: data.name,
  269. name: pa.name,
  270. mobile: pa.auth_mobile.substr(0, 3) + '****' + pa.auth_mobile.substr(7),
  271. account: pa.account,
  272. };
  273. } else {
  274. response.index = 1;
  275. throw '项目不存在,请检查是否输入有误。';
  276. }
  277. } catch (err) {
  278. response.err = 1;
  279. response.msg = err;
  280. }
  281. ctx.body = response;
  282. }
  283. /**
  284. * 接口登录页面
  285. *
  286. * @param {Object} ctx - egg全局页面
  287. * @return {void}
  288. */
  289. async port(ctx) {
  290. // 获取系统维护信息
  291. const maintainData = await ctx.service.maintain.getDataById(1);
  292. if (!ctx.app.config.is_debug) {
  293. await ctx.service.maintain.syncMaintainData();
  294. }
  295. let pa;
  296. try {
  297. if (ctx.session.loginError !== null && ctx.session.loginError !== undefined) {
  298. throw ctx.session.loginError;
  299. }
  300. if (!ctx.query.mobile) {
  301. throw '参数有误';
  302. }
  303. pa = await ctx.service.projectAccount.getDataByCondition({ mobile: ctx.query.mobile, project_id: ctx.projectData.id });
  304. if (!pa) {
  305. throw '您无权限登录系统。';
  306. }
  307. if (pa.bind === 0) {
  308. // 先绑定再登录
  309. throw '';
  310. } else {
  311. if (pa.enable !== 1) {
  312. // 判断是否有设置停用提示,有则展示
  313. const msg = await ctx.service.projectStopmsg.getMsg(ctx.projectData.id);
  314. throw msg;
  315. }
  316. const result = await ctx.service.projectAccount.accountLogin({ project: ctx.projectData, accountData: pa }, 3);
  317. if (!result) {
  318. throw '登录出错';
  319. }
  320. const returnUrl = ctx.projectData.after_login_url ? ctx.projectData.after_login_url : '/dashboard';
  321. ctx.redirect(returnUrl);
  322. }
  323. } catch (error) {
  324. // this.log(error);
  325. console.log(error);
  326. ctx.session.loginError = error;
  327. }
  328. const errorMessage = ctx.session.loginError;
  329. // 显示完删除
  330. ctx.session.loginError = null;
  331. const renderData = {
  332. maintainData,
  333. maintainConst,
  334. errorMessage,
  335. projectData: ctx.projectData,
  336. accountData: pa,
  337. };
  338. await ctx.render('login/login_port.ejs', renderData);
  339. }
  340. /**
  341. * 登录操作
  342. *
  343. * @param {Object} ctx - egg全局变量
  344. * @return {void}
  345. */
  346. async loginPort(ctx) {
  347. let loginType = ctx.request.body.type;
  348. try {
  349. loginType = parseInt(loginType);
  350. const data = await ctx.service.project.getProjectByCode(ctx.request.body.code.toString().trim());
  351. if (data === null) {
  352. throw '不存在项目数据';
  353. }
  354. if (data.custom === 0) {
  355. throw '无法通过接口登录本系统';
  356. }
  357. if (data && data.custom === 1) {
  358. const pa = await ctx.service.projectAccount.getDataById(ctx.request.body.accountId);
  359. if (!pa) {
  360. throw '您无权限登录系统。';
  361. }
  362. if (pa.enable !== 1) {
  363. // 判断是否有设置停用提示,有则展示
  364. const msg = await ctx.service.projectStopmsg.getMsg(pa.project_id);
  365. throw msg;
  366. }
  367. const updateData = {
  368. bind: 1,
  369. };
  370. await ctx.service.projectAccount.update(updateData, { id: pa.id });
  371. const result = await ctx.service.projectAccount.accountLogin({ project: data, accountData: pa }, loginType);
  372. if (!result) {
  373. throw '绑定登录出错,请使用账号密码登录';
  374. }
  375. const projectData = await this.ctx.service.project.getProjectByCode(ctx.request.body.code.toString().trim());
  376. const returnUrl = projectData.after_login_url ? projectData.after_login_url : '/dashboard';
  377. ctx.redirect(returnUrl);
  378. // ctx.redirect('/dashboard');
  379. }
  380. } catch (error) {
  381. this.log(error);
  382. ctx.session.loginError = error;
  383. if (ctx.request.body && ctx.request.body.code) {
  384. ctx.redirect('/login/' + ctx.request.body.code);
  385. } else {
  386. ctx.redirect('/login');
  387. }
  388. }
  389. }
  390. /**
  391. * (项目管理)获取账号
  392. * @param {Object} ctx - egg全局变量
  393. */
  394. async account(ctx) {
  395. const data = ctx.data;
  396. const response = {
  397. code: 0,
  398. data: 0,
  399. msg: '',
  400. };
  401. try {
  402. const project = await ctx.service.project.getProjectByCode(data.code);
  403. if (!project) throw '未找到该项目';
  404. const pa = await ctx.service.projectAccount.getAccountInfoByAccountWithPid(data.account, project.id);
  405. if (!pa ) throw '该账号不存在,请联系管理员';
  406. const manager = await ctx.service.manager.getDataById(project.manager_id)
  407. const { is_admin: isAdmin, account_group: accountGroup, ...otherObj } = pa
  408. response.data = {
  409. account: { ...otherObj, accountGroup, isAdmin},
  410. project: {
  411. code: project.code,
  412. name: project.name,
  413. categoryId: project.manager_office,
  414. category: office.list[project.manager_office],
  415. staff: manager.real_name
  416. }
  417. }
  418. } catch (error) {
  419. console.log(error);
  420. response.code = -1;
  421. response.msg = error.toString();
  422. }
  423. ctx.body = response;
  424. }
  425. /**
  426. * (项目管理)获取项目
  427. * @param {Object} ctx - egg全局变量
  428. */
  429. async project(ctx) {
  430. const data = ctx.data;
  431. const response = {
  432. code: 0,
  433. data: 0,
  434. msg: '',
  435. };
  436. try {
  437. const project = await ctx.service.project.getProjectByCode(data.code);
  438. if (!project) throw '未找到该项目';
  439. response.data = project;
  440. } catch (error) {
  441. response.code = -1;
  442. response.msg = error.toString();
  443. }
  444. ctx.body = response;
  445. }
  446. /**
  447. * (项目管理)校验项目
  448. * @param {Object} ctx - egg全局变量
  449. */
  450. async vertifyProject(ctx) {
  451. const response = {
  452. code: 0,
  453. data: 0,
  454. msg: '',
  455. };
  456. try {
  457. const code = ctx.session.sessionProject.code
  458. const accountData = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId)
  459. if (!code || !accountData) {
  460. throw new Error('参数错误')
  461. }
  462. const result = await ctx.service.project.verifyManagementProject(ctx.helper.createJWT({ code }));
  463. const token = ctx.helper.createJWT({ code, account: accountData.account })
  464. const redirect = `${app.config.managementPath}/auth?token=${token}`
  465. response.data = { ...result, is_admin: accountData.is_admin, redirect, env: app.config.env};
  466. } catch (error) {
  467. response.code = -1;
  468. response.msg = error.toString();
  469. }
  470. ctx.body = response;
  471. }
  472. /**
  473. * (项目管理)新增项目
  474. * @param {Object} ctx - egg全局变量
  475. */
  476. async addProject(ctx) {
  477. const response = {
  478. code: 0,
  479. data: {},
  480. msg: '',
  481. };
  482. try {
  483. const result = await ctx.service.project.addProjectFromManagement()
  484. if (!result) {
  485. throw new Error('请求失败')
  486. }
  487. const { code = -1, data: { token = ''} = { token: ''}, msg = '请求失败' } = result
  488. if ( code === 0 && token) {
  489. response.data = {
  490. redirect: `${app.config.managementPath}/auth?token=${token}`,
  491. }
  492. } else {
  493. throw new Error(msg)
  494. }
  495. } catch (error) {
  496. response.code = -1;
  497. response.msg = error.toString();
  498. }
  499. ctx.body = response;
  500. }
  501. /**
  502. * 项目管理授权页面
  503. *
  504. * @param {Object} ctx - egg全局页面
  505. * @return {void}
  506. */
  507. async management(ctx) {
  508. const data = ctx.data;
  509. // 获取系统维护信息
  510. const maintainData = await ctx.service.maintain.getDataById(1);
  511. if (!ctx.app.config.is_debug) {
  512. await ctx.service.maintain.syncMaintainData();
  513. }
  514. let account, project;
  515. try {
  516. if (ctx.session.loginError !== null) {
  517. throw ctx.session.loginError;
  518. }
  519. if (!data) {
  520. throw '参数有误';
  521. }
  522. project = await ctx.service.project.getDataByCondition({ code: data.code })
  523. if (!project) {
  524. throw '未找到该项目';
  525. }
  526. account = await ctx.service.projectAccount.getDataByCondition({ project_id: project.id, account: data.account });
  527. if (!account) {
  528. throw '您无权限登录系统。';
  529. }
  530. if (account.enable !== 1) {
  531. // 判断是否有设置停用提示,有则展示
  532. const msg = await ctx.service.projectStopmsg.getMsg(project.id);
  533. throw msg;
  534. }
  535. const result = await ctx.service.projectAccount.accountLogin({ project, accountData: account }, 3);
  536. if (!result) {
  537. throw '登录出错';
  538. }
  539. ctx.redirect('/dashboard');
  540. } catch (error) {
  541. // this.log(error);
  542. console.log(error);
  543. ctx.session.loginError = error;
  544. }
  545. const errorMessage = ctx.session.loginError;
  546. // 显示完删除
  547. ctx.session.loginError = null;
  548. const renderData = {
  549. maintainData,
  550. maintainConst,
  551. errorMessage,
  552. projectData: project,
  553. accountData: account,
  554. };
  555. await ctx.render('login/login_management.ejs', renderData);
  556. }
  557. /** 拉取项目下所有计量账号至项目管理 */
  558. async syncProjectAccount(ctx) {
  559. const response = {
  560. code: 0,
  561. data: [],
  562. msg: '',
  563. };
  564. try {
  565. const { code = ''} = ctx.data
  566. if (!code) throw '参数错误';
  567. const projectData = await ctx.service.project.getProjectByCode(code)
  568. if (!projectData) throw '未找到项目';
  569. const data = await ctx.service.projectAccount.getAllProjectAccountByPid(projectData.id)
  570. response.data = data || []
  571. } catch (error) {
  572. response.code = -1
  573. response.msg = error.toString()
  574. }
  575. ctx.body = response
  576. }
  577. /** (项目管理) 验证账号密码 */
  578. async syncValidAccount(ctx) {
  579. const response = {
  580. code: 0,
  581. data: {},
  582. msg: '',
  583. };
  584. try {
  585. if (!ctx.data) {
  586. throw '参数有误';
  587. }
  588. const { code, account, password} = ctx.data;
  589. if (!code || !account || !password) {
  590. throw '参数有误';
  591. }
  592. const projectData = await ctx.service.project.getProjectByCode(code)
  593. if (!projectData) throw '未找到项目';
  594. const result = await ctx.service.projectAccount.accountLogin({ project: code, project_password: password, account }, 2);
  595. if (!result) {
  596. throw '用户名或密码错误';
  597. }
  598. if (result === 2) {
  599. // 判断是否有设置停用提示,有则展示
  600. const msg = await ctx.service.projectStopmsg.getMsg(projectData.id);
  601. throw msg;
  602. }
  603. } catch (error) {
  604. response.code = -1;
  605. response.msg = error.toString();
  606. }
  607. ctx.body = response;
  608. }
  609. }
  610. return LoginController;
  611. };