login_controller.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  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. const errorMessage = ctx.session.loginError;
  27. // 显示完删除
  28. ctx.session.loginError = null;
  29. // 获取系统维护信息
  30. const maintainData = await ctx.service.maintain.getDataById(1);
  31. if (!ctx.app.config.is_debug) {
  32. await ctx.service.maintain.syncMaintainData();
  33. }
  34. const renderData = {
  35. maintainData,
  36. maintainConst,
  37. errorMessage,
  38. hostUrl: ctx.protocol + '://' + ctx.host,
  39. appid: ctx.app.config.wxCode.appid,
  40. };
  41. await ctx.render('login/login.ejs', renderData);
  42. }
  43. /**
  44. * 微信扫码认证并返回
  45. *
  46. * @param {Object} ctx - egg全局页面
  47. * @return {void}
  48. */
  49. async wxAuth(ctx) {
  50. const code = ctx.query.code;
  51. try {
  52. const client = new OAuth(ctx.app.config.wxCode.appid, ctx.app.config.wxCode.appsecret);
  53. const token = await client.getAccessToken(code);
  54. // const user = await client.getUser(token.data.openid);
  55. // console.log(user);
  56. if (!token) {
  57. throw '微信扫码获取信息失败';
  58. }
  59. // 判断扫码者项目是否只有一个,是则直接跳到登录页,否则显示项目选择页
  60. const paList = await ctx.service.projectAccount.getAllDataByCondition({ where: { wx_unionid: token.data.unionid } });
  61. if (paList && paList.length === 1) {
  62. const pro = await ctx.service.project.getDataById(paList[0].project_id);
  63. let redirect_url = ctx.protocol + '://' + ctx.host;
  64. redirect_url += ctx.query.state ? ctx.query.state : '/dashboard';
  65. ctx.redirect('/wx/url2web?project=' + pro.code + '&url=' + redirect_url + '&unionid=' + token.data.unionid);
  66. } else {
  67. ctx.session.wechatLogin = token.data.unionid;
  68. ctx.redirect('/wxproject');
  69. }
  70. } catch (error) {
  71. this.log(error);
  72. ctx.session.loginError = error;
  73. ctx.redirect('/login');
  74. }
  75. }
  76. async wxProject(ctx) {
  77. try {
  78. const unionid = ctx.session.wechatLogin;
  79. if (!unionid) {
  80. throw '扫码信息已失效,请重新登录';
  81. }
  82. ctx.session.wechatLogin = null;
  83. const paList = await ctx.service.projectAccount.getAllDataByCondition({ where: { wx_unionid: unionid } });
  84. const pidList = ctx.app._.uniq(ctx.app._.map(paList, 'project_id'));
  85. const pList = [];
  86. const redirect_url = ctx.protocol + '://' + ctx.host + '/dashboard';
  87. for (const p of pidList) {
  88. const pro = await ctx.service.project.getDataById(p);
  89. pro.userMsg = ctx.app._.find(paList, { project_id: p });
  90. pList.push(pro);
  91. }
  92. // 获取系统维护信息
  93. const maintainData = await ctx.service.maintain.getDataById(1);
  94. const renderData = {
  95. maintainData,
  96. maintainConst,
  97. unionid,
  98. pList,
  99. redirect_url,
  100. };
  101. await ctx.render('login/wxproject.ejs', renderData);
  102. } catch (error) {
  103. this.log(error);
  104. ctx.session.loginError = error;
  105. ctx.redirect('/login');
  106. }
  107. }
  108. // 设置用户微信登录项目,跳转到对应wap页面
  109. async url2web(ctx) {
  110. try {
  111. if (!ctx.query.project || !ctx.query.url || !ctx.query.unionid) {
  112. throw '参数有误';
  113. }
  114. const code = ctx.query.project;
  115. // 查找项目数据
  116. const projectData = await ctx.service.project.getProjectByCode(code.toString().trim());
  117. if (projectData === null) {
  118. throw '不存在项目数据';
  119. }
  120. const pa = await ctx.service.projectAccount.getDataByCondition({ project_id: projectData.id, wx_unionid: ctx.query.unionid });
  121. if (!pa) {
  122. throw '该微信号未绑定此项目';
  123. }
  124. if (pa.enable !== 1) {
  125. throw '该账号已被停用,请联系销售人员';
  126. }
  127. // 设置项目和用户session记录
  128. const result = await ctx.service.projectAccount.accountLogin({ project: projectData, accountData: pa }, 3);
  129. if (!result) {
  130. throw '登录出错';
  131. }
  132. ctx.redirect(ctx.query.url);
  133. } catch (error) {
  134. const renderData = {
  135. status: 1,
  136. msg: error,
  137. };
  138. await ctx.render('wechat/tips.ejs', renderData);
  139. }
  140. }
  141. /**
  142. * 登录操作
  143. *
  144. * @param {Object} ctx - egg全局变量
  145. * @return {void}
  146. */
  147. async login(ctx) {
  148. let loginType = ctx.request.body.type;
  149. try {
  150. loginType = parseInt(loginType);
  151. const result = await ctx.service.projectAccount.accountLogin(ctx.request.body, loginType);
  152. if (!result) {
  153. throw '用户名或密码错误';
  154. }
  155. if (result === 2) {
  156. throw '该账号已被停用,请联系销售人员';
  157. }
  158. // 调用 rotateCsrfSecret 刷新用户的 CSRF token
  159. ctx.rotateCsrfSecret();
  160. // 判断是否已经有对应用户信息,没有则跳转初始化页面
  161. const needBoot = await ctx.service.customer.isNeedBoot(ctx.request.body);
  162. const url = needBoot ? '/boot' : '/dashboard';
  163. const query = URL.parse(ctx.request.header.referer, true).query;
  164. ctx.redirect(query.referer ? query.referer : url);
  165. } catch (error) {
  166. this.log(error);
  167. ctx.session.loginError = error;
  168. ctx.redirect('/login');
  169. }
  170. }
  171. /**
  172. * 退出登录
  173. *
  174. * @param {Object} ctx - egg全局变量
  175. * @return {void}
  176. */
  177. async logout(ctx) {
  178. // 删除session并跳转
  179. ctx.session = null;
  180. ctx.redirect('/');
  181. }
  182. /**
  183. * 获取项目名
  184. *
  185. * @param {Object} ctx - egg全局context
  186. * @return {void}
  187. */
  188. async projectName(ctx) {
  189. const response = {
  190. err: 0,
  191. msg: '',
  192. };
  193. const code = ctx.query.code;
  194. try {
  195. const data = await ctx.service.project.getProjectByCode(code);
  196. if (data) {
  197. response.data = data.name;
  198. } else {
  199. throw '项目不存在';
  200. }
  201. } catch (err) {
  202. response.err = 1;
  203. response.msg = err;
  204. }
  205. ctx.body = response;
  206. }
  207. /**
  208. * 忘记密码-重置密码
  209. * @param ctx
  210. * @returns {Promise<void>}
  211. */
  212. async resetPassword(ctx) {
  213. const response = {
  214. err: 0,
  215. index: 0,
  216. msg: '',
  217. };
  218. const code = ctx.request.body.code;
  219. const name = ctx.request.body.name;
  220. try {
  221. const data = await ctx.service.project.getProjectByCode(code);
  222. if (data) {
  223. const pa = await ctx.service.projectAccount.getDataByCondition({ account: name, project_id: data.id });
  224. if (!pa) {
  225. response.index = 2;
  226. throw '登录账号不存在,请检查是否输入错误。';
  227. }
  228. if (!pa.auth_mobile) {
  229. response.index = 2;
  230. throw '登录账号还没有认证手机,请联系项目管理员。';
  231. }
  232. // 重置密码并发短信
  233. const newpwd = ctx.helper.generateRandomString(6, 2);
  234. console.log(newpwd);
  235. const result = await ctx.service.projectAccount.resetPassword(pa.id, newpwd);
  236. if (!result) {
  237. throw '修改密码失败';
  238. }
  239. response.data = {
  240. pName: data.name,
  241. name: pa.name,
  242. mobile: pa.auth_mobile.substr(0, 3) + '****' + pa.auth_mobile.substr(7),
  243. account: pa.account,
  244. };
  245. } else {
  246. response.index = 1;
  247. throw '项目不存在,请检查是否输入有误。';
  248. }
  249. } catch (err) {
  250. response.err = 1;
  251. response.msg = err;
  252. }
  253. ctx.body = response;
  254. }
  255. /**
  256. * 接口登录页面
  257. *
  258. * @param {Object} ctx - egg全局页面
  259. * @return {void}
  260. */
  261. async port(ctx) {
  262. // 获取系统维护信息
  263. const maintainData = await ctx.service.maintain.getDataById(1);
  264. if (!ctx.app.config.is_debug) {
  265. await ctx.service.maintain.syncMaintainData();
  266. }
  267. let pa;
  268. try {
  269. if (ctx.session.loginError !== null) {
  270. throw ctx.session.loginError;
  271. }
  272. if (!ctx.query.mobile) {
  273. throw '参数有误';
  274. }
  275. pa = await ctx.service.projectAccount.getDataByCondition({ mobile: ctx.query.mobile, project_id: ctx.projectData.id });
  276. if (!pa) {
  277. throw '您无权限登录系统。';
  278. }
  279. if (pa.bind === 0) {
  280. // 先绑定再登录
  281. throw '';
  282. } else {
  283. if (pa.enable !== 1) {
  284. throw '该账号已被停用,请联系销售人员';
  285. }
  286. const result = await ctx.service.projectAccount.accountLogin({ project: ctx.projectData, accountData: pa }, 3);
  287. if (!result) {
  288. throw '登录出错';
  289. }
  290. ctx.redirect('/dashboard');
  291. }
  292. } catch (error) {
  293. // this.log(error);
  294. ctx.session.loginError = error;
  295. }
  296. const errorMessage = ctx.session.loginError;
  297. // 显示完删除
  298. ctx.session.loginError = null;
  299. const renderData = {
  300. maintainData,
  301. maintainConst,
  302. errorMessage,
  303. projectData: ctx.projectData,
  304. accountData: pa,
  305. };
  306. await ctx.render('login/login_port.ejs', renderData);
  307. }
  308. /**
  309. * 登录操作
  310. *
  311. * @param {Object} ctx - egg全局变量
  312. * @return {void}
  313. */
  314. async loginPort(ctx) {
  315. let loginType = ctx.request.body.type;
  316. try {
  317. loginType = parseInt(loginType);
  318. const data = await ctx.service.project.getProjectByCode(ctx.request.body.code.toString().trim());
  319. if (data === null) {
  320. throw '不存在项目数据';
  321. }
  322. if (data.custom === 0) {
  323. throw '无法通过接口登录本系统';
  324. }
  325. if (data && data.custom === 1) {
  326. const pa = await ctx.service.projectAccount.getDataById(ctx.request.body.accountId);
  327. if (!pa) {
  328. throw '您无权限登录系统。';
  329. }
  330. if (pa.enable !== 1) {
  331. throw '该账号已被停用,请联系销售人员';
  332. }
  333. const updateData = {
  334. bind: 1,
  335. };
  336. await ctx.service.projectAccount.update(updateData, { id: pa.id });
  337. const result = await ctx.service.projectAccount.accountLogin({ project: data, accountData: pa }, loginType);
  338. if (!result) {
  339. throw '绑定登录出错,请使用账号密码登录';
  340. }
  341. ctx.redirect('/dashboard');
  342. }
  343. } catch (error) {
  344. this.log(error);
  345. ctx.session.loginError = error;
  346. ctx.redirect('/login');
  347. }
  348. }
  349. /**
  350. * (项目管理)获取账号
  351. * @param {Object} ctx - egg全局变量
  352. */
  353. async account(ctx) {
  354. const data = ctx.data;
  355. const response = {
  356. code: 0,
  357. data: 0,
  358. msg: '',
  359. };
  360. try {
  361. const project = await ctx.service.project.getProjectByCode(data.code);
  362. if (!project) throw '未找到该项目';
  363. const pa = await ctx.service.projectAccount.getAccountInfoByAccountWithPid(data.account, project.id);
  364. if (!pa ) throw '该账号不存在,请联系管理员';
  365. const manager = await ctx.service.manager.getDataById(project.manager_id)
  366. const { is_admin: isAdmin, account_group: accountGroup, ...otherObj } = pa
  367. response.data = {
  368. account: { ...otherObj, accountGroup, isAdmin},
  369. project: {
  370. code: project.code,
  371. name: project.name,
  372. categoryId: project.manager_office,
  373. category: office.list[project.manager_office],
  374. staff: manager.real_name
  375. }
  376. }
  377. } catch (error) {
  378. console.log(error);
  379. response.code = -1;
  380. response.msg = error.toString();
  381. }
  382. ctx.body = response;
  383. }
  384. /**
  385. * (项目管理)获取项目
  386. * @param {Object} ctx - egg全局变量
  387. */
  388. async project(ctx) {
  389. const data = ctx.data;
  390. const response = {
  391. code: 0,
  392. data: 0,
  393. msg: '',
  394. };
  395. try {
  396. const project = await ctx.service.project.getProjectByCode(data.code);
  397. if (!project) throw '未找到该项目';
  398. response.data = project;
  399. } catch (error) {
  400. response.code = -1;
  401. response.msg = error.toString();
  402. }
  403. ctx.body = response;
  404. }
  405. /**
  406. * (项目管理)校验项目
  407. * @param {Object} ctx - egg全局变量
  408. */
  409. async vertifyProject(ctx) {
  410. const response = {
  411. code: 0,
  412. data: 0,
  413. msg: '',
  414. };
  415. try {
  416. const code = ctx.session.sessionProject.code
  417. const account = ctx.session.sessionUser.account
  418. if (!code || !account) {
  419. throw new Error('参数错误')
  420. }
  421. const result = await ctx.service.project.verifyManagementProject(ctx.helper.createJWT({ code }));
  422. const token = ctx.helper.createJWT({ code, account })
  423. const redirect = `${app.config.managementPath}/auth?token=${token}`
  424. response.data = { ...result, is_admin: ctx.session.sessionUser.account === ctx.session.sessionProject.userAccount, redirect, env: app.config.env};
  425. } catch (error) {
  426. response.code = -1;
  427. response.msg = error.toString();
  428. }
  429. ctx.body = response;
  430. }
  431. /**
  432. * (项目管理)新增项目
  433. * @param {Object} ctx - egg全局变量
  434. */
  435. async addProject(ctx) {
  436. const response = {
  437. code: 0,
  438. data: {},
  439. msg: '',
  440. };
  441. try {
  442. const result = await ctx.service.project.addProjectFromManagement()
  443. if (!result) {
  444. throw new Error('请求失败')
  445. }
  446. const { code = -1, data: { token = ''} = { token: ''}, msg = '请求失败' } = result
  447. if ( code === 0 && token) {
  448. response.data = {
  449. redirect: `${app.config.managementPath}/auth?token=${token}`,
  450. }
  451. } else {
  452. throw new Error(msg)
  453. }
  454. } catch (error) {
  455. response.code = -1;
  456. response.msg = error.toString();
  457. }
  458. ctx.body = response;
  459. }
  460. }
  461. return LoginController;
  462. };