login_controller.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  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.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. ctx.redirect('/dashboard');
  312. }
  313. } catch (error) {
  314. // this.log(error);
  315. ctx.session.loginError = error;
  316. }
  317. const errorMessage = ctx.session.loginError;
  318. // 显示完删除
  319. ctx.session.loginError = null;
  320. const renderData = {
  321. maintainData,
  322. maintainConst,
  323. errorMessage,
  324. projectData: ctx.projectData,
  325. accountData: pa,
  326. };
  327. await ctx.render('login/login_port.ejs', renderData);
  328. }
  329. /**
  330. * 登录操作
  331. *
  332. * @param {Object} ctx - egg全局变量
  333. * @return {void}
  334. */
  335. async loginPort(ctx) {
  336. let loginType = ctx.request.body.type;
  337. try {
  338. loginType = parseInt(loginType);
  339. const data = await ctx.service.project.getProjectByCode(ctx.request.body.code.toString().trim());
  340. if (data === null) {
  341. throw '不存在项目数据';
  342. }
  343. if (data.custom === 0) {
  344. throw '无法通过接口登录本系统';
  345. }
  346. if (data && data.custom === 1) {
  347. const pa = await ctx.service.projectAccount.getDataById(ctx.request.body.accountId);
  348. if (!pa) {
  349. throw '您无权限登录系统。';
  350. }
  351. if (pa.enable !== 1) {
  352. throw '该账号已被停用,请联系销售人员';
  353. }
  354. const updateData = {
  355. bind: 1,
  356. };
  357. await ctx.service.projectAccount.update(updateData, { id: pa.id });
  358. const result = await ctx.service.projectAccount.accountLogin({ project: data, accountData: pa }, loginType);
  359. if (!result) {
  360. throw '绑定登录出错,请使用账号密码登录';
  361. }
  362. ctx.redirect('/dashboard');
  363. }
  364. } catch (error) {
  365. this.log(error);
  366. ctx.session.loginError = error;
  367. if (ctx.request.body && ctx.request.body.code) {
  368. ctx.redirect('/login/' + ctx.request.body.code);
  369. } else {
  370. ctx.redirect('/login');
  371. }
  372. }
  373. }
  374. /**
  375. * (项目管理)获取账号
  376. * @param {Object} ctx - egg全局变量
  377. */
  378. async account(ctx) {
  379. const data = ctx.data;
  380. const response = {
  381. code: 0,
  382. data: 0,
  383. msg: '',
  384. };
  385. try {
  386. const project = await ctx.service.project.getProjectByCode(data.code);
  387. if (!project) throw '未找到该项目';
  388. const pa = await ctx.service.projectAccount.getAccountInfoByAccountWithPid(data.account, project.id);
  389. if (!pa ) throw '该账号不存在,请联系管理员';
  390. const manager = await ctx.service.manager.getDataById(project.manager_id)
  391. const { is_admin: isAdmin, account_group: accountGroup, ...otherObj } = pa
  392. response.data = {
  393. account: { ...otherObj, accountGroup, isAdmin},
  394. project: {
  395. code: project.code,
  396. name: project.name,
  397. categoryId: project.manager_office,
  398. category: office.list[project.manager_office],
  399. staff: manager.real_name
  400. }
  401. }
  402. } catch (error) {
  403. console.log(error);
  404. response.code = -1;
  405. response.msg = error.toString();
  406. }
  407. ctx.body = response;
  408. }
  409. /**
  410. * (项目管理)获取项目
  411. * @param {Object} ctx - egg全局变量
  412. */
  413. async project(ctx) {
  414. const data = ctx.data;
  415. const response = {
  416. code: 0,
  417. data: 0,
  418. msg: '',
  419. };
  420. try {
  421. const project = await ctx.service.project.getProjectByCode(data.code);
  422. if (!project) throw '未找到该项目';
  423. response.data = project;
  424. } catch (error) {
  425. response.code = -1;
  426. response.msg = error.toString();
  427. }
  428. ctx.body = response;
  429. }
  430. /**
  431. * (项目管理)校验项目
  432. * @param {Object} ctx - egg全局变量
  433. */
  434. async vertifyProject(ctx) {
  435. const response = {
  436. code: 0,
  437. data: 0,
  438. msg: '',
  439. };
  440. try {
  441. const code = ctx.session.sessionProject.code
  442. const accountData = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId)
  443. if (!code || !accountData) {
  444. throw new Error('参数错误')
  445. }
  446. const result = await ctx.service.project.verifyManagementProject(ctx.helper.createJWT({ code }));
  447. const token = ctx.helper.createJWT({ code, account: accountData.account })
  448. const redirect = `${app.config.managementPath}/auth?token=${token}`
  449. response.data = { ...result, is_admin: accountData.is_admin, redirect, env: app.config.env};
  450. } catch (error) {
  451. response.code = -1;
  452. response.msg = error.toString();
  453. }
  454. ctx.body = response;
  455. }
  456. /**
  457. * (项目管理)新增项目
  458. * @param {Object} ctx - egg全局变量
  459. */
  460. async addProject(ctx) {
  461. const response = {
  462. code: 0,
  463. data: {},
  464. msg: '',
  465. };
  466. try {
  467. const result = await ctx.service.project.addProjectFromManagement()
  468. if (!result) {
  469. throw new Error('请求失败')
  470. }
  471. const { code = -1, data: { token = ''} = { token: ''}, msg = '请求失败' } = result
  472. if ( code === 0 && token) {
  473. response.data = {
  474. redirect: `${app.config.managementPath}/auth?token=${token}`,
  475. }
  476. } else {
  477. throw new Error(msg)
  478. }
  479. } catch (error) {
  480. response.code = -1;
  481. response.msg = error.toString();
  482. }
  483. ctx.body = response;
  484. }
  485. /**
  486. * 项目管理授权页面
  487. *
  488. * @param {Object} ctx - egg全局页面
  489. * @return {void}
  490. */
  491. async management(ctx) {
  492. const data = ctx.data;
  493. // 获取系统维护信息
  494. const maintainData = await ctx.service.maintain.getDataById(1);
  495. if (!ctx.app.config.is_debug) {
  496. await ctx.service.maintain.syncMaintainData();
  497. }
  498. let account, project;
  499. try {
  500. if (ctx.session.loginError !== null) {
  501. throw ctx.session.loginError;
  502. }
  503. if (!data) {
  504. throw '参数有误';
  505. }
  506. project = await ctx.service.project.getDataByCondition({ code: data.code })
  507. if (!project) {
  508. throw '未找到该项目';
  509. }
  510. account = await ctx.service.projectAccount.getDataByCondition({ project_id: project.id, account: data.account });
  511. if (!account) {
  512. throw '您无权限登录系统。';
  513. }
  514. if (account.enable !== 1) {
  515. throw '该账号已被停用,请联系销售人员';
  516. }
  517. const result = await ctx.service.projectAccount.accountLogin({ project, accountData: account }, 3);
  518. if (!result) {
  519. throw '登录出错';
  520. }
  521. ctx.redirect('/dashboard');
  522. } catch (error) {
  523. // this.log(error);
  524. console.log(error);
  525. ctx.session.loginError = error;
  526. }
  527. const errorMessage = ctx.session.loginError;
  528. // 显示完删除
  529. ctx.session.loginError = null;
  530. const renderData = {
  531. maintainData,
  532. maintainConst,
  533. errorMessage,
  534. projectData: project,
  535. accountData: account,
  536. };
  537. await ctx.render('login/login_management.ejs', renderData);
  538. }
  539. /** 拉取项目下所有计量账号至项目管理 */
  540. async syncProjectAccount(ctx) {
  541. const response = {
  542. code: 0,
  543. data: [],
  544. msg: '',
  545. };
  546. try {
  547. const { code = ''} = ctx.data
  548. if (!code) throw '参数错误';
  549. const projectData = await ctx.service.project.getProjectByCode(code)
  550. if (!projectData) throw '未找到项目';
  551. const data = await ctx.service.projectAccount.getAllProjectAccountByPid(projectData.id)
  552. response.data = data || []
  553. } catch (error) {
  554. response.code = -1
  555. response.msg = error.toString()
  556. }
  557. ctx.body = response
  558. }
  559. }
  560. return LoginController;
  561. };