x-movie/server/handler.go
eson 1a058a31c8 feat(server): 添加删除视频文件的功能
新增 `/movie/delete` 接口用于删除指定视频文件及其缩略图,并从全局电影列表中移除记录。
同时完善了前端删除交互,包括确认对话框、成功提示及错误处理。

- 后端:
  - 新增 `PostDelete` 处理函数,支持通过文件名删除视频
  - 实现 `Movie.DeleteVideo()` 方法,用于删除视频文件和关联缩略图
 - 更新路由注册,增加 `/delete` 接口
- 前端:
  - 新增删除确认弹窗与交互逻辑
  - 添加删除成功的 Snackbar 提示
  - 调整 MovieCard 按钮布局以容纳删除按钮
  - 传递并使用 onDelete 回调函数处理删除操作

该功能增强了系统的文件管理能力,使用户能够安全地移除不需要的视频内容。
2025-11-12 01:21:20 +08:00

263 lines
6.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"log"
"net/http"
"sort"
"strconv"
"strings"
"github.com/gin-gonic/gin"
)
// GetCategoryList 获取分类列表
func GetCategoryList(c *gin.Context) {
response := gin.H{
"code": http.StatusOK,
"message": "Success",
"data": Categories,
}
c.JSON(http.StatusOK, response)
}
// MovieList 电影列表
func MovieList(c *gin.Context) {
response := gin.H{
"code": http.StatusInternalServerError,
"message": "An unexpected error occurred.",
"data": gin.H{"items": []Movie{}, "total": 0},
}
var moviesToPaginate []*Movie
categoryName := c.Query("category")
searchQuery := c.Query("search") // 获取搜索参数
// === 第一步:基础过滤(类别)===
if categoryName != "" && categoryName != "最新添加" {
// 普通类别:直接过滤
for _, m := range Movies {
if m.TimeCategory == categoryName {
moviesToPaginate = append(moviesToPaginate, m)
}
}
} else {
// 最新添加/所有电影使用全局movies
moviesToPaginate = make([]*Movie, len(Movies))
copy(moviesToPaginate, Movies)
}
// === 第二步:搜索过滤 ===
if searchQuery != "" {
var searchResults []*Movie
lowerSearch := strings.ToLower(searchQuery)
for _, m := range moviesToPaginate {
// 检查文件名是否包含搜索词(不区分大小写)
if strings.Contains(strings.ToLower(m.FileName), lowerSearch) {
searchResults = append(searchResults, m)
}
}
moviesToPaginate = searchResults
}
// === 第三步:排序处理 ===
sortBy := c.Query("sort")
order := c.Query("order")
if sortBy == "" {
sortBy = "duration" // 默认按创建时间排序
}
// 应用排序
sort.Slice(moviesToPaginate, func(i, j int) bool {
switch sortBy {
case "created_time":
if order == "desc" {
return moviesToPaginate[i].CreatedTime > moviesToPaginate[j].CreatedTime
}
return moviesToPaginate[i].CreatedTime < moviesToPaginate[j].CreatedTime
case "duration":
if order == "desc" {
return moviesToPaginate[i].Duration > moviesToPaginate[j].Duration
}
return moviesToPaginate[i].Duration < moviesToPaginate[j].Duration
default:
// 默认按创建时间降序
return moviesToPaginate[i].CreatedTime > moviesToPaginate[j].CreatedTime
}
})
// === 第四步:分页处理 ===
page := 0
spage := c.Query("page")
if spage != "" {
p, err := strconv.Atoi(spage)
if err != nil || p < 1 {
log.Println("Invalid page number:", spage, err)
response["code"] = http.StatusBadRequest
response["message"] = "Invalid page number. Must be a positive integer."
c.JSON(http.StatusBadRequest, response)
return
}
page = p - 1
}
limit := 12
slimit := c.Query("limit")
if slimit != "" {
l, err := strconv.Atoi(slimit)
if err != nil || l < 1 {
log.Println("Invalid limit number:", slimit, err)
response["code"] = http.StatusBadRequest
response["message"] = "Invalid limit number. Must be a positive integer."
c.JSON(http.StatusBadRequest, response)
return
}
limit = l
}
start := page * limit
end := start + limit
total := len(moviesToPaginate)
// 处理超出范围的情况
if start >= total {
response["data"] = gin.H{
"items": []Movie{},
"total": total,
}
response["code"] = http.StatusOK
response["message"] = "Success"
c.JSON(http.StatusOK, response)
return
}
if end > total {
end = total
}
responseData := gin.H{
"items": moviesToPaginate[start:end],
"total": total,
}
response["code"] = http.StatusOK
response["message"] = "Success"
response["data"] = responseData
c.JSON(http.StatusOK, response)
}
// PostRename 重命名文件
func PostRename(c *gin.Context) {
var requestData struct {
OldName string `json:"old_name"`
NewName string `json:"new_name"`
}
response := gin.H{
"code": http.StatusOK,
"message": "Success",
"data": nil,
}
if err := c.ShouldBindJSON(&requestData); err != nil {
response["code"] = http.StatusBadRequest
response["message"] = "Invalid request data: " + err.Error()
c.JSON(http.StatusBadRequest, response)
return
}
if requestData.OldName == "" || requestData.NewName == "" {
response["code"] = http.StatusBadRequest
response["message"] = "Both old_name and new_name are required"
c.JSON(http.StatusBadRequest, response)
return
}
// 查找要重命名的电影
movie, exists := MovieDict[requestData.OldName]
if !exists {
response["code"] = http.StatusNotFound
response["message"] = "Movie not found"
c.JSON(http.StatusNotFound, response)
return
}
// 执行重命名
if err := movie.RenameVideo(requestData.NewName); err != nil {
response["code"] = http.StatusInternalServerError
response["message"] = "Failed to rename video: " + err.Error()
c.JSON(http.StatusInternalServerError, response)
return
}
// 更新全局字典
delete(MovieDict, requestData.OldName)
MovieDict[requestData.NewName] = movie
response["message"] = "Rename successful"
c.JSON(http.StatusOK, response)
}
// PostDelete 删除文件
func PostDelete(c *gin.Context) {
var requestData struct {
FileName string `json:"file_name"`
}
response := gin.H{
"code": http.StatusOK,
"message": "Success",
"data": nil,
}
if err := c.ShouldBindJSON(&requestData); err != nil {
response["code"] = http.StatusBadRequest
response["message"] = "Invalid request data: " + err.Error()
c.JSON(http.StatusBadRequest, response)
return
}
if requestData.FileName == "" {
response["code"] = http.StatusBadRequest
response["message"] = "file_name is required"
c.JSON(http.StatusBadRequest, response)
return
}
// 查找要删除的电影
movie, exists := MovieDict[requestData.FileName]
if !exists {
response["code"] = http.StatusNotFound
response["message"] = "Movie not found"
c.JSON(http.StatusNotFound, response)
return
}
// 执行删除
if err := movie.DeleteVideo(); err != nil {
response["code"] = http.StatusInternalServerError
response["message"] = "Failed to delete video: " + err.Error()
c.JSON(http.StatusInternalServerError, response)
return
}
// 从全局Movies切片中移除记录
MovieDictLock.Lock()
defer MovieDictLock.Unlock()
// 从MovieDict中删除
delete(MovieDict, requestData.FileName)
// 从Movies切片中移除记录
for i, m := range Movies {
if m.FileName == requestData.FileName {
// 移除切片中的元素
Movies = append(Movies[:i], Movies[i+1:]...)
break
}
}
response["message"] = "Delete successful"
c.JSON(http.StatusOK, response)
}