You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RShiny考勤录入应用点击动作按钮出现行数不匹配报错求助

报错原因

你遇到的行数不匹配报错由以下几个拼写与逻辑错误直接导致:

  1. 输入ID拼写错误:UI中日期输入组件的ID是dateinput,但服务器端req()校验写的是input$dateinputa,多了末尾的a,导致校验永远不通过,input$dateinputa返回空值(0行),和选中的球员列表(≥1行)拼接数据框时行数不一致触发报错。
  2. 写入文件时调用对象错误:write.csv()中写的是不存在的全局变量AttendanceDF,实际存储考勤数据的是响应式变量v$AttendanceDF,对象不存在返回空值也会触发行数异常。
  3. 潜在日期格式不兼容: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 23:54:03