Cost Calculator

This sample employs the Shiny package to create a service fee calculator app.
Shiny
Author

NING LI

Published

Apr 05, 2023

Introduction to Shiny

Shiny is an R package for creating interactive web applications directly from R without requiring web development knowledge. A Shiny app generally consists of a user interface (UI) and a server component that contains the app’s logic and computations.

Purpose of this app

This Shiny app is a service fee calculator designed to calculate and track service fees based on various parameters, such as customer name, service type, add-on services, and service time. The app also allows users to apply or remove a 15% Goods and Services Tax (GST) on the total cost.

User Interface (UI)

The UI is divided into three main sections:

  1. Header Panel: Contains the app’s title “服务费用计算器” (Service Fee Calculator).

  2. Sidebar Panel: Includes input fields for customer name, service type, add-on services, service time, and service date. It also has action buttons for adding/removing GST, adding a service record, and generating a chart.

  3. Main Panel: Displays the calculated total cost, a table of service records, a time series plot of service costs, and a download button for exporting the service records as a CSV file.

Server Component

The server component handles the app’s logic and computations, including:

  1. Calculating the total cost: Determines the total cost based on service type, add-on services, and service time.

  2. Applying/removing GST: Applies or removes a 15% GST on the total cost based on user input.

  3. Managing service records: Stores service records in a reactive data frame, updates the records when a new entry is added, and arranges the records in descending order by date.

  4. Generating a time series plot: Creates a time series plot of service costs using ggplot2 when the “生成图表” (Generate Chart) button is clicked.

  5. Downloading service records: Allows users to download service records as a CSV file, with a filename containing the current date.

In summary, this Shiny app is a user-friendly service fee calculator that helps users input various parameters, calculate the total cost, apply or remove GST, store and display service records, and generate a time series plot of service costs.

# load packages    
library(shiny)
library(dplyr)
library(ggplot2)
library(shinythemes)


custom_css <- "
.record-table {
  margin-top: 20px;
}
"

# 定义 UI 组件
ui <- bootstrapPage(
  theme = shinytheme("flatly"),
  headerPanel("服务费用计算器"),
  sidebarPanel(
    textInput(inputId = "name", label = "客户名字:", value = ""),
    selectInput(inputId = "service", label = "服务类型:", 
                choices = c("日常清洁", "深层清洁", "搬出/搬入")),
    checkboxGroupInput(inputId = "addone", label = "附加服务:", 
                       choices = c("烤箱" = "烤箱", "窗户" = "窗户", "墙和天花板" = "墙和天花板")),
    numericInput(inputId = "oven_num", label = "烤箱数量:", value = 1, min = 1),
    numericInput(inputId = "window_num", label = "窗户数量:", value = 1, min = 1),
    textInput(inputId = "time", label = "服务时间(小时):", value = "1"),
    dateInput(inputId = "date", label = "服务日期:", 
              value = Sys.Date()),
    actionButton(inputId = "add_gst_button", label = "添加 GST(15%)"),
    actionButton(inputId = "remove_gst_button", label = "取消 GST(15%)"),
    actionButton(inputId = "add", label = "添加服务记录"),
    actionButton(inputId = "plot_button", label = "生成图表")
  ),
  mainPanel(
    h3("计算结果:"),
    textOutput(outputId = "total"),
    downloadButton(outputId = "download", label = "下载服务记录"),
    tags$head(tags$style(HTML(custom_css))),
    fluidRow(
      column(12,
             plotOutput(outputId = "plot")
      ),
      column(12,
             div(class = "record-table",
                 tableOutput(outputId = "records")
             )
      )
    )
  ),
)
  

# 定义 server 组件
server <- function(input, output, session) {
  gst_active <- reactiveVal(FALSE)
  
  observeEvent(input$add_gst_button, {
    gst_active(TRUE)
  })
  
  observeEvent(input$remove_gst_button, {
    gst_active(FALSE)
  })
  
  
  service_records <- reactiveValues(data = data.frame(Date = character(),
                                                      Name = character(),
                                                      Service = character(),
                                                      Time = numeric(),
                                                      Cost = numeric(),
                                                      Deleted = logical(),
                                                      stringsAsFactors = FALSE))
  
  
  # 计算总费用
  total_cost <- reactive({
    if(input$service == "日常清洁") {
      cost_per_hour_service <- 40
    } else if(input$service == "深层清洁") {
      cost_per_hour_service <- 100
    } else {
      cost_per_hour_service <- 200
    }
    
    # 初始化 cost_per_hour_addone 变量
    cost_per_hour_addone <- 0
    
    if("烤箱" %in% input$addone) {
      cost_per_hour_addone <- cost_per_hour_addone + (60 * input$oven_num)
    }
    if("窗户" %in% input$addone) {
      cost_per_hour_addone <- cost_per_hour_addone + (30 * input$window_num)
    }
    if("墙和天花板" %in% input$addone) {
      cost_per_hour_addone <- cost_per_hour_addone + 120
    }
    
    total <- (cost_per_hour_service) * as.numeric(input$time) + cost_per_hour_addone
    
    # 应用 GST
    if (gst_active()) {
      total <- total * 1.15
    }
    
    return(total)
  })
  
  
  # 添加服务记录
  observeEvent(input$add, {
    if(input$name != "") {
      record <- data.frame(Date = format(input$date, "%m/%d/%y"),
                           Name = input$name,
                           Service = paste(input$service, "和", paste(input$addone, collapse = ",")),
                           Time = as.numeric(input$time),
                           Cost = total_cost(),
                           stringsAsFactors = FALSE)
      service_records$data <- rbind(service_records$data, record)
    }
  })
  
  
  # 显示计算结果
  output$total <- renderText({
    if(input$name != "") {
      cost <- total_cost()
      paste0(input$name, " 需要支付 $", round(cost, 2), " 的服务费用。")
    } else {
      "请输入客户名字。"
    }
  })
  
  # 绘制时间序列图
  output$plot <- renderPlot({
    if(input$plot_button > 0) {
      plot_data <- service_records$data %>%
        mutate(Date = as.Date(Date, "%m/%d/%y")) %>%
        group_by(Date) %>%
        summarize(TotalCost = sum(Cost))
      
      ggplot(plot_data, aes(x = Date, y = TotalCost)) +
        geom_line() +
        geom_text(aes(label = round(TotalCost, 2)), vjust = -0.5, size = 4) +
        labs(title = "服务费用时间序列图", x = "日期", y = "服务费用") +
        theme_minimal()
    }
  })
  
  
  # 下载服务记录
  output$download <- downloadHandler(
    filename = function() {
      paste("service_records_", Sys.Date(), ".csv", sep = "")
    },
    content = function(file) {
      req(service_records$data)
      write.csv(service_records$data, file, row.names = FALSE)
    }
  )
  
  # 显示服务记录
  output$records <- renderTable({
    service_records$data %>%
      arrange(desc(Date))
  })
  
}

# 运行应用程序
shinyApp(ui, server)

👉 Run Cost Calculator App

Social share button
Back to top