rpt_tpl_controller.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. /**
  2. * Created by Tony on 2017/6/1.
  3. */
  4. import mongoose from "mongoose";
  5. import async from "async";
  6. import counter from "../../../public/counter/counter";
  7. let RptTplModel = mongoose.model("rpt_templates");
  8. let TreeNodeModel = mongoose.model("rpt_tpl_tree");
  9. let rptExtCodeModel = mongoose.model("rpt_ext_code_tpl");
  10. let Rpt_Map_Fld_Mdl = mongoose.model("rpt_mapping_field");
  11. let rpt_cfg_mdl = mongoose.model("rpt_cfg");
  12. let rptCustCfgFacade = require("../facade/rpt_cust_cfg_facade");
  13. import JV from "../rpt_component/jpc_value_define";
  14. import rttFacade from "../facade/rpt_tpl_tree_node_facade";
  15. import CompilationModel from "../../users/models/compilation_model";
  16. import fs from "fs";
  17. let JSZip = require("jszip");
  18. //统一回调函数
  19. let callback = function (req, res, err, message, data) {
  20. res.json({ error: err, message: message, data: data });
  21. };
  22. let mExport = {
  23. getCustomerCfg: function (req, res) {
  24. let params = JSON.parse(req.body.params),
  25. userId = params.userId,
  26. me = this;
  27. if (req.session.sessionUser && req.session.sessionUser.id)
  28. userId = req.session.sessionUser.id;
  29. let userIds = [];
  30. userIds.push(userId);
  31. if (userId !== "-100") {
  32. userIds.push("-100");
  33. }
  34. rptCustCfgFacade.getCustomizeCfg(userIds).then(function (custCfg) {
  35. if (custCfg) {
  36. //success
  37. let rst = null;
  38. if (custCfg.length > 0) {
  39. rst = [];
  40. rst.push(null);
  41. for (let itemCfg of custCfg) {
  42. // rst = itemCfg;
  43. let doc = itemCfg._doc ? itemCfg._doc : itemCfg;
  44. let dest = {};
  45. copyRptCfg(doc, dest);
  46. if (doc.userId !== "-100") {
  47. rst.push(dest);
  48. } else {
  49. rst[0] = dest;
  50. }
  51. }
  52. }
  53. if (rst !== null && rst.length === 1) {
  54. //copy dft config
  55. let userDest = {};
  56. copyRptCfg(rst[0], userDest);
  57. rst.push(userDest);
  58. }
  59. callback(req, res, false, "", rst);
  60. } else {
  61. //failed
  62. callback(req, res, true, "失败!", null);
  63. }
  64. });
  65. },
  66. saveCustomerCfg: function (req, res) {
  67. let params = JSON.parse(req.body.params),
  68. userId = params.userId,
  69. custCfg = params.custCfg;
  70. if (req.session.sessionUser && req.session.sessionUser.id)
  71. userId = req.session.sessionUser.id;
  72. custCfg.userId = userId;
  73. rptCustCfgFacade.saveCustomizeCfg(custCfg).then(function (rst) {
  74. if (rst) {
  75. //success
  76. callback(req, res, false, "", "success!");
  77. } else {
  78. //failed
  79. callback(req, res, true, "更新失败!", null);
  80. }
  81. });
  82. },
  83. getDftTemplates: function (req, res) {
  84. let filter = {
  85. userId: "-100",
  86. $or: [{ isDeleted: null }, { isDeleted: false }],
  87. };
  88. TreeNodeModel.find(filter, "-_id", function (err, data) {
  89. if (err) {
  90. callback(req, res, true, "", null);
  91. } else {
  92. callback(req, res, false, "", data);
  93. }
  94. });
  95. },
  96. getExtCodeTpl: function (req, res) {
  97. rptExtCodeModel
  98. .find({})
  99. .exec()
  100. .then(function (rstCodeTpl) {
  101. if (rstCodeTpl) {
  102. callback(req, res, false, "", rstCodeTpl);
  103. } else {
  104. callback(req, res, "The report template was not found!", null);
  105. }
  106. });
  107. },
  108. async getCompilationList(req, res) {
  109. let compilationModel = new CompilationModel();
  110. // let compilationList = await compilationModel.getPermissionCompilationList(req);
  111. let compilationList = await compilationModel.getCompilationList();
  112. if (compilationList) {
  113. // compilationList.then(function (rst) {
  114. // callback(req,res,false,"", rst);
  115. // })
  116. callback(req, res, false, "", compilationList);
  117. } else {
  118. callback(req, res, true, "no result", null);
  119. }
  120. },
  121. getRptTplTree: function (req, res) {
  122. let params = JSON.parse(req.body.params),
  123. compilationId = params.compilationId,
  124. userId = params.userId,
  125. sessionUserId = null;
  126. let userIds = ["-100"];
  127. if (req.session.sessionUser && req.session.sessionUser.id)
  128. sessionUserId = req.session.sessionUser.id;
  129. if (userId !== null) {
  130. if (typeof userId === "string") {
  131. if (userIds.indexOf(userId) < 0) userIds.push(userId);
  132. } else if (userId instanceof Array) {
  133. for (let uid of userId) {
  134. userIds.push(uid);
  135. }
  136. }
  137. } else {
  138. }
  139. if (sessionUserId && userIds.indexOf(sessionUserId) < 0)
  140. userIds.push(sessionUserId);
  141. if (!compilationId) {
  142. compilationId = req.session.sessionCompilation._id;
  143. }
  144. rttFacade.findTplTree(compilationId, userIds).then(function (result) {
  145. if (result) {
  146. callback(req, res, false, "", result);
  147. } else {
  148. callback(req, res, true, "no result", null);
  149. }
  150. });
  151. },
  152. getTplTreeByCompilation: function (req, res) {
  153. let params = JSON.parse(req.body.params),
  154. compilationId = params.compilationId;
  155. // if (req.session.sessionUser && req.session.sessionUser.id) sessionUserId = req.session.sessionUser.id;
  156. if (!compilationId) {
  157. compilationId = req.session.sessionCompilation._id;
  158. }
  159. rttFacade.findTplTreeByCompilation(compilationId).then(function (result) {
  160. if (result) {
  161. callback(req, res, false, "", result);
  162. } else {
  163. callback(req, res, true, "no result", null);
  164. }
  165. });
  166. },
  167. updateTreeNodes: function (req, res) {
  168. let params = JSON.parse(req.body.params),
  169. nodes = params.nodes;
  170. let functions = [];
  171. for (let node of nodes) {
  172. functions.push(
  173. (function (doc) {
  174. return function (cb) {
  175. TreeNodeModel.update({ ID: doc.ID }, doc, cb);
  176. };
  177. })(node)
  178. );
  179. }
  180. async.parallel(functions, function (err, results) {
  181. callback(req, res, err, "", results);
  182. });
  183. },
  184. deleteRptTplNodes: function (req, res) {
  185. let params = JSON.parse(req.body.params),
  186. nodeIds = params.nodeIds,
  187. preNodeId = params.preNodeId,
  188. preNodeNextId = params.preNodeNextId;
  189. let functions = [];
  190. if (preNodeId !== -1) {
  191. functions.push(
  192. (function (nodeId, nextId) {
  193. return function (cb) {
  194. TreeNodeModel.update({ ID: nodeId }, { NextSiblingID: nextId }, cb);
  195. };
  196. })(preNodeId, preNodeNextId)
  197. );
  198. }
  199. for (let nId of nodeIds) {
  200. functions.push(
  201. (function (nodeId) {
  202. return function (cb) {
  203. TreeNodeModel.update({ ID: nodeId }, { isDeleted: true }, cb);
  204. };
  205. })(nId)
  206. );
  207. }
  208. async.parallel(functions, function (err, results) {
  209. callback(req, res, err, "", results);
  210. });
  211. },
  212. createTreeRootNode: function (req, res) {
  213. let params = JSON.parse(req.body.params),
  214. doc = params.doc;
  215. rttFacade.createNewTree(doc).then(function (rst) {
  216. if (rst) {
  217. //success
  218. callback(req, res, false, "", rst);
  219. } else {
  220. //failed
  221. callback(req, res, true, "创建失败!", null);
  222. }
  223. });
  224. },
  225. updateTreeRootNode: function (req, res) {
  226. let params = JSON.parse(req.body.params),
  227. doc = params.doc;
  228. rttFacade
  229. .updateTree(doc.compilationId, doc.engineerId, doc.userId, doc)
  230. .then(function (rst) {
  231. if (rst) {
  232. //success
  233. callback(req, res, false, "", rst);
  234. } else {
  235. //failed
  236. callback(req, res, true, "更新失败!", null);
  237. }
  238. });
  239. },
  240. partialUpdateTreeNode: function (req, res) {
  241. const params = JSON.parse(req.body.params);
  242. const pathArray = params.pathArray;
  243. const nodeArray = params.nodeArray;
  244. const _getCurrentNodeSerialOrder = function (parentItems, pathName) {
  245. let rst = -1;
  246. if (parentItems) {
  247. for (let idx = 0; idx < parentItems.length; idx++) {
  248. if (parentItems[idx].name === pathName) {
  249. rst = idx;
  250. break;
  251. }
  252. }
  253. }
  254. return rst;
  255. };
  256. const _updateNodeByPath = function (path, node, topNodeItems) {
  257. let rst = false;
  258. let tmpParentItems = topNodeItems;
  259. for (let idx = 0; idx < path.node_path.length; idx++) {
  260. const nIdx = _getCurrentNodeSerialOrder(
  261. tmpParentItems,
  262. path.node_path[idx]
  263. );
  264. if (nIdx >= 0) {
  265. if (idx === path.node_path.length - 1) {
  266. tmpParentItems[nIdx] = node;
  267. rst = true;
  268. } else {
  269. tmpParentItems = tmpParentItems[nIdx].items;
  270. }
  271. }
  272. }
  273. return rst;
  274. };
  275. const _addNodeByPath = function (path, node, topNodeItems) {
  276. let rst = false;
  277. let tmpParentItems = topNodeItems;
  278. if (path === null || path === "" || path.node_path.length === 0) {
  279. topNodeItems.push(node);
  280. rst = true;
  281. } else {
  282. for (let idx = 0; idx < path.node_path.length; idx++) {
  283. const nIdx = _getCurrentNodeSerialOrder(
  284. tmpParentItems,
  285. path.node_path[idx]
  286. );
  287. if (nIdx >= 0) {
  288. if (idx === path.node_path.length - 1) {
  289. if (tmpParentItems[nIdx].nodeType === 1) {
  290. if (!tmpParentItems[nIdx].items) {
  291. tmpParentItems[nIdx].items = [];
  292. }
  293. tmpParentItems[nIdx].items.push(node);
  294. rst = true;
  295. }
  296. } else {
  297. tmpParentItems = tmpParentItems[nIdx].items;
  298. }
  299. }
  300. }
  301. }
  302. return rst;
  303. };
  304. const _deleteNodeByPath = function (path, node, topNodeItems) {
  305. let rst = false;
  306. let tmpParentItems = topNodeItems;
  307. for (let idx = 0; idx < path.node_path.length; idx++) {
  308. const nIdx = _getCurrentNodeSerialOrder(
  309. tmpParentItems,
  310. path.node_path[idx]
  311. );
  312. if (nIdx >= 0) {
  313. if (idx === path.node_path.length - 1) {
  314. tmpParentItems.splice(nIdx, 1);
  315. rst = true;
  316. } else {
  317. tmpParentItems = tmpParentItems[nIdx].items;
  318. }
  319. }
  320. }
  321. return rst;
  322. };
  323. // console.log('compilationId: ' + compilationId);
  324. rttFacade
  325. .findTplTree(params.compilationId, params.userId)
  326. .then(function (targetTplTreeNode) {
  327. if (
  328. pathArray &&
  329. pathArray.length > 0 &&
  330. nodeArray &&
  331. nodeArray.length === pathArray.length
  332. ) {
  333. let doc = targetTplTreeNode._doc
  334. ? targetTplTreeNode._doc[0]
  335. : targetTplTreeNode[0];
  336. // console.log(doc);
  337. const topNodeItems = doc.items;
  338. for (let idx = 0; idx < pathArray.length; idx++) {
  339. if (pathArray[idx].operation_type === "update") {
  340. _updateNodeByPath(pathArray[idx], nodeArray[idx], topNodeItems);
  341. } else if (pathArray[idx].operation_type === "add") {
  342. _addNodeByPath(pathArray[idx], nodeArray[idx], topNodeItems);
  343. } else if (pathArray[idx].operation_type === "delete") {
  344. _deleteNodeByPath(pathArray[idx], nodeArray[idx], topNodeItems);
  345. } else {
  346. // out of control
  347. }
  348. }
  349. // console.log(topNodeItems);
  350. // console.log(doc);
  351. rttFacade
  352. .updateTree(doc.compilationId, doc.engineerId, doc.userId, doc)
  353. .then(function (rst) {
  354. if (rst) {
  355. //success
  356. callback(req, res, false, "", rst);
  357. } else {
  358. //failed
  359. callback(req, res, true, "更新失败!", null);
  360. }
  361. });
  362. }
  363. });
  364. },
  365. updateTopNodeName: function (req, res) {
  366. //备注:因设计的更改,此方法将被放弃
  367. let params = JSON.parse(req.body.params),
  368. compilationId = params.compilationId,
  369. engineerId = params.engineerId,
  370. userId = params.userId,
  371. nodeName = params.nodeName;
  372. if (req.session.sessionUser && req.session.sessionUser.id)
  373. userId = req.session.sessionUser.id;
  374. let filter = {
  375. compilationId: compilationId,
  376. engineerId: engineerId,
  377. userId: userId,
  378. $or: [{ isDeleted: null }, { isDeleted: false }],
  379. };
  380. let updateStatement = { $set: { name: nodeName } };
  381. rttFacade.updateTreeInDetail(filter, updateStatement).then(function (rst) {
  382. if (rst) {
  383. //success
  384. callback(req, res, false, "", rst);
  385. } else {
  386. //failed
  387. callback(req, res, true, "更新失败!", null);
  388. }
  389. });
  390. },
  391. updateSubLevelOneNode: function (req, res) {
  392. let params = JSON.parse(req.body.params),
  393. compilationId = params.compilationId,
  394. // engineerId = params.engineerId,
  395. userId = params.userId,
  396. subNode = params.subNode;
  397. if (req.session.sessionUser && req.session.sessionUser.id)
  398. userId = req.session.sessionUser.id; //备注:这段逻辑只会在前端有效,后端运维不会走到
  399. let filter = {
  400. compilationId: compilationId,
  401. userId: userId,
  402. "items.ID": subNode.ID,
  403. $or: [{ isDeleted: null }, { isDeleted: false }],
  404. };
  405. let updateStatement = { $set: { "items.$": subNode } };
  406. rttFacade.updateTreeInDetail(filter, updateStatement).then(function (rst) {
  407. if (rst) {
  408. //success
  409. callback(req, res, false, "", rst);
  410. } else {
  411. //failed
  412. callback(req, res, true, "更新失败!", null);
  413. }
  414. });
  415. },
  416. removeTreeRootNode: function (req, res) {
  417. let params = JSON.parse(req.body.params),
  418. compilationId = params.compilationId,
  419. engineerId = params.engineerId,
  420. userId = params.userId,
  421. isPhysically = params.isPhysically;
  422. if (req.session.sessionUser && req.session.sessionUser.id)
  423. userId = req.session.sessionUser.id;
  424. if (isPhysically) {
  425. rttFacade
  426. .removeTreePhycically(compilationId, engineerId, userId)
  427. .then(function (rst) {
  428. if (rst) {
  429. //success
  430. callback(req, res, false, "", rst);
  431. } else {
  432. //failed
  433. callback(req, res, true, "删除失败!", null);
  434. }
  435. });
  436. } else {
  437. rttFacade
  438. .removeTree(compilationId, engineerId, userId)
  439. .then(function (rst) {
  440. if (rst) {
  441. //success
  442. callback(req, res, false, "", rst);
  443. } else {
  444. //failed
  445. callback(req, res, true, "删除失败!", null);
  446. }
  447. });
  448. }
  449. },
  450. getNewNodeID: function (req, res) {
  451. let params = JSON.parse(req.body.params),
  452. scope = params.scope;
  453. counter.counterDAO.getIDAfterCount(
  454. counter.moduleName.report,
  455. scope,
  456. function (err, result) {
  457. callback(req, res, false, "", result.sequence_value);
  458. }
  459. );
  460. },
  461. createDftRptTpl: function (req, res) {
  462. let params = JSON.parse(req.body.params),
  463. treeNodeId = params.treeNodeId,
  464. rptDftTplId = params.rptDftTplId,
  465. rptName = params.rptName,
  466. grpKey = params.grpKey,
  467. compilationId = params.compilationId,
  468. engineerId = params.engineerId,
  469. userId = params.userId,
  470. subNode = params.subNode;
  471. if (req.session.sessionUser && req.session.sessionUser.id)
  472. userId = req.session.sessionUser.id;
  473. let filter = { ID: rptDftTplId };
  474. RptTplModel.findOne(filter, "-_id")
  475. .exec()
  476. .then(function (dftTplRst) {
  477. if (dftTplRst) {
  478. let _doc = dftTplRst["_doc"];
  479. _doc["ID"] = treeNodeId;
  480. _doc["GROUP_KEY"] = grpKey;
  481. _doc["ID_KEY"] = "";
  482. _doc[JV.NODE_MAIN_INFO][JV.NODE_MAIN_INFO_RPT_NAME] = rptName;
  483. let rptTpl = new RptTplModel(_doc);
  484. rptTpl.save(function (err, actTplRst) {
  485. if (err) {
  486. callback(req, res, "报表模板创建错误", "", null);
  487. } else {
  488. let filter = {
  489. compilationId: compilationId,
  490. engineerId: engineerId,
  491. userId: userId,
  492. "items.ID": subNode.ID,
  493. $or: [{ isDeleted: null }, { isDeleted: false }],
  494. };
  495. let updateStatement = { $set: { "items.$": subNode } };
  496. rttFacade
  497. .updateTreeInDetail(filter, updateStatement)
  498. .then(function (rst) {
  499. if (rst) {
  500. //success
  501. callback(req, res, false, "", actTplRst);
  502. } else {
  503. //failed
  504. callback(req, res, true, "更新失败!", null);
  505. }
  506. });
  507. }
  508. });
  509. } else {
  510. callback(req, res, "Create report template failed!", null);
  511. }
  512. });
  513. },
  514. getRefRptTpl: function (req, res) {
  515. let params = JSON.parse(req.body.params),
  516. rptTplId = params.rptTplId;
  517. let filter = { ID: rptTplId };
  518. RptTplModel.findOne(filter, "-_id")
  519. .exec()
  520. .then(function (rstTpl) {
  521. if (rstTpl) {
  522. callback(req, res, false, "", rstTpl);
  523. } else {
  524. callback(req, res, "The report template was not found!", null);
  525. }
  526. });
  527. },
  528. updateRptTpl: function (req, res) {
  529. let params = JSON.parse(req.body.params),
  530. rptTpl = JSON.parse(params.rptTpl);
  531. let filter = { ID: parseInt(rptTpl[JV.PROP_ID]) },
  532. options = { overwrite: true };
  533. RptTplModel.update(filter, rptTpl, options, function (err, rst) {
  534. if (err) {
  535. callback(
  536. req,
  537. res,
  538. true,
  539. "The report template was updated failed!",
  540. false
  541. );
  542. } else {
  543. callback(
  544. req,
  545. res,
  546. false,
  547. "The report template was updated successfully!",
  548. true
  549. );
  550. }
  551. });
  552. },
  553. copyRptTpl: function (req, res) {
  554. let params = JSON.parse(req.body.params),
  555. orgRptTplId = params.orgRptTplId,
  556. newID = params.newRptTplId;
  557. let filter = { ID: orgRptTplId };
  558. RptTplModel.findOne(filter, "-_id")
  559. .exec()
  560. .then(function (baseTplRst) {
  561. if (baseTplRst) {
  562. let _doc = baseTplRst["_doc"];
  563. _doc["ID"] = newID;
  564. if (_doc["GROUP_KEY"].indexOf("(Copy)") < 0) {
  565. _doc["GROUP_KEY"] = _doc["GROUP_KEY"] + "(Copy)";
  566. }
  567. let rptTpl = new RptTplModel(_doc);
  568. rptTpl.save(function (err, actTplRst) {
  569. if (err) {
  570. callback(req, res, "报表模板创建错误", "", null);
  571. } else {
  572. callback(req, res, false, "", newID);
  573. }
  574. });
  575. } else {
  576. callback(req, res, "Create report template failed!", null);
  577. }
  578. });
  579. },
  580. // 导出所有的报表数据
  581. async getAllBackupData(req, res) {
  582. try {
  583. const filePath = "./public/highWay_reportBackup.zip";
  584. const rptConfig = await rpt_cfg_mdl.find({}, "-_id");
  585. const rptTemplate = await RptTplModel.find({}, "-_id");
  586. const rptTplTree = await TreeNodeModel.find({}, "-_id");
  587. const rptField = await Rpt_Map_Fld_Mdl.find({}, "-_id");
  588. var zip = new JSZip();
  589. zip.file(
  590. "报表模板备份.json",
  591. JSON.stringify({
  592. type: `building`,
  593. name: `reportTemplate`,
  594. data: rptTemplate,
  595. })
  596. );
  597. zip.file(
  598. "报表树备份.json",
  599. JSON.stringify({
  600. type: `building`,
  601. name: `reportTree`,
  602. data: rptTplTree,
  603. })
  604. );
  605. zip.file(
  606. "报表配置备份.json",
  607. JSON.stringify({
  608. type: `building`,
  609. name: `reportConfig`,
  610. data: rptConfig,
  611. })
  612. );
  613. zip.file(
  614. "报表指标备份.json",
  615. JSON.stringify({
  616. type: `building`,
  617. name: `reportField`,
  618. data: rptField,
  619. })
  620. );
  621. // 将Zip打包成Blob对象
  622. zip
  623. .generateNodeStream({ type: "nodebuffer", streamFiles: true })
  624. .pipe(fs.createWriteStream(filePath))
  625. .on("finish", function () {
  626. // JSZip generates a readable stream with a "end" event,
  627. // but is piped here in a writable stream which emits a "finish" event.
  628. console.log("报表模板备份已导出");
  629. callback(req, res, false, "", filePath);
  630. });
  631. } catch (e) {
  632. callback(req, res, true, "no result", null);
  633. }
  634. },
  635. };
  636. function copyRptCfg(src, dest) {
  637. dest.margins = {
  638. Left: src.margins.Left,
  639. Right: src.margins.Right,
  640. Top: src.margins.Top,
  641. Bottom: src.margins.Bottom,
  642. };
  643. dest.showVerticalLine = src.showVerticalLine;
  644. dest.isNarrow = src.isNarrow;
  645. dest.fillZero = src.fillZero;
  646. dest.fonts = [];
  647. for (let font of src.fonts) {
  648. dest.fonts.push({
  649. ID: font["ID"],
  650. CfgDispName: font["CfgDispName"],
  651. Name: font["Name"],
  652. FontHeight: font["FontHeight"],
  653. FontColor: font["FontColor"],
  654. FontBold: font["FontBold"],
  655. FontItalic: font["FontItalic"],
  656. FontUnderline: font["FontUnderline"],
  657. FontStrikeOut: font["FontStrikeOut"],
  658. FontAngle: font["FontAngle"],
  659. });
  660. }
  661. }
  662. export default mExport;