206 lines
5.4 KiB
Go
206 lines
5.4 KiB
Go
// Package handlers 实现API请求处理器
|
||
// 包含工作簿(Excel文档)的增删改查操作
|
||
// 工作簿通过 documents 表存储元数据,workbooks 表存储Excel特化数据
|
||
package handlers
|
||
|
||
import (
|
||
"excel-api/models"
|
||
"excel-api/utils"
|
||
"net/http"
|
||
"strconv"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// GetWorkbooks 获取工作簿列表
|
||
// 支持分页查询,通过JOIN关联文档表获取完整信息
|
||
// 请求方式: GET
|
||
// 路径: /api/workbooks
|
||
// 查询参数: page(页码,默认1), pageSize(每页条数,默认20)
|
||
func GetWorkbooks(c *gin.Context) {
|
||
// 解析分页参数
|
||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||
pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "20"))
|
||
if page < 1 {
|
||
page = 1
|
||
}
|
||
if pageSize < 1 || pageSize > 100 {
|
||
pageSize = 20
|
||
}
|
||
|
||
var workbooks []models.Workbook
|
||
var total int64
|
||
|
||
// 查询总数(关联文档表)
|
||
models.DB.Model(&models.Workbook{}).Joins("JOIN documents ON documents.id = workbooks.document_id").Count(&total)
|
||
// 分页查询工作簿列表,预加载关联的工作表
|
||
result := models.DB.
|
||
Joins("JOIN documents ON documents.id = workbooks.document_id").
|
||
Preload("Sheets").
|
||
Offset((page - 1) * pageSize).Limit(pageSize).
|
||
Order("documents.created_at DESC").
|
||
Find(&workbooks)
|
||
if result.Error != nil {
|
||
utils.Error(c, 500, "查询工作簿列表失败")
|
||
return
|
||
}
|
||
|
||
utils.SuccessPage(c, workbooks, total, page, pageSize)
|
||
}
|
||
|
||
// CreateWorkbook 创建新工作簿
|
||
// 同时创建对应的文档记录和默认工作表
|
||
// 请求方式: POST
|
||
// 路径: /api/workbooks
|
||
// 请求体: { "title": "文档标题", "description": "描述" }
|
||
func CreateWorkbook(c *gin.Context) {
|
||
var req struct {
|
||
Title string `json:"title" binding:"required"` // 文档标题,必填
|
||
Description string `json:"description"` // 文档描述,可选
|
||
}
|
||
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
utils.Error(c, 400, "参数错误: "+err.Error())
|
||
return
|
||
}
|
||
|
||
// 创建文档记录(excel类型)
|
||
document := models.Document{
|
||
Type: "excel",
|
||
Title: req.Title,
|
||
Description: req.Description,
|
||
CreatorID: 1, // 前期默认用户ID
|
||
Status: 1,
|
||
}
|
||
result := models.DB.Create(&document)
|
||
if result.Error != nil {
|
||
utils.Error(c, 500, "创建文档失败")
|
||
return
|
||
}
|
||
|
||
// 创建工作簿记录
|
||
workbook := models.Workbook{
|
||
DocumentID: document.ID,
|
||
}
|
||
result = models.DB.Create(&workbook)
|
||
if result.Error != nil {
|
||
utils.Error(c, 500, "创建工作簿失败")
|
||
return
|
||
}
|
||
|
||
// 为新工作簿创建默认工作表
|
||
defaultSheet := models.Sheet{
|
||
WorkbookID: workbook.ID,
|
||
Name: "Sheet1",
|
||
Index: 0,
|
||
ColCount: 26,
|
||
RowCount: 100,
|
||
}
|
||
models.DB.Create(&defaultSheet)
|
||
|
||
// 返回完整信息
|
||
workbook.Document = document
|
||
utils.SuccessWithMessage(c, "创建工作簿成功", workbook)
|
||
}
|
||
|
||
// GetWorkbook 获取工作簿详情
|
||
// 请求方式: GET
|
||
// 路径: /api/workbooks/:id
|
||
// 路径参数: id - 工作簿ID
|
||
func GetWorkbook(c *gin.Context) {
|
||
id := c.Param("id")
|
||
var workbook models.Workbook
|
||
|
||
// 查询工作簿并预加载关联的工作表和文档
|
||
result := models.DB.Preload("Sheets").Preload("Document").First(&workbook, id)
|
||
if result.Error != nil {
|
||
utils.Error(c, 404, "工作簿不存在")
|
||
return
|
||
}
|
||
|
||
utils.Success(c, workbook)
|
||
}
|
||
|
||
// UpdateWorkbook 更新工作簿信息
|
||
// 更新关联的文档表信息
|
||
// 请求方式: PUT
|
||
// 路径: /api/workbooks/:id
|
||
// 路径参数: id - 工作簿ID
|
||
// 请求体: { "title": "新标题", "description": "新描述" }
|
||
func UpdateWorkbook(c *gin.Context) {
|
||
id := c.Param("id")
|
||
var workbook models.Workbook
|
||
|
||
// 查找要更新的工作簿
|
||
result := models.DB.First(&workbook, id)
|
||
if result.Error != nil {
|
||
utils.Error(c, 404, "工作簿不存在")
|
||
return
|
||
}
|
||
|
||
var req struct {
|
||
Title string `json:"title"` // 文档标题
|
||
Description string `json:"description"` // 文档描述
|
||
}
|
||
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
utils.Error(c, 400, "参数错误: "+err.Error())
|
||
return
|
||
}
|
||
|
||
// 更新关联的文档表
|
||
var document models.Document
|
||
if err := models.DB.First(&document, workbook.DocumentID).Error; err == nil {
|
||
if req.Title != "" {
|
||
document.Title = req.Title
|
||
}
|
||
document.Description = req.Description
|
||
models.DB.Save(&document)
|
||
}
|
||
|
||
utils.SuccessWithMessage(c, "更新工作簿成功", workbook)
|
||
}
|
||
|
||
// DeleteWorkbook 删除工作簿(软删除)
|
||
// 同时删除关联的文档、工作表和单元格
|
||
// 请求方式: DELETE
|
||
// 路径: /api/workbooks/:id
|
||
// 路径参数: id - 工作簿ID
|
||
func DeleteWorkbook(c *gin.Context) {
|
||
id := c.Param("id")
|
||
var workbook models.Workbook
|
||
|
||
// 查找要删除的工作簿
|
||
result := models.DB.First(&workbook, id)
|
||
if result.Error != nil {
|
||
utils.Error(c, 404, "工作簿不存在")
|
||
return
|
||
}
|
||
|
||
// 获取关联的工作表IDs
|
||
var sheetIDs []uint
|
||
models.DB.Model(&models.Sheet{}).Where("workbook_id = ?", id).Pluck("id", &sheetIDs)
|
||
|
||
// 软删除单元格
|
||
if len(sheetIDs) > 0 {
|
||
models.DB.Where("sheet_id IN ?", sheetIDs).Delete(&models.Cell{})
|
||
}
|
||
|
||
// 软删除工作表
|
||
models.DB.Where("workbook_id = ?", id).Delete(&models.Sheet{})
|
||
|
||
// 软删除工作簿
|
||
models.DB.Delete(&workbook)
|
||
|
||
// 软删除关联的文档
|
||
models.DB.Delete(&models.Document{}, workbook.DocumentID)
|
||
|
||
utils.SuccessWithMessage(c, "删除工作簿成功", nil)
|
||
}
|
||
|
||
// HandleOptions 处理OPTIONS预检请求
|
||
// 用于CORS跨域请求的预检
|
||
func HandleOptions(c *gin.Context) {
|
||
c.Status(http.StatusNoContent)
|
||
}
|