diff --git a/end/CellReport.dll b/end/CellReport.dll index 578b36a..a3d7034 100644 Binary files a/end/CellReport.dll and b/end/CellReport.dll differ diff --git a/end/reportWeb/Controllers/DesignController.cs b/end/reportWeb/Controllers/DesignController.cs index 77abcbf..186cae9 100644 --- a/end/reportWeb/Controllers/DesignController.cs +++ b/end/reportWeb/Controllers/DesignController.cs @@ -128,8 +128,8 @@ public async Task Preview(String _content, String _ConnectionId, if (reportName != null && reportName.Contains(":")) reportName = reportName.Split(":")[1]; - var reportDefine = await XmlReport.loadReportFromXmlDoc(xmlDoc, this.rpt_group.report_path, reportName ?? "temp.cr"); - var report_env = reportDefine.getEnv(); + using var reportDefine = await XmlReport.loadReportFromXmlDoc(xmlDoc, this.rpt_group.report_path, reportName ?? "temp.cr"); + using var report_env = reportDefine.getEnv(); if (!String.IsNullOrEmpty(_fresh_ds)) { report_env.getExprFaced().addVariable("_fresh_ds", _fresh_ds); @@ -201,6 +201,8 @@ public async Task Preview(String _content, String _ConnectionId, Engine engine = new Engine(reportDefine); long end = DateTime.Now.Ticks; report_env.logger.Debug($"分析xml耗时:{(DateTime.Now.Ticks - start) / 10000000.0}秒"); + report_env.rpt_group_name = rpt_group.name; + report_env.report_name = "设计报表预览"+Guid.NewGuid().ToString("N"); Exception cur_exception = null; Func my_out_act = async () => { @@ -335,10 +337,11 @@ public IActionResult test_expr(String expr, int line, int column, string word) public async Task exec_expr(String expr, String report_content) { + Env report_env = null; try { BaseExprFaced exprFaced; - Env report_env; + CellReport.dataSet.GroupMap cur_GroupMap = null; @@ -365,7 +368,7 @@ public async Task exec_expr(String expr, String report_content) string reportName = null; if (reportName != null && reportName.Contains(":")) reportName = reportName.Split(":")[1]; - var reportDefine = await XmlReport.loadReportFromXmlDoc(xmlDoc, this.rpt_group.report_path, reportName ?? "temp.cr"); + using var reportDefine = await XmlReport.loadReportFromXmlDoc(xmlDoc, this.rpt_group.report_path, reportName ?? "temp.cr"); report_env = reportDefine.getEnv(); exprFaced = report_env.getExprFaced(); exprFaced.getVariableDefine("__page__").value = HttpContext.Request; @@ -397,6 +400,11 @@ public async Task exec_expr(String expr, String report_content) } return Json(new { errcode = 1, message = sb_err.ToString() }, json_option); } + finally + { + if (report_env != null) + report_env.Dispose(); + } } public IActionResult exec_cmd(String cmd, string from, string to) { @@ -494,7 +502,7 @@ public async Task Open(String reportName, string zb_dict_str, str if (file_path.StartsWith(this.rpt_group.report_path) && System.IO.File.Exists(file_path)) { - Env parent_env = new Env(); + using Env parent_env = new Env(); await XmlReport.templateValue2Env(this.rpt_group.report_path, reportName, parent_env); var xmlDoc = (await XmlReport.getReportXmlDoc(this.rpt_group.report_path, reportName, isDesign: true)).xml; //var ret = XmlReport.reportToXmlDocumnt(XmlReport.loadReport(file_path), false).OuterXml; @@ -708,7 +716,7 @@ public async Task open_template(String path) else path = path + "/template.xml"; var file_path = Path.Combine(this.rpt_group.report_path, path); - Env parent_env = new Env(); + using Env parent_env = new Env(); await XmlReport.templateValue2Env(this.rpt_group.report_path, path, parent_env, true); if (file_path.StartsWith(this.rpt_group.report_path) && System.IO.File.Exists(file_path)) @@ -743,7 +751,7 @@ public async Task Save_template(String path, String content) { System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument(); xmlDoc.LoadXml(content); - var report = await XmlReport.loadReportFromXmlDoc(xmlDoc, this.rpt_group.report_path, reportName ?? "temp.cr"); + using var report = await XmlReport.loadReportFromXmlDoc(xmlDoc, this.rpt_group.report_path, reportName ?? "temp.cr"); Engine engine = new Engine(report); engine.buildRelation(); engine.prepareCalcLevelForCell(); diff --git a/end/reportWeb/Controllers/UserController.cs b/end/reportWeb/Controllers/UserController.cs index 6bd51d6..17b31cd 100644 --- a/end/reportWeb/Controllers/UserController.cs +++ b/end/reportWeb/Controllers/UserController.cs @@ -58,7 +58,7 @@ public UserController(IConfiguration configuration, ReportDbContext reportDb, public IActionResult test_connection([FromBody] Rpt_db_connection rpt_Db_Connection) { - var ret = DbProviderFactories.GetFactory(rpt_Db_Connection.db_type).CreateConnection(); + using var ret = DbProviderFactories.GetFactory(rpt_Db_Connection.db_type).CreateConnection(); if (ret == null) { throw new Exception("程序在取数据库连接时异常。通知开发人员升级"); @@ -87,7 +87,7 @@ public IActionResult test_login(String login_script, string test_user, string te var ef = new CellReport.core.expr.ExprFaced2(); ef.addNewScopeForScript(); - var report_env = new Env(); + using var report_env = new Env(); report_env.logger = logger; ef.addVariable("env", report_env); ef.addVariable("__env__", report_env); @@ -119,7 +119,8 @@ public IActionResult index() [AllowAnonymous] public IActionResult login([FromBody] UserInfo userinfo) { - var verfiy_code_script = new CellReport.running.Env().TemplateGet("verfiy_code_script"); + using var cur_env=new CellReport.running.Env(); + var verfiy_code_script = cur_env.TemplateGet("verfiy_code_script"); CR_Object result = new CR_Object() { { "errcode", 1 }, { "message", "用户名或密码错误" } }; var verfiy_code = HttpContext.Session.GetString("verfiy_code"); if (!string.IsNullOrWhiteSpace(verfiy_code_script) || !string.IsNullOrEmpty(verfiy_code)) @@ -158,8 +159,9 @@ public IActionResult login([FromBody] UserInfo userinfo) { var ef = new CellReport.core.expr.ExprFaced2(); ef.addNewScopeForScript(); - ef.addVariable("env", new Env()); - ef.addVariable("__env__", new Env()); + using var report_env = new Env(); + ef.addVariable("env", report_env); + ef.addVariable("__env__", report_env); ef.addVariable("userid", username); ef.addVariable("password", password); var //conf=reportDbContext.Rpt_config.FirstOrDefault(); @@ -341,7 +343,7 @@ public string GenerateJwtToken(UserInfo user, bool refresh = false) new Claim("username",user.username), new Claim("token_type", refresh?"refresh":""), }), - Expires = DateTime.Now.AddMinutes(refresh ? jwtConfig.REFRESH_TOKEN_EXPIRES : jwtConfig.ACCESS_TOKEN_EXPIRES), + Expires = DateTime.UtcNow.AddMinutes(refresh ? jwtConfig.REFRESH_TOKEN_EXPIRES : jwtConfig.ACCESS_TOKEN_EXPIRES), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256) }; var token = tokenHandler.CreateToken(tokenDescriptor); @@ -371,6 +373,8 @@ public static UserInfo ValidateJwtToken(HttpContext HttpContext, string raw_toke }, out SecurityToken validatedToken); var jwtToken = (JwtSecurityToken)validatedToken; + if (jwtToken.ValidTo < DateTime.UtcNow) + return null; var user = new UserInfo() { userid = jwtToken.Claims.FirstOrDefault(x => x.Type == "userid").Value, @@ -389,7 +393,8 @@ public static UserInfo ValidateJwtToken(HttpContext HttpContext, string raw_toke [AllowAnonymous] public IActionResult VerifyCode(string userid, int code_len) { - var verfiy_code_script = new CellReport.running.Env().TemplateGet("verfiy_code_script"); + using var cur_env = new CellReport.running.Env(); + var verfiy_code_script = cur_env.TemplateGet("verfiy_code_script"); if (string.IsNullOrWhiteSpace(verfiy_code_script)) verfiy_code_script = configuration["verfiy_code_script"]; if (string.IsNullOrWhiteSpace(verfiy_code_script)) @@ -408,7 +413,7 @@ public IActionResult VerifyCode(string userid, int code_len) HttpContext.Session.SetString("send_time", DateTime.Now.Ticks.ToString()); var ef = new CellReport.core.expr.ExprFaced2(); ef.addNewScopeForScript(); - var report_env = new Env(); + using var report_env = new Env(); report_env.logger = logger; ef.addVariable("env", report_env); ef.addVariable("__env__", report_env); @@ -425,6 +430,38 @@ public IActionResult VerifyCode(string userid, int code_len) } #endregion + #region 报表监控 + [AllowAnonymous] + public IActionResult rpt_montior() + { + return new JsonResult(new + { + errcode = 0, + running = new List { new Object[] { "rpt_group_name", "report_name", "calc_type", "report_param", "start", "end", "datasource_name", "sql", "ds_name", "sql_start", "sql_end", "datasource_stat", "info" } }.Concat( + reportWeb.other.ReportMonitor.Instance.running.Values.SelectMany(rpt_info => rpt_info.DataSourceInfoBag, (rpt_info, datasource_info) => { + return new Object[] + { + rpt_info.rpt_group_name, + rpt_info.report_name, + rpt_info.calc_type, + rpt_info.report_param, + rpt_info.start, + rpt_info.end, + datasource_info.datasource_name, + datasource_info.sql, + datasource_info.ds_name, + datasource_info.sql_start, + datasource_info.sql_end, + datasource_info.datasource_stat, + datasource_info.info, + }; + })), + rpt_static = new List { new Object[] { "时间", "运行报表数", "打开连接数", "正在运行报表数", } }.Concat(reportWeb.other.ReportMonitor.Instance.rpt_static), + }, json_option); + } + #endregion + + #region 校验码图片 /* [AllowAnonymous] diff --git a/end/reportWeb/Pages/ReportModel.cs b/end/reportWeb/Pages/ReportModel.cs index 4d32791..29c2cd5 100644 --- a/end/reportWeb/Pages/ReportModel.cs +++ b/end/reportWeb/Pages/ReportModel.cs @@ -145,6 +145,10 @@ public async Task Page_Load() //} report_env = reportDefineForWeb.CurrentReportDefine.getEnv(); + if (!Request.Query.TryGetValue("reportName", out var report_name)) + throw new Exception("没有设置reportName参数"); + report_env.rpt_group_name = rpt_group.name; + report_env.report_name = report_name; Dictionary user_dict = new Dictionary(); foreach (var one in HttpContext?.User?.Claims) { @@ -176,8 +180,7 @@ public async Task Page_Load() } //exprFaced.addVariable("_cache_", RedisHelper.Instance);page_var_dict parse_fresh_ds(); - if (!Request.Query.TryGetValue("reportName", out var a1)) - throw new Exception("没有设置reportName参数"); ; + var start_time = DateTime.Now; reportDefineForWeb.putRequestParamForForm(); diff --git a/end/reportWeb/Startup.cs b/end/reportWeb/Startup.cs index 10c5421..81385e9 100644 --- a/end/reportWeb/Startup.cs +++ b/end/reportWeb/Startup.cs @@ -248,6 +248,7 @@ public void ConfigureServices(IServiceCollection services) public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { ReportDbContext.EnsureDbExists(env); + reportWeb.other.ReportMonitor.start(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); diff --git a/end/reportWeb/other/Func_kata.cs b/end/reportWeb/other/Func_kata.cs index db8bd6b..6ddb053 100644 --- a/end/reportWeb/other/Func_kata.cs +++ b/end/reportWeb/other/Func_kata.cs @@ -25,13 +25,31 @@ public override Object calculate(IList args) return new Variable(ret_obj); } } - + public class CrQueryFactory : QueryFactory, IDisposable + { + public RunReportDataSourceInfo CurrentDataSourceInfo { get; private set; } + public CrQueryFactory(DbConnection cur_connection, Compiler compiler, RunReportDataSourceInfo CurrentDataSourceInfo) : base(cur_connection, compiler) + { + this.CurrentDataSourceInfo = CurrentDataSourceInfo; + } + public void close() + { + base.Dispose(); + CurrentDataSourceInfo.datasource_stat = "ر"; + //this.close(); + } + public new void Dispose() + { + close(); + } + } public class Func_kata : FunctionUnit { static Func_kata() { ExprHelper.AddCSFuncOperator("kata", DirectCallObjectMethod); } + RunReportDataSourceInfo CurrentDataSourceInfo = new(); public override SqlKata.Execution.QueryFactory calculate(IList args) { if (args.Count == 0) @@ -44,6 +62,7 @@ public override SqlKata.Execution.QueryFactory calculate(IList args) ds_struct = new(); ds_struct.ds_link = cr_obj["db_link"].ToString(); ds_struct.ds_type = cr_obj["ds_type"].ToString(); + ds_struct.name = "ָ̬" + ds_struct.ds_type; } else ds_struct = (DatasourceStruct)(getEnv().getDataSource(ret_obj.ToString())); @@ -76,21 +95,28 @@ public override SqlKata.Execution.QueryFactory calculate(IList args) default: throw new core.ReportRuntimeException($"sqlKataû{ds_type}Ӧı"); } - var db = new QueryFactory(getEnv().getConnection(ds_struct, "openDbʱݼ"), compiler); + DbConnection cur_connection = getEnv().getConnection(ds_struct, "openDbʱݼ"); + var ret = new CrQueryFactory(cur_connection, compiler, CurrentDataSourceInfo); + CurrentDataSourceInfo.ds_name = "kata"; + CurrentDataSourceInfo.datasource_name = ds_struct.name; + CurrentDataSourceInfo.datasource_stat = "Ԥ"; + this.getEnv().CurrentRunReportInfo.DataSourceInfoBag.Add(CurrentDataSourceInfo); + this.getEnv().Disposables.Add(ret); //db.Query("Users").Get(); //db.Query("Books").Where().OrderBy("Date").Paginate(1) - this.getEnv().Disposables.Add(db); - return db; + return ret; } private static Type extend_type; public static (bool, bool, object) DirectCallObjectMethod(Object obj, string methodName, object[] methodParams, BaseExprFaced exprFaced = null, bool alreadyCalc = false) { - if (obj is QueryFactory queryFactory) + if (obj is CrQueryFactory queryFactory) { var logger = (exprFaced.getVariable("__env__") as Env).logger; queryFactory.Logger = compiled => { + queryFactory.CurrentDataSourceInfo.datasource_stat = "ִ"; + queryFactory.CurrentDataSourceInfo.sql = compiled.ToString(); logger.Debug("kata sql:" + compiled.ToString()); }; } diff --git a/end/reportWeb/other/ReportMonitor.cs b/end/reportWeb/other/ReportMonitor.cs new file mode 100644 index 0000000..37c78cd --- /dev/null +++ b/end/reportWeb/other/ReportMonitor.cs @@ -0,0 +1,74 @@ +using CellReport.running; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System; +using Microsoft.Extensions.Caching.Memory; +using System.Timers; +using System.Linq; +using System.Threading; + +namespace reportWeb.other +{ + public class ReportMonitor + { + private static System.Timers.Timer timer = new(); + public Queue rpt_static { get; private set; } = new(); + public static ReportMonitor Instance { get; private set; } = new(); + + private ReportMonitor() + { + Env.report_start_action = start_report; + Env.report_end_action = end_report; + // 设置定时器的间隔(以毫秒为单位) + timer.Interval = 2 * 1000; // 每2秒执行一次 + // 设置定时器的重复行为 + timer.AutoReset = true; // 设置为 true,表示重复执行;设置为 false,表示只执行一次 + // 添加定时器的事件处理程序 + timer.Elapsed += (sender, e) => + { + var cur_time = DateTime.Now; + while (Instance.rpt_static.Count > 0 && cur_time - TimeSpan.FromMinutes(60) > (DateTime)(Instance.rpt_static.Peek()[0])) + { + Instance.rpt_static.Dequeue(); + } + lock (Instance) + { + int runnig_cnt = Instance.running.Values.Sum(x => x.DataSourceInfoBag.Count(y => y.datasource_stat != null && y.datasource_stat.Contains("打开"))); + Instance.rpt_static.Enqueue(new Object[] { cur_time + ,rpt_cnt + ,runnig_cnt , Instance.running.Count + }); + rpt_cnt = runnig_cnt; + } + + }; + timer.Start(); + } + private int rpt_cnt=0; + + public ConcurrentDictionary running { get; private set; } = new(); + + public static ReportMonitor start() + { + return Instance; + } + public void end_report(RunReportInfo rpt_info) + { + lock (Instance) + { + //Interlocked.Decrement(ref rpt_cnt); + running.TryRemove(rpt_info.id, out _); + } + } + public void start_report(RunReportInfo rpt_info) + { + lock (Instance) + { + Interlocked.Increment(ref rpt_cnt); + running.TryAdd(rpt_info.id, rpt_info); + } + } + + + } +} diff --git a/end/reportWeb/template.xml b/end/reportWeb/template.xml index 8416757..02fc15f 100644 --- a/end/reportWeb/template.xml +++ b/end/reportWeb/template.xml @@ -290,7 +290,7 @@ var schema_kind={ data_type:x.type}).toList()`], }, - "MySql.Data.MySqlClient.MySqlClientFactory":{ + "MySqlConnector.MySqlConnectorFactory":{ tables:`select '' TABLE_CATALOG, TABLE_SCHEMA, table_name AS TABLE_NAME from information_schema.tables where table_schema='$Database$';`, foreign:[ `SELECT diff --git a/front/public/pc_form.html b/front/public/pc_form.html index e8d26ec..e958c3e 100644 --- a/front/public/pc_form.html +++ b/front/public/pc_form.html @@ -85,11 +85,30 @@ mounted(){ //console.info("pc form mounted!",this.queryForm) }, - //methods:{ + methods:{ + my_export_pdf(){ + let data=new FormData(); + data.append('report_obj',JSON.stringify(this.result)) + return axios.request({ + headers: { + 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + }, + responseType: 'blob', //设置响应的数据类型为一个包含二进制数据的 Blob 对象,必须设置!!! + method: 'post', + data, + url: `pdf`, + withCredentials: true, + }).then(response => { + tool.saveAs(response, (this.result._zb_var_.file_name??"xxx")+".pdf"); + }) + .catch(error => { + _this.$notify({title: '文件下载失败:',message: error,duration: 0}); + }); + } // validate_submit(){ // debugger // this.parentCompent.validate_submit(); // } - //} + } } \ No newline at end of file