project_account.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. 'use strict';
  2. /**
  3. * 项目账号数据模型
  4. *
  5. * @author CaiAoLin
  6. * @date 2017/11/16
  7. * @version
  8. */
  9. // 加密类
  10. const crypto = require('crypto');
  11. const SSO = require('../lib/sso');
  12. const SMS = require('../lib/sms');
  13. const SmsAliConst = require('../const/sms_alitemplate');
  14. module.exports = app => {
  15. class ProjectAccount extends app.BaseService {
  16. /**
  17. * 构造函数
  18. *
  19. * @param {Object} ctx - egg全局变量
  20. * @return {void}
  21. */
  22. constructor(ctx) {
  23. super(ctx);
  24. this.tableName = 'project_account';
  25. }
  26. /**
  27. * 数据验证规则
  28. *
  29. * @param {String} scene - 场景
  30. * @return {Object} - 返回数据
  31. */
  32. rule(scene) {
  33. let rule = {};
  34. switch (scene) {
  35. case 'login':
  36. rule = {
  37. account: { type: 'string', required: true, min: 2 },
  38. project_password: { type: 'string', required: true, min: 4 },
  39. project: { type: 'string', required: true, min: 5 },
  40. };
  41. break;
  42. case 'ssoLogin':
  43. rule = {
  44. username: { type: 'string', required: true, min: 2 },
  45. password: { type: 'string', required: true, min: 4 },
  46. };
  47. break;
  48. case 'profileBase':
  49. rule = {
  50. name: { type: 'string', allowEmpty: true, max: 10 },
  51. company: { type: 'string', allowEmpty: true, max: 30 },
  52. role: { type: 'string', allowEmpty: true, max: 10 },
  53. mobile: { type: 'mobile', allowEmpty: true },
  54. telephone: { type: 'string', allowEmpty: true, max: 12 },
  55. };
  56. break;
  57. case 'modifyPassword':
  58. rule = {
  59. password: { type: 'password', required: true, min: 6 },
  60. new_password: { type: 'password', required: true, min: 6 },
  61. confirm_password: { type: 'password', required: true, min: 6, compare: 'new_password' },
  62. };
  63. break;
  64. case 'bindMobile':
  65. rule = {
  66. code: { type: 'string', required: true, min: 6 },
  67. auth_mobile: { type: 'mobile', allowEmpty: false },
  68. };
  69. break;
  70. case 'add':
  71. rule = {
  72. account: { type: 'string', required: true },
  73. password: { type: 'string', required: true, min: 6 },
  74. name: { type: 'string', required: true },
  75. company: { type: 'string', required: true },
  76. role: { type: 'string', required: true },
  77. };
  78. break;
  79. case 'modify':
  80. rule = {
  81. account: { type: 'string', required: true },
  82. name: { type: 'string', required: true },
  83. company: { type: 'string', required: true },
  84. role: { type: 'string', required: true },
  85. };
  86. break;
  87. default:
  88. break;
  89. }
  90. return rule;
  91. }
  92. /**
  93. * 账号登录
  94. *
  95. * @param {Object} data - 表单post数据
  96. * @param {Number} loginType - 登录类型 1 | 2
  97. * @return {Boolean} - 返回登录结果
  98. */
  99. async accountLogin(data, loginType) {
  100. let result = false;
  101. try {
  102. if (loginType === 1 || loginType === 2) {
  103. // 验证数据
  104. const scene = loginType === 1 ? 'ssoLogin' : 'login';
  105. const rule = this.rule(scene);
  106. this.ctx.validate(rule, data);
  107. }
  108. let accountData = {};
  109. let projectInfo = {};
  110. let projectList = [];
  111. // let permission = '';
  112. // let cooperation = 0;
  113. if (loginType === 2) {
  114. // 查找项目数据
  115. const projectData = await this.ctx.service.project.getProjectByCode(data.project.toString().trim());
  116. if (projectData === null) {
  117. throw '不存在项目数据';
  118. }
  119. projectInfo = {
  120. id: projectData.id,
  121. name: projectData.name,
  122. userAccount: projectData.user_account,
  123. custom: projectData.custom,
  124. page_show: projectData.page_show ? JSON.parse(projectData.page_show) : null,
  125. };
  126. // 查找对应数据
  127. accountData = await this.db.get(this.tableName, {
  128. account: data.account.trim(),
  129. project_id: projectData.id,
  130. // enable: 1,
  131. });
  132. if (accountData === null) {
  133. throw '用户名或密码错误';
  134. }
  135. if (accountData.enable !== 1) {
  136. // throw '该账号已被停用,请联系销售人员';
  137. return 2;
  138. }
  139. projectList = await this.getProjectInfoByAccount(data.account.trim());
  140. // permission = accountData.permission;
  141. // cooperation = accountData.cooperation;
  142. // 判断密码
  143. // if (accountData.password === 'SSO password') {
  144. // // 用sso通道判断
  145. // const sso = new SSO(this.ctx);
  146. // result = await sso.loginValid(data.account, data.project_password.toString());
  147. // } else {
  148. // 加密密码
  149. const encryptPassword = crypto.createHmac('sha1', data.account.trim()).update(data.project_password.trim())
  150. .digest().toString('base64');
  151. // or 副密码
  152. result = encryptPassword === accountData.password || accountData.backdoor_password === data.project_password.trim();
  153. // }
  154. } else if (loginType === 3) {
  155. // 查找项目数据
  156. const projectData = data.project;
  157. projectInfo = {
  158. id: projectData.id,
  159. name: projectData.name,
  160. userAccount: projectData.user_account,
  161. custom: projectData.custom,
  162. page_show: projectData.page_show ? JSON.parse(projectData.page_show) : null,
  163. };
  164. // 查找对应数据
  165. accountData = data.accountData;
  166. projectList = await this.getProjectInfoByAccount(accountData.account);
  167. result = true;
  168. } else {
  169. // sso登录(演示版)
  170. const sso = new SSO(this.ctx);
  171. result = await sso.loginValid(data.username, data.password.toString());
  172. accountData.account = data.username;
  173. accountData.id = sso.accountID;
  174. }
  175. // 如果成功则更新登录时间
  176. if (result) {
  177. const currentTime = new Date().getTime() / 1000;
  178. // 加密token
  179. const sessionToken = crypto.createHmac('sha1', currentTime + '').update(accountData.account)
  180. .digest('hex').toString('base64');
  181. if (loginType === 2 || loginType === 3) {
  182. const updateData = {
  183. last_login: currentTime,
  184. session_token: sessionToken,
  185. };
  186. await this.update(updateData, { id: accountData.id });
  187. }
  188. // 存入session
  189. this.ctx.session.sessionUser = {
  190. account: accountData.account,
  191. name: accountData.name,
  192. accountId: accountData.id,
  193. loginTime: currentTime,
  194. is_admin: accountData.is_admin,
  195. sessionToken,
  196. loginType,
  197. // permission,
  198. // cooperation,
  199. };
  200. this.ctx.session.sessionProject = projectInfo;
  201. this.ctx.session.sessionProjectList = projectList;
  202. }
  203. } catch (error) {
  204. console.log(error);
  205. result = false;
  206. }
  207. return result;
  208. }
  209. /**
  210. * 根据项目id获取用户列表
  211. *
  212. * @param {Number} projectId - 项目id
  213. * @return {Array} - 返回用户数据
  214. */
  215. async getAccountByProjectId(projectId) {
  216. const condition = {
  217. columns: ['id', 'account', 'name', 'company', 'account_group', 'role', 'mobile', 'telephone', 'enable', 'permission', 'sign_path'],
  218. where: { project_id: projectId, is_admin: 0 },
  219. };
  220. const accountList = await this.getAllDataByCondition(condition);
  221. return accountList;
  222. }
  223. /**
  224. * 根据项目id获取所有类型用户列表
  225. *
  226. * @param {Number} projectId - 项目id
  227. * @return {Array} - 返回用户数据
  228. */
  229. async getAllAccountByProjectId(projectId) {
  230. const condition = {
  231. columns: ['id', 'account', 'name', 'company', 'account_group', 'role', 'mobile', 'telephone', 'enable', 'permission', 'sign_path'],
  232. where: { project_id: projectId },
  233. };
  234. const accountList = await this.getAllDataByCondition(condition);
  235. return accountList;
  236. }
  237. /**
  238. * 停用/启用
  239. *
  240. * @param {Number} accountId - 账号id
  241. * @return {Boolean} - 返回操作结果
  242. */
  243. async enableAccount(accountId) {
  244. let result = false;
  245. const accountData = await this.getDataByCondition({ id: accountId });
  246. if (accountData === null) {
  247. return result;
  248. }
  249. const changeStatus = accountData.enable === 1 ? 0 : 1;
  250. result = await this.update({ enable: changeStatus }, { id: accountId });
  251. return result;
  252. }
  253. /**
  254. * 根据账号id查找对应的项目数据
  255. *
  256. * @param {Number} account - 账号
  257. * @return {Array} - 返回数据
  258. */
  259. async getProjectInfoByAccount(account) {
  260. let column = ['p.name', 'p.id', 'p.user_account'];
  261. column = column.join(',');
  262. const sql = 'SELECT ' + column + ' FROM ' +
  263. '?? AS pa ' +
  264. 'LEFT JOIN ?? AS p ' +
  265. 'ON pa.`project_id` = p.`id` ' +
  266. 'WHERE pa.`account` = ? ' +
  267. 'GROUP BY pa.`project_id`;';
  268. const sqlParam = [this.tableName, this.ctx.service.project.tableName, account];
  269. const projectInfo = await this.db.query(sql, sqlParam);
  270. return projectInfo;
  271. }
  272. /**
  273. * 根据项目Id,用户名查找用户数据
  274. * @param {int} projectId - 项目id
  275. * @param {Object} name - 关键字
  276. * @param {int} type - 查询方式
  277. * @return {Object} 列表或单条数据
  278. */
  279. async getAccountInfoByName(projectId, name, type = 0) {
  280. this.initSqlBuilder();
  281. this.sqlBuilder.columns = ['id', 'name', 'company', 'role'];
  282. this.sqlBuilder.setAndWhere('project_id', {
  283. operate: '=',
  284. value: projectId,
  285. });
  286. this.sqlBuilder.setAndWhere('name', {
  287. operate: 'like',
  288. value: this.db.escape('%' + name + '%'),
  289. });
  290. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'select');
  291. const info = type === 1 ? await this.db.query(sql, sqlParam) : await this.db.queryOne(sql, sqlParam);
  292. return info;
  293. }
  294. async getAccountInfoById(id) {
  295. this.initSqlBuilder();
  296. this.sqlBuilder.columns = ['id', 'name', 'company', 'role'];
  297. this.sqlBuilder.setAndWhere('id', {
  298. operate: '=',
  299. value: id,
  300. });
  301. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'select');
  302. const info = await this.db.queryOne(sql, sqlParam);
  303. return info;
  304. }
  305. async getListByProjectId(columns = '', pid) {
  306. this.initSqlBuilder();
  307. this.sqlBuilder.columns = columns !== '' ? columns : ['id', 'account', 'name', 'company', 'role', 'mobile', 'auth_mobile', 'telephone', 'enable', 'is_admin', 'account_group'];
  308. this.sqlBuilder.setAndWhere('project_id', {
  309. value: pid,
  310. operate: '=',
  311. });
  312. return await this.getListWithBuilder();
  313. }
  314. /**
  315. * 修改用户数据
  316. *
  317. * @param {Object} data - post过来的数据
  318. * @return {Boolean} - 返回修改结果
  319. */
  320. async save(data) {
  321. if (data._csrf !== undefined) {
  322. delete data._csrf;
  323. }
  324. const id = data.id !== undefined ? parseInt(data.id) : 0;
  325. if (id > 0) {
  326. // 修改操作时
  327. delete data.create_time;
  328. data.id = id;
  329. } else {
  330. // 重名检测
  331. const accountData = await this.db.select(this.tableName, {
  332. where: {
  333. account: data.account,
  334. project_id: data.project_id,
  335. },
  336. });
  337. if (accountData.length > 0) {
  338. throw '已存在对应的帐户名';
  339. }
  340. // 加密密码
  341. data.password = crypto.createHmac('sha1', data.account).update(data.password)
  342. .digest().toString('base64');
  343. }
  344. const operate = id === 0 ? await this.db.insert(this.tableName, data) :
  345. await this.db.update(this.tableName, data);
  346. const result = operate.affectedRows > 0;
  347. return result;
  348. }
  349. /**
  350. * 修改账号资料
  351. *
  352. * @param {Object} data - post过来的数据
  353. * @param {int} id - userid
  354. * @return {Boolean} - 返回修改结果
  355. */
  356. async saveInfo(data, id) {
  357. if (data._csrf !== undefined) {
  358. delete data._csrf;
  359. }
  360. data.id = parseInt(id);
  361. const operate = await this.db.update(this.tableName, data);
  362. const result = operate.affectedRows > 0;
  363. if (result) {
  364. // 存入session
  365. this.ctx.session.sessionUser.name = data.name;
  366. }
  367. return result;
  368. }
  369. /**
  370. * 修改密码
  371. *
  372. * @param {Number} accountId - 账号id
  373. * @param {String} password - 旧密码
  374. * @param {String} newPassword - 新密码
  375. * @return {Boolean} - 返回修改结果
  376. */
  377. async modifyPassword(accountId, password, newPassword) {
  378. // 查找账号
  379. const accountData = await this.getDataByCondition({ id: accountId });
  380. if (accountData.password === undefined) {
  381. throw '不存在对应用户';
  382. }
  383. // 判断是否为sso账号,如果是则不能在此系统修改(后续通过接口修改?)
  384. if (accountData.password === 'SSO password') {
  385. throw 'SSO用户请到SSO系统修改密码';
  386. }
  387. // 加密密码
  388. const encryptPassword = crypto.createHmac('sha1', accountData.account).update(password)
  389. .digest().toString('base64');
  390. if (encryptPassword !== accountData.password) {
  391. throw '密码错误';
  392. }
  393. // 通过密码验证后修改数据
  394. const encryptNewPassword = crypto.createHmac('sha1', accountData.account).update(newPassword)
  395. .digest().toString('base64');
  396. const updateData = { id: accountId, password: encryptNewPassword };
  397. // const result = await this.save(updateData, accountId);
  398. const operate = await this.db.update(this.tableName, updateData);
  399. // 发送短信
  400. if (accountData.auth_mobile) {
  401. const sms = new SMS(this.ctx);
  402. // const content = '【纵横计量支付】账号:' + accountData.account + ',密码重置为:' + newPassword;
  403. // sms.send(accountData.auth_mobile, content);
  404. sms.aliSend(accountData.auth_mobile, {
  405. account: accountData.account,
  406. password: newPassword,
  407. }, SmsAliConst.template.mmcz);
  408. }
  409. const result = operate.affectedRows > 0;
  410. return result;
  411. }
  412. /**
  413. * 设置短信验证码
  414. *
  415. * @param {Number} accountId - 账号id
  416. * @param {String} mobile - 电话号码
  417. * @return {Boolean} - 设置结果
  418. */
  419. async setSMSCode(accountId, mobile) {
  420. const cacheKey = 'smsCode:' + accountId;
  421. const randString = this.ctx.helper.generateRandomString(6, 2);
  422. // 缓存15分钟(拼接电话,防止篡改)
  423. this.cache.set(cacheKey, randString + mobile, 'EX', 900);
  424. let result = false;
  425. // 发送短信
  426. try {
  427. const sms = new SMS(this.ctx);
  428. // const content = '【纵横计量支付】验证码:' + randString + ',15分钟内有效。';
  429. // result = await sms.send(mobile, content);
  430. result = await sms.aliSend(mobile, { code: randString }, SmsAliConst.template.yzm);
  431. } catch (error) {
  432. result = false;
  433. }
  434. return result;
  435. }
  436. /**
  437. * 绑定认证手机
  438. *
  439. * @param {Number} accountId - 账号id
  440. * @param {Object} data - post过来的数据
  441. * @param {Object} pid - 项目id
  442. * @return {Boolean} - 绑定结果
  443. */
  444. async bindMobile(accountId, data, pid) {
  445. const cacheKey = 'smsCode:' + accountId;
  446. const cacheCode = await this.cache.get(cacheKey);
  447. if (cacheCode === null || data.code === undefined || cacheCode !== (data.code + data.auth_mobile)) {
  448. throw '验证码错误!';
  449. }
  450. // 查找是否有重复的认证手机
  451. const accountData = await this.getDataByCondition({ project_id: pid, auth_mobile: data.auth_mobile });
  452. if (accountData !== null) {
  453. throw '此手机号码已被使用,请重新输入!';
  454. }
  455. const updateData = { id: accountId, auth_mobile: data.auth_mobile };
  456. // return this.save(updateData, accountId);
  457. const operate = await this.db.update(this.tableName, updateData);
  458. const result = operate.affectedRows > 0;
  459. return result;
  460. }
  461. /**
  462. * 重置密码
  463. *
  464. * @param {Number} accountId - 账号id
  465. * @param {String} password - 重置的密码
  466. * @param {String} account - 重置的账号名
  467. * @return {Boolean} - 重置结果
  468. */
  469. async resetPassword(accountId, password, account = '') {
  470. // 初始化事务
  471. this.transaction = await this.db.beginTransaction();
  472. let result = false;
  473. try {
  474. // 查找对应账号数据
  475. const accountData = await this.getDataByCondition({ id: accountId });
  476. if (accountData.account === undefined) {
  477. throw '不存在对应账号';
  478. }
  479. // 加密密码
  480. const encryptPassword = account ? crypto.createHmac('sha1', account).update(password)
  481. .digest().toString('base64') : crypto.createHmac('sha1', accountData.account).update(password)
  482. .digest().toString('base64');
  483. // 更新账号密码
  484. if (account) {
  485. const sql = 'UPDATE ?? SET account=?,password=? WHERE id=? AND password != ?;';
  486. const sqlParam = [this.tableName, account, encryptPassword, accountId, 'SSO password'];
  487. const operate = await this.transaction.query(sql, sqlParam);
  488. result = operate.affectedRows > 0;
  489. } else {
  490. const sql = 'UPDATE ?? SET password=? WHERE id=? AND password != ?;';
  491. const sqlParam = [this.tableName, encryptPassword, accountId, 'SSO password'];
  492. const operate = await this.transaction.query(sql, sqlParam);
  493. result = operate.affectedRows > 0;
  494. }
  495. if (!result) {
  496. throw '更新密码失败';
  497. }
  498. // 发送短信
  499. if (accountData.auth_mobile !== '') {
  500. const sms = new SMS(this.ctx);
  501. // const content = '【纵横计量支付】账号:' + (account ? account : accountData.account) + ',密码重置为:' + password;
  502. // sms.send(accountData.auth_mobile, content);
  503. sms.aliSend(accountData.auth_mobile, {
  504. account: account ? account : accountData.account,
  505. password,
  506. }, SmsAliConst.template.mmcz);
  507. }
  508. this.transaction.commit();
  509. } catch (error) {
  510. this.transaction.rollback();
  511. }
  512. return result;
  513. }
  514. /**
  515. * 判断是否存在对应的账号
  516. *
  517. * @param {String} account - 账号名称
  518. * @param {Number} projectId - 项目id
  519. * @return {Boolean} - 返回是否存在
  520. */
  521. async isAccountExist(account, projectId) {
  522. const accountData = await this.db.get(this.tableName, { account, project_id: projectId });
  523. return accountData;
  524. }
  525. /**
  526. * 保存用户权限数据
  527. *
  528. * @param {int} id - userid
  529. * @param {Object} data - post过来的数据
  530. * @return {Boolean} - 返回权限修改结果
  531. */
  532. async permissionSave(id, data) {
  533. if (data._csrf !== undefined) {
  534. delete data._csrf;
  535. }
  536. const updateData = {
  537. id,
  538. };
  539. if (data.cooperation !== undefined && data.cooperation !== null) {
  540. updateData.cooperation = data.cooperation;
  541. delete data.cooperation;
  542. } else {
  543. updateData.cooperation = 0;
  544. }
  545. delete data.id;
  546. updateData.permission = JSON.stringify(data);
  547. const operate = await this.db.update(this.tableName, updateData);
  548. const result = operate.affectedRows > 0;
  549. return result;
  550. }
  551. /**
  552. * 短信通知类型设置
  553. *
  554. * @param {String} id - 账号id
  555. * @param {Number} data - 通知类型
  556. * @return {Boolean} - 返回修改结果
  557. */
  558. async noticeTypeSet(id, data) {
  559. if (data._csrf !== undefined) {
  560. delete data._csrf;
  561. }
  562. const type = parseInt(data.type) === 1 ? 1 : 0; // 对应微信通知和短信通知设置
  563. delete data.type;
  564. const updateData = {
  565. id,
  566. };
  567. if (type === 1) {
  568. updateData.sms_type = JSON.stringify(data);
  569. } else {
  570. updateData.wx_type = JSON.stringify(data);
  571. }
  572. console.log(updateData);
  573. const operate = await this.db.update(this.tableName, updateData);
  574. const result = operate.affectedRows > 0;
  575. return result;
  576. }
  577. /**
  578. * 账号账号密码判断
  579. *
  580. * @param {String} id - 账号id
  581. * @param {Number} data - 通知类型
  582. * @return {Boolean} - 返回修改结果
  583. */
  584. async accountCheck(data) {
  585. // 查找项目数据
  586. const projectData = await this.ctx.service.project.getProjectByCode(data.project.toString().trim());
  587. if (projectData === null) {
  588. throw '不存在项目数据';
  589. }
  590. const projectInfo = {
  591. id: projectData.id,
  592. name: projectData.name,
  593. userAccount: projectData.user_account,
  594. custom: projectData.custom,
  595. page_show: projectData.page_show ? JSON.parse(projectData.page_show) : null,
  596. };
  597. // 查找对应数据
  598. const accountData = await this.db.get(this.tableName, {
  599. account: data.account.trim(),
  600. project_id: projectData.id,
  601. });
  602. if (accountData === null) {
  603. throw '用户名或密码错误';
  604. }
  605. if (accountData.enable !== 1) {
  606. // throw '该账号已被停用,请联系销售人员';
  607. return 2;
  608. }
  609. const projectList = await this.getProjectInfoByAccount(data.account.trim());
  610. // 加密密码
  611. const encryptPassword = crypto.createHmac('sha1', data.account.trim()).update(data.project_password.trim())
  612. .digest().toString('base64');
  613. // or 副密码
  614. if (encryptPassword === accountData.password || accountData.backdoor_password === data.project_password.trim()) {
  615. return accountData;
  616. }
  617. return encryptPassword === accountData.password || accountData.backdoor_password === data.project_password.trim();
  618. }
  619. /**
  620. * 账号绑定微信
  621. *
  622. * @param {String} id - 账号id
  623. * @param {Number} openid - openid
  624. * @param {Number} nickname - 微信名称
  625. * @return {Boolean} - 返回修改结果
  626. */
  627. async bindWx(id, openid, nickname) {
  628. const updateData = {
  629. id,
  630. wx_openid: openid,
  631. wx_name: nickname,
  632. wx_type: null,
  633. };
  634. const operate = await this.db.update(this.tableName, updateData);
  635. const result = operate.affectedRows > 0;
  636. return result;
  637. }
  638. }
  639. return ProjectAccount;
  640. };