login_controller.js 22 KB

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