index.js 14 KB

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