RShiny考勤录入应用点击动作按钮出现行数不匹配报错求助
报错原因
你遇到的行数不匹配报错由以下几个拼写与逻辑错误直接导致:
- 输入ID拼写错误:UI中日期输入组件的ID是
dateinput,但服务器端req()校验写的是input$dateinputa,多了末尾的a,导致校验永远不通过,input$dateinputa返回空值(0行),和选中的球员列表(≥1行)拼接数据框时行数不一致触发报错。 - 写入文件时调用对象错误:
write.csv()中写的是不存在的全局变量AttendanceDF,实际存储考勤数据的是响应式变量v$AttendanceDF,对象不存在返回空值也会触发行数异常。 - 潜在日期格式不兼容:UI中
dateInput的输出格式默认是yyyy-mm-dd,但你读取CSV时指定的日期解析格式是%m/%d/%Y(月/日/年),写入和读取格式不匹配会导致后续读入时日期列变为NA,触发隐式行数异常。
修复后代码
服务器端修正代码
library(tidyverse) library(shiny) library(plotly) library(DT) server <- function(session, input, output) { v <- reactiveValues() # 新增初始文件不存在的兼容逻辑 attendance_path <- "Data/Source Data/Attendance.csv" if(!file.exists(attendance_path)){ # 初始创建空考勤表,列类型和后续写入保持一致 init_df <- data.frame(Date = as.Date(character()), Playername = character()) write.csv(init_df, attendance_path, row.names = FALSE) } v$AttendanceDF <- read_csv(attendance_path, col_types = cols(Date = col_date(format = "%Y-%m-%d"), Playername = col_character())) observeEvent(input$submit,{ # 修正输入ID拼写 req(input$dateinput, input$AttendanceInput) tmpDF <- data.frame(Date = input$dateinput, Playername = input$AttendanceInput) # 新增去重逻辑,避免同一日期同一球员重复录入 tmpDF <- tmpDF[!paste(tmpDF$Date, tmpDF$Playername) %in% paste(v$AttendanceDF$Date, v$AttendanceDF$Playername),] if(nrow(tmpDF) > 0){ v$AttendanceDF <- rbind(v$AttendanceDF, tmpDF) # 修正写入对象,去掉行号 write.csv(v$AttendanceDF, attendance_path, row.names = FALSE) # 删去多余的重读CSV步骤,内存中已经是最新数据 showNotification("考勤数据提交成功", type = "message") # 提交后清空选项避免重复提交 updateCheckboxGroupInput(session, "AttendanceInput", selected = character()) } else { showNotification("当前选择的人员当日考勤已录入,无需重复提交", type = "warning") } }) output$AttendanceTable <- DT::renderDataTable({ v$AttendanceDF }) # 补充参会频次可视化逻辑 output$plot <- renderPlotly({ req(input$daterange) # 支持单人员筛选和全部人员展示 plot_df <- v$AttendanceDF %>% filter(Date >= input$daterange[1], Date <= input$daterange[2]) if(input$Playernameinput != "全部"){ plot_df <- plot_df %>% filter(Playername == input$Playernameinput) } plot_df <- plot_df %>% mutate(统计月份 = lubridate::floor_date(Date, unit = "month")) %>% count(统计月份, Playername, name = "参会频次") p <- ggplot(plot_df, aes(x = 统计月份, y = 参会频次, fill = Playername)) + geom_col(position = "dodge") + scale_fill_brewer(palette = "Set1") + labs(x = "时间", y = "参会频次") + theme_minimal() ggplotly(p) }) }
UI补充修正
你UI中checkboxGroupInput的choices写的是FlamesRoster$Playername,但你的花名册数据框叫Roster,需要修正,同时给人员筛选下拉加「全部」选项:
checkboxGroupInput(inputId = 'AttendanceInput', label = "Select Players", choices = Roster$Playername, inline = FALSE) # 人员筛选下拉修正 selectInput("Playernameinput", "Select Player", choices = c("全部", Roster$Playername))
额外优化建议
- 权限控制:如果是多用户使用,可以加登录校验,避免所有人都能修改考勤数据
- 批量导出:增加数据导出按钮,支持筛选后的数据一键导出为Excel
- 异常处理:给CSV读写逻辑加
tryCatch捕获文件占用、路径不存在等异常,避免程序直接崩溃
内容的提问来源于stack exchange,提问作者zmcclean
相关产品推荐
相关产品推荐

