helper.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. 'use strict';
  2. const moment = require('moment');
  3. // 实销用户id
  4. exports.saledRoleId = 90;// '90'
  5. // 远控行为ID
  6. exports.rcBehaviorId = 6016;
  7. exports.rcResult = {
  8. FAILED: { $in: [ 'false', 'FAILED' ] },
  9. SUCCEED: { $in: [ 'true', 'SUCCEED' ] },
  10. };
  11. exports.rcDict = {
  12. 车门解锁: { op: 'UNLOCK', behavior_id: 60160001 },
  13. 车门上锁: { op: 'LOCK', behavior_id: 60160001 },
  14. 车辆启动: { op: 'OPEN', behavior_id: 60160002 },
  15. 车辆熄火: { op: 'CLOSE', behavior_id: 60160002 },
  16. 空调开启: { op: 'OPEN', behavior_id: 60160003 },
  17. 空调关闭: { op: 'CLOSE', behavior_id: 60160003 },
  18. 空调温度控制: { behavior_id: 60160004 },
  19. 空调风量档位设置: { behavior_id: 60160005 },
  20. 前除霜模式开启: { op: 'OPEN', behavior_id: 60160006 },
  21. 前除霜模式关闭: { op: 'CLOSE', behavior_id: 60160006 },
  22. 后风窗加热开启: { op: 'OPEN', behavior_id: 60160007 },
  23. 后风窗加热关闭: { op: 'CLOSE', behavior_id: 60160007 },
  24. 空调运行时长设置: { behavior_id: 60160008 },
  25. 一键调温: { behavior_id: 60160009 },
  26. 主驾座椅加热开启: { behavior_id: 60160010, op: 'OPEN', opType: 'HOSTSEAT_HEAT' },
  27. 主驾座椅加热关闭: { behavior_id: 60160010, op: 'CLOSE', opType: 'HOSTSEAT_HEAT' },
  28. 副驾座椅加热开启: { behavior_id: 60160010, op: 'OPEN', opType: 'VICESEAT_HEAT' },
  29. 副驾座椅加热关闭: { behavior_id: 60160010, op: 'CLOSE', opType: 'VICESEAT_HEAT' },
  30. 左后座椅加热开启: { behavior_id: 60160010, op: 'OPEN', opType: 'LEFT_REAR_HEAT' },
  31. 左后座椅加热关闭: { behavior_id: 60160010, op: 'CLOSE', opType: 'LEFT_REAR_HEAT' },
  32. 右后座椅加热开启: { behavior_id: 60160010, op: 'OPEN', opType: 'RIGHT_REAR_HEAT' },
  33. 右后座椅加热关闭: { behavior_id: 60160010, op: 'CLOSE', opType: 'RIGHT_REAR_HEAT' },
  34. 空调预约: { behavior_id: 60160011 },
  35. 方向盘加热开启: { op: 'OPEN', behavior_id: 60160012 },
  36. 方向盘加热关闭: { op: 'CLOSE', behavior_id: 60160012 },
  37. 通风开启: { op: 'OPEN', behavior_id: 60160013 },
  38. 通风关闭: { op: 'CLOSE', behavior_id: 60160013 },
  39. 天窗开启: { op: 'OPEN', behavior_id: 60160014 },
  40. 天窗关闭: { op: 'CLOSE', behavior_id: 60160014 },
  41. 车灯开启: { op: 'OPEN', behavior_id: 60160015 },
  42. 车灯关闭: { op: 'CLOSE', behavior_id: 60160015 },
  43. 远程寻车: { behavior_id: 60160016 },
  44. 设置充电限值: { behavior_id: 60160017 },
  45. 设置放电电量限值: { behavior_id: 60160018 },
  46. 开始充电: { behavior_id: 60160019 },
  47. 结束充电: { behavior_id: 60160020 },
  48. 定时充电: { behavior_id: 60160021 },
  49. 充电完成提醒开启: { op: 'OPEN', behavior_id: 60160022 },
  50. 充电完成提醒关闭: { op: 'CLOSE', behavior_id: 60160022 },
  51. 充电状态查询: { behavior_id: 60160023 },
  52. 远程监控开启: { behavior_id: 60160024 },
  53. 远程监控正常关闭: { closeType: 'NORMAL', behavior_id: 60160025 },
  54. 远程监控异常关闭: { closeType: 'EXCEPTION', behavior_id: 60160025 },
  55. '控制充电桩(基于蓝牙)TBD': { behavior_id: 60160026 },
  56. 代客泊车: { behavior_id: 60160027 },
  57. 代客模式: { behavior_id: 60160028 },
  58. };
  59. exports.drivingSafetyScoreProject = {
  60. acceleration_score: 1,
  61. decelerate_score: 1,
  62. speeding_score: 1,
  63. fa_score: 1,
  64. fd_score: 1,
  65. turn_score: 1,
  66. clu_score: 1,
  67. flc_score: 1,
  68. io_score: 1,
  69. hs_turn_score: 1,
  70. at_night_drive_score: 1,
  71. un_tie_sb_score: 1,
  72. leave_sw_score: 1,
  73. dsm_score: 1,
  74. fcw_score: 1,
  75. bsd_score: 1,
  76. lka_score: 1,
  77. ldw_score: 1,
  78. };
  79. exports.energyConservationScoreProject = {
  80. energyConservationScore: 1,
  81. acceleration_score: 1,
  82. decelerate_score: 1,
  83. idling_score: 1,
  84. drive_anticipation_score: 1,
  85. oil_score: 1,
  86. sa_score: 1,
  87. sd_score: 1,
  88. steady_score: 1,
  89. };
  90. // 格式化时间
  91. exports.formatTime = time => moment(time).format('YYYY-MM-DD HH:mm:ss');
  92. // 获取昨日0:0:0
  93. exports.yesterday = () => moment().subtract(1, 'days').set('hour', 0)
  94. .set('minute', 0)
  95. .set('second', 0)
  96. .set('millisecond', 0)
  97. .valueOf();
  98. // 获取今日0:0:0
  99. exports.today = () => moment().set('hour', 0)
  100. .set('minute', 0)
  101. .set('second', 0)
  102. .set('millisecond', 0)
  103. .valueOf();
  104. // 解析时间字符串YYYY-MM-DD为时间戳
  105. exports.parse = str => moment(str, 'YYYY-MM-DD').valueOf();
  106. // 解析时间字符串为moment对象
  107. exports.momentDate = str => moment(str, 'YYYY-MM-DD');
  108. // 判断是否是今日
  109. exports.isToday = time => moment(new Date()).isSame(moment(time));
  110. // 当前年 今年
  111. exports.nowYear = () => moment().set('month', 0)
  112. .set('date', 1)
  113. .set('hour', 0)
  114. .set('minute', 0)
  115. .set('second', 0)
  116. .set('millisecond', 0)
  117. .valueOf();
  118. // 获取月头
  119. exports.getMonthTop = time => moment(time).set('date', 1)
  120. .set('hour', 0)
  121. .set('minute', 0)
  122. .set('second', 0)
  123. .set('millisecond', 0)
  124. .valueOf();
  125. // 上个月
  126. exports.preMonth = time => moment(time).subtract(1, 'months').set('date', 1)
  127. .set('hour', 0)
  128. .set('minute', 0)
  129. .set('second', 0)
  130. .set('millisecond', 0)
  131. .valueOf();
  132. // 获取转换时间戳对象project 默认转换字段$create_date
  133. exports.getTimeGenProject = (type, dateStr = 'create_date') => {
  134. // dateString: { $dateToString: { format: '%Y-%m-%d', date: { $toDate: dateStr } } },
  135. switch (type) {
  136. case '0':
  137. return {
  138. day: { $dayOfMonth: { $toDate: `$${dateStr}` } },
  139. month: { $month: { $toDate: `$${dateStr}` } },
  140. year: { $year: { $toDate: `$${dateStr}` } },
  141. };
  142. case '1':
  143. return {
  144. month: { $month: { $toDate: `$${dateStr}` } },
  145. year: { $year: { $toDate: `$${dateStr}` } },
  146. };
  147. case '2':
  148. return {
  149. year: { $year: { $toDate: `$${dateStr}` } },
  150. };
  151. default:
  152. break;
  153. }
  154. };
  155. // 获取转换时间戳范围match 默认字段$create_date
  156. exports.getTimeRangMatch = (startTime, endTime, dateStr = 'create_date') => {
  157. const match = {};
  158. match[dateStr] = { $gte: startTime, $lt: endTime };
  159. return match;
  160. };
  161. // 获取活跃car的条件
  162. exports.getCarActiveCond = ({ startTime, endTime }) => {
  163. return [
  164. { $lookup: {
  165. from: 'driving_behavior_info',
  166. let: { vin: '$vin' },
  167. pipeline: [{ $match: { $expr: { $and:
  168. [
  169. { $eq: [ '$vin', '$$vin' ] },
  170. { $gte: [ '$start_time', this.getMonthTop(startTime) ] },
  171. { $lt: [ '$start_time', endTime ] },
  172. ] } } }], as: 'drive',
  173. } },
  174. { $unwind: { path: '$drive', preserveNullAndEmptyArrays: true } },
  175. { $group: {
  176. _id: '$vin',
  177. mileage: { $sum: { $cond: [ '$drive.mileage', { $toDouble: '$drive.mileage' }, 0 ] } },
  178. pro_code: { $first: '$pro_code' }, city_code: { $first: '$city_code' },
  179. is_saled_car: { $first: '$is_saled_car' }, sale_date: { $first: '$sale_date' },
  180. user_id: { $first: '$user_id' },
  181. series_code: { $first: '$series_code' }, model_code: { $first: '$model_code' },
  182. } },
  183. ];
  184. };
  185. // 获取区域分组语句 (之前的前置语句或者结果必须存在 元素属性:city_name,area_name,provice_name)
  186. exports.getLocationMongo = () => {
  187. return [
  188. { $group: { _id: { area_name: '$area_name', provice_name: '$provice_name', city_name: '$city_name' },
  189. count: { $sum: 1 } } },
  190. { $group: { _id: { area_name: '$_id.area_name', provice_name: '$_id.provice_name' },
  191. cities: { $push: { city_name: '$_id.city_name', count: '$count' } },
  192. count: { $sum: '$count' } } },
  193. { $group: { _id: { area_name: '$_id.area_name' },
  194. provinces: { $push: { provice_name: '$_id.provice_name', cities: '$cities', count: '$count' } },
  195. count: { $sum: '$count' } } },
  196. { $group: { _id: null,
  197. areas: { $push: { area_name: '$_id.area_name', provinces: '$provinces', count: '$count' } },
  198. count: { $sum: '$count' } } },
  199. ];
  200. };
  201. // 获取年龄和性别分组语句 (之前的前置语句或者结果必须存在 元素属性: id_card,gender)
  202. exports.getAggAndSexMongo = () => {
  203. return [
  204. {
  205. $bucket: {
  206. groupBy: { $cond: [ '$id_card',
  207. { $subtract: [{ $year: { $toDate: new Date() } },
  208. { $convert: {
  209. input: { $substr: [ '$id_card', 6, 4 ] },
  210. to: 'int',
  211. onError: { $add: [{ $year: { $toDate: new Date() } }, 1 ] } } },
  212. ] }, -1 ] },
  213. boundaries: [ 18, 25, 30, 35, 40, 200 ],
  214. default: 'Other',
  215. output: {
  216. mCount: { $sum: {
  217. $cond: [{ $eq: [ '$gender', 'M' ] }, 1, 0 ],
  218. } },
  219. fCount: { $sum: {
  220. $cond: [{ $eq: [ '$gender', 'F' ] }, 1, 0 ],
  221. } },
  222. count: { $sum: 1 },
  223. },
  224. },
  225. },
  226. ];
  227. };
  228. exports.unionArray = (a, b) => {
  229. return [ ...new Set([ ...a, ...b ]) ];
  230. };
  231. // 获取消息类型 时间分组语句
  232. exports.getMsgTimeGroupMongo = type => {
  233. switch (type) {
  234. case '0':
  235. return [
  236. { $group: { _id: { year: '$year', month: '$month', day: '$day', msgType: '$msgType._id' },
  237. count: { $sum: '$msgType.count' } } },
  238. { $group: { _id: { year: '$_id.year', month: '$_id.month', day: '$_id.day' },
  239. msgType: { $push: { _id: '$_id.msgType', count: '$count' } } } },
  240. ];
  241. case '1':
  242. return [
  243. { $group: { _id: { year: '$year', month: '$month', msgType: '$msgType._id' },
  244. count: { $sum: '$msgType.count' } } },
  245. { $group: { _id: { year: '$_id.year', month: '$_id.month' },
  246. msgType: { $push: { _id: '$_id.msgType', count: '$count' } } } },
  247. ];
  248. case '2':
  249. return [
  250. { $group: { _id: { year: '$year', msgType: '$msgType._id' },
  251. count: { $sum: '$msgType.count' } } },
  252. { $group: { _id: { year: '$_id.year' },
  253. msgType: { $push: { _id: '$_id.msgType', count: '$count' } } } },
  254. ];
  255. default:
  256. return [];
  257. }
  258. };
  259. // 获取车辆出行和疲劳次数分布 时间分组语句
  260. exports.getCarDSMTimeGroupMongo = type => {
  261. switch (type) {
  262. case '0':
  263. return [
  264. { $group: {
  265. _id: { year: '$year', month: '$month', day: '$day', _id: '$mileageStartTimeAndDsm._id._id' },
  266. count: { $sum: '$mileageStartTimeAndDsm.count' }, dsmCount: { $sum: '$mileageStartTimeAndDsm.dsmCount' } } },
  267. { $group: { _id: { year: '$_id.year', month: '$_id.month', day: '$_id.day' },
  268. data: { $push: { _id: '$_id._id', count: '$count', dsmCount: '$dsmCount' } } } },
  269. ];
  270. case '1':
  271. return [
  272. { $group: { _id: { year: '$year', month: '$month', _id: '$mileageStartTimeAndDsm._id._id' },
  273. count: { $sum: '$mileageStartTimeAndDsm.count' }, dsmCount: { $sum: '$mileageStartTimeAndDsm.dsmCount' } } },
  274. { $group: { _id: { year: '$_id.year', month: '$_id.month' },
  275. data: { $push: { _id: '$_id._id', count: '$count', dsmCount: '$dsmCount' } } } },
  276. ];
  277. case '2':
  278. return [
  279. { $group: { _id: { year: '$year', _id: '$mileageStartTimeAndDsm._id._id' },
  280. count: { $sum: '$mileageStartTimeAndDsm.count' }, dsmCount: { $sum: '$mileageStartTimeAndDsm.dsmCount' } } },
  281. { $group: { _id: { year: '$_id.year' },
  282. data: { $push: { _id: '$_id._id', count: '$count', dsmCount: '$dsmCount' } } } },
  283. ];
  284. default:
  285. return [];
  286. }
  287. };
  288. // 获取车辆根据 某个维度字段求和 进行时间分组语句
  289. exports.getCarTimeGroupMongo = (type, value) => {
  290. switch (type) {
  291. case '0':
  292. return [
  293. { $group: {
  294. _id: { year: '$year', month: '$month', day: '$day', _id: `$${value}._id._id` },
  295. count: { $sum: `$${value}.count` } } },
  296. { $group: { _id: { year: '$_id.year', month: '$_id.month', day: '$_id.day' },
  297. data: { $push: { _id: '$_id._id', count: '$count' } } } },
  298. ];
  299. case '1':
  300. return [
  301. { $group: { _id: { year: '$year', month: '$month', _id: `$${value}._id._id` },
  302. count: { $sum: `$${value}.count` } } },
  303. { $group: { _id: { year: '$_id.year', month: '$_id.month' },
  304. data: { $push: { _id: '$_id._id', count: '$count' } } } },
  305. ];
  306. case '2':
  307. return [
  308. { $group: { _id: { year: '$year', _id: `$${value}._id._id` },
  309. count: { $sum: `$${value}.count` } } },
  310. { $group: { _id: { year: '$_id.year' },
  311. data: { $push: { _id: '$_id._id', count: '$count' } } } },
  312. ];
  313. default:
  314. return [];
  315. }
  316. };
  317. // 获取车辆根据 某个维度字段求平均值 进行时间分组语句
  318. exports.getCarAvgTimeGroupMongo = (type, value) => {
  319. switch (type) {
  320. case '0':
  321. return [
  322. { $group: {
  323. _id: { year: '$year', month: '$month', day: '$day', _id: `$${value}._id._id` },
  324. count: { $avg: `$${value}.count` } } },
  325. { $group: { _id: { year: '$_id.year', month: '$_id.month', day: '$_id.day' },
  326. data: { $push: { _id: '$_id._id', count: '$count' } } } },
  327. ];
  328. case '1':
  329. return [
  330. { $group: { _id: { year: '$year', month: '$month', _id: `$${value}._id._id` },
  331. count: { $avg: `$${value}.count` } } },
  332. { $group: { _id: { year: '$_id.year', month: '$_id.month' },
  333. data: { $push: { _id: '$_id._id', count: '$count' } } } },
  334. ];
  335. case '2':
  336. return [
  337. { $group: { _id: { year: '$year', _id: `$${value}._id._id` },
  338. count: { $avg: `$${value}.count` } } },
  339. { $group: { _id: { year: '$_id.year' },
  340. data: { $push: { _id: '$_id._id', count: '$count' } } } },
  341. ];
  342. default:
  343. return [];
  344. }
  345. };
  346. // 获取分页语句
  347. exports.getPageMongo = (pageNumber, pageSize) => {
  348. return [
  349. { $skip: (pageNumber - 1) * pageSize },
  350. { $limit: pageSize },
  351. ];
  352. };
  353. // 获取根据某个维度字段进行桶分组语句 -(区分车型车系)
  354. exports.getBucketMongo = (group, boundaries, sum = { $sum: 1 }, bucketF) => {
  355. return [
  356. {
  357. $bucket: {
  358. groupBy: group,
  359. boundaries,
  360. default: 'Other',
  361. output: {
  362. v: { $push: { vin: '$vin', ...bucketF } },
  363. },
  364. },
  365. },
  366. { $unwind: '$v' },
  367. { $lookup: { from: 't_vehicle_record', localField: 'v.vin', foreignField: 'vin', as: 'car' } },
  368. { $unwind: '$car' },
  369. { $group: {
  370. _id: { series_code: '$car.series_code', model_code: '$car.model_code', _id: '$_id' },
  371. count: sum,
  372. } },
  373. ];
  374. };
  375. // 获取时间分组 type 0日 1月 2年
  376. exports.getTimeGroup = (type, baseCond = { count: { $sum: 1 } }) => {
  377. switch (type) {
  378. case '0':
  379. return {
  380. ...baseCond, _id: { year: '$year', month: '$month', day: '$day' },
  381. };
  382. case '1':
  383. return {
  384. ...baseCond, _id: { year: '$year', month: '$month' },
  385. };
  386. case '2':
  387. return {
  388. ...baseCond, _id: { year: '$year' },
  389. };
  390. default:
  391. break;
  392. }
  393. };
  394. // 通用的时间范围匹配 + 时间分组求和
  395. exports.getCommonAggSum = ({ type, startTime, endTime, value }) => {
  396. return [
  397. { $match: this.getTimeRangMatch(startTime, endTime) },
  398. { $group: this.getTimeGroup(type, { count: { $sum: `$${value}` } }) },
  399. ];
  400. };
  401. // 通用的时间范围匹配 + 时间分组平均值
  402. exports.getCommonAggAvg = ({ type, startTime, endTime, value }) => {
  403. return [
  404. { $match: this.getTimeRangMatch(startTime, endTime) },
  405. { $group: this.getTimeGroup(type, { count: { $avg: `$${value}` } }) },
  406. ];
  407. };
  408. // 通用的时间范围匹配 + 时间分组求最大(最近)时间数据
  409. exports.getCommonAggMax = ({ type, startTime, endTime, value }) => {
  410. return [
  411. { $match: this.getTimeRangMatch(startTime, endTime) },
  412. { $sort: { create_date: -1 } },
  413. { $group: this.getTimeGroup(type, { count: { $first: `$${value}` } }) },
  414. ];
  415. };
  416. // 车辆基本信息 字典字段映射
  417. exports.statusInfoDict = {
  418. statsAcceCnt: { k: 'stats_acce_cnt', num: 10, v: 'ar=', mode: [ 'dr_mode_auto', 'dr_mode_eco', 'dr_mode_sport', 'dr_mode_confort' ] },
  419. statsSpRange: { k: 'stats_sp_range', num: 13, v: 'range=_cnt' },
  420. statsDece: { k: 'stats_dece', num: 10, v: 'dece=' },
  421. statsRotate: { k: 'stats_rotate', num: 8, v: 'rotate=' },
  422. statsSpRotate: { k: 'stats_sp_rotate', num: 8, v: 'rotate=', mode: [ 'sp_1_cnt', 'sp_2_cnt', 'sp_3_cnt' ] },
  423. statsHighSp: { k: 'stats_high_sp', num: 3, v: 'high_sp=' },
  424. statsStartSp: { k: 'stats_start_sp', num: 14, v: 'start_sp=' },
  425. statsSpDeceCnt: { k: 'stats_sp_dece_cnt', num: 10, superNum: 7, v: 'sp_=_cnt.dece.dece=',
  426. mode: [ 'dr_mode_auto', 'dr_mode_eco', 'dr_mode_sport', 'dr_mode_confort' ] },
  427. statsSpAcceCnt: {
  428. multi: {
  429. acce: { k: 'stats_sp_acce_cnt', num: 10, superNum: 6, v: 'sp_=_cnt.acce.acce=' },
  430. as: { k: 'stats_sp_acce_cnt', num: 12, superNum: 6, v: 'sp_=_cnt.as.as=' },
  431. },
  432. },
  433. };
  434. // 根据车辆基本信息 字典字段映射 获取计算数组
  435. exports.getStatusInfoArr = () => {
  436. const arr = [];
  437. Object.keys(this.statusInfoDict).forEach(item => {
  438. const obj = this.statusInfoDict[item];
  439. if (obj.multi) {
  440. Object.keys(obj.multi).forEach(m => {
  441. const multiObj = obj.multi[m];
  442. if (multiObj.mode) {
  443. multiObj.mode.forEach(mode => {
  444. arr.push({ dbStr: `${multiObj.k}.${mode}.${multiObj.v}`, num: multiObj.num, superNum: multiObj.superNum });
  445. });
  446. } else {
  447. arr.push({ dbStr: `${multiObj.k}.${multiObj.v}`, num: multiObj.num, superNum: multiObj.superNum });
  448. }
  449. });
  450. } else {
  451. if (obj.mode) {
  452. obj.mode.forEach(mode => {
  453. arr.push({ dbStr: `${obj.k}.${mode}.${obj.v}`, num: obj.num, superNum: obj.superNum });
  454. });
  455. } else {
  456. arr.push({ dbStr: `${obj.k}.${obj.v}`, num: obj.num, superNum: obj.superNum });
  457. }
  458. }
  459. });
  460. return arr;
  461. };
  462. // 弃用 来源唯一
  463. exports.statusInfo = [
  464. [
  465. { dbStr: 'stats_acce_cnt.dr_mode_auto.ar=', num: 10 },
  466. { dbStr: 'stats_acce_cnt.dr_mode_eco.ar=', num: 10 },
  467. { dbStr: 'stats_acce_cnt.dr_mode_sport.ar=', num: 10 },
  468. { dbStr: 'stats_acce_cnt.dr_mode_confort.ar=', num: 10 },
  469. { dbStr: 'stats_sp_range.range=_cnt', num: 13 },
  470. { dbStr: 'stats_dece.dece=', num: 10 },
  471. { dbStr: 'stats_rotate.rotate=', num: 8 },
  472. { dbStr: 'stats_sp_rotate.sp_1_cnt.rotate=', num: 8 },
  473. { dbStr: 'stats_sp_rotate.sp_2_cnt.rotate=', num: 8 },
  474. { dbStr: 'stats_sp_rotate.sp_3_cnt.rotate=', num: 8 },
  475. { dbStr: 'stats_high_sp.high_sp=', num: 3 },
  476. { dbStr: 'stats_start_sp.start_sp=', num: 14 },
  477. { dbStr: 'stats_sp_dece_cnt.dr_mode_auto.sp_=_cnt.dece.dece=', superNum: 7, num: 10 },
  478. { dbStr: 'stats_sp_dece_cnt.dr_mode_eco.sp_=_cnt.dece.dece=', superNum: 7, num: 10 },
  479. { dbStr: 'stats_sp_dece_cnt.dr_mode_sport.sp_=_cnt.dece.dece=', superNum: 7, num: 10 },
  480. { dbStr: 'stats_sp_dece_cnt.dr_mode_confort.sp_=_cnt.dece.dece=', superNum: 7, num: 10 },
  481. { dbStr: 'stats_sp_acce_cnt.sp_=_cnt.acce.acce=', superNum: 6, num: 10 },
  482. { dbStr: 'stats_sp_acce_cnt.sp_=_cnt.as.as=', superNum: 6, num: 12 },
  483. ],
  484. ];
  485. // 获取活跃app的条件
  486. exports.getAppActiveCond = ({ startTime, endTime }) => {
  487. return [
  488. { $match: { ...this.getTimeRangMatch(startTime, endTime, 'login_time'), login_state: 1 } },
  489. { $sort: { login_time: 1 } },
  490. { $group: {
  491. _id: '$user_Id',
  492. login_count: { $sum: 1 },
  493. provice_name: { $first: '$provice_name' }, city_name: { $first: '$city_name' },
  494. } },
  495. { $lookup: { from: 't_sync_county', localField: 'provice_name', foreignField: 'province_name', as: 'area' } },
  496. { $project: {
  497. login_count: 1,
  498. area_name: { $arrayElemAt: [ '$area.area_name', 0 ] },
  499. provice_name: '$provice_name',
  500. city_name: '$city_name',
  501. } },
  502. { $lookup:
  503. {
  504. from: 'app_behavior_record',
  505. let: { user_id: '$_id' },
  506. pipeline: [{ $match: { $expr: { $and:
  507. [
  508. { $eq: [ '$user_id', '$$user_id' ] },
  509. { $gte: [ '$create_time', startTime ] },
  510. { $lt: [ '$create_time', endTime ] },
  511. ] } } }], as: 'behaviors',
  512. },
  513. },
  514. { $unwind: { path: '$behaviors', preserveNullAndEmptyArrays: true } },
  515. { $group: {
  516. _id: '$_id', login_count: { $first: '$login_count' },
  517. use_duration: { $sum: { $cond: [ '$behaviors.use_duration', '$behaviors.use_duration', 0 ] } },
  518. area_name: { $first: '$area_name' }, provice_name: { $first: '$provice_name' }, city_name: { $first: '$city_name' },
  519. } },
  520. { $match: { $or: [{ use_duration: { $gt: 30 * 60 * 1000 } }, { login_count: { $gte: 3 } }] } },
  521. ];
  522. };