login_controller.js 24 KB

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