index.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. 'use strict';
  2. const { CrudService } = require('naf-framework-mongoose-free/lib/service');
  3. const { BusinessError, ErrorCode } = require('naf-core').Error;
  4. const { ObjectId } = require('mongoose').Types;
  5. const _ = require('lodash');
  6. const assert = require('assert');
  7. // 首页-数据动态统计
  8. class IndexService extends CrudService {
  9. constructor(ctx) {
  10. super(ctx, 'index');
  11. this.redis = this.app.redis;
  12. this.patentModel = this.ctx.model.Dock.Patent;
  13. this.code = this.ctx.model.System.Code;
  14. this.productModel = this.ctx.model.News.Product;
  15. this.expertModel = this.ctx.model.User.Expert;
  16. // this.userModel = this.ctx.model.User;
  17. this.personalModel = this.ctx.model.User.Personal;
  18. this.organizationModel = this.ctx.model.User.Organization;
  19. this.surveyModel = this.ctx.model.News.Survey;
  20. this.dockUser = this.ctx.model.Dock.DockUser; // 没改
  21. this.tranModel = this.ctx.model.Dock.DockTranscation; // 没改
  22. }
  23. /**
  24. * 首页专利统计
  25. */
  26. async patent() {
  27. const res = await this.patentModel.aggregate([
  28. {
  29. $group: {
  30. _id: '$apply_personal',
  31. value: { $sum: 1 },
  32. },
  33. },
  34. ]);
  35. let arr = [];
  36. const other = { name: '其他', value: 0 };
  37. for (const i of res) {
  38. const { _id, value } = i;
  39. const unitList = this.patentUnitList();
  40. const unit = unitList.find(f => (_id && _id.includes(f.name)) || f.name.includes(_id));
  41. if (unit) {
  42. // 说明是需要单拎出来的数据,现查arr中是否有该单位:有=>数字合并;没有=>创建条目
  43. const { name } = unit;
  44. const arrItem = arr.find(f => f.name === name);
  45. if (arrItem) {
  46. const index = arr.findIndex(f => f.name === name);
  47. arr[index] = { name, value: (arrItem.value || 0) + value };
  48. } else {
  49. arr.push({ name, value });
  50. }
  51. } else {
  52. other.value += value;
  53. }
  54. }
  55. arr = _.orderBy(arr, [ 'value' ], [ 'desc' ]);
  56. arr.push(other);
  57. return arr;
  58. }
  59. /**
  60. * 首页成果统计
  61. */
  62. async product() {
  63. const categroy = await this.code.find({ category: '01' });
  64. const condition = { type: '1', status: '2' };
  65. const arr = [];
  66. for (const c of categroy) {
  67. const { name } = c;
  68. const value = await this.productModel.count({
  69. ...condition,
  70. field: name,
  71. });
  72. arr.push({ value, name });
  73. }
  74. return arr;
  75. }
  76. /**
  77. * 首页统计专家
  78. */
  79. async expert() {
  80. const res = await this.expertModel.aggregate([
  81. {
  82. $group: {
  83. _id: '$company',
  84. value: { $sum: 1 },
  85. },
  86. },
  87. ]);
  88. let arr = [];
  89. const other = { name: '其他', value: 0 };
  90. for (const i of res) {
  91. const { _id, value } = i;
  92. const unitList = this.expertList();
  93. const unit = unitList.find(f => (_id && _id.includes(f.name)) || f.name.includes(_id));
  94. if (unit) {
  95. // 说明是需要单拎出来的数据,现查arr中是否有该单位:有=>数字合并;没有=>创建条目
  96. const { name, sort } = unit;
  97. const arrItem = arr.find(f => f.name === name);
  98. if (arrItem) {
  99. const index = arr.findIndex(f => f.name === name);
  100. arr[index] = { ...arr[index], value: (arrItem.value || 0) + value };
  101. } else {
  102. arr.push({ name, value, sort });
  103. }
  104. } else {
  105. other.value += value;
  106. }
  107. }
  108. arr = _.orderBy(arr, [ 'sort' ], [ 'asc' ]);
  109. arr.push(other);
  110. // 换名
  111. arr.map(i => {
  112. const r = this.expertList().find(f => f.name === i.name);
  113. if (r && r.alias) i.name = r.alias;
  114. return i;
  115. });
  116. return arr;
  117. }
  118. /**
  119. * 首页数据统计
  120. */
  121. async circle() {
  122. const arr = [];
  123. const organization = await this.organizationModel.count({ status: '1' });
  124. arr.push({
  125. name: '企业注册数量',
  126. value: organization,
  127. });
  128. // TODO:如果需要专家和个人用户区分开,则is_expert:false, 混查则不需要is_expert条件
  129. const user = await this.personalModel.count({
  130. status: '1',
  131. is_expert: false,
  132. });
  133. arr.push({
  134. name: '个人注册数量',
  135. value: user,
  136. });
  137. const exports = await this.expertModel.count();
  138. arr.push({
  139. name: '专家注册数量',
  140. value: exports,
  141. });
  142. const products = await this.productModel.count({ status: '2' });
  143. arr.push({
  144. name: '产品发布数量',
  145. value: products,
  146. });
  147. const surveys = await this.surveyModel.count();
  148. arr.push({
  149. name: '交流互动',
  150. value: surveys,
  151. });
  152. const trans = await this.tranModel.aggregate([
  153. { $match: { status: { $in: [ '0', '1', '3' ] } } },
  154. {
  155. $group: {
  156. _id: '$status',
  157. value: { $sum: 1 },
  158. },
  159. },
  160. ]);
  161. arr.push({
  162. name: '正在洽谈',
  163. value: _.get(
  164. trans.find(f => f._id === '0'),
  165. 'value',
  166. 0
  167. ),
  168. });
  169. arr.push({
  170. name: '达成意向',
  171. value: _.get(
  172. trans.find(f => f._id === '1'),
  173. 'value',
  174. 0
  175. ),
  176. });
  177. arr.push({
  178. name: '对接完成',
  179. value: _.get(
  180. trans.find(f => f._id === '3'),
  181. 'value',
  182. 0
  183. ),
  184. });
  185. return arr;
  186. }
  187. /**
  188. * 专家列表
  189. */
  190. expertList() {
  191. return [
  192. { name: '中科院长春光学精密机械与物理研究所', alias: '光机所', sort: 1 },
  193. { name: '中国科学院长春应用化学研究所', alias: '应化所', sort: 2 },
  194. { name: '中国科学院东北地理与农业生态研究所', alias: '地理所', sort: 3 },
  195. { name: '吉林大学', sort: 4 },
  196. { name: '长春工业大学', sort: 5 },
  197. ];
  198. }
  199. /**
  200. * 专利单位列表
  201. */
  202. patentUnitList() {
  203. return [
  204. { name: '吉林大学' },
  205. { name: '长春理工大学' },
  206. { name: '东北电力大学' },
  207. { name: '吉林工程技术师范学院' },
  208. { name: '长春工业大学' },
  209. { name: '北华大学' },
  210. { name: '吉林农业大学' },
  211. { name: '吉林师范大学' },
  212. { name: '长春工程学院' },
  213. { name: '吉林建筑大学' },
  214. { name: '通化师范学院' },
  215. { name: '长春大学' },
  216. { name: '东北师范大学' },
  217. { name: '吉林农业科技学院' },
  218. ];
  219. }
  220. // 展会首页统计
  221. async dockIndex({ dock_id }) {
  222. // 同时在线人数(伪)
  223. let tszx = _.random(100, 1000);
  224. if (this.redis) {
  225. tszx = (await this.redis.get('login_number')) || tszx;
  226. }
  227. // 特邀嘉宾
  228. // const tyjb = await this.personalModel.count({ is_expert: true });
  229. const tyjb = 81;
  230. console.log(tyjb);
  231. // 洽谈合作 达成意向 交易完成
  232. const trans = await this.tranModel.aggregate([
  233. { $match: { status: { $in: [ '0', '1', '3' ] } } },
  234. {
  235. $group: {
  236. _id: '$status',
  237. value: { $sum: 1 },
  238. },
  239. },
  240. ]);
  241. const qthz = _.get(
  242. trans.find(f => f._id === '0'),
  243. 'value',
  244. 0
  245. );
  246. const dcyx = _.get(
  247. trans.find(f => f._id === '1'),
  248. 'value',
  249. 0
  250. );
  251. const jywc = _.get(
  252. trans.find(f => f._id === '3'),
  253. 'value',
  254. 0
  255. );
  256. // 参展项目
  257. const res = await this.dockUser
  258. .aggregate()
  259. .match({
  260. dock_id: ObjectId(dock_id),
  261. 'productList.status': '1',
  262. })
  263. .unwind('$productList')
  264. .group({
  265. _id: '$dock_id',
  266. count: { $sum: 1 },
  267. });
  268. const czxm = _.get(res[0], 'count');
  269. const arr = [
  270. { name: '同时在线', num: tszx, unit: '人' },
  271. { name: '特邀嘉宾', num: tyjb, unit: '人' },
  272. { name: '洽谈合作', num: qthz, unit: '项' },
  273. { name: '达成意向', num: dcyx, unit: '项' },
  274. { name: '交易完成', num: jywc, unit: '项' },
  275. { name: '参展项目', num: czxm, unit: '项' },
  276. ];
  277. return arr;
  278. }
  279. /**
  280. * 高企申报, 兑付成功(is_cashing=='1')
  281. * 研发补贴/奖励兑现, 兑付成功(is_cashing==='1'),类型要区分
  282. */
  283. async pac() {
  284. const gq = await this.ctx.model.Cysci.Declare.count({ is_cashing: '1' });
  285. const yfjl = await this.ctx.model.Cysci.Reward.aggregate([
  286. { $match: { is_cashing: '1' } },
  287. {
  288. $group: {
  289. _id: '$type',
  290. count: { $sum: 1 },
  291. },
  292. },
  293. ]);
  294. const arr = [
  295. { key: '奖励兑现', name: '奖励兑现' },
  296. { key: '研发补贴', name: '研发补贴' },
  297. ];
  298. const obj = this.setData(yfjl, arr);
  299. obj.push({ name: '高企申报', value: gq });
  300. return obj;
  301. }
  302. /**
  303. * 高企申报个步骤统计
  304. */
  305. async declare() {
  306. const res = await this.ctx.model.Cysci.Declare.aggregate([
  307. {
  308. $group: {
  309. _id: '$status',
  310. count: { $sum: 1 },
  311. },
  312. },
  313. ]);
  314. const arr = [
  315. { key: '0', name: '企业信息待审中' },
  316. { key: '1', name: '企业信息审核成功' },
  317. { key: '-1', name: '企业信息审核失败' },
  318. { key: '2', name: '高企申报成功' },
  319. { key: '-2', name: '高企申报失败' },
  320. ];
  321. const obj = this.setData(res, arr);
  322. return obj;
  323. }
  324. /**
  325. * 安排返回值
  326. * @param {Array} list 数据[{_id,count}]
  327. * @param {*} meta 变换成的另一部信息[{key:_id,name:zh}]
  328. */
  329. setData(list, meta) {
  330. const obj = [];
  331. for (const i of meta) {
  332. const { key, name } = i;
  333. const r = list.find(f => f._id === key);
  334. if (r) {
  335. obj.push({ name, value: r.count });
  336. } else {
  337. obj.push({ name, value: 0 });
  338. }
  339. }
  340. return obj;
  341. }
  342. async dockProduct({ skip = 0, limit = 10, ...query } = {}) {
  343. const productQuery = {};
  344. const userQuery = {};
  345. for (const key in query) {
  346. if (query[key].length > 12) {
  347. if (ObjectId.isValid(query[key])) query[key] = ObjectId(query[key]);
  348. }
  349. if (key.includes('.')) productQuery[key] = query[key];
  350. else userQuery[key] = query[key];
  351. }
  352. const publics = [{ $match: userQuery }, { $project: { productList: 1, _id: 0 } }, { $unwind: '$productList' }, { $match: productQuery }];
  353. const data = await this.ctx.model.Dock.DockUser.aggregate([ ...publics, { $skip: parseInt(skip) }, { $limit: parseInt(limit) }]).replaceRoot('productList');
  354. let total = await this.ctx.model.Dock.DockUser.aggregate([
  355. ...publics,
  356. {
  357. $group: {
  358. _id: null,
  359. count: { $sum: 1 },
  360. },
  361. },
  362. ]);
  363. if (total && _.isArray(total)) {
  364. total = _.get(_.head(total), 'count', 0);
  365. }
  366. return { data, total };
  367. }
  368. async patentUserIndex({ id }) {
  369. // 审核通知
  370. const patentExamine = this.ctx.model.Patent.Patentexamine;
  371. // 未读消息
  372. const unread = await patentExamine.count({ to: id, is_read: false });
  373. // 通知信息
  374. const patentNotice = this.ctx.model.Patent.Patentnotice;
  375. const notice = await patentNotice.count({ to_id: { $elemMatch: { $in: [ ObjectId(id) ] } }, is_read: false });
  376. // 专利申请
  377. const papply = this.ctx.model.Patent.Patentapply;
  378. const apply = await papply.count({
  379. status: [ '0', '1', '-1', '2', '3', '4', '-4', '5', '-5', '6', '-6', '7' ],
  380. user_id: id,
  381. });
  382. // 查询检索
  383. const palysis = this.ctx.model.Patent.Patentanalysis;
  384. const analysis = await palysis.count({ status: [ '0', '1', '-1', '2' ], user_id: id });
  385. // 价值评估
  386. const paccess = this.ctx.model.Patent.Patentassess;
  387. const access = await paccess.count({ status: [ '0', '1', '-1', '2' ], user_id: id });
  388. // 专利信息
  389. const patentInfo = this.ctx.model.Patent.Patentinfo;
  390. const information = await patentInfo.count({ user_id: { $elemMatch: { user_id: id } } });
  391. // 专利维权
  392. const patentsafeg = this.ctx.model.Patent.Patentsafeg;
  393. const safeg = await patentsafeg.count({ status: [ '0', '1', '2' ], user_id: id });
  394. // 专利预警
  395. const patentEarly = this.ctx.model.Patent.Patentearly;
  396. const early = await patentEarly.count({ user_id: { $elemMatch: { $in: [ ObjectId(id) ] } } });
  397. // 专利交易
  398. const patentTrans = this.ctx.model.Patent.Patenttrans;
  399. const trans1 = await patentTrans.count({ type: '转让', user_id: id });
  400. const trans2 = await patentTrans.count({ type: '许可', user_id: id });
  401. const trans3 = await patentTrans.count({ type: '免费许可', user_id: id });
  402. const trans4 = await patentTrans.count({ type: '招商', user_id: id });
  403. const trans5 = await patentTrans.count({ type: '质押', user_id: id });
  404. return {
  405. message: { unread, notice },
  406. apply: { apply, analysis, access },
  407. patent: { information, safeg, early },
  408. transaction: { trans1, trans2, trans3, trans4, trans5 },
  409. };
  410. }
  411. /**
  412. * 根据申请人统计,申请人所在的专利信息数量
  413. */
  414. async patentInfoByApplyPerson() {
  415. console.time('p1');
  416. const pImodel = this.ctx.model.Patent.Patentinfo;
  417. // const data = await pImodel.find({}, { apply_personal: 1 });
  418. const data = await pImodel.aggregate([{ $project: { apply_personal: 1 } }]);
  419. if (data.length <= 0) {
  420. return '未找到专利信息相关数据';
  421. }
  422. let nameList = data.map(i => i.apply_personal).map(i => i.split(';'));
  423. nameList = _.uniq(_.flattenDeep(nameList).map(i => _.trim(i)));
  424. const arr = [];
  425. for (const i of nameList) {
  426. const reg = new RegExp(i);
  427. const query = { apply_personal: reg };
  428. const res = await pImodel.aggregate([{ $match: query }, { $count: 'id' }]);
  429. if (res) {
  430. const head = _.head(res);
  431. const num = _.get(head, 'id', 0);
  432. arr.push({ name: i, num });
  433. }
  434. }
  435. return arr;
  436. }
  437. }
  438. module.exports = IndexService;