feat(ssa): Complete Phase 2A frontend integration - multi-step workflow end-to-end

Phase 2A: WorkflowPlannerService, WorkflowExecutorService, Python data quality, 6 bug fixes, DescriptiveResultView, multi-step R code/Word export, MVP UI reuse. V11 UI: Gemini-style, multi-task, single-page scroll, Word export. Architecture: Block-based rendering consensus (4 block types). New R tools: chi_square, correlation, descriptive, logistic_binary, mann_whitney, t_test_paired. Docs: dev summary, block-based plan, status updates, task list v2.0.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-02-20 23:09:27 +08:00
parent 23b422f758
commit 428a22adf2
62 changed files with 15416 additions and 299 deletions

View File

@@ -29,23 +29,59 @@ load_input_data <- function(input) {
# 调试:打印原始数据结构
message(glue("[DataLoader] 原始数据类型: {class(raw_data)}"))
message(glue("[DataLoader] 原始数据字段: {paste(names(raw_data), collapse=', ')}"))
message(glue("[DataLoader] 原始数据长度: {length(raw_data)}"))
# 安全转换:处理不同的 JSON 解析结果
if (is.data.frame(raw_data)) {
# 已经是 data.frame
df <- raw_data
} else if (is.list(raw_data)) {
# JSON 对象 {"col1": [...], "col2": [...]} -> data.frame
# JSON 数组可能被解析为 list 而非 vector需要先 unlist
df <- data.frame(
lapply(raw_data, function(x) {
if (is.list(x)) unlist(x) else x
}),
stringsAsFactors = FALSE
)
message("[DataLoader] 数据已是 data.frame")
} else if (is.list(raw_data) && length(raw_data) > 0) {
# 检查是行格式还是列格式
first_elem <- raw_data[[1]]
if (is.list(first_elem) && !is.null(names(first_elem))) {
# 行格式: [{"col1": val1, "col2": val2}, {...}, ...]
# 每个元素是一行数据
message("[DataLoader] 检测到行格式数据 (JSON array of objects)")
# 使用 jsonlite 的 bind_rows 功能
df <- tryCatch({
# 方法1使用 do.call + rbind.data.frame
df_list <- lapply(raw_data, function(row) {
# 将每一行转为 data.frame
as.data.frame(lapply(row, function(val) {
if (is.null(val)) NA else val
}), stringsAsFactors = FALSE)
})
do.call(rbind, df_list)
}, error = function(e) {
# 方法2如果上面失败尝试 jsonlite 转换
message(glue("[DataLoader] rbind 失败,尝试 jsonlite 转换: {e$message}"))
jsonlite::fromJSON(jsonlite::toJSON(raw_data), flatten = TRUE)
})
} else if (!is.null(names(raw_data))) {
# 列格式: {"col1": [...], "col2": [...]}
message("[DataLoader] 检测到列格式数据 (JSON object with arrays)")
df <- data.frame(
lapply(raw_data, function(x) {
if (is.list(x)) unlist(x) else x
}),
stringsAsFactors = FALSE
)
} else {
# 未知格式
message(glue("[DataLoader] 未知数据格式first_elem class: {class(first_elem)}"))
stop(make_error(ERROR_CODES$E100_INTERNAL_ERROR,
details = "无法识别的数据格式"))
}
} else {
stop(make_error(ERROR_CODES$E100_INTERNAL_ERROR,
details = paste("无法解析的数据类型:", class(raw_data))))
details = paste("无法解析的数据类型:", class(raw_data), "或数据为空")))
}
message(glue("[DataLoader] 转换后: {nrow(df)} 行, {ncol(df)} 列, 列名: {paste(names(df), collapse=', ')}"))