server_data_statisticsv2.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. const logger = require('./logger')
  2. var remote_config_db = require("./db/remote_config_db");
  3. var collect_coins_db = require("./db/collect_coins_db");
  4. var withdraw_db = require("./db/withdraw_db");
  5. var moralis = require("./moralis_sdk");
  6. var utils = require("./utils");
  7. const axios = require('axios');
  8. var { account_config } = require('../config/config.js');
  9. const { max } = require('moment');
  10. const redis = require('./db/redis_db');
  11. // 拿到飞书写入的 token
  12. const feishu_write_table_token_url = 'https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal'
  13. const feishu_write_table_data_url = 'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg/values_batch_update'
  14. const feishu_insert_table_url = 'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg/insert_dimension_range'
  15. const feishu_delete_table_url = 'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg/dimension_range'
  16. const feishu_get_table_metadata_url = 'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg/metainfo'
  17. const feishu_create_table_url = 'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg/dimension_range'
  18. const mTokenPriceCache = new Map()
  19. const mDecimalsCache = new Map()
  20. //########################################### 出入金数据统计 ########################################
  21. const http_request_get = async (data) => {
  22. var host = account_config.STATISTICS_URL
  23. // host = 'https://api.denetme.net/denet/wallet/stat/getMoneyStat?date='
  24. var path = data
  25. var url = host + path
  26. logger.log('http_request_get', url)
  27. return new Promise(response => {
  28. axios.get(url)
  29. .then(res => {
  30. logger.log('res=>', res.status, res.data);
  31. if (res.data.code == 0) {
  32. response(res.data)
  33. } else {
  34. response({
  35. code: 0,
  36. msg: err.toString(),
  37. data: {
  38. canNotWithdrawUSD: '0',
  39. canWithdrawUSD: '0',
  40. incomeUSDTotal: '0',
  41. incomeUSDFee: '0'
  42. }
  43. })
  44. }
  45. }).catch(err => {
  46. logger.error('http_request_get', err.toString(), url.toString());
  47. response({
  48. code: -1,
  49. msg: err.toString(),
  50. data: {
  51. canNotWithdrawUSD: '0',
  52. canWithdrawUSD: '0',
  53. incomeUSDTotal: '0',
  54. incomeUSDFee: '0'
  55. }
  56. })
  57. });
  58. })
  59. }
  60. function getBscEnv() {
  61. var bsc_env
  62. switch (process.env.NODE_ENV) {
  63. case 'dev':
  64. case 'test':
  65. bsc_env = 'bsc_testnet'
  66. bsc_env = 'bsc_mainnet'
  67. break
  68. case 'prd':
  69. bsc_env = 'bsc_mainnet'
  70. break
  71. default:
  72. bsc_env = 'bsc_mainnet'
  73. break
  74. }
  75. return bsc_env;
  76. }
  77. async function findCurBalance(type, address) {
  78. var balances
  79. var price
  80. var tokenItems = []
  81. switch (type) {
  82. case 'bsc':
  83. balances = await moralis.getAccountAllCoins({
  84. chain: getBscEnv(),
  85. address: address
  86. })
  87. // price = await moralis.getAllTotkenPrice({ chain: getBscEnv() })
  88. price = await getPrice(getBscEnv())
  89. break
  90. case 'czz':
  91. balances = await moralis.getAccountAllCoins({
  92. chain: 'czz',
  93. address: address
  94. })
  95. price = await getPrice('czz')
  96. // price = await moralis.getAllTotkenPrice({ chain: 'czz' })
  97. break
  98. }
  99. logger.info('findCurBalance', type, address, balances, price)
  100. if (typeof price === 'string') {
  101. price = JSON.parse(price)
  102. }
  103. if (!balances || !price) return null
  104. priceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price)
  105. if (!balances.native.balance) {
  106. balances.native.balance = '0'
  107. }
  108. if (balances.native) {
  109. balances.native.usdPrice = parseFloat(balances.native.balance) / parseFloat(10 ** 18) * priceItem.usdPrice
  110. logger.info('findTokenPriceItem 0x0000000000000000000000000000000000000000 ', balances, priceItem, type)
  111. var bo = {
  112. address: address,
  113. token_address: '0x0000000000000000000000000000000000000000',
  114. chain: type,
  115. amount: balances.native.balance,
  116. decimals: 18,
  117. price: priceItem.usdPrice,
  118. usd: balances.native.usdPrice
  119. }
  120. tokenItems.push(bo)
  121. }
  122. if (balances.other && Array.isArray(balances.other)) {
  123. for (let index = 0; index < balances.other.length; index++) {
  124. const element = balances.other[index];
  125. priceItem = moralis.findTokenPriceItem(element.token_address, price)
  126. logger.info('findTokenPriceItem element ', priceItem, element.token_address)
  127. if (priceItem) {
  128. if (!element.decimals || element.decimals == 0)
  129. element.decimals = 18
  130. element.usdPrice = parseFloat(element.balance) / parseFloat(10 ** element.decimals) * priceItem.usdPrice
  131. var bo = {
  132. address: address,
  133. token_address: element.token_address,
  134. chain: type,
  135. amount: element.balance,
  136. decimals: element.decimals,
  137. price: priceItem.usdPrice,
  138. usd: element.usdPrice
  139. }
  140. tokenItems.push(bo)
  141. }
  142. }
  143. }
  144. logger.debug('tokenUsds', tokenItems, type)
  145. return {
  146. nativeUsd: balances.native.usdPrice,
  147. tokenUsds: tokenItems,
  148. totalUsd: addUsds(tokenItems, 'token_balance')
  149. }
  150. }
  151. async function getAllBalanceV2() {
  152. var company = await moralis.queryCompanyInfoFromId(0)
  153. logger.info('getAllBalance company', company)
  154. var bsc_balances = await findCurBalance('bsc', company.user_address)
  155. var czz_balances = await findCurBalance('czz', company.user_address)
  156. logger.info('findCurBalance bsc_balances', bsc_balances)
  157. logger.info('findCurBalance czz_balances', czz_balances)
  158. let lists = bsc_balances.tokenUsds.concat(czz_balances.tokenUsds);
  159. return {
  160. bsc: bsc_balances,
  161. czz: czz_balances,
  162. infos: lists,
  163. totalUsd: bsc_balances.totalUsd + czz_balances.totalUsd,
  164. totalNativeBalanceUsd: bsc_balances.nativeUsd + czz_balances.nativeUsd
  165. }
  166. }
  167. function parseGas(response, index, price) {
  168. try {
  169. logger.info('parseGas in', response, index)
  170. if (response && Array.isArray(response) && response.length > 0) {
  171. var obj
  172. if (response[index] && typeof response[index] === 'string')
  173. try {
  174. obj = JSON.parse(response[index])
  175. } catch (error) {
  176. logger.error('JSON.parse(response[index])', error.toString)
  177. }
  178. return parseFloat(obj.gasPrice.number) * parseFloat(obj.gasLimit.number) / parseFloat(10 ** 18) * parseFloat(price)
  179. }
  180. else return 0
  181. } catch (error) {
  182. logger.error('parseGas', error.toString(), JSON.stringify(response))
  183. return 0
  184. }
  185. }
  186. async function getPrice(key) {
  187. if (mTokenPriceCache.has(key)) {
  188. price = mTokenPriceCache.get(key)
  189. } else {
  190. var price = await moralis.getAllTotkenPrice({
  191. chain: key
  192. })
  193. if (typeof price === 'string') {
  194. price = JSON.parse(price)
  195. }
  196. mTokenPriceCache.set(key, price)
  197. }
  198. return price
  199. }
  200. async function getPriceFromCache(key, address) {
  201. console.info('getPriceFromCache>', key, address)
  202. var price = await getPrice(key)
  203. // var price = await moralis.getAllTotkenPrice({
  204. // chain: key
  205. // })
  206. // if (typeof price === 'string') {
  207. // price = JSON.parse(price)
  208. // }
  209. var priceItem = moralis.findTokenPriceItem(address, price)
  210. if (priceItem && priceItem.usdPrice) {
  211. return priceItem.usdPrice
  212. } else {
  213. return '0'
  214. }
  215. }
  216. function convertChain(chain) {
  217. return chain
  218. }
  219. function balance2USDPrice(amount, decimals, price) {
  220. return parseFloat(amount) / parseFloat(10 ** decimals) * parseFloat(price)
  221. }
  222. async function getDecimalsFromRedis(chain, address) {
  223. var decimals = 18
  224. try {
  225. var newKey = redis.formatRedisKey('REDIS_ERC20_CONTRACT_DECIMALS', chain, address.toLowerCase())
  226. if (mDecimalsCache.has(newKey)) {
  227. decimals = mDecimalsCache.get(newKey)
  228. } else {
  229. decimals = await redis.readAppendRedis('REDIS_ERC20_CONTRACT_DECIMALS', chain, address.toLowerCase())
  230. mDecimalsCache.set(newKey, decimals)
  231. }
  232. if (!decimals) decimals = '18'
  233. } catch (error) {
  234. logger.error('getDecimalsFromRedis', chain, address, error.toString())
  235. decimals = 18
  236. }
  237. return decimals
  238. }
  239. function addUsds(infos, type) {
  240. var total = 0
  241. if (infos && Array.isArray(infos) && infos.length > 0) {
  242. for (let index = 0; index < infos.length; index++) {
  243. const element = infos[index];
  244. switch (type) {
  245. case 'gas':
  246. // logger.info('addUsds total ', type, element.gasUsd, element, total)
  247. total += element.gasUsd
  248. break
  249. case 'withdraw':
  250. total += element.withdrawUsd
  251. break
  252. case 'collect_coins':
  253. total += element.withdrawUsd
  254. break
  255. case 'slGas':
  256. total += element.slGasUsd
  257. break
  258. case 'token_balance':
  259. total += element.usd
  260. break
  261. case 'native_in_coins':
  262. if (element.token_address && element.token_address == '0x0000000000000000000000000000000000000000')
  263. total += element.inUsd
  264. break
  265. case 'native_token_in_coins':
  266. total += element.inUsd
  267. break
  268. }
  269. }
  270. }
  271. return total
  272. }
  273. async function getWithdrawOutInfoV2(startTime, endTime) {
  274. if (startTime && endTime) {
  275. startTime = new Date(startTime).getTime()
  276. endTime = new Date(endTime).getTime()
  277. }
  278. var withdraw_ret = await withdraw_db.getWidthdrawTotalFee(startTime, endTime)
  279. var withDrawInfos = []
  280. for (let index = 0; index < withdraw_ret.length; index++) {
  281. const trs = withdraw_ret[index];
  282. // console.log('getWithdrawOutInfoV2 element ', trs)
  283. var token_address = trs.contract_address
  284. if (!trs.contract_address)
  285. token_address = '0x0000000000000000000000000000000000000000'
  286. try {
  287. var input = {
  288. dt: utils.chinaTimeMs(trs.update_time),
  289. user_address: trs.to_address,
  290. token_address: token_address,
  291. chain: convertChain(trs.chain_id + ""),
  292. amount: trs.amount,
  293. decimals: await getDecimalsFromRedis(convertChain(trs.chain_id + ""), token_address),
  294. price: await getPriceFromCache(convertChain(trs.chain_id + ""), token_address),
  295. gasUsd: parseFloat(trs.gas_price) * parseFloat(trs.gas_limit) / parseFloat(10 ** 18) * await getPriceFromCache(convertChain(trs.chain_id + ""), '0x0000000000000000000000000000000000000000')
  296. }
  297. if (!input.gasUsd) {
  298. logger.info('withdraw_ret input ', trs, input)
  299. input.gasUsd = 0
  300. }
  301. //换算成美元
  302. input.withdrawUsd = balance2USDPrice(input.amount, input.decimals, input.price)
  303. console.log('getWithdrawOutInfoV2 input ', input)
  304. withDrawInfos.push(input)
  305. } catch (error) {
  306. logger.error('getWithdrawOutInfoV2 trs', error.toString())
  307. }
  308. }
  309. // logger.log('getWithdrawOutInfoV2 totalOutGasFeeUsd addUsds', addUsds(withDrawInfos, 'gas'), withDrawInfos[0], withDrawInfos[1])
  310. return {
  311. infos: withDrawInfos,
  312. totalOutGasFeeUsd: addUsds(withDrawInfos, 'gas'),
  313. totalWithdrawUsd: addUsds(withDrawInfos, 'withdraw'),
  314. }
  315. }
  316. async function getCollectCoinsOutInfoV2(startTime, endTime) {
  317. var collect_ret = await collect_coins_db.query_collect_total_fee(startTime, endTime);
  318. // console.log('getCollectCoinsOutInfoV2 collect_ret', collect_ret.results.length)
  319. //每笔入金的详细信息
  320. var infos = []
  321. //入金充值的 gas 和实际消费的 gas
  322. var inGasFeeInfo = []
  323. if (collect_ret && collect_ret.results && Array.isArray(collect_ret.results) && collect_ret.results.length > 0) {
  324. for (let index = 0; index < collect_ret.results.length; index++) {
  325. var element = collect_ret.results[index]
  326. if (!element.chain)
  327. element.chain = 'bsc_mainnet'
  328. var update_tm = element.update_time
  329. var user_address = element.user_address
  330. // console.log('getCollectCoinsOutInfoV2 element', element.before_gas_fee, element.resposes, typeof element.resposes, JSON.parse(element.resposes))
  331. var resposes;
  332. if (element.resposes && typeof element.resposes === 'string') {
  333. try {
  334. resposes = JSON.parse(element.resposes)
  335. } catch (error) {
  336. logger.error('element.response parse', error.toString())
  337. }
  338. }
  339. if (element.prestore_gas_fee && typeof element.prestore_gas_fee === 'string') {
  340. try {
  341. var gasObj = JSON.parse(element.prestore_gas_fee)
  342. var before_gas_fee = element.before_gas_fee ? element.before_gas_fee : '0'
  343. if (gasObj) {
  344. // logger.log('element.prestore_gas_fee parse', before_gas_fee, gasObj, gasObj.chain)
  345. var newGasObj = {
  346. chain: convertChain(gasObj.chain),
  347. amount: gasObj.amount,
  348. useGas: before_gas_fee,
  349. price: await getPriceFromCache(convertChain(gasObj.chain), '0x0000000000000000000000000000000000000000'),
  350. }
  351. //实际充值手续费用到的 usd
  352. newGasObj.gasUsd = balance2USDPrice(newGasObj.useGas, 18, newGasObj.price)
  353. //散落 gas
  354. newGasObj.slGasUsd = balance2USDPrice(parseFloat(newGasObj.amount) - parseFloat(newGasObj.useGas), 18, newGasObj.price)
  355. inGasFeeInfo.push(newGasObj)
  356. }
  357. } catch (error) {
  358. logger.error('element.prestore_gas_fee parse', error.toString())
  359. }
  360. }
  361. if (element.transfers && typeof element.transfers === 'string') {
  362. try {
  363. var trss = JSON.parse(element.transfers)
  364. // console.log('trss.transfers', trss.chain)
  365. for (let index = 0; index < trss.length; index++) {
  366. const trs = trss[index];
  367. var address = trs.contractAddress == null ? '0x0000000000000000000000000000000000000000' : trs.contractAddress
  368. console.log('trss.transfers', address, trs)
  369. var input = {
  370. dt: update_tm,
  371. user_address: user_address,
  372. token_address: address,
  373. chain: convertChain(trs.chain),
  374. amount: trs.amount,
  375. decimals: trs.contractAddress == null ? 18 : await getDecimalsFromRedis(convertChain(trs.chain), trs.contractAddress),
  376. price: await getPriceFromCache(convertChain(trs.chain), address),
  377. gasUsd: parseGas(resposes, index, await getPriceFromCache(convertChain(trs.chain), '0x0000000000000000000000000000000000000000')) //入金 gas 手续费
  378. }
  379. //换算成美元
  380. input.inUsd = balance2USDPrice(input.amount, input.decimals, input.price)
  381. infos.push(input)
  382. }
  383. } catch (error) {
  384. logger.error('transfers handle error', error.toString())
  385. }
  386. }
  387. }
  388. }
  389. return {
  390. infos: infos,
  391. totalNativeInFee: addUsds(infos, 'native_in_coins'), //总 native 入金
  392. totalInFee: addUsds(infos, 'native_token_in_coins'), //总入金
  393. totalInGasFeeUsd: addUsds(infos, 'gas') + addUsds(inGasFeeInfo, 'gas'),//总入金消耗的 gas 包含打 gas fee
  394. slTotalGasFeeUsd: addUsds(inGasFeeInfo, 'slGas') //散落 gas
  395. }
  396. }
  397. async function getServerData(startTime, endTime) {
  398. //拿到所有归集 list
  399. var collectCoinsInfos = await getCollectCoinsOutInfoV2(startTime, endTime)
  400. // console.log('getCollectCoinsOutInfoV2 collectCoinsInfos ', collectCoinsInfos)
  401. //拿到所有出金
  402. var withdrawInfos = await getWithdrawOutInfoV2(startTime, endTime)
  403. // console.log('getWithdrawOutInfoV2 withdrawInfos ', withdrawInfos)
  404. return {
  405. collectCoinsInfos: collectCoinsInfos,
  406. withdrawInfos: withdrawInfos
  407. }
  408. }
  409. function sortList(lists) {
  410. lists.sort((a, b) => {
  411. let t1 = new Date(a.dt)
  412. let t2 = new Date(b.dt)
  413. return t2.getTime() - t1.getTime()
  414. })
  415. return lists
  416. }
  417. async function getStatisticsInfoV2(day) {
  418. // //今日
  419. var startTime = utils.getLastDay(day, 'YYYY-MM-DD') + " 00:00:00"
  420. var endTime = utils.getLastDay(day, 'YYYY-MM-DD') + " 23:59:59"
  421. logger.info('getTotalOutGasFee', startTime, endTime)
  422. var rangeData = await getServerData(startTime, endTime)
  423. logger.info('getServerData rangeData', rangeData)
  424. var allData = await getServerData(null, null)
  425. logger.info('getServerData allData', allData)
  426. var data = await http_request_get(utils.getLastDay(day, 'YYYYMMDD'))
  427. logger.info('http_request_get data', data)
  428. //获取当前账户总余额
  429. var curBalances = await getAllBalanceV2()
  430. logger.info('getAllBalanceV2 curBalances', curBalances)
  431. return {
  432. updateTime: utils.getLastDay(day, 'YYYY-MM-DD'),
  433. todayTotalProfit: parseFloat(data.data.incomeUSDTotal) - parseFloat(rangeData.collectCoinsInfos.totalInGasFeeUsd + rangeData.withdrawInfos.totalOutGasFeeUsd),//今日收入
  434. todayTotalOutGasFee: rangeData.collectCoinsInfos.totalInGasFeeUsd + rangeData.withdrawInfos.totalOutGasFeeUsd,//今日总支出的 gas fee
  435. canNotWithdrawUSD: parseFloat(data.data.canNotWithdrawUSD), //不可提现余额
  436. canWithdrawUSD: parseFloat(data.data.canWithdrawUSD), //可提现余额
  437. todayIncomeUSDTotal: parseFloat(data.data.incomeUSDTotal), //今日总收入
  438. todayIncomeUSDFee: parseFloat(data.data.incomeUSDFee), //今日固定收入
  439. totalOutGasFee: allData.collectCoinsInfos.totalInGasFeeUsd + allData.withdrawInfos.totalOutGasFeeUsd, //总支出 gas fee
  440. totalWithdrawGasFee: allData.withdrawInfos.totalOutGasFeeUsd, //总提币 gas fee
  441. totalCollectCoinsGasFee: allData.collectCoinsInfos.totalInGasFeeUsd, //总归集 gas fee
  442. totalInFee: allData.collectCoinsInfos.totalInFee, //总入金
  443. totalNativeInFee: allData.collectCoinsInfos.totalNativeInFee, //总 native 入金
  444. totalOutFee: allData.withdrawInfos.totalWithdrawUsd, //总出金
  445. totalBalances: curBalances.totalUsd, //总余额
  446. ylGasBalance: curBalances.totalNativeBalanceUsd - allData.collectCoinsInfos.totalNativeInFee, //预留 gas 费余额 native 总余额 - 总入金
  447. slGasBalance: allData.collectCoinsInfos.slTotalGasFeeUsd, //散落 gas 费余额 充值 0.5 gas - 使用 0.3 gas= 散落 0.2gas
  448. todayInUsdLists: sortList(rangeData.collectCoinsInfos.infos),//入金列表
  449. todayOutUsdLists: sortList(rangeData.withdrawInfos.infos),//出金列表
  450. totalInUsdLists: sortList(allData.collectCoinsInfos.infos),//总入金列表
  451. totalOutUsdLists: sortList(allData.withdrawInfos.infos),//总出金列表
  452. totalBalanceLists: curBalances.infos //总余额
  453. }
  454. }
  455. const getFeishuToken = async (params) => {
  456. return new Promise(resolve => {
  457. axios.post(feishu_write_table_token_url,
  458. {
  459. app_id: "cli_a223f015abbad00e",
  460. app_secret: "DMCF6tBwIpeOQPnWrFUMYd6tmjb53C4n"
  461. },
  462. {
  463. timeout: 1 * 60 * 1000,
  464. headers: {
  465. 'Content-Type': "application/json; charset=utf-8"
  466. }
  467. })
  468. .then(res => {
  469. logger.log('getFeishuToken res=>', res.status, res.data);
  470. resolve(res.data)
  471. }).catch(err => {
  472. logger.error('getFeishuToken error ', JSON.stringify(err));
  473. resolve(JSON.stringify(err))
  474. });
  475. })
  476. }
  477. function writeTable(app_token, data) {
  478. logger.info('writeTable', data)
  479. var body = {
  480. 'valueRanges': [
  481. {
  482. 'range': '0pRQpu!A2:C2',
  483. 'values': [
  484. [data.totalCollectCoinsGasFee, //归集总 gas
  485. data.totalWithdrawGasFee, //提币总 gas
  486. data.totalOutGasFee], //总支出 gas
  487. ]
  488. },
  489. {
  490. 'range': '1ygrMB!A2:B2',
  491. 'values': [
  492. [
  493. data.totalInFee, //总入金
  494. data.totalOutFee,//总出金
  495. ],
  496. ]
  497. },
  498. {
  499. 'range': 'BMjMDr!A3:J3',
  500. 'values': [
  501. [
  502. data.updateTime, //更新时间
  503. data.todayTotalProfit,//今日总利润
  504. data.todayIncomeUSDTotal,//今日总收入
  505. data.todayIncomeUSDFee,//今日固定手续费收入
  506. data.todayTotalOutGasFee,//今日总 gas 支出
  507. data.totalBalances, //总余额
  508. data.canNotWithdrawUSD, //不可提现余额
  509. data.canWithdrawUSD,//可提现余额
  510. data.ylGasBalance.total,//预留 gas
  511. data.slGasBalance.total,//散落 gas
  512. ],
  513. ]
  514. }
  515. ]
  516. }
  517. return new Promise(resolve => {
  518. axios.post(feishu_write_table_data_url,
  519. body,
  520. {
  521. timeout: 1 * 60 * 1000,
  522. headers: {
  523. 'Content-Type': "application/json; charset=utf-8",
  524. 'Authorization': 'Bearer ' + app_token
  525. }
  526. })
  527. .then(res => {
  528. logger.log('writeTable res=>', res.status, res.data);
  529. resolve(res.data)
  530. }).catch(err => {
  531. logger.error('writeTable error ', JSON.stringify(err));
  532. resolve(JSON.stringify(err))
  533. });
  534. })
  535. }
  536. async function getTableRows(app_token, index) {
  537. return new Promise(resolve => {
  538. axios.get(feishu_get_table_metadata_url,
  539. {
  540. timeout: 1 * 60 * 1000,
  541. headers: {
  542. 'Content-Type': "application/json; charset=utf-8",
  543. 'Authorization': 'Bearer ' + app_token
  544. }
  545. })
  546. .then(res => {
  547. console.log('res=>', res.status, res.data, res.data.data.sheets);
  548. resolve(res.data.data.sheets[index].rowCount)
  549. }).catch(err => {
  550. logger.error('error ', JSON.stringify(err));
  551. resolve(0)
  552. });
  553. })
  554. }
  555. async function delTableRows(app_token, sheetId, startIndex, endIndex) {
  556. var body = {
  557. dimension: {
  558. sheetId: sheetId,
  559. majorDimension: 'ROWS',
  560. startIndex: startIndex,
  561. endIndex: endIndex,
  562. },
  563. }
  564. return new Promise(resolve => {
  565. axios.delete(feishu_delete_table_url,
  566. {
  567. data: body,
  568. timeout: 1 * 60 * 1000,
  569. headers: {
  570. 'Content-Type': "application/json; charset=utf-8",
  571. 'Authorization': 'Bearer ' + app_token
  572. }
  573. })
  574. .then(res => {
  575. console.log('delTableRows res=>', res.status, res.data);
  576. resolve(res.data)
  577. }).catch(err => {
  578. logger.error('delTableRows error ', JSON.stringify(err));
  579. resolve(JSON.stringify(err))
  580. });
  581. })
  582. }
  583. async function insertTableRows(app_token, sheetId, startIndex, endIndex) {
  584. var body = {
  585. dimension: {
  586. sheetId: sheetId,
  587. majorDimension: 'ROWS',
  588. startIndex: startIndex,
  589. endIndex: endIndex,
  590. },
  591. inheritStyle: 'AFTER'
  592. }
  593. return new Promise(resolve => {
  594. axios.post(feishu_insert_table_url,
  595. JSON.stringify(body),
  596. {
  597. timeout: 1 * 60 * 1000,
  598. headers: {
  599. 'Content-Type': "application/json; charset=utf-8",
  600. 'Authorization': 'Bearer ' + app_token
  601. }
  602. })
  603. .then(res => {
  604. console.log('res=>', res.status, res.data);
  605. resolve(res.data)
  606. }).catch(err => {
  607. logger.error('error ', JSON.stringify(err));
  608. resolve(JSON.stringify(err))
  609. });
  610. })
  611. }
  612. async function addTableRows(app_token, sheetId, endIndex) {
  613. var body = {
  614. dimension: {
  615. sheetId: sheetId,
  616. majorDimension: 'ROWS',
  617. length: endIndex,
  618. },
  619. }
  620. return new Promise(resolve => {
  621. axios.post(feishu_create_table_url,
  622. JSON.stringify(body),
  623. {
  624. timeout: 1 * 60 * 1000,
  625. headers: {
  626. 'Content-Type': "application/json; charset=utf-8",
  627. 'Authorization': 'Bearer ' + app_token
  628. }
  629. })
  630. .then(res => {
  631. console.log('res=>', res.status, res.data);
  632. resolve(res.data)
  633. }).catch(err => {
  634. logger.error('error ', JSON.stringify(err));
  635. resolve(JSON.stringify(err))
  636. });
  637. })
  638. }
  639. async function exec(data) {
  640. var app = await getFeishuToken()
  641. // await insertTableRows(app.app_access_token, 'Ji1hLG', 2, data.totalInUsdLists.length)
  642. // await insertTableRows(app.app_access_token, 'aFCrrP', 2, data.totalOutUsdLists.length)
  643. var rows = await getTableRows(app.app_access_token, 2)
  644. if (rows > 1) {
  645. logger.info('getTableRows', rows)
  646. await delTableRows(app.app_access_token, '2hNaot', 2, rows)
  647. await addTableRows(app.app_access_token, '2hNaot', rows)
  648. }
  649. // await writeTable(app.app_access_token, data)
  650. }
  651. async function report2FeishuTable() {
  652. try {
  653. logger.error('数据统计 start')
  654. logger.info('report2FeishuTable')
  655. var data = await getStatisticsInfoV2(2);
  656. logger.info('getStatisticsInfo', data)
  657. var ret = await exec(data)
  658. logger.error('数据统计 end', 'https://st94nif1cq.feishu.cn/sheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg?sheet=BMjMDr', JSON.stringify(data), JSON.stringify(ret))
  659. mTokenPriceCache.clear()
  660. } catch (error) {
  661. logger.error('report2FeishuTable', error.toString())
  662. }
  663. }
  664. async function test() {
  665. // var ret = await getStatisticsInfoV2(2)
  666. // logger.debug('getStatisticsInfoV2', await getStatisticsInfoV2(2), mTokenPriceCache.size)
  667. report2FeishuTable()
  668. }
  669. // test()
  670. // exec()
  671. module.exports = {
  672. getStatisticsInfoV2
  673. }