| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- use std::collections::BTreeMap;
- use std::fs::File;
- use std::io::Write;
- use std::str::FromStr;
- use chrono::NaiveDateTime;
- use handlebars::Handlebars;
- use rust_decimal::Decimal;
- use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
- use rust_decimal_macros::dec;
- use serde_json::json;
- use tracing::info;
- use crate::utils::utils::{BalanceConfigInfo};
- pub fn export_html(config: BalanceConfigInfo, acc_name_all: &Vec<String>, x_time: &Vec<i64>, data_list: &Vec<Vec<String>>, statistic_result: String) {
- info!("正在生成网页,请稍后!");
- let export_path = if config.export_path == "" { "./" } else { config.export_path.as_str() };
- let export_name = if config.export_name == "" { "export_balance" } else { config.export_name.as_str() };
- let path = format!("{}/{}.html", export_path, export_name).replace("//", "/");
- // 创建 Handlebars 实例
- let mut handlebars = Handlebars::new();
- //时间片数据组装
- let mut time_str_x = vec![];
- for time in x_time {
- let time_str = NaiveDateTime::from_timestamp_millis((time + 8 * 3600) * 1000).unwrap().format("%Y-%m-%d %H:%M:%S%.3f").to_string();
- time_str_x.push(time_str);
- }
- //每个账号的数据
- let mut map: BTreeMap<String, Vec<f64>> = BTreeMap::new();
- let mut capital_info: BTreeMap<String, Decimal> = Default::default();
- for acc_name in acc_name_all.clone() {
- capital_info.insert(acc_name.parse().unwrap(), dec!(0));
- }
- for acc_name in acc_name_all.clone() {
- let mut pr_data: Vec<f64> = vec![];
- let z = acc_name.clone();
- let key = z.as_str();
- if map.contains_key(key) {
- pr_data = map.get(key).unwrap().clone();
- }
- let mut income = dec!(0);
- let mut earnings = dec!(0);
- for data in data_list.clone() {
- if data[0].clone().as_str() == key {
- let pr = Decimal::from_str(&data[4]).unwrap();
- if capital_info[key] == dec!(0) || data[5] == "transfer" {
- earnings = income;
- capital_info.insert(key.parse().unwrap(), pr);
- }
- income = if capital_info[key] == dec!(0) { dec!(0) } else { ((pr - capital_info[key]) / capital_info[key] * dec!(100.0) + earnings).round_dp(2) };
- pr_data.push(f64::try_from(income).unwrap());
- }
- }
- map.insert(key.to_string(), pr_data);
- }
- let mut series_all = Vec::new();
- for (key, val) in map {
- let series = json!({"name": key.to_string(), "type": "line", "smooth": true, "data": val});
- series_all.push(series);
- }
- let series_array = if config.is_total { [series_all[series_all.len() - 1].clone()].to_vec() } else { series_all };
- let json = json!({
- "data":series_array
- });
- let series_str = format!("{}", json["data"]);
- let data = serde_json::json!({
- "chart_title": format!("账户合约余额变更历史"),
- "acc_name_all": acc_name_all.clone(),
- "statistic_result": statistic_result.clone()
- });
- // HTML 模板
- let template = r#"
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>{{chart_title}}</title>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.3/echarts.min.js"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.10/dayjs.min.js"></script>
- <style>
- * {
- margin: 0;
- padding: 0;
- }
- #main {
- margin: 50px auto 0;
- width: calc(100vw - 100px);
- height: calc(100vh - 150px);
- }
- .info_wp{
- padding: 0 40px;
- }
- </style>
- </head>
- <body>
- <div id="main"></div>
- <div class="info_wp">{{{statistic_result}}}</div>
- </body>
- <script>
- var exchangeColor = {binance: '#F4BC0C', gate: '#0068FF', okx: '#171F30'};
- var chartDom = document.getElementById('main');
- var myChart = echarts.init(chartDom);
- var option;
- option = {
- title: {
- text: '{{chart_title}}'
- },
- tooltip: {
- trigger: 'axis'
- },
- toolbox: {
- feature: {
- dataZoom: {},
- brush: {
- type: ['rect', 'clear']
- }
- }
- },
- legend: {
- data: "#.to_owned() + format!("{:?}", acc_name_all).as_ref() + r#"
- },
- xAxis: {
- type: 'category',
- data: "# + format!("{:?}", time_str_x).as_ref() + r#"
- },
- yAxis: {
- type: 'value',
- axisLabel: {
- formatter: (value, index) => {
- return `${value}%`;
- }
- },
- scale: true
- },
- series: "# + format!("{}", series_str).as_ref() + r#"
- };
- option && myChart.setOption(option);
- </script>
- </html>
- "#;
- // 编译模板
- handlebars
- .register_template_string("page", template)
- .expect("编译模版失败!");
- // 渲染模板
- let output = handlebars
- .render("page", &data)
- .expect("渲染模版失败!");
- // 将 HTML 写入文件
- let mut file = File::create(&path).expect("创建文件失败!");
- file.write_all(output.as_bytes()).expect("写入文件到本地失败!");
- info!("Balance信息网页生成成功!路径:{:?}\n\n", path);
- }
|