Parcourir la source

数据统计完成

DevYK il y a 3 ans
Parent
commit
29e574e836
2 fichiers modifiés avec 830 ajouts et 1 suppressions
  1. 828 0
      model/server_data_statisticsv2.js
  2. 2 1
      routes/sdk.js

+ 828 - 0
model/server_data_statisticsv2.js

@@ -0,0 +1,828 @@
+const logger = require('./logger')
+var remote_config_db = require("./db/remote_config_db");
+var collect_coins_db = require("./db/collect_coins_db");
+var withdraw_db = require("./db/withdraw_db");
+var moralis = require("./moralis_sdk");
+var utils = require("./utils");
+const axios = require('axios');
+var { account_config } = require('../config/config.js');
+const { max } = require('moment');
+const redis = require('./db/redis_db');
+
+// 拿到飞书写入的 token
+const feishu_write_table_token_url = 'https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal'
+const feishu_write_table_data_url = 'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg/values_batch_update'
+const feishu_insert_table_url = 'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg/insert_dimension_range'
+const feishu_delete_table_url = 'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg/dimension_range'
+const feishu_get_table_metadata_url = 'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg/metainfo'
+const feishu_create_table_url = 'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg/dimension_range'
+
+const mTokenPriceCache = new Map()
+const mDecimalsCache = new Map()
+
+//########################################### 出入金数据统计 ########################################
+
+const http_request_get = async (data) => {
+    var host = account_config.STATISTICS_URL
+    // host = 'https://api.denetme.net/denet/wallet/stat/getMoneyStat?date='
+    var path = data
+    var url = host + path
+    logger.log('http_request_get', url)
+    return new Promise(response => {
+        axios.get(url)
+            .then(res => {
+                logger.log('res=>', res.status, res.data);
+                if (res.data.code == 0) {
+                    response(res.data)
+                } else {
+                    response({
+                        code: 0,
+                        msg: err.toString(),
+                        data: {
+                            canNotWithdrawUSD: '0',
+                            canWithdrawUSD: '0',
+                            incomeUSDTotal: '0',
+                            incomeUSDFee: '0'
+                        }
+                    })
+                }
+            }).catch(err => {
+                logger.error('http_request_get', err.toString(), url.toString());
+                response({
+                    code: -1,
+                    msg: err.toString(),
+                    data: {
+                        canNotWithdrawUSD: '0',
+                        canWithdrawUSD: '0',
+                        incomeUSDTotal: '0',
+                        incomeUSDFee: '0'
+                    }
+                })
+            });
+    })
+}
+
+
+function getBscEnv() {
+    var bsc_env
+    switch (process.env.NODE_ENV) {
+        case 'dev':
+        case 'test':
+            bsc_env = 'bsc_testnet'
+            bsc_env = 'bsc_mainnet'
+            break
+        case 'prd':
+            bsc_env = 'bsc_mainnet'
+            break
+        default:
+            bsc_env = 'bsc_mainnet'
+            break
+    }
+    return bsc_env;
+}
+
+
+
+async function findCurBalance(type, address) {
+    var balances
+    var price
+    var tokenItems = []
+    switch (type) {
+        case 'bsc':
+            balances = await moralis.getAccountAllCoins({
+                chain: getBscEnv(),
+                address: address
+            })
+            // price = await moralis.getAllTotkenPrice({ chain: getBscEnv() })
+            price = await getPrice(getBscEnv())
+            break
+        case 'czz':
+            balances = await moralis.getAccountAllCoins({
+                chain: 'czz',
+                address: address
+            })
+            price = await getPrice('czz')
+            // price = await moralis.getAllTotkenPrice({ chain: 'czz' })
+            break
+    }
+    logger.info('findCurBalance', type, address, balances, price)
+    if (typeof price === 'string') {
+        price = JSON.parse(price)
+    }
+    if (!balances || !price) return null
+    priceItem = moralis.findTokenPriceItem('0x0000000000000000000000000000000000000000', price)
+    if (!balances.native.balance) {
+        balances.native.balance = '0'
+    }
+    if (balances.native) {
+        balances.native.usdPrice = parseFloat(balances.native.balance) / parseFloat(10 ** 18) * priceItem.usdPrice
+        logger.info('findTokenPriceItem 0x0000000000000000000000000000000000000000 ', balances, priceItem, type)
+        var bo = {
+            address: address,
+            token_address: '0x0000000000000000000000000000000000000000',
+            chain: type,
+            amount: balances.native.balance,
+            decimals: 18,
+            price: priceItem.usdPrice,
+            usd: balances.native.usdPrice
+        }
+        tokenItems.push(bo)
+    }
+
+    if (balances.other && Array.isArray(balances.other)) {
+        for (let index = 0; index < balances.other.length; index++) {
+            const element = balances.other[index];
+            priceItem = moralis.findTokenPriceItem(element.token_address, price)
+            logger.info('findTokenPriceItem element ', priceItem, element.token_address)
+            if (priceItem) {
+
+                if (!element.decimals || element.decimals == 0)
+                    element.decimals = 18
+                element.usdPrice = parseFloat(element.balance) / parseFloat(10 ** element.decimals) * priceItem.usdPrice
+
+                var bo = {
+                    address: address,
+                    token_address: element.token_address,
+                    chain: type,
+                    amount: element.balance,
+                    decimals: element.decimals,
+                    price: priceItem.usdPrice,
+                    usd: element.usdPrice
+                }
+                tokenItems.push(bo)
+            }
+        }
+    }
+
+    logger.debug('tokenUsds', tokenItems, type)
+    return {
+        nativeUsd: balances.native.usdPrice,
+        tokenUsds: tokenItems,
+        totalUsd: addUsds(tokenItems, 'token_balance')
+    }
+}
+
+async function getAllBalanceV2() {
+    var company = await moralis.queryCompanyInfoFromId(0)
+    logger.info('getAllBalance company', company)
+
+    var bsc_balances = await findCurBalance('bsc', company.user_address)
+    var czz_balances = await findCurBalance('czz', company.user_address)
+
+    logger.info('findCurBalance bsc_balances', bsc_balances)
+    logger.info('findCurBalance czz_balances', czz_balances)
+    let lists = bsc_balances.tokenUsds.concat(czz_balances.tokenUsds);
+    return {
+        bsc: bsc_balances,
+        czz: czz_balances,
+        infos: lists,
+        totalUsd: bsc_balances.totalUsd + czz_balances.totalUsd,
+        totalNativeBalanceUsd: bsc_balances.nativeUsd + czz_balances.nativeUsd
+    }
+}
+
+
+
+
+function parseGas(response, index, price) {
+    try {
+        logger.info('parseGas in', response, index)
+        if (response && Array.isArray(response) && response.length > 0) {
+            var obj
+            if (response[index] && typeof response[index] === 'string')
+                try {
+                    obj = JSON.parse(response[index])
+                } catch (error) {
+                    logger.error('JSON.parse(response[index])', error.toString)
+                }
+            return parseFloat(obj.gasPrice.number) * parseFloat(obj.gasLimit.number) / parseFloat(10 ** 18) * parseFloat(price)
+        }
+
+        else return 0
+    } catch (error) {
+        logger.error('parseGas', error.toString(), JSON.stringify(response))
+        return 0
+    }
+}
+
+async function getPrice(key) {
+    if (mTokenPriceCache.has(key)) {
+        price = mTokenPriceCache.get(key)
+    } else {
+        var price = await moralis.getAllTotkenPrice({
+            chain: key
+        })
+        if (typeof price === 'string') {
+            price = JSON.parse(price)
+        }
+        mTokenPriceCache.set(key, price)
+    }
+    return price
+}
+
+async function getPriceFromCache(key, address) {
+    console.info('getPriceFromCache>', key, address)
+    var price = await getPrice(key)
+
+
+    // var price = await moralis.getAllTotkenPrice({
+    //     chain: key
+    // })
+    // if (typeof price === 'string') {
+    //     price = JSON.parse(price)
+    // }
+
+    var priceItem = moralis.findTokenPriceItem(address, price)
+    if (priceItem && priceItem.usdPrice) {
+        return priceItem.usdPrice
+    } else {
+        return '0'
+    }
+}
+
+
+function convertChain(chain) {
+    return chain
+}
+
+function balance2USDPrice(amount, decimals, price) {
+    return parseFloat(amount) / parseFloat(10 ** decimals) * parseFloat(price)
+}
+
+async function getDecimalsFromRedis(chain, address) {
+    var decimals = 18
+    try {
+        var newKey = redis.formatRedisKey('REDIS_ERC20_CONTRACT_DECIMALS', chain, address.toLowerCase())
+        if (mDecimalsCache.has(newKey)) {
+            decimals = mDecimalsCache.get(newKey)
+        } else {
+            decimals = await redis.readAppendRedis('REDIS_ERC20_CONTRACT_DECIMALS', chain, address.toLowerCase())
+            mDecimalsCache.set(newKey, decimals)
+        }
+        if (!decimals) decimals = '18'
+    } catch (error) {
+        logger.error('getDecimalsFromRedis', chain, address, error.toString())
+        decimals = 18
+    }
+    return decimals
+}
+
+
+function addUsds(infos, type) {
+    var total = 0
+    if (infos && Array.isArray(infos) && infos.length > 0) {
+        for (let index = 0; index < infos.length; index++) {
+            const element = infos[index];
+            switch (type) {
+                case 'gas':
+                    // logger.info('addUsds total ', type, element.gasUsd, element, total)
+                    total += element.gasUsd
+                    break
+                case 'withdraw':
+                    total += element.withdrawUsd
+                    break
+                case 'collect_coins':
+                    total += element.withdrawUsd
+                    break
+                case 'slGas':
+                    total += element.slGasUsd
+                    break
+                case 'token_balance':
+                    total += element.usd
+                    break
+                case 'native_in_coins':
+                    if (element.token_address && element.token_address == '0x0000000000000000000000000000000000000000')
+                        total += element.inUsd
+                    break
+                case 'native_token_in_coins':
+                    total += element.inUsd
+                    break
+            }
+        }
+    }
+    return total
+}
+
+async function getWithdrawOutInfoV2(startTime, endTime) {
+    if (startTime && endTime) {
+        startTime = new Date(startTime).getTime()
+        endTime = new Date(endTime).getTime()
+    }
+    var withdraw_ret = await withdraw_db.getWidthdrawTotalFee(startTime, endTime)
+
+    var withDrawInfos = []
+    for (let index = 0; index < withdraw_ret.length; index++) {
+        const trs = withdraw_ret[index];
+        // console.log('getWithdrawOutInfoV2 element ', trs)
+        var token_address = trs.contract_address
+        if (!trs.contract_address)
+            token_address = '0x0000000000000000000000000000000000000000'
+        try {
+            var input = {
+                dt: utils.chinaTimeMs(trs.update_time),
+                user_address: trs.to_address,
+                token_address: token_address,
+                chain: convertChain(trs.chain_id + ""),
+                amount: trs.amount,
+                decimals: await getDecimalsFromRedis(convertChain(trs.chain_id + ""), token_address),
+                price: await getPriceFromCache(convertChain(trs.chain_id + ""), token_address),
+                gasUsd: parseFloat(trs.gas_price) * parseFloat(trs.gas_limit) / parseFloat(10 ** 18) * await getPriceFromCache(convertChain(trs.chain_id + ""), '0x0000000000000000000000000000000000000000')
+            }
+            if (!input.gasUsd) {
+                logger.info('withdraw_ret input ', trs, input)
+                input.gasUsd = 0
+            }
+
+            //换算成美元
+            input.withdrawUsd = balance2USDPrice(input.amount, input.decimals, input.price)
+            console.log('getWithdrawOutInfoV2 input ', input)
+            withDrawInfos.push(input)
+        } catch (error) {
+            logger.error('getWithdrawOutInfoV2 trs', error.toString())
+        }
+    }
+
+    // logger.log('getWithdrawOutInfoV2 totalOutGasFeeUsd addUsds', addUsds(withDrawInfos, 'gas'), withDrawInfos[0], withDrawInfos[1])
+    return {
+        infos: withDrawInfos,
+        totalOutGasFeeUsd: addUsds(withDrawInfos, 'gas'),
+        totalWithdrawUsd: addUsds(withDrawInfos, 'withdraw'),
+    }
+}
+
+
+async function getCollectCoinsOutInfoV2(startTime, endTime) {
+    var collect_ret = await collect_coins_db.query_collect_total_fee(startTime, endTime);
+    // console.log('getCollectCoinsOutInfoV2 collect_ret', collect_ret.results.length)
+    //每笔入金的详细信息
+    var infos = []
+    //入金充值的 gas 和实际消费的 gas
+    var inGasFeeInfo = []
+    if (collect_ret && collect_ret.results && Array.isArray(collect_ret.results) && collect_ret.results.length > 0) {
+        for (let index = 0; index < collect_ret.results.length; index++) {
+            var element = collect_ret.results[index]
+            if (!element.chain)
+                element.chain = 'bsc_mainnet'
+            var update_tm = element.update_time
+            var user_address = element.user_address
+
+            // console.log('getCollectCoinsOutInfoV2 element', element.before_gas_fee, element.resposes, typeof element.resposes, JSON.parse(element.resposes))
+            var resposes;
+            if (element.resposes && typeof element.resposes === 'string') {
+                try {
+                    resposes = JSON.parse(element.resposes)
+                } catch (error) {
+                    logger.error('element.response parse', error.toString())
+                }
+            }
+
+
+            if (element.prestore_gas_fee && typeof element.prestore_gas_fee === 'string') {
+                try {
+                    var gasObj = JSON.parse(element.prestore_gas_fee)
+
+                    var before_gas_fee = element.before_gas_fee ? element.before_gas_fee : '0'
+                    if (gasObj) {
+                        // logger.log('element.prestore_gas_fee parse', before_gas_fee, gasObj, gasObj.chain)
+                        var newGasObj = {
+                            chain: convertChain(gasObj.chain),
+                            amount: gasObj.amount,
+                            useGas: before_gas_fee,
+                            price: await getPriceFromCache(convertChain(gasObj.chain), '0x0000000000000000000000000000000000000000'),
+                        }
+                        //实际充值手续费用到的 usd
+                        newGasObj.gasUsd = balance2USDPrice(newGasObj.useGas, 18, newGasObj.price)
+                        //散落 gas
+                        newGasObj.slGasUsd = balance2USDPrice(parseFloat(newGasObj.amount) - parseFloat(newGasObj.useGas), 18, newGasObj.price)
+                        inGasFeeInfo.push(newGasObj)
+                    }
+                } catch (error) {
+                    logger.error('element.prestore_gas_fee parse', error.toString())
+                }
+            }
+
+            if (element.transfers && typeof element.transfers === 'string') {
+                try {
+                    var trss = JSON.parse(element.transfers)
+                    // console.log('trss.transfers', trss.chain)
+                    for (let index = 0; index < trss.length; index++) {
+                        const trs = trss[index];
+                        var address = trs.contractAddress == null ? '0x0000000000000000000000000000000000000000' : trs.contractAddress
+                        console.log('trss.transfers', address, trs)
+                        var input = {
+                            dt: update_tm,
+                            user_address: user_address,
+                            token_address: address,
+                            chain: convertChain(trs.chain),
+                            amount: trs.amount,
+                            decimals: trs.contractAddress == null ? 18 : await getDecimalsFromRedis(convertChain(trs.chain), trs.contractAddress),
+                            price: await getPriceFromCache(convertChain(trs.chain), address),
+                            gasUsd: parseGas(resposes, index, await getPriceFromCache(convertChain(trs.chain), '0x0000000000000000000000000000000000000000')) //入金 gas 手续费
+                        }
+                        //换算成美元
+                        input.inUsd = balance2USDPrice(input.amount, input.decimals, input.price)
+                        infos.push(input)
+                    }
+                } catch (error) {
+                    logger.error('transfers handle error', error.toString())
+                }
+            }
+        }
+    }
+    return {
+        infos: infos,
+        totalNativeInFee: addUsds(infos, 'native_in_coins'), //总 native 入金
+        totalInFee: addUsds(infos, 'native_token_in_coins'), //总入金
+        totalInGasFeeUsd: addUsds(infos, 'gas') + addUsds(inGasFeeInfo, 'gas'),//总入金消耗的 gas 包含打 gas fee
+        slTotalGasFeeUsd: addUsds(inGasFeeInfo, 'slGas') //散落 gas
+    }
+}
+
+async function getServerData(startTime, endTime) {
+    //拿到所有归集 list
+    var collectCoinsInfos = await getCollectCoinsOutInfoV2(startTime, endTime)
+    // console.log('getCollectCoinsOutInfoV2 collectCoinsInfos ', collectCoinsInfos)
+
+    //拿到所有出金
+    var withdrawInfos = await getWithdrawOutInfoV2(startTime, endTime)
+    // console.log('getWithdrawOutInfoV2 withdrawInfos ', withdrawInfos)
+    return {
+        collectCoinsInfos: collectCoinsInfos,
+        withdrawInfos: withdrawInfos
+    }
+}
+
+function sortList(lists) {
+    lists.sort((a, b) => {
+        let t1 = new Date(a.dt)
+        let t2 = new Date(b.dt)
+        return t2.getTime() - t1.getTime()
+    })
+    return lists
+}
+
+function formatTableData(type, datas) {
+    var arrs = []
+    for (let index = 0; index < datas.length; index++) {
+        const element = datas[index];
+        switch (type) {
+            case 'incoins':
+                arrs.push([element.dt,
+                element.user_address,
+                element.token_address,
+                element.chain,
+                element.amount,
+                element.decimals,
+                element.price,
+                element.gasUsd,
+                element.inUsd
+                ])
+                break;
+            case 'outcoins':
+                arrs.push([element.dt,
+                element.user_address,
+                element.token_address,
+                element.chain,
+                element.amount,
+                element.decimals,
+                element.price,
+                element.gasUsd,
+                element.withdrawUsd
+                ])
+                break
+            case 'balances':
+                arrs.push([element.address,
+                element.token_address,
+                element.chain,
+                element.amount,
+                element.decimals,
+                element.price,
+                element.usd
+                ])
+                break
+            default:
+                break;
+        }
+    }
+    logger.info('formatTableData', arrs)
+    return arrs
+}
+
+async function getStatisticsInfoV2(day) {
+    // //今日
+    var startTime = utils.getLastDay(day, 'YYYY-MM-DD') + " 00:00:00"
+    var endTime = utils.getLastDay(day, 'YYYY-MM-DD') + " 23:59:59"
+    logger.info('getTotalOutGasFee', startTime, endTime)
+    var rangeData = await getServerData(startTime, endTime)
+    logger.info('getServerData rangeData', rangeData)
+
+    var allData = await getServerData(null, null)
+    // var allData = rangeData
+    logger.info('getServerData allData', allData)
+
+    var data = await http_request_get(utils.getLastDay(day, 'YYYYMMDD'))
+    logger.info('http_request_get data', data)
+    //获取当前账户总余额
+    var curBalances = await getAllBalanceV2()
+    logger.info('getAllBalanceV2 curBalances', curBalances)
+
+
+    return {
+        updateTime: utils.getLastDay(day, 'YYYY-MM-DD'),
+        todayTotalProfit: parseFloat(data.data.incomeUSDTotal) - parseFloat(rangeData.collectCoinsInfos.totalInGasFeeUsd + rangeData.withdrawInfos.totalOutGasFeeUsd),//今日收入
+        todayTotalOutGasFee: rangeData.collectCoinsInfos.totalInGasFeeUsd + rangeData.withdrawInfos.totalOutGasFeeUsd,//今日总支出的 gas fee
+        canNotWithdrawUSD: parseFloat(data.data.canNotWithdrawUSD),                                    //不可提现余额
+        canWithdrawUSD: parseFloat(data.data.canWithdrawUSD),                                          //可提现余额
+        todayIncomeUSDTotal: parseFloat(data.data.incomeUSDTotal),                                     //今日总收入
+        todayIncomeUSDFee: parseFloat(data.data.incomeUSDFee),                                         //今日固定收入
+        totalOutGasFee: allData.collectCoinsInfos.totalInGasFeeUsd + allData.withdrawInfos.totalOutGasFeeUsd, //总支出 gas fee
+        totalWithdrawGasFee: allData.withdrawInfos.totalOutGasFeeUsd,                        //总提币 gas fee
+        totalCollectCoinsGasFee: allData.collectCoinsInfos.totalInGasFeeUsd,                            //总归集 gas fee
+        totalInFee: allData.collectCoinsInfos.totalInFee,                                               //总入金
+        totalNativeInFee: allData.collectCoinsInfos.totalNativeInFee,                                   //总 native 入金
+        totalOutFee: allData.withdrawInfos.totalWithdrawUsd,                                            //总出金
+        totalBalances: curBalances.totalUsd,                                                            //总余额
+        ylGasBalance: curBalances.totalNativeBalanceUsd - allData.collectCoinsInfos.totalNativeInFee,   //预留 gas 费余额  native 总余额 - 总入金
+        slGasBalance: allData.collectCoinsInfos.slTotalGasFeeUsd,   //散落 gas 费余额  充值 0.5 gas - 使用 0.3 gas= 散落 0.2gas
+
+        todayInUsdLists: sortList(rangeData.collectCoinsInfos.infos),//入金列表
+        todayOutUsdLists: sortList(rangeData.withdrawInfos.infos),//出金列表
+        totalInUsdLists: sortList(allData.collectCoinsInfos.infos),//总入金列表
+        totalOutUsdLists: sortList(allData.withdrawInfos.infos),//总出金列表
+        totalBalanceLists: curBalances.infos //总余额
+    }
+}
+
+
+
+
+
+
+
+const getFeishuToken = async (params) => {
+    return new Promise(resolve => {
+        axios.post(feishu_write_table_token_url,
+            {
+                app_id: "cli_a223f015abbad00e",
+                app_secret: "DMCF6tBwIpeOQPnWrFUMYd6tmjb53C4n"
+            },
+            {
+                timeout: 1 * 60 * 1000,
+                headers: {
+                    'Content-Type': "application/json; charset=utf-8"
+                }
+            })
+            .then(res => {
+                logger.log('getFeishuToken res=>', res.status, res.data);
+                resolve(res.data)
+            }).catch(err => {
+                logger.error('getFeishuToken error ', JSON.stringify(err));
+                resolve(JSON.stringify(err))
+            });
+    })
+}
+
+function formatTableRangle(id, size) {
+    var newId = id + size
+    logger.info('formatTableRangle', id, size, newId)
+    return newId
+}
+async function writeTable(app_token, data) {
+    logger.info('writeTable', data)
+    var valueRanges = []
+    if (data.todayInUsdLists.length > 0) {
+        await insertTableRows(app_token, 'Ji1hLG', 1, data.todayInUsdLists.length + 1)
+        valueRanges.push({//入金汇总
+            'range': formatTableRangle('Ji1hLG!A2:I', data.todayInUsdLists.length + 1),
+            'values': formatTableData('incoins', data.todayInUsdLists)
+        })
+    }
+
+    if (data.todayOutUsdLists.length > 0) {
+        await insertTableRows(app_token, 'aFCrrP', 1, data.todayOutUsdLists.length + 1)
+        valueRanges.push({//出金汇总
+            'range': formatTableRangle('aFCrrP!A2:I', data.todayOutUsdLists.length + 1),
+            'values': formatTableData('outcoins', data.todayOutUsdLists)
+        })
+    }
+
+    if (data.totalBalanceLists.length > 0) {
+        var rows = await getTableRows(app_token, 2)
+        if (rows > 1) {
+            logger.info('getTableRows', rows)
+            await delTableRows(app_token, '2hNaot', 2, rows)
+            await addTableRows(app_token, '2hNaot', rows)
+        }
+        valueRanges.push({ //总余额汇总
+            'range': formatTableRangle('2hNaot!A2:I', data.totalBalanceLists.length + 1),
+            'values': formatTableData('balances', data.totalBalanceLists)
+        })
+    }
+
+    valueRanges.push({//归集汇总
+        'range': formatTableRangle('0pRQpu!A2:C', 2),
+        'values': [
+            [data.totalCollectCoinsGasFee, //归集总 gas
+            data.totalWithdrawGasFee, //提币总 gas
+            data.totalOutGasFee], //总支出 gas
+        ]
+    })
+
+    valueRanges.push({//总入账
+        'range': formatTableRangle('1ygrMB!A2:B', 2),
+        'values': [
+            [
+                data.totalInFee, //总入金
+                data.totalOutFee,//总出金
+            ]
+        ]
+    })
+
+    valueRanges.push({//利润表单
+        'range': formatTableRangle('BMjMDr!A3:J', 3),
+        'values': [
+            [
+                data.updateTime,      //更新时间
+                data.todayTotalProfit,//今日总利润
+                data.todayIncomeUSDTotal,//今日总收入
+                data.todayIncomeUSDFee,//今日固定手续费收入
+                data.todayTotalOutGasFee,//今日总 gas 支出
+                data.totalBalances, //总余额
+                data.canNotWithdrawUSD, //不可提现余额
+                data.canWithdrawUSD,//可提现余额
+                data.ylGasBalance,//预留 gas
+                data.slGasBalance,//散落 gas
+            ],
+        ]
+    })
+
+    var body = {
+        'valueRanges': valueRanges
+    }
+    return new Promise(resolve => {
+        axios.post(feishu_write_table_data_url,
+            body,
+            {
+                timeout: 1 * 60 * 1000,
+                headers: {
+                    'Content-Type': "application/json; charset=utf-8",
+                    'Authorization': 'Bearer ' + app_token
+                }
+            })
+            .then(res => {
+                logger.log('writeTable res=>', res.status, res.data);
+                resolve(res.data)
+            }).catch(err => {
+                logger.error('writeTable error ', JSON.stringify(err));
+                resolve(JSON.stringify(err))
+            });
+    })
+}
+
+async function getTableRows(app_token, index) {
+    return new Promise(resolve => {
+        axios.get(feishu_get_table_metadata_url,
+            {
+                timeout: 1 * 60 * 1000,
+                headers: {
+                    'Content-Type': "application/json; charset=utf-8",
+                    'Authorization': 'Bearer ' + app_token
+                }
+            })
+            .then(res => {
+                console.log('res=>', res.status, res.data, res.data.data.sheets);
+                resolve(res.data.data.sheets[index].rowCount)
+            }).catch(err => {
+                logger.error('error ', JSON.stringify(err));
+                resolve(0)
+            });
+    })
+}
+
+async function delTableRows(app_token, sheetId, startIndex, endIndex) {
+    var body = {
+        dimension: {
+            sheetId: sheetId,
+            majorDimension: 'ROWS',
+            startIndex: startIndex,
+            endIndex: endIndex,
+        },
+    }
+
+
+    return new Promise(resolve => {
+        axios.delete(feishu_delete_table_url,
+            {
+                data: body,
+                timeout: 1 * 60 * 1000,
+                headers: {
+                    'Content-Type': "application/json; charset=utf-8",
+                    'Authorization': 'Bearer ' + app_token
+                }
+            })
+            .then(res => {
+                console.log('delTableRows res=>', res.status, res.data);
+                resolve(res.data)
+            }).catch(err => {
+                logger.error('delTableRows error ', JSON.stringify(err));
+                resolve(JSON.stringify(err))
+            });
+    })
+}
+
+async function insertTableRows(app_token, sheetId, startIndex, endIndex) {
+    logger.info('insertTableRows', app_token, sheetId, startIndex, endIndex)
+    var body = {
+        dimension: {
+            sheetId: sheetId,
+            majorDimension: 'ROWS',
+            startIndex: startIndex,
+            endIndex: endIndex,
+        },
+        inheritStyle: 'AFTER'
+    }
+    return new Promise(resolve => {
+        axios.post(feishu_insert_table_url,
+            JSON.stringify(body),
+            {
+                timeout: 1 * 60 * 1000,
+                headers: {
+                    'Content-Type': "application/json; charset=utf-8",
+                    'Authorization': 'Bearer ' + app_token
+                }
+            })
+            .then(res => {
+                console.log('res=>', res.status, res.data);
+                resolve(res.data)
+            }).catch(err => {
+                logger.error('error ', JSON.stringify(err));
+                resolve(JSON.stringify(err))
+            });
+    })
+}
+
+async function addTableRows(app_token, sheetId, endIndex) {
+    var body = {
+        dimension: {
+            sheetId: sheetId,
+            majorDimension: 'ROWS',
+            length: endIndex,
+        },
+    }
+    return new Promise(resolve => {
+        axios.post(feishu_create_table_url,
+            JSON.stringify(body),
+            {
+                timeout: 1 * 60 * 1000,
+                headers: {
+                    'Content-Type': "application/json; charset=utf-8",
+                    'Authorization': 'Bearer ' + app_token
+                }
+            })
+            .then(res => {
+                console.log('res=>', res.status, res.data);
+                resolve(res.data)
+            }).catch(err => {
+                logger.error('error ', JSON.stringify(err));
+                resolve(JSON.stringify(err))
+            });
+    })
+}
+
+async function exec(data) {
+    var app = await getFeishuToken()
+
+    await insertTableRows(app.app_access_token, 'BMjMDr', 2, 3)
+    return await writeTable(app.app_access_token, data)
+}
+
+async function report2FeishuTable(day) {
+    try {
+        logger.error('数据统计 start')
+        logger.info('report2FeishuTable')
+        var data = await getStatisticsInfoV2(day);
+        // data = ''
+        logger.info('getStatisticsInfo', data)
+        var ret = await exec(data)
+        logger.error('数据统计完成:', 'https://st94nif1cq.feishu.cn/sheets/shtcnp6zbrsep1Sz3Cvk7NXRpDg?sheet=BMjMDr')
+        mTokenPriceCache.clear()
+    } catch (error) {
+        logger.error('report2FeishuTable', error.toString())
+    }
+}
+
+
+async function test() {
+    // var ret = await getStatisticsInfoV2(2)
+    // logger.debug('getStatisticsInfoV2', await getStatisticsInfoV2(2), mTokenPriceCache.size)
+    // for (let index = 40; index >=0; index--) {
+    await report2FeishuTable(1)
+    // }
+
+}
+test()
+// exec()
+module.exports = {
+    report2FeishuTable
+}
+

+ 2 - 1
routes/sdk.js

@@ -13,6 +13,7 @@ var remote_config_db = require("../model/db/remote_config_db");
 const account_mysql = require("../model/db/account_info_db")  //导入 db.js
 var collect_coins_db = require("../model/db/collect_coins_db");
 var stat = require('../model/server_data_statistics')
+var stat2 = require('../model/server_data_statisticsv2')
 /** 
  * 获取代币价格
  * @param {*} ctx 
@@ -833,7 +834,7 @@ router.post('/getWithdrawStatus', getWithdrawStatus);
 //获取所有地址的所要消耗的最低提取费
 router.post('/getAllTokenWithdrawInfoLists', getAllTokenWithdrawInfoLists)
 router.get('/report2FeishuTable', async (ctx) => {
-    stat.report2FeishuTable()
+    stat2.report2FeishuTable(1)
     ctx.body = 'ok'
 })