diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3b510aa --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue,css,scss,sass,less,styl}] +charset = utf-8 +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true +end_of_line = lf +max_line_length = 100 diff --git a/.env.production b/.env.production index 08272f0..35bc16d 100644 --- a/.env.production +++ b/.env.production @@ -1,5 +1,5 @@ # 页面标题 -VITE_APP_TITLE = 管理系统 +VITE_APP_TITLE = # 生产环境配置 VITE_APP_ENV = 'production' diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..29a2402 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/prettierrc", + "semi": false, + "singleQuote": true, + "printWidth": 100 +} diff --git a/RuoYi-Vue3 b/RuoYi-Vue3 new file mode 160000 index 0000000..b8019c9 --- /dev/null +++ b/RuoYi-Vue3 @@ -0,0 +1 @@ +Subproject commit b8019c9f8e64c181a40bae5e98977c0270b58a98 diff --git a/dist (3).zip b/dist (3).zip new file mode 100644 index 0000000..d1c88e2 Binary files /dev/null and b/dist (3).zip differ diff --git a/dist.zip b/dist.zip new file mode 100644 index 0000000..cfe2138 Binary files /dev/null and b/dist.zip differ diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..7807d8b --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,26 @@ +import { defineConfig, globalIgnores } from 'eslint/config' +import globals from 'globals' +import js from '@eslint/js' +import pluginVue from 'eslint-plugin-vue' +import skipFormatting from '@vue/eslint-config-prettier/skip-formatting' + +export default defineConfig([ + { + name: 'app/files-to-lint', + files: ['**/*.{js,mjs,jsx,vue}'], + }, + + globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']), + + { + languageOptions: { + globals: { + ...globals.browser, + }, + }, + }, + + js.configs.recommended, + ...pluginVue.configs['flat/essential'], + skipFormatting, +]) diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..5a1f2d2 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "paths": { + "@/*": ["./src/*"] + } + }, + "exclude": ["node_modules", "dist"] +} diff --git a/openapi.json b/openapi.json new file mode 100644 index 0000000..0647c74 --- /dev/null +++ b/openapi.json @@ -0,0 +1 @@ +{"openapi":"3.1.0","info":{"title":"FastAPI","version":"0.1.0"},"paths":{"/nuclide/upload_nuclide_excel":{"post":{"summary":"Upload Nuclide Excel","description":"上传核素检测Excel文件并解析数据","operationId":"upload_nuclide_excel_nuclide_upload_nuclide_excel_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_nuclide_excel_nuclide_upload_nuclide_excel_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/nuclide/query_pollution_data":{"get":{"summary":"Query Pollution Data","description":"查询污染物浓度数据 - 近7天数据","operationId":"query_pollution_data_nuclide_query_pollution_data_get","parameters":[{"name":"loc_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"位置ID,不传则查询全部","title":"Loc Id"},"description":"位置ID,不传则查询全部"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/nuclide/mark_sample":{"post":{"summary":"Mark Sample","description":"为样本打标记","operationId":"mark_sample_nuclide_mark_sample_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_mark_sample_nuclide_mark_sample_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/nuclide/batch_mark_samples":{"post":{"summary":"Batch Mark Samples","description":"批量为样本打标记(键值对格式)\n参数格式: {'sample_id1': 'type1', 'sample_id2': 'type2', ...}","operationId":"batch_mark_samples_nuclide_batch_mark_samples_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Marks","description":"批量标记数据,格式: {'sample_id1': 'type1', 'sample_id2': 'type2', ...}"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/nuclide/query_samples":{"get":{"summary":"Query Samples","description":"查询样本数据\n根据acquisition_start, acquisition_stop, ev_type, site_det_code进行查询\n返回按acquisition_start正序的结果,只取最新的100条(通过分页实现)","operationId":"query_samples_nuclide_query_samples_get","parameters":[{"name":"site_det_code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"站点检测代码","title":"Site Det Code"},"description":"站点检测代码"},{"name":"ev_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"标记类型","title":"Ev Type"},"description":"标记类型"},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"开始时间,格式: YYYY-MM-DD HH:MM:SS 或 YYYY-MM-DD","title":"Start Time"},"description":"开始时间,格式: YYYY-MM-DD HH:MM:SS 或 YYYY-MM-DD"},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"结束时间,格式: YYYY-MM-DD HH:MM:SS 或 YYYY-MM-DD","title":"End Time"},"description":"结束时间,格式: YYYY-MM-DD HH:MM:SS 或 YYYY-MM-DD"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"页码,从1开始","default":1,"title":"Page"},"description":"页码,从1开始"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"每页数量,最大200","default":100,"title":"Size"},"description":"每页数量,最大200"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/nuclide/query_latest_samples":{"get":{"summary":"Query Latest Samples","description":"查询最新的样本数据\n按acquisition_start倒序排列,返回最新的数据","operationId":"query_latest_samples_nuclide_query_latest_samples_get","parameters":[{"name":"site_det_code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"站点检测代码","title":"Site Det Code"},"description":"站点检测代码"},{"name":"ev_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"标记类型","title":"Ev Type"},"description":"标记类型"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"description":"返回数量,最大500","default":100,"title":"Limit"},"description":"返回数量,最大500"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/nuclide-sim/get_wind_temperature_pressure_data":{"post":{"summary":"Get Wind Temperature Pressure Data","description":"获取指定日期0点的风场、温度场和气压场数据","operationId":"get_wind_temperature_pressure_data_nuclide_sim_get_wind_temperature_pressure_data_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_get_wind_temperature_pressure_data_nuclide_sim_get_wind_temperature_pressure_data_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/nuclide-sim/calculate_atmospheric_stability":{"post":{"summary":"Calculate Atmospheric Stability","description":"计算指定日期0点、指定区域的大气稳定度(理查逊数)","operationId":"calculate_atmospheric_stability_nuclide_sim_calculate_atmospheric_stability_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_calculate_atmospheric_stability_nuclide_sim_calculate_atmospheric_stability_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/nuclide-sim/simulate_nuclide_diffusion":{"post":{"summary":"Simulate Nuclide Diffusion","description":"模拟核素扩散 - 直接返回数据流","operationId":"simulate_nuclide_diffusion_nuclide_sim_simulate_nuclide_diffusion_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_simulate_nuclide_diffusion_nuclide_sim_simulate_nuclide_diffusion_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/weather/query_city_aqi":{"get":{"summary":"Query City Aqi","description":"查询城市AQI数据 - 默认查询前一天的数据","operationId":"query_city_aqi_weather_query_city_aqi_get","parameters":[{"name":"query_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"查询日期,格式: yyyy-MM-dd,不传则查询前一天","title":"Query Date"},"description":"查询日期,格式: yyyy-MM-dd,不传则查询前一天"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/weather/upload_grib_files":{"post":{"summary":"Upload Grib Files","description":"上传GRIB2文件 - 如果文件已存在则跳过","operationId":"upload_grib_files_weather_upload_grib_files_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_grib_files_weather_upload_grib_files_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/weather/list_grib_files":{"get":{"summary":"List Grib Files","description":"查询GRIB文件夹中的.grib2文件列表和创建日期 - 忽略索引文件","operationId":"list_grib_files_weather_list_grib_files_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/train-oneday/upload_train_dataset":{"post":{"summary":"Upload Train Dataset","description":"上传训练数据集到指定工作空间\n- 校验必须包含1.xlsx, 2.xlsx, 3.xlsx三个文件","operationId":"upload_train_dataset_train_oneday_upload_train_dataset_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_train_dataset_train_oneday_upload_train_dataset_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/train-oneday/query_train_datasets":{"get":{"summary":"Query Train Datasets","description":"查询训练数据集\n- 仅查询type为oneday的数据集\n- 按照创建时间倒序排列\n- 返回结果不显示type字段","operationId":"query_train_datasets_train_oneday_query_train_datasets_get","parameters":[{"name":"create_by","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"创建者,支持模糊匹配","title":"Create By"},"description":"创建者,支持模糊匹配"},{"name":"dataset_cnt_min","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"description":"数据集行数最小值","title":"Dataset Cnt Min"},"description":"数据集行数最小值"},{"name":"dataset_cnt_max","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"description":"数据集行数最大值","title":"Dataset Cnt Max"},"description":"数据集行数最大值"},{"name":"create_time_start","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"创建时间范围-开始","title":"Create Time Start"},"description":"创建时间范围-开始"},{"name":"create_time_end","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"创建时间范围-结束","title":"Create Time End"},"description":"创建时间范围-结束"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"页码,从1开始","default":1,"title":"Page"},"description":"页码,从1开始"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"每页数量,最大100","default":10,"title":"Size"},"description":"每页数量,最大100"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/train-oneday/train_models":{"post":{"summary":"Train Models","description":"训练模型接口 - 异步版本\n- 立即返回case_no,前端可以轮询查询进度\n- 多个模型使用同一个case_no\n- 所有结果都放在同一个输出文件夹","operationId":"train_models_train_oneday_train_models_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_train_models_train_oneday_train_models_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/train-oneday/query_train_cases":{"get":{"summary":"Query Train Cases","description":"查询训练案例","operationId":"query_train_cases_train_oneday_query_train_cases_get","parameters":[{"name":"dataset_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"数据集ID","title":"Dataset Id"},"description":"数据集ID"},{"name":"model_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"模型类型","title":"Model Type"},"description":"模型类型"},{"name":"case_no","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"案例编号","title":"Case No"},"description":"案例编号"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"页码,从1开始","default":1,"title":"Page"},"description":"页码,从1开始"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"每页数量,最大100","default":10,"title":"Size"},"description":"每页数量,最大100"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/train-oneday/predict":{"post":{"summary":"Predict","description":"使用训练好的模型进行预测\n- 根据case_no加载对应的模型\n- 对上传的文件数据进行预测\n- 返回原始数据和预测结果","operationId":"predict_train_oneday_predict_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_predict_train_oneday_predict_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/train-oneday/predict_with_label":{"post":{"summary":"Predict With Label","description":"使用训练好的模型进行带标签预测\n- 根据case_no加载对应的模型\n- 对上传的文件数据进行预测\n- 返回前100条数据和每个模型在不同类别上的准确率统计","operationId":"predict_with_label_train_oneday_predict_with_label_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_predict_with_label_train_oneday_predict_with_label_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/train-oneday/get_available_models":{"get":{"summary":"Get Available Models","description":"获取指定case_no下可用的模型列表","operationId":"get_available_models_train_oneday_get_available_models_get","parameters":[{"name":"case_no","in":"query","required":true,"schema":{"type":"string","description":"训练案例编号","title":"Case No"},"description":"训练案例编号"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/train-oneday/query_training_time":{"get":{"summary":"Query Training Time","description":"查询在相同数据集规模、迭代次数、模型类型条件下的训练用时\n\n返回每个模型的训练秒数,只看训练成功的记录(有res_accu)\n每个模型类型最多返回10条记录,避免数据库负载过大","operationId":"query_training_time_train_oneday_query_training_time_get","parameters":[{"name":"dataset_id","in":"query","required":true,"schema":{"type":"integer","description":"数据集ID","title":"Dataset Id"},"description":"数据集ID"},{"name":"model_type","in":"query","required":true,"schema":{"type":"string","description":"模型类型,多个用逗号分隔,如: BDT,MLP,CNN","title":"Model Type"},"description":"模型类型,多个用逗号分隔,如: BDT,MLP,CNN"},{"name":"iter_value","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"迭代次数,可选项","title":"Iter Value"},"description":"迭代次数,可选项"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/train-series/generate-nuclear-data":{"get":{"summary":"Generate Nuclear Data","description":"生成核素浓度数据的GET接口\n\nArgs:\n n_samples: 每种类型的样本数\n days: 模拟天数\n monitor_lon: 监测站经度\n monitor_lat: 监测站纬度\n output_filename: 输出文件名\n\nReturns:\n 任务启动状态","operationId":"generate_nuclear_data_train_series_generate_nuclear_data_get","parameters":[{"name":"n_samples","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"样本数量","title":"N Samples"},"description":"样本数量"},{"name":"days","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"模拟天数","title":"Days"},"description":"模拟天数"},{"name":"monitor_lon","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"监测站经度","title":"Monitor Lon"},"description":"监测站经度"},{"name":"monitor_lat","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"监测站纬度","title":"Monitor Lat"},"description":"监测站纬度"},{"name":"output_filename","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"输出文件名","title":"Output Filename"},"description":"输出文件名"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/train-series/get-config":{"get":{"summary":"Get Config","description":"获取当前配置","operationId":"get_config_train_series_get_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/train-series/extract_features":{"post":{"summary":"Extract Features","description":"提取Excel数据的特征(generate-nuclear-data生成的)\n\n输入Excel格式要求:\n- 表头固定为指定的155列\n- 数据量不超过5000条\n\n输出特征:\n1. 四种核素每天变化率的均值 (4个特征)\n2. 四种核素7天的浓度均值和峰值 (8个特征)\n3. 风场每天的最大风速和平均风速 (14个特征)","operationId":"extract_features_train_series_extract_features_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_extract_features_train_series_extract_features_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/":{"get":{"summary":"Read Root","operationId":"read_root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/download":{"get":{"summary":"Download File","description":"输入:\n{\n 根目录相对路径,setting里的WORKSPACE_BASE,数据库里保存的都是带WORKSPACE_BASE的\n 如果路径开头不是WORKSPACE_BASE会自己拼一个(防止前端不知道相对路径)\n}","operationId":"download_file_download_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"Body_calculate_atmospheric_stability_nuclide_sim_calculate_atmospheric_stability_post":{"properties":{"date":{"type":"string","title":"Date","description":"日期,格式: yyyy-MM-dd"},"lon_center":{"type":"integer","title":"Lon Center","description":"中心经度(整数)"},"lat_center":{"type":"integer","title":"Lat Center","description":"中心纬度(整数)"},"grid_halfwidth_deg":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Grid Halfwidth Deg","description":"网格半宽(整数),最大10度"}},"type":"object","required":["date","lon_center","lat_center","grid_halfwidth_deg"],"title":"Body_calculate_atmospheric_stability_nuclide_sim_calculate_atmospheric_stability_post"},"Body_extract_features_train_series_extract_features_post":{"properties":{"file":{"type":"string","format":"binary","title":"File","description":"Excel数据文件"}},"type":"object","required":["file"],"title":"Body_extract_features_train_series_extract_features_post"},"Body_get_wind_temperature_pressure_data_nuclide_sim_get_wind_temperature_pressure_data_post":{"properties":{"date":{"type":"string","title":"Date","description":"日期,格式: yyyy-MM-dd"},"lon_center":{"type":"integer","title":"Lon Center","description":"中心经度(整数)"},"lat_center":{"type":"integer","title":"Lat Center","description":"中心纬度(整数)"},"grid_halfwidth_deg":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Grid Halfwidth Deg","description":"网格半宽(整数),最大10度"}},"type":"object","required":["date","lon_center","lat_center","grid_halfwidth_deg"],"title":"Body_get_wind_temperature_pressure_data_nuclide_sim_get_wind_temperature_pressure_data_post"},"Body_mark_sample_nuclide_mark_sample_post":{"properties":{"sample_id":{"type":"integer","title":"Sample Id","description":"样本ID"},"ev_type":{"type":"string","title":"Ev Type","description":"标记类型"}},"type":"object","required":["sample_id","ev_type"],"title":"Body_mark_sample_nuclide_mark_sample_post"},"Body_predict_train_oneday_predict_post":{"properties":{"case_no":{"type":"string","title":"Case No","description":"训练案例编号"},"model_types":{"type":"string","title":"Model Types","description":"模型类型,逗号分隔 (BDT,MLP,RF,SVM,CNN)"},"file":{"type":"string","format":"binary","title":"File","description":"预测数据文件 (Excel格式)"}},"type":"object","required":["case_no","model_types","file"],"title":"Body_predict_train_oneday_predict_post"},"Body_predict_with_label_train_oneday_predict_with_label_post":{"properties":{"case_no":{"type":"string","title":"Case No","description":"训练案例编号"},"model_types":{"type":"string","title":"Model Types","description":"模型类型,逗号分隔 (BDT,MLP,RF,SVM,CNN)"},"file":{"type":"string","format":"binary","title":"File","description":"预测数据文件 (Excel格式,第5列为真实标签)"}},"type":"object","required":["case_no","model_types","file"],"title":"Body_predict_with_label_train_oneday_predict_with_label_post"},"Body_simulate_nuclide_diffusion_nuclide_sim_simulate_nuclide_diffusion_post":{"properties":{"start_time":{"type":"string","title":"Start Time","description":"开始时间,格式: yyyy-mm-dd HH"},"duration_hours":{"type":"integer","maximum":168.0,"minimum":1.0,"title":"Duration Hours","description":"持续时间(小时)"},"lon_center":{"type":"integer","title":"Lon Center","description":"中心经度(整数)"},"lat_center":{"type":"integer","title":"Lat Center","description":"中心纬度(整数)"},"Q_series":{"type":"string","title":"Q Series","description":"排放序列,逗号分隔的数值"},"grid_resolution_deg":{"type":"number","title":"Grid Resolution Deg","description":"网格分辨率(0.1的倍数)"},"grid_halfwidth_deg":{"type":"integer","title":"Grid Halfwidth Deg","description":"网格半宽(整数)"},"Kh":{"type":"number","title":"Kh","description":"水平扩散系数"},"Kz":{"type":"number","title":"Kz","description":"垂直扩散系数"},"vd":{"type":"number","title":"Vd","description":"沉降速度"},"Hmix":{"type":"number","title":"Hmix","description":"混合层高度"}},"type":"object","required":["start_time","duration_hours","lon_center","lat_center","Q_series","grid_resolution_deg","grid_halfwidth_deg","Kh","Kz","vd","Hmix"],"title":"Body_simulate_nuclide_diffusion_nuclide_sim_simulate_nuclide_diffusion_post"},"Body_train_models_train_oneday_train_models_post":{"properties":{"dataset_id":{"type":"integer","title":"Dataset Id","description":"数据集ID"},"model_types":{"type":"string","title":"Model Types","description":"模型类型,逗号分隔 (BDT,MLP,RF,SVM,CNN)"}},"type":"object","required":["dataset_id","model_types"],"title":"Body_train_models_train_oneday_train_models_post"},"Body_upload_grib_files_weather_upload_grib_files_post":{"properties":{"files":{"items":{"type":"string","format":"binary"},"type":"array","title":"Files","description":"GRIB2文件,支持多个文件"}},"type":"object","required":["files"],"title":"Body_upload_grib_files_weather_upload_grib_files_post"},"Body_upload_nuclide_excel_nuclide_upload_nuclide_excel_post":{"properties":{"event_type":{"type":"string","title":"Event Type","description":"事件类型"},"data_type":{"type":"string","title":"Data Type","description":"数据类型"},"file":{"type":"string","format":"binary","title":"File","description":"Excel文件"}},"type":"object","required":["event_type","data_type","file"],"title":"Body_upload_nuclide_excel_nuclide_upload_nuclide_excel_post"},"Body_upload_train_dataset_train_oneday_upload_train_dataset_post":{"properties":{"files":{"items":{"type":"string","format":"binary"},"type":"array","title":"Files","description":"训练数据集文件 (1.xlsx, 2.xlsx, 3.xlsx)"},"create_by":{"type":"string","title":"Create By","description":"创建者","default":"system"}},"type":"object","required":["files"],"title":"Body_upload_train_dataset_train_oneday_upload_train_dataset_post"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}} \ No newline at end of file diff --git a/package.json b/package.json index 20095c1..c3d4818 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,8 @@ "vue-cropper": "1.1.1", "vue-router": "4.5.1", "vuedraggable": "4.1.0", - "wind-core": "^1.1.8" + "wind-core": "^1.1.8", + "yarn": "^1.22.22" }, "devDependencies": { "@vitejs/plugin-vue": "5.2.4", diff --git a/src/utils/request.js b/src/utils/request.js index 1da8f6d..cabb70b 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -134,14 +134,16 @@ export function download(url, params, filename, config) { const isBlob = blobValidate(data) if (isBlob) { const blob = new Blob([data]) + // 先关闭遮罩再触发下载,避免全屏 loading 阻塞浏览器下载行为 + downloadLoadingInstance.close() saveAs(blob, filename) } else { const resText = await data.text() const rspObj = JSON.parse(resText) const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'] ElMessage.error(errMsg) + downloadLoadingInstance.close() } - downloadLoadingInstance.close() }).catch((r) => { console.error(r) ElMessage.error('下载文件出现错误,请联系管理员!') diff --git a/src/views/chart/pages/Calculation.vue b/src/views/chart/pages/Calculation.vue index c802154..2923fb6 100644 --- a/src/views/chart/pages/Calculation.vue +++ b/src/views/chart/pages/Calculation.vue @@ -57,11 +57,11 @@ + @click="onSearch" :disabled="isTraining" :loading="isTraining"> Start training + @click="onEnd" :disabled="!isTraining"> End training @@ -192,8 +192,13 @@ export default { label: 'RF', }, ], + isTraining: false, caseNo: '', timer: null, + trainingStartTime: null, + maxTrainingDuration: 1800000, // 最大训练时长30分钟 + pollErrorCount: 0, + maxPollErrors: 5, // 轮询连续失败最大次数 chartData: { xAxisData: [], seriesData: [] @@ -206,65 +211,112 @@ export default { this.chart() this.getDataset() }, + beforeUnmount() { + if (this.timer) { + clearInterval(this.timer) + this.timer = null + } + }, methods: { getDataset() { - this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_datasets', { params: { page: 1, size: 100 } }).then((res) => { + // this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_datasets', { params: { page: 1, size: 100 } }).then((res) => { + this.$axios.get(window.CONFIG.baseUrl + '/python-api/train-oneday/query_train_datasets', { params: { page: 1, size: 100 } }).then((res) => { this.datasetIdOptions = res.data.items }) }, onSearch() { + if (this.isTraining) return + this.isTraining = true + this.pollErrorCount = 0 + this.trainingStartTime = Date.now() if (this.myChart) { this.myChart.dispose() this.chart() } this.getTrainingTime() - this.loading = true - this.$axios.post(window.CONFIG.baseUrl + '/train-oneday/train_models', this.queryParams, { + // this.$axios.post(window.CONFIG.baseUrl + '/train-oneday/train_models', this.queryParams, { + this.$axios.post(window.CONFIG.baseUrl + '/python-api/train-oneday/train_models', this.queryParams, { + timeout: this.maxTrainingDuration, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).then((res) => { if (res.case_no) { this.caseNo = res.case_no } this.queryModalProcess() - }).finally(() => { - this.loading = false + }).catch(() => { + this.isTraining = false }) }, onEnd() { + if (!this.isTraining) return clearInterval(this.timer) + this.timer = null + this.isTraining = false + this.trainingStartTime = null }, // 获取训练用时时间 async getTrainingTime() { - const res = await this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_training_time', { params: { dataset_id: this.queryParams.dataset_id, model_type: this.queryParams.model_types } }) + // const res = await this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_training_time', { params: { dataset_id: this.queryParams.dataset_id, model_type: this.queryParams.model_types } }) + const res = await this.$axios.get(window.CONFIG.baseUrl + '/python-api/train-oneday/query_training_time', { params: { dataset_id: this.queryParams.dataset_id, model_type: this.queryParams.model_types } }) debugger }, queryModalProcess() { this.timer = setInterval(async () => { - // const res = await this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/get_available_models', { params: { case_no: this.caseNo } }) - const res = await this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_cases', { params: { /*dataset_id: this.queryParams.dataset_id, model_type: this.queryParams.model_types,*/ case_no: this.caseNo, page: 1, size: 30 } }) - res.data.items.forEach((item, index) => { - if (item.model_type === 'CNN') { - if (item.end_time) { - clearInterval(this.timer) - } - if (item.loss) { - this.chartData.xAxisData.push(new Date().toLocaleString().replaceAll('/', '-')) - this.chartData.seriesData.push(item.loss) + // 检查是否超过最大训练时长 + if (this.trainingStartTime && (Date.now() - this.trainingStartTime > this.maxTrainingDuration)) { + clearInterval(this.timer) + this.timer = null + this.isTraining = false + this.trainingStartTime = null + this.$message.warning('训练已超过最大时长(30分钟),自动终止') + return + } + + try { + // const res = await this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_cases', { + const res = await this.$axios.get(window.CONFIG.baseUrl + '/python-api/train-oneday/query_train_cases', { + timeout: 30000, + params: { case_no: this.caseNo, page: 1, size: 30 } + }) + this.pollErrorCount = 0 + + res.data.items.forEach((item, index) => { + if (item.model_type === 'CNN') { + if (item.end_time) { + clearInterval(this.timer) + this.timer = null + this.isTraining = false + this.trainingStartTime = null + } + if (item.loss) { + this.chartData.xAxisData.push(new Date().toLocaleString().replaceAll('/', '-')) + this.chartData.seriesData.push(item.loss) + } } + }) + this.myChart.setOption({ + xAxis: { + data: this.chartData.xAxisData + }, + series: [ + { + name: 'CNN', + type: 'line', + data: this.chartData.seriesData, + } + ] + }) + } catch (err) { + this.pollErrorCount++ + console.error('轮询训练状态失败:', err) + if (this.pollErrorCount >= this.maxPollErrors) { + clearInterval(this.timer) + this.timer = null + this.isTraining = false + this.trainingStartTime = null + this.$message.warning('连续多次查询训练状态失败,已自动终止') } - }) - this.myChart.setOption({ - xAxis: { - data: this.chartData.xAxisData - }, - series: [ - { - name: 'CNN', - type: 'line', - data: this.chartData.seriesData, - } - ] - }) + } }, 3000) }, chart() { diff --git a/src/views/chart/pages/Configure.vue b/src/views/chart/pages/Configure.vue index 996233e..36e398f 100644 --- a/src/views/chart/pages/Configure.vue +++ b/src/views/chart/pages/Configure.vue @@ -76,7 +76,8 @@ export default { methods: { onSearch () { this.loading = true - this.$axios.get(window.CONFIG.baseUrl + '/nuclide/query_samples', { params: this.queryParams }).then((res) => { + // this.$axios.get(window.CONFIG.baseUrl + '/nuclide/query_samples', { params: this.queryParams }).then((res) => { + this.$axios.get(window.CONFIG.baseUrl + '/python-api/nuclide/query_samples', { params: this.queryParams }).then((res) => { this.tableData = res.data.items this.total = res.data.pagination.total_count }).finally(() => { @@ -95,7 +96,8 @@ export default { this.typeData[item.sample_id] = item.ev_type } }) - const res = await this.$axios.post(window.CONFIG.baseUrl + '/nuclide/batch_mark_samples', this.typeData) + // const res = await this.$axios.post(window.CONFIG.baseUrl + '/nuclide/batch_mark_samples', this.typeData) + const res = await this.$axios.post(window.CONFIG.baseUrl + '/python-api/nuclide/batch_mark_samples', this.typeData) this.$message.info(res.message) }, }, diff --git a/src/views/chart/pages/ConfigureChart.vue b/src/views/chart/pages/ConfigureChart.vue index 6b9e8bb..277754c 100644 --- a/src/views/chart/pages/ConfigureChart.vue +++ b/src/views/chart/pages/ConfigureChart.vue @@ -65,7 +65,8 @@ export default { methods: { onSearch () { this.loading = true - this.$axios.get(window.CONFIG.baseUrl + '/nuclide/query_latest_samples').then((res) => { + // this.$axios.get(window.CONFIG.baseUrl + '/nuclide/query_latest_samples').then((res) => { + this.$axios.get(window.CONFIG.baseUrl + '/python-api/nuclide/query_latest_samples').then((res) => { debugger this.tableData = res.data.items this.total = res.data.pagination.total_count diff --git a/src/views/chart/pages/Dataset.vue b/src/views/chart/pages/Dataset.vue index 03ccb51..0024b81 100644 --- a/src/views/chart/pages/Dataset.vue +++ b/src/views/chart/pages/Dataset.vue @@ -71,13 +71,15 @@ export default { }, computed: { uploadUrl () { - return window.CONFIG.baseUrl + '/train-oneday/upload_train_dataset' + // return window.CONFIG.baseUrl + '/train-oneday/upload_train_dataset' + return window.CONFIG.baseUrl + '/python-api/train-oneday/upload_train_dataset' } }, methods: { onSearch () { this.loading = true - this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_datasets', { params: this.queryParams }).then((res) => { + // this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_datasets', { params: this.queryParams }).then((res) => { + this.$axios.get(window.CONFIG.baseUrl + '/python-api/train-oneday/query_train_datasets', { params: this.queryParams }).then((res) => { this.tableData = res.data.items this.total = res.data.pagination.total_count }).finally(() => { @@ -111,7 +113,8 @@ export default { // 使用 axios 发送请求 return new Promise((resolve, reject) => { - this.$axios.post(window.CONFIG.baseUrl + '/train-oneday/upload_train_dataset', formData, { + // this.$axios.post(window.CONFIG.baseUrl + '/train-oneday/upload_train_dataset', formData, { + this.$axios.post(window.CONFIG.baseUrl + '/python-api/train-oneday/upload_train_dataset', formData, { headers: { 'Content-Type': 'multipart/form-data' }, diff --git a/src/views/chart/pages/LoadFromDb.vue b/src/views/chart/pages/LoadFromDb.vue index b444a52..83e85b1 100644 --- a/src/views/chart/pages/LoadFromDb.vue +++ b/src/views/chart/pages/LoadFromDb.vue @@ -85,13 +85,15 @@ export default { }, computed: { uploadUrl () { - return window.CONFIG.baseUrl + '/nuclide/upload_nuclide_excel' + // return window.CONFIG.baseUrl + '/nuclide/upload_nuclide_excel' + return window.CONFIG.baseUrl + '/python-api/nuclide/upload_nuclide_excel' } }, methods: { onSearch () { this.loading = true - this.$axios.get(window.CONFIG.baseUrl + '/nuclide/query_samples', { params: this.queryParams }).then((res) => { + // this.$axios.get(window.CONFIG.baseUrl + '/nuclide/query_samples', { params: this.queryParams }).then((res) => { + this.$axios.get(window.CONFIG.baseUrl + '/python-api/nuclide/query_samples', { params: this.queryParams }).then((res) => { this.tableData = res.data.items this.total = res.data.pagination.total_count }).finally(() => { diff --git a/src/views/chart/pages/MarkerMap.vue b/src/views/chart/pages/MarkerMap.vue index 496a07f..79be30d 100644 --- a/src/views/chart/pages/MarkerMap.vue +++ b/src/views/chart/pages/MarkerMap.vue @@ -411,7 +411,8 @@ export default { }, methods: { getData() { - this.$axios.get(window.CONFIG.baseUrl + '/nuclide/query_pollution_data', { params: { loc_id: 86 } }).then((res) => { + // this.$axios.get(window.CONFIG.baseUrl + '/nuclide/query_pollution_data', { params: { loc_id: 86 } }).then((res) => { + this.$axios.get(window.CONFIG.baseUrl + '/python-api/nuclide/query_pollution_data', { params: { loc_id: 86 } }).then((res) => { this.imgData.nrl = [] this.imgData.nuclearFacilities = [] this.imgData.groudMonitoringStation = [] diff --git a/src/views/chart/pages/MonitorResult.vue b/src/views/chart/pages/MonitorResult.vue index ffb4b79..ce5548a 100644 --- a/src/views/chart/pages/MonitorResult.vue +++ b/src/views/chart/pages/MonitorResult.vue @@ -36,9 +36,27 @@
-
-
-
+
+
+
+ 下载数据 +
+
+
+
+
+ 下载数据 +
+
+
+
+
+ 下载数据 +
+
@@ -108,7 +126,8 @@ export default { }, methods: { getDataset() { - this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_datasets', { params: { page: 1, size: 100 } }) + // this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_datasets', { params: { page: 1, size: 100 } }) + this.$axios.get(window.CONFIG.baseUrl + '/python-api/train-oneday/query_train_datasets', { params: { page: 1, size: 100 } }) .then((res) => { this.datasetIdOptions = res.data.items || [] }) @@ -116,7 +135,8 @@ export default { }, async getCaseData(datasetId) { try { - const res = await this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_cases', { + // const res = await this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_cases', { + const res = await this.$axios.get(window.CONFIG.baseUrl + '/python-api/train-oneday/query_train_cases', { params: { dataset_id: datasetId, model_type: '', case_no: '', page: 1, size: 100 } }) this.caseOptions = this.removeDuplicatesByMap(res.data.items || []) @@ -160,7 +180,8 @@ export default { // 返回:图例名称 + 异步请求(未执行) return { legendName: item, - request: this.$axios.get(window.CONFIG.baseUrl + '/download', { params: { path: path } }) + // request: this.$axios.get(window.CONFIG.baseUrl + '/download', { params: { path: path } }) + request: this.$axios.get(window.CONFIG.baseUrl + '/python-api/download', { params: { path: path } }) } }) @@ -295,6 +316,28 @@ export default { this.myChart3 = this.$echarts.init(this.$refs.chartDom3) this.myChart3.setOption(this.initChartOption()) }, + downloadChartData(chartIndex) { + const dataMap = { + 1: this.chartData.seriesData, + 2: this.chartData.seriesData2, + 3: this.chartData.seriesData3 + } + const data = dataMap[chartIndex] + if (!data || data.length === 0) { + this.$message.warning('暂无数据可下载') + return + } + const json = JSON.stringify(data, null, 2) + const blob = new Blob([json], { type: 'application/json' }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = `chart${chartIndex}_data.json` + document.body.appendChild(a) + a.click() + document.body.removeChild(a) + URL.revokeObjectURL(url) + }, } } diff --git a/src/views/chart/pages/Predict.vue b/src/views/chart/pages/Predict.vue index d170f6c..5cefc35 100644 --- a/src/views/chart/pages/Predict.vue +++ b/src/views/chart/pages/Predict.vue @@ -38,16 +38,16 @@ - Upload - Select 识别中... - Download @@ -124,7 +124,8 @@ export default { formData.append("case_no", this.queryParams.case_no) formData.append("model_types", this.queryParams.model_types) // this.$axios.post(window.CONFIG.baseUrl + '/train-oneday/predict', formData, { headers: { "Content-Type": "multipart/form-data" } }).then((res) => { - this.$axios.post(window.CONFIG.baseUrl + '/train-oneday/predict', formData, { timeout: 1800000, headers: { "Content-Type": "multipart/form-data" } }).then((res) => { + // this.$axios.post(window.CONFIG.baseUrl + '/train-oneday/predict', formData, { timeout: 1800000, headers: { "Content-Type": "multipart/form-data" } }).then((res) => { + this.$axios.post(window.CONFIG.baseUrl + '/python-api/train-oneday/predict', formData, { timeout: 1800000, headers: { "Content-Type": "multipart/form-data" } }).then((res) => { // this.chartData.dataset = res.echart_data // this.myChart.setOption({ // dataset: { @@ -133,17 +134,23 @@ export default { // }) console.log('Predict_output_path', res.output_path) this.output_path = res?.output_path + this.$message.success('预测成功') + }).catch((err) => { + this.$message.error('请求失败:' + err.message) + console.error('接口错误:', err) }).finally(() => { this.loading = false }) }, getDataset() { - this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_datasets', { params: { page: 1, size: 100 } }).then((res) => { + // this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_datasets', { params: { page: 1, size: 100 } }).then((res) => { + this.$axios.get(window.CONFIG.baseUrl + '/python-api/train-oneday/query_train_datasets', { params: { page: 1, size: 100 } }).then((res) => { this.datasetIdOptions = res.data.items }) }, async getCaseData(datasetId) { - const res = await this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_cases', { params: { dataset_id: datasetId, model_type: '', case_no: '', page: 1, size: 100 } }) + // const res = await this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_cases', { params: { dataset_id: datasetId, model_type: '', case_no: '', page: 1, size: 100 } }) + const res = await this.$axios.get(window.CONFIG.baseUrl + '/python-api/train-oneday/query_train_cases', { params: { dataset_id: datasetId, model_type: '', case_no: '', page: 1, size: 100 } }) this.caseOptions = this.removeDuplicatesByMap(res.data.items) }, removeDuplicatesByMap(arr) { @@ -165,6 +172,7 @@ export default { handleChange(file, fileList) { if (file) { this.currentFile = file.raw || file + this.$message.success('文件选择成功:' + (file.name || '')) } else { this.currentFile = null } @@ -185,16 +193,24 @@ export default { this.$message.warning('暂无下载文件!'); return false } - this.$axios.get(window.CONFIG.baseUrl + '/download', { params: { path: this.output_path }, responseType: 'blob', }).then(res => { + // this.$axios.get(window.CONFIG.baseUrl + '/download', { params: { path: this.output_path }, responseType: 'blob', }).then(res => { + this.$axios.get(window.CONFIG.baseUrl + '/python-api/download', { params: { path: this.output_path }, responseType: 'blob', }).then(res => { const downLoadName = 'pred.xlsx' // 通过a标签打开新页面下载文件 const a = document.createElement('a') - a.href = URL.createObjectURL(res) + const blobUrl = URL.createObjectURL(res) + a.href = blobUrl // a标签里有download属性可以自定义文件名 a.setAttribute('download', downLoadName) document.body.appendChild(a) a.click() - document.body.removeChild(a) + // 延迟移除a标签和释放blob URL,确保浏览器已完成下载触发 + setTimeout(() => { + document.body.removeChild(a) + URL.revokeObjectURL(blobUrl) + }, 200) + }).catch(err => { + this.$message.error('下载失败:' + (err.message || '未知错误')) }) }, chart() { diff --git a/src/views/chart/pages/Test.vue b/src/views/chart/pages/Test.vue index 9b9a1d4..d602733 100644 --- a/src/views/chart/pages/Test.vue +++ b/src/views/chart/pages/Test.vue @@ -31,16 +31,16 @@ - Upload - Select 识别中... - Download @@ -117,7 +117,7 @@ export default { formData.append("model_types", this.queryParams.model_types) this.$axios.post( - window.CONFIG.baseUrl + '/train-oneday/predict_with_label', + window.CONFIG.baseUrl + '/python-api/train-oneday/predict_with_label', formData, { timeout: 1800000, headers: { "Content-Type": "multipart/form-data" } } ).then((res) => { @@ -125,6 +125,7 @@ export default { this.output_path = res?.output_path // 1. 缓存接口返回的数据源 this.chartData.datasetSource = res.echart_data || [] + this.$message.success('上传成功') }).catch((err) => { this.$message.error('请求失败:' + err.message) console.error('接口错误:', err) @@ -133,7 +134,7 @@ export default { }) }, getDataset() { - this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_datasets', { params: { page: 1, size: 100 } }) + this.$axios.get(window.CONFIG.baseUrl + '/python-api/train-oneday/query_train_datasets', { params: { page: 1, size: 100 } }) .then((res) => { this.datasetIdOptions = res.data.items || [] }).catch(err => { @@ -143,7 +144,7 @@ export default { async getCaseData(datasetId) { try { const res = await this.$axios.get( - window.CONFIG.baseUrl + '/train-oneday/query_train_cases', + window.CONFIG.baseUrl + '/python-api/train-oneday/query_train_cases', { params: { dataset_id: datasetId, model_type: '', case_no: '', page: 1, size: 100 } } ) this.caseOptions = this.removeDuplicatesByMap(res.data.items || []) @@ -169,6 +170,7 @@ export default { handleChange(file, fileList) { if (file) { this.currentFile = file.raw || file + this.$message.success('文件选择成功:' + (file.name || '')) } else { this.currentFile = null } @@ -182,17 +184,21 @@ export default { return false } this.$axios.get( - window.CONFIG.baseUrl + '/download', + window.CONFIG.baseUrl + '/python-api/download', { params: { path: this.output_path }, responseType: 'blob' } ).then(res => { const downLoadName = 'test.xlsx' const a = document.createElement('a') - a.href = URL.createObjectURL(res) // 修复:res.data才是blob数据 + const blobUrl = URL.createObjectURL(res) + a.href = blobUrl a.setAttribute('download', downLoadName) document.body.appendChild(a) a.click() - document.body.removeChild(a) - URL.revokeObjectURL(a.href) // 释放URL对象 + // 延迟移除a标签和释放blob URL,确保浏览器已完成下载触发 + setTimeout(() => { + document.body.removeChild(a) + URL.revokeObjectURL(blobUrl) + }, 200) }).catch(err => { this.$message.error('下载失败:' + err.message) }) diff --git a/src/views/chart/pages/WeatherData.vue b/src/views/chart/pages/WeatherData.vue index b80c983..d7561e6 100644 --- a/src/views/chart/pages/WeatherData.vue +++ b/src/views/chart/pages/WeatherData.vue @@ -67,13 +67,15 @@ export default { }, computed: { uploadUrl () { - return window.CONFIG.baseUrl + '/weather/upload_grib_files' + // return window.CONFIG.baseUrl + '/weather/upload_grib_files' + return window.CONFIG.baseUrl + '/python-api/weather/upload_grib_files' } }, methods: { onSearch () { this.loading = true - this.$axios.get(window.CONFIG.baseUrl + '/weather/list_grib_files', { params: this.queryParams }).then((res) => { + // this.$axios.get(window.CONFIG.baseUrl + '/weather/list_grib_files', { params: this.queryParams }).then((res) => { + this.$axios.get(window.CONFIG.baseUrl + '/python-api/weather/list_grib_files', { params: this.queryParams }).then((res) => { this.tableData = res.files // this.total = res.data.pagination.total_count }).finally(() => { diff --git a/src/views/chart/pages/WindMap.vue b/src/views/chart/pages/WindMap.vue index 8ca5213..f4e286c 100644 --- a/src/views/chart/pages/WindMap.vue +++ b/src/views/chart/pages/WindMap.vue @@ -49,7 +49,8 @@ export default { grid_halfwidth_deg: this.gridHalfwidthDeg } this.loading = true - const res = await this.$axios.post(window.CONFIG.baseUrl + '/nuclide-sim/calculate_atmospheric_stability', params, { + // const res = await this.$axios.post(window.CONFIG.baseUrl + '/nuclide-sim/calculate_atmospheric_stability', params, { + const res = await this.$axios.post(window.CONFIG.baseUrl + '/python-api/nuclide-sim/calculate_atmospheric_stability', params, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }) this.loading = false @@ -66,7 +67,8 @@ export default { } try { this.loading = true - const res = await this.$axios.post(window.CONFIG.baseUrl + '/nuclide-sim/get_wind_temperature_pressure_data', params, { + // const res = await this.$axios.post(window.CONFIG.baseUrl + '/nuclide-sim/get_wind_temperature_pressure_data', params, { + const res = await this.$axios.post(window.CONFIG.baseUrl + '/python-api/nuclide-sim/get_wind_temperature_pressure_data', params, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }) this.loading = false diff --git a/test b/test new file mode 100644 index 0000000..db60e61 --- /dev/null +++ b/test @@ -0,0 +1 @@ +_psycopg.cpython-311-x86_64-linux-gnu.so: undefined symbol: lo_truncate64 diff --git a/vite.config.js b/vite.config.js index 228ec01..347c4b1 100644 --- a/vite.config.js +++ b/vite.config.js @@ -43,7 +43,7 @@ export default defineConfig(({ mode, command }) => { }, // vite 相关配置 server: { - port: 80, + port: 90, host: '0.0.0.0', open: false, proxy: {