mirror of
https://github.com/fish2018/GoComicMosaic.git
synced 2025-11-25 03:15:02 +08:00
update
This commit is contained in:
25
README.md
25
README.md
@@ -504,10 +504,22 @@ sudo systemctl status nginx
|
||||
- Teenage Mutant Ninja Turtles(忍者神龟)✅
|
||||
- Carmen Sandiego(大神偷卡门)✅
|
||||
- RWBY(红白黑黄)✅
|
||||
- Avatar: The Last Airbender(降世神通:最后的气宗)✅
|
||||
- Avatar: The Legend of Korra(降世神通:科拉传奇)✅
|
||||
- Bluey(布鲁伊)✅
|
||||
- Hilda(希尔达)✅
|
||||
- The Owl House(猫头鹰魔法社)✅
|
||||
- Clarence(小胖克莱伦斯 / 我爱阿噗)✅
|
||||
- Heroes of Pure Heart(猫猫:纯心之谷的英雄们)✅
|
||||
- Sym-Bionic Titan(合神泰坦)✅
|
||||
- Generator Rex(变形小雷 / 机械战士REX)✅
|
||||
- Di-Gata Defenders(迪卡塔卫士)✅
|
||||
- Over the Garden Wall(花园墙外)✅
|
||||
- The Dragon Prince(龙王子)✅
|
||||
- OK K.O.! Let's Be Heroes(成为英雄吧)✅
|
||||
- Bob's Burgers(开心汉堡店)
|
||||
- SpongeBob SquarePants(海绵宝宝)
|
||||
- Harley Quinn(哈莉·奎茵)
|
||||
- The Owl House(猫头鹰魔法社)
|
||||
- Guardians of Ga’Hoole(守护者)
|
||||
- Gravity Falls(怪诞小镇)
|
||||
- We Bare Bears(咱们裸熊)
|
||||
@@ -536,7 +548,6 @@ sudo systemctl status nginx
|
||||
- Ugly Americans(俗世乐土)
|
||||
- Primal(史前战纪)
|
||||
- Blue Eye Samurai(蓝眼武士)
|
||||
- Hilda(希尔达)
|
||||
- HouseBroken(一家之主)
|
||||
- Star vs. the Forces of Evil(星蝶公主)
|
||||
- The Great North(东倒西歪)
|
||||
@@ -544,7 +555,6 @@ sudo systemctl status nginx
|
||||
- House of Demons(恶魔之家)
|
||||
- The Amazing Digital Circus(神奇数字马戏团)
|
||||
- Summer Camp Island(夏令营岛)
|
||||
- OK K.O.! Let's Be Heroes(超级科学伙伴)
|
||||
- The Midnight Gospel(午夜福音)
|
||||
- Pantheon(万神殿)
|
||||
- Ten Year Old Tom(十岁的汤姆)
|
||||
@@ -557,7 +567,6 @@ sudo systemctl status nginx
|
||||
- My Adventures with Superman(我亲爱的怪物伙伴)
|
||||
- Ben 10(少年骇客)
|
||||
- She-Ra and the Princesses of Power(神勇战士)
|
||||
- Over the Garden Wall(花园墙外)
|
||||
- Central Park(中央公园)
|
||||
- The Age of the Chip and the Amazing Animals(奇波和神奇动物的时代)
|
||||
- Daria(拽妹黛薇儿)
|
||||
@@ -574,7 +583,6 @@ sudo systemctl status nginx
|
||||
- Johnny Bravo(强尼布拉沃)
|
||||
- Samurai Jack(武士杰克)
|
||||
- Star Wars: The Clone Wars(星球大战:克隆人战争)
|
||||
- Avatar: The Legend of Korra(科拉传奇)
|
||||
- Regular Show(普通秀)
|
||||
- Archer(间谍亚契)
|
||||
- Final Space(终空)
|
||||
@@ -585,8 +593,13 @@ sudo systemctl status nginx
|
||||
- Space Ghost Coast to Coast(太空幽灵海岸到海岸)
|
||||
|
||||
# 更新日志
|
||||
- 2020506051132
|
||||
- 202506061607
|
||||
✅ 优化悬浮按钮样式问题
|
||||
✅ 修复最近播放恢复播放失败问题
|
||||
✅ 新增的资源,如果没有批准任何图片和链接,则代表审核不通过,直接删除该条数据
|
||||
✅ 修复编辑资源时,将新上传的图片设置为海报失败问题
|
||||
|
||||
- 2020506051132
|
||||
✅ 增加golang版动态生成sitemap工具`sitemap-generator`,为将来容器化做准备
|
||||
✅ 允许通过环境变量指定assets和数据库路径,为将来容器化做准备
|
||||
✅ 自动判断vite.config.js中是否需要启用`base: '/static/',`,只有正式编译时启用,本地开发不会启用,避免每次编译手动修改一遍
|
||||
|
||||
@@ -519,7 +519,7 @@ body {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
left: -170%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
|
||||
@@ -506,13 +506,17 @@ export default {
|
||||
playHistory.value.splice(existingItemIndex, 1);
|
||||
}
|
||||
|
||||
// 获取当前数据源ID
|
||||
const currentDataSourceId = selectedDataSource.value || '';
|
||||
|
||||
// 添加到开头
|
||||
playHistory.value.unshift({
|
||||
id: item.id,
|
||||
title: item.title || '自定义流媒体',
|
||||
src: item.src,
|
||||
poster: item.poster || '',
|
||||
timestamp: new Date().getTime()
|
||||
timestamp: new Date().getTime(),
|
||||
dataSourceId: currentDataSourceId // 保存数据源ID
|
||||
});
|
||||
|
||||
// 限制历史记录数量
|
||||
@@ -530,6 +534,20 @@ export default {
|
||||
|
||||
// 播放历史记录中的项目
|
||||
const playHistoryItem = (item) => {
|
||||
// 先检查并切换到记录对应的数据源
|
||||
if (item.dataSourceId && item.dataSourceId !== selectedDataSource.value) {
|
||||
try {
|
||||
const dataSourceManager = getDataSourceManager();
|
||||
if (dataSourceManager.getAllDataSources()[item.dataSourceId]) {
|
||||
console.log(`切换到历史记录对应的数据源: ${item.dataSourceId}`);
|
||||
selectedDataSource.value = item.dataSourceId;
|
||||
dataSourceManager.setCurrentDataSource(item.dataSourceId);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('切换数据源失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.id) {
|
||||
// 这是预设的视频
|
||||
loadStreamById(item.id);
|
||||
|
||||
@@ -14,6 +14,7 @@ gobackend/
|
||||
│ ├── diagnostic/ # 诊断工具
|
||||
│ │ └── main.go # 数据库诊断程序
|
||||
│ └── test/ # 测试工具
|
||||
├── config/ # 配置文件
|
||||
├── internal/ # 内部包
|
||||
│ ├── models/ # 数据模型
|
||||
│ │ ├── models.go # 定义数据模型结构
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"dongman/internal/models"
|
||||
"dongman/internal/utils"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
@@ -8,35 +11,33 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
"strings"
|
||||
"encoding/json"
|
||||
"github.com/gin-gonic/gin"
|
||||
"time"
|
||||
|
||||
"dongman/internal/models"
|
||||
"dongman/internal/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// ApproveResource 审批资源 - 仅管理员可访问
|
||||
func ApproveResource(c *gin.Context) {
|
||||
// 获取路径参数
|
||||
resourceID, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
// 获取资源ID
|
||||
resourceID, errParse := strconv.Atoi(c.Param("id"))
|
||||
if errParse != nil {
|
||||
log.Printf("[ERROR] 无效的资源ID: %v", errParse)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的资源ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// 解析请求
|
||||
var approval models.ResourceApproval
|
||||
if err := c.ShouldBindJSON(&approval); err != nil {
|
||||
if errBind := c.ShouldBindJSON(&approval); errBind != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的请求参数"})
|
||||
return
|
||||
}
|
||||
|
||||
// 检查资源是否存在
|
||||
var resource models.Resource
|
||||
err = models.DB.Get(&resource, `SELECT * FROM resources WHERE id = ?`, resourceID)
|
||||
if err != nil {
|
||||
errGet := models.DB.Get(&resource, `SELECT * FROM resources WHERE id = ?`, resourceID)
|
||||
if errGet != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "资源未找到"})
|
||||
return
|
||||
}
|
||||
@@ -60,31 +61,42 @@ func ApproveResource(c *gin.Context) {
|
||||
// 保存所有新路径
|
||||
newImagePaths := make([]string, 0, len(approval.ApprovedImages))
|
||||
if strings.ToLower(string(approval.Status)) == strings.ToLower(string(models.ResourceStatusApproved)){
|
||||
// 检查是否没有批准任何图片和链接
|
||||
if len(approval.ApprovedImages) == 0 && len(approval.ApprovedLinks) == 0 {
|
||||
log.Printf("[INFO] 资源ID: %d 被批准但没有批准任何图片和链接,将直接删除该资源", resourceID)
|
||||
|
||||
// 删除资源
|
||||
_, errDelete := models.DB.Exec(`DELETE FROM resources WHERE id = ?`, resourceID)
|
||||
if errDelete != nil {
|
||||
log.Printf("[ERROR] 删除资源失败: %v", errDelete)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("删除资源失败: %v", errDelete)})
|
||||
return
|
||||
}
|
||||
|
||||
// 返回成功消息
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "资源已删除,因为没有批准任何图片和链接",
|
||||
"deleted": true,
|
||||
"resource_id": resourceID,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 移动已批准的图片
|
||||
if len(approval.ApprovedImages) > 0 {
|
||||
log.Printf("[DEBUG] 开始移动已批准的图片,资源ID: %d, 图片数量: %d", resource.ID, len(approval.ApprovedImages))
|
||||
log.Printf("[DEBUG] 原始图片路径: %v", approval.ApprovedImages)
|
||||
|
||||
// 获取工作目录
|
||||
workDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] 获取工作目录失败: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取工作目录失败"})
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] 当前工作目录: %s", workDir)
|
||||
|
||||
// 构建assets目录路径
|
||||
assetsDir := filepath.Join(workDir, "..", "assets")
|
||||
// 获取assets目录路径
|
||||
assetsDir := utils.GetAssetsDir()
|
||||
log.Printf("[DEBUG] Assets目录路径: %s", assetsDir)
|
||||
|
||||
// 创建目标目录
|
||||
imgsDir := filepath.Join(assetsDir, "imgs", fmt.Sprintf("%d", resourceID))
|
||||
log.Printf("[DEBUG] 创建目标目录: %s", imgsDir)
|
||||
if err := os.MkdirAll(imgsDir, 0755); err != nil {
|
||||
log.Printf("[ERROR] 创建目录失败: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("创建图片目录失败: %v", err)})
|
||||
if errMkdir := os.MkdirAll(imgsDir, 0755); errMkdir != nil {
|
||||
log.Printf("[ERROR] 创建目录失败: %v", errMkdir)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("创建图片目录失败: %v", errMkdir)})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -107,7 +119,7 @@ func ApproveResource(c *gin.Context) {
|
||||
log.Printf("[DEBUG] 移动图片: %s -> %s", sourcePath, destPath)
|
||||
|
||||
// 检查源文件是否存在
|
||||
if _, err := os.Stat(sourcePath); os.IsNotExist(err) {
|
||||
if _, errStat := os.Stat(sourcePath); os.IsNotExist(errStat) {
|
||||
log.Printf("[ERROR] 源文件不存在: %s", sourcePath)
|
||||
continue
|
||||
} else {
|
||||
@@ -115,40 +127,49 @@ func ApproveResource(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 确保目标目录存在
|
||||
err = os.MkdirAll(filepath.Dir(destPath), 0755)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] 创建目标目录失败: %v", err)
|
||||
errDir := os.MkdirAll(filepath.Dir(destPath), 0755)
|
||||
if errDir != nil {
|
||||
log.Printf("[ERROR] 创建目标目录失败: %v", errDir)
|
||||
continue
|
||||
}
|
||||
|
||||
// 移动文件(复制后删除)
|
||||
// 1. 复制文件
|
||||
sourceFile, err := os.Open(sourcePath)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] 打开源文件失败: %v", err)
|
||||
sourceFile, errOpen := os.Open(sourcePath)
|
||||
if errOpen != nil {
|
||||
log.Printf("[ERROR] 打开源文件失败: %v", errOpen)
|
||||
continue
|
||||
}
|
||||
|
||||
destFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] 创建目标文件失败: %v", err)
|
||||
sourceFile.Close()
|
||||
defer sourceFile.Close()
|
||||
|
||||
// 创建目标文件
|
||||
destFile, errCreate := os.Create(destPath)
|
||||
if errCreate != nil {
|
||||
log.Printf("[ERROR] 创建目标文件失败: %v", errCreate)
|
||||
continue
|
||||
}
|
||||
|
||||
defer destFile.Close()
|
||||
|
||||
// 复制内容
|
||||
bytesWritten, err := io.Copy(destFile, sourceFile)
|
||||
sourceFile.Close()
|
||||
destFile.Close()
|
||||
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] 复制文件内容失败: %v", err)
|
||||
_, errCopy := io.Copy(destFile, sourceFile)
|
||||
if errCopy != nil {
|
||||
log.Printf("[ERROR] 复制文件内容失败: %v", errCopy)
|
||||
continue
|
||||
}
|
||||
log.Printf("[DEBUG] 复制了 %d 字节数据", bytesWritten)
|
||||
|
||||
|
||||
// 关闭文件以确保所有内容都已写入
|
||||
errSource := sourceFile.Close()
|
||||
if errSource != nil {
|
||||
log.Printf("[ERROR] 关闭源文件失败: %v", errSource)
|
||||
}
|
||||
|
||||
errDest := destFile.Close()
|
||||
if errDest != nil {
|
||||
log.Printf("[ERROR] 关闭目标文件失败: %v", errDest)
|
||||
}
|
||||
|
||||
// 验证目标文件已创建
|
||||
if _, err := os.Stat(destPath); os.IsNotExist(err) {
|
||||
if _, errStat := os.Stat(destPath); os.IsNotExist(errStat) {
|
||||
log.Printf("[ERROR] 复制后目标文件不存在: %s", destPath)
|
||||
continue
|
||||
} else {
|
||||
@@ -156,11 +177,11 @@ func ApproveResource(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 2. 删除原文件
|
||||
if err := os.Remove(sourcePath); err != nil {
|
||||
log.Printf("[WARN] 删除源文件失败,将重试: %v", err)
|
||||
if errRemove := os.Remove(sourcePath); errRemove != nil {
|
||||
log.Printf("[WARN] 删除源文件失败,将重试: %v", errRemove)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
if err := os.Remove(sourcePath); err != nil {
|
||||
log.Printf("[ERROR] 第二次删除源文件失败: %v", err)
|
||||
if errRetry := os.Remove(sourcePath); errRetry != nil {
|
||||
log.Printf("[ERROR] 第二次删除源文件失败: %v", errRetry)
|
||||
} else {
|
||||
log.Printf("[DEBUG] 第二次尝试删除源文件成功")
|
||||
}
|
||||
@@ -269,7 +290,7 @@ func ApproveResource(c *gin.Context) {
|
||||
log.Printf("[DEBUG] 资源海报图片: %v", resource.PosterImage)
|
||||
|
||||
// approval_records插入审批记录
|
||||
result, err := models.DB.Exec(
|
||||
result, errInsert := models.DB.Exec(
|
||||
`INSERT INTO approval_records (
|
||||
resource_id, status, field_approvals, field_rejections,
|
||||
approved_images, rejected_images, poster_image, notes,
|
||||
@@ -283,18 +304,19 @@ func ApproveResource(c *gin.Context) {
|
||||
approvalRecord.CreatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("创建审批记录失败: %v", err)
|
||||
// 继续处理,不要因为审批记录创建失败而中断流程
|
||||
} else {
|
||||
id, _ := result.LastInsertId()
|
||||
log.Printf("已创建审批记录,ID: %d", id)
|
||||
}
|
||||
if errInsert != nil {
|
||||
log.Printf("创建审批记录失败: %v", errInsert)
|
||||
// 继续处理,不要因为审批记录创建失败而中断流程
|
||||
} else {
|
||||
id, _ := result.LastInsertId()
|
||||
log.Printf("已创建审批记录,ID: %d", id)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// resources 更新资源
|
||||
_, err = models.DB.Exec(
|
||||
var errUpdate error
|
||||
_, errUpdate = models.DB.Exec(
|
||||
`UPDATE resources SET
|
||||
status = ?, images = ?, poster_image = ?,
|
||||
approval_history = ?, updated_at = ?
|
||||
@@ -303,18 +325,18 @@ func ApproveResource(c *gin.Context) {
|
||||
resource.ApprovalHistory, resource.UpdatedAt, resource.ID,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] 更新资源失败: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("更新资源失败: %v", err)})
|
||||
if errUpdate != nil {
|
||||
log.Printf("[ERROR] 更新资源失败: %v", errUpdate)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("更新资源失败: %v", errUpdate)})
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("[INFO] 成功更新资源,ID: %d", resourceID)
|
||||
|
||||
// 再次从数据库获取资源,确保返回最新数据
|
||||
err = models.DB.Get(&resource, `SELECT * FROM resources WHERE id = ?`, resourceID)
|
||||
if err != nil {
|
||||
log.Printf("警告:获取更新后的资源失败,但资源已更新: %v", err)
|
||||
errGet = models.DB.Get(&resource, `SELECT * FROM resources WHERE id = ?`, resourceID)
|
||||
if errGet != nil {
|
||||
log.Printf("警告:获取更新后的资源失败,但资源已更新: %v", errGet)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, resource)
|
||||
@@ -437,26 +459,16 @@ func approveResourceSupplement(c *gin.Context, resourceID int, resource models.R
|
||||
log.Printf("[DEBUG] 开始移动已批准的补充图片,资源ID: %d, 图片数量: %d", resource.ID, len(approval.ApprovedImages))
|
||||
log.Printf("[DEBUG] 原始图片路径: %v", approval.ApprovedImages)
|
||||
|
||||
// 获取工作目录
|
||||
workDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] 获取工作目录失败: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取工作目录失败"})
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] 当前工作目录: %s", workDir)
|
||||
|
||||
// 构建assets目录路径
|
||||
assetsDir := filepath.Join(workDir, "..", "assets")
|
||||
// 获取assets目录路径
|
||||
assetsDir := utils.GetAssetsDir()
|
||||
log.Printf("[DEBUG] Assets目录路径: %s", assetsDir)
|
||||
|
||||
// 创建目标目录
|
||||
imgsDir := filepath.Join(assetsDir, "imgs", fmt.Sprintf("%d", resourceID))
|
||||
log.Printf("[DEBUG] 创建目标目录: %s", imgsDir)
|
||||
if err := os.MkdirAll(imgsDir, 0755); err != nil {
|
||||
log.Printf("[ERROR] 创建目录失败: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("创建图片目录失败: %v", err)})
|
||||
if errMkdir := os.MkdirAll(imgsDir, 0755); errMkdir != nil {
|
||||
log.Printf("[ERROR] 创建目录失败: %v", errMkdir)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("创建图片目录失败: %v", errMkdir)})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -479,7 +491,7 @@ func approveResourceSupplement(c *gin.Context, resourceID int, resource models.R
|
||||
log.Printf("[DEBUG] 移动图片: %s -> %s", sourcePath, destPath)
|
||||
|
||||
// 检查源文件是否存在
|
||||
if _, err := os.Stat(sourcePath); os.IsNotExist(err) {
|
||||
if _, errStat := os.Stat(sourcePath); os.IsNotExist(errStat) {
|
||||
log.Printf("[ERROR] 源文件不存在: %s", sourcePath)
|
||||
continue
|
||||
} else {
|
||||
@@ -487,40 +499,49 @@ func approveResourceSupplement(c *gin.Context, resourceID int, resource models.R
|
||||
}
|
||||
|
||||
// 确保目标目录存在
|
||||
err = os.MkdirAll(filepath.Dir(destPath), 0755)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] 创建目标目录失败: %v", err)
|
||||
errDir := os.MkdirAll(filepath.Dir(destPath), 0755)
|
||||
if errDir != nil {
|
||||
log.Printf("[ERROR] 创建目标目录失败: %v", errDir)
|
||||
continue
|
||||
}
|
||||
|
||||
// 移动文件(复制后删除)
|
||||
// 1. 复制文件
|
||||
sourceFile, err := os.Open(sourcePath)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] 打开源文件失败: %v", err)
|
||||
sourceFile, errOpen := os.Open(sourcePath)
|
||||
if errOpen != nil {
|
||||
log.Printf("[ERROR] 打开源文件失败: %v", errOpen)
|
||||
continue
|
||||
}
|
||||
|
||||
destFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] 创建目标文件失败: %v", err)
|
||||
sourceFile.Close()
|
||||
defer sourceFile.Close()
|
||||
|
||||
// 创建目标文件
|
||||
destFile, errCreate := os.Create(destPath)
|
||||
if errCreate != nil {
|
||||
log.Printf("[ERROR] 创建目标文件失败: %v", errCreate)
|
||||
continue
|
||||
}
|
||||
|
||||
defer destFile.Close()
|
||||
|
||||
// 复制内容
|
||||
bytesWritten, err := io.Copy(destFile, sourceFile)
|
||||
sourceFile.Close()
|
||||
destFile.Close()
|
||||
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] 复制文件内容失败: %v", err)
|
||||
_, errCopy := io.Copy(destFile, sourceFile)
|
||||
if errCopy != nil {
|
||||
log.Printf("[ERROR] 复制文件内容失败: %v", errCopy)
|
||||
continue
|
||||
}
|
||||
log.Printf("[DEBUG] 复制了 %d 字节数据", bytesWritten)
|
||||
|
||||
|
||||
// 关闭文件以确保所有内容都已写入
|
||||
errSource := sourceFile.Close()
|
||||
if errSource != nil {
|
||||
log.Printf("[ERROR] 关闭源文件失败: %v", errSource)
|
||||
}
|
||||
|
||||
errDest := destFile.Close()
|
||||
if errDest != nil {
|
||||
log.Printf("[ERROR] 关闭目标文件失败: %v", errDest)
|
||||
}
|
||||
|
||||
// 验证目标文件已创建
|
||||
if _, err := os.Stat(destPath); os.IsNotExist(err) {
|
||||
if _, errStat := os.Stat(destPath); os.IsNotExist(errStat) {
|
||||
log.Printf("[ERROR] 复制后目标文件不存在: %s", destPath)
|
||||
continue
|
||||
} else {
|
||||
@@ -528,11 +549,11 @@ func approveResourceSupplement(c *gin.Context, resourceID int, resource models.R
|
||||
}
|
||||
|
||||
// 2. 删除原文件
|
||||
if err := os.Remove(sourcePath); err != nil {
|
||||
log.Printf("[WARN] 删除源文件失败,将重试: %v", err)
|
||||
if errRemove := os.Remove(sourcePath); errRemove != nil {
|
||||
log.Printf("[WARN] 删除源文件失败,将重试: %v", errRemove)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
if err := os.Remove(sourcePath); err != nil {
|
||||
log.Printf("[ERROR] 第二次删除源文件失败: %v", err)
|
||||
if errRetry := os.Remove(sourcePath); errRetry != nil {
|
||||
log.Printf("[ERROR] 第二次删除源文件失败: %v", errRetry)
|
||||
} else {
|
||||
log.Printf("[DEBUG] 第二次尝试删除源文件成功")
|
||||
}
|
||||
@@ -655,7 +676,8 @@ func approveResourceSupplement(c *gin.Context, resourceID int, resource models.R
|
||||
}
|
||||
|
||||
// 更新数据库中的资源信息
|
||||
_, err := models.DB.Exec(
|
||||
var errUpdate error
|
||||
_, errUpdate = models.DB.Exec(
|
||||
`UPDATE resources SET
|
||||
images = ?, poster_image = ?, links = ?,
|
||||
updated_at = ?
|
||||
@@ -664,9 +686,9 @@ func approveResourceSupplement(c *gin.Context, resourceID int, resource models.R
|
||||
time.Now(), resourceID,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] 更新资源图片失败: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("更新资源图片失败: %v", err)})
|
||||
if errUpdate != nil {
|
||||
log.Printf("[ERROR] 更新资源图片失败: %v", errUpdate)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("更新资源图片失败: %v", errUpdate)})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -679,22 +701,23 @@ func approveResourceSupplement(c *gin.Context, resourceID int, resource models.R
|
||||
resource.UpdatedAt = time.Now()
|
||||
|
||||
// 更新资源
|
||||
_, err := models.DB.Exec(
|
||||
var errUpdate error
|
||||
_, errUpdate = models.DB.Exec(
|
||||
`UPDATE resources SET is_supplement_approval = 'True', supplement = NULL, updated_at = ? WHERE id = ?`,
|
||||
resource.UpdatedAt, resourceID,
|
||||
)
|
||||
|
||||
// 检查错误
|
||||
if err != nil {
|
||||
log.Printf("更新资源is_supplement_approval失败: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("更新资源is_supplement_approval失败: %v", err)})
|
||||
if errUpdate != nil {
|
||||
log.Printf("更新资源is_supplement_approval失败: %v", errUpdate)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("更新资源is_supplement_approval失败: %v", errUpdate)})
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("资源ID: %d 的is_supplement_approval已成功更新为True,supplement已清空", resourceID)
|
||||
|
||||
// 插入审批记录
|
||||
result, err := models.DB.Exec(
|
||||
result, errInsert := models.DB.Exec(
|
||||
`INSERT INTO approval_records (
|
||||
resource_id, status, field_approvals, field_rejections,
|
||||
approved_images, rejected_images, poster_image, notes,
|
||||
@@ -709,8 +732,8 @@ func approveResourceSupplement(c *gin.Context, resourceID int, resource models.R
|
||||
)
|
||||
|
||||
|
||||
if err != nil {
|
||||
log.Printf("创建补充内容审批记录失败: %v", err)
|
||||
if errInsert != nil {
|
||||
log.Printf("创建补充内容审批记录失败: %v", errInsert)
|
||||
// 继续处理,不要因为审批记录创建失败而中断流程
|
||||
} else {
|
||||
id, _ := result.LastInsertId()
|
||||
@@ -720,9 +743,9 @@ func approveResourceSupplement(c *gin.Context, resourceID int, resource models.R
|
||||
|
||||
// 返回更新后的资源
|
||||
var updatedResource models.Resource
|
||||
err = models.DB.Get(&updatedResource, `SELECT * FROM resources WHERE id = ?`, resourceID)
|
||||
if err != nil {
|
||||
log.Printf("警告:获取更新后的资源失败,但资源已更新: %v", err)
|
||||
errGet := models.DB.Get(&updatedResource, `SELECT * FROM resources WHERE id = ?`, resourceID)
|
||||
if errGet != nil {
|
||||
log.Printf("警告:获取更新后的资源失败,但资源已更新: %v", errGet)
|
||||
c.JSON(http.StatusOK, resource)
|
||||
} else {
|
||||
c.JSON(http.StatusOK, updatedResource)
|
||||
@@ -763,18 +786,18 @@ func convertImagesToWebP(imagePaths []string) {
|
||||
}
|
||||
|
||||
// 将路径转换为JSON字符串
|
||||
pathsJSON, err := json.Marshal(adjustedPaths)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] 无法将图片路径转为JSON: %v", err)
|
||||
pathsJSON, errJSON := json.Marshal(adjustedPaths)
|
||||
if errJSON != nil {
|
||||
log.Printf("[ERROR] 无法将图片路径转为JSON: %v", errJSON)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] 准备调用WebP转换工具,处理以下图片: %s", string(pathsJSON))
|
||||
|
||||
// 调用WebP转换工具
|
||||
resultPaths, err := utils.ConvertMultipleImages(string(pathsJSON), true, false, 4)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] 转换WebP过程中发生错误: %v", err)
|
||||
resultPaths, errConvert := utils.ConvertMultipleImages(string(pathsJSON), true, false, 4)
|
||||
if errConvert != nil {
|
||||
log.Printf("[ERROR] 转换WebP过程中发生错误: %v", errConvert)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -785,9 +808,9 @@ func convertImagesToWebP(imagePaths []string) {
|
||||
// DeleteApprovalRecord 删除审批记录 - 仅管理员可访问
|
||||
func DeleteApprovalRecord(c *gin.Context) {
|
||||
// 获取路径参数
|
||||
recordID, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
log.Printf("解析审批记录ID失败: %v, 参数: %s", err, c.Param("id"))
|
||||
recordID, errParse := strconv.Atoi(c.Param("id"))
|
||||
if errParse != nil {
|
||||
log.Printf("解析审批记录ID失败: %v, 参数: %s", errParse, c.Param("id"))
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的审批记录ID"})
|
||||
return
|
||||
}
|
||||
@@ -796,9 +819,9 @@ func DeleteApprovalRecord(c *gin.Context) {
|
||||
|
||||
// 检查记录是否存在
|
||||
var record models.ApprovalRecord
|
||||
err = models.DB.Get(&record, `SELECT * FROM approval_records WHERE id = ?`, recordID)
|
||||
if err != nil {
|
||||
log.Printf("未找到ID为%d的审批记录: %v", recordID, err)
|
||||
errGet := models.DB.Get(&record, `SELECT * FROM approval_records WHERE id = ?`, recordID)
|
||||
if errGet != nil {
|
||||
log.Printf("未找到ID为%d的审批记录: %v", recordID, errGet)
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "未找到审批记录"})
|
||||
return
|
||||
}
|
||||
@@ -806,17 +829,17 @@ func DeleteApprovalRecord(c *gin.Context) {
|
||||
log.Printf("找到ID为%d的审批记录,资源ID: %d", recordID, record.ResourceID)
|
||||
|
||||
// 删除记录
|
||||
result, err := models.DB.Exec(`DELETE FROM approval_records WHERE id = ?`, recordID)
|
||||
if err != nil {
|
||||
log.Printf("删除ID为%d的审批记录失败: %v", recordID, err)
|
||||
result, errDelete := models.DB.Exec(`DELETE FROM approval_records WHERE id = ?`, recordID)
|
||||
if errDelete != nil {
|
||||
log.Printf("删除ID为%d的审批记录失败: %v", recordID, errDelete)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "删除审批记录失败"})
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否真的删除了记录
|
||||
affected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
log.Printf("获取影响行数失败: %v", err)
|
||||
affected, errAffected := result.RowsAffected()
|
||||
if errAffected != nil {
|
||||
log.Printf("获取影响行数失败: %v", errAffected)
|
||||
} else if affected == 0 {
|
||||
log.Printf("ID为%d的审批记录未被删除", recordID)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "删除审批记录失败,没有记录被删除"})
|
||||
@@ -830,23 +853,23 @@ func DeleteApprovalRecord(c *gin.Context) {
|
||||
// SupplementResource 为资源添加补充内容
|
||||
func SupplementResource(c *gin.Context) {
|
||||
// 获取路径参数
|
||||
resourceID, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
resourceID, errParse := strconv.Atoi(c.Param("id"))
|
||||
if errParse != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的资源ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// 解析请求
|
||||
var supplement models.SupplementCreate
|
||||
if err := c.ShouldBindJSON(&supplement); err != nil {
|
||||
if errBind := c.ShouldBindJSON(&supplement); errBind != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的请求参数"})
|
||||
return
|
||||
}
|
||||
|
||||
// 检查资源是否存在并且是已批准的
|
||||
var resource models.Resource
|
||||
err = models.DB.Get(&resource, `SELECT * FROM resources WHERE id = ?`, resourceID)
|
||||
if err != nil {
|
||||
errGet := models.DB.Get(&resource, `SELECT * FROM resources WHERE id = ?`, resourceID)
|
||||
if errGet != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "资源未找到"})
|
||||
return
|
||||
}
|
||||
@@ -927,13 +950,13 @@ func SupplementResource(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 更新资源,添加补充内容
|
||||
_, err = models.DB.Exec(
|
||||
_, errUpdate := models.DB.Exec(
|
||||
`UPDATE resources SET supplement = ?, is_supplement_approval = ?, updated_at = ? WHERE id = ?`,
|
||||
supplementData, false, time.Now(), resourceID,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("添加补充内容失败: %v", err)})
|
||||
if errUpdate != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("添加补充内容失败: %v", errUpdate)})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -956,13 +979,13 @@ func SupplementResource(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 更新资源,添加补充内容
|
||||
_, err = models.DB.Exec(
|
||||
_, errUpdate := models.DB.Exec(
|
||||
`UPDATE resources SET supplement = ?, is_supplement_approval = ?, updated_at = ? WHERE id = ?`,
|
||||
supplementData, false, time.Now(), resourceID,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("添加补充内容失败: %v", err)})
|
||||
if errUpdate != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("添加补充内容失败: %v", errUpdate)})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -976,16 +999,16 @@ func SupplementResource(c *gin.Context) {
|
||||
// GetResourceSupplement 获取资源的补充内容 - 仅管理员可访问
|
||||
func GetResourceSupplement(c *gin.Context) {
|
||||
// 获取路径参数
|
||||
resourceID, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
resourceID, errParse := strconv.Atoi(c.Param("id"))
|
||||
if errParse != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的资源ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// 查询资源
|
||||
var resource models.Resource
|
||||
err = models.DB.Get(&resource, `SELECT * FROM resources WHERE id = ?`, resourceID)
|
||||
if err != nil {
|
||||
errGet := models.DB.Get(&resource, `SELECT * FROM resources WHERE id = ?`, resourceID)
|
||||
if errGet != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "资源未找到"})
|
||||
return
|
||||
}
|
||||
@@ -1006,10 +1029,10 @@ func GetPendingSupplementResources(c *gin.Context) {
|
||||
|
||||
// 查询所有包含补充内容的资源
|
||||
var resources []models.Resource
|
||||
err := models.DB.Select(&resources,
|
||||
errSelect := models.DB.Select(&resources,
|
||||
`SELECT * FROM resources WHERE supplement IS NOT NULL LIMIT ? OFFSET ?`,
|
||||
limit, skip)
|
||||
if err != nil {
|
||||
if errSelect != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "查询待审批补充内容资源失败"})
|
||||
return
|
||||
}
|
||||
@@ -1048,8 +1071,8 @@ func DeleteApprovalRecords(c *gin.Context) {
|
||||
IDs []int `json:"ids" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
log.Printf("解析请求体失败: %v", err)
|
||||
if errBind := c.ShouldBindJSON(&request); errBind != nil {
|
||||
log.Printf("解析请求体失败: %v", errBind)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的请求参数"})
|
||||
return
|
||||
}
|
||||
@@ -1068,23 +1091,23 @@ func DeleteApprovalRecords(c *gin.Context) {
|
||||
for _, id := range request.IDs {
|
||||
// 检查记录是否存在
|
||||
var count int
|
||||
err := models.DB.Get(&count, `SELECT COUNT(*) FROM approval_records WHERE id = ?`, id)
|
||||
if err != nil || count == 0 {
|
||||
errCount := models.DB.Get(&count, `SELECT COUNT(*) FROM approval_records WHERE id = ?`, id)
|
||||
if errCount != nil || count == 0 {
|
||||
log.Printf("未找到ID为%d的审批记录", id)
|
||||
failedIDs = append(failedIDs, id)
|
||||
continue
|
||||
}
|
||||
|
||||
// 删除记录
|
||||
result, err := models.DB.Exec(`DELETE FROM approval_records WHERE id = ?`, id)
|
||||
if err != nil {
|
||||
log.Printf("删除ID为%d的审批记录失败: %v", id, err)
|
||||
result, errDelete := models.DB.Exec(`DELETE FROM approval_records WHERE id = ?`, id)
|
||||
if errDelete != nil {
|
||||
log.Printf("删除ID为%d的审批记录失败: %v", id, errDelete)
|
||||
failedIDs = append(failedIDs, id)
|
||||
continue
|
||||
}
|
||||
|
||||
affected, err := result.RowsAffected()
|
||||
if err != nil || affected == 0 {
|
||||
affected, errAffected := result.RowsAffected()
|
||||
if errAffected != nil || affected == 0 {
|
||||
log.Printf("ID为%d的审批记录未被删除", id)
|
||||
failedIDs = append(failedIDs, id)
|
||||
continue
|
||||
@@ -1110,9 +1133,9 @@ func GetApprovalRecords(c *gin.Context) {
|
||||
|
||||
// 获取审批记录总数
|
||||
var count int
|
||||
err := models.DB.Get(&count, "SELECT COUNT(*) FROM approval_records")
|
||||
if err != nil {
|
||||
log.Printf("获取审批记录总数失败: %v", err)
|
||||
errCount := models.DB.Get(&count, "SELECT COUNT(*) FROM approval_records")
|
||||
if errCount != nil {
|
||||
log.Printf("获取审批记录总数失败: %v", errCount)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取审批记录总数失败"})
|
||||
return
|
||||
}
|
||||
@@ -1136,9 +1159,9 @@ func GetApprovalRecords(c *gin.Context) {
|
||||
LIMIT ? OFFSET ?
|
||||
`
|
||||
|
||||
rows, err := models.DB.Queryx(query, limit, skip)
|
||||
if err != nil {
|
||||
log.Printf("查询审批记录失败: %v", err)
|
||||
rows, errQuery := models.DB.Queryx(query, limit, skip)
|
||||
if errQuery != nil {
|
||||
log.Printf("查询审批记录失败: %v", errQuery)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "查询审批记录失败"})
|
||||
return
|
||||
}
|
||||
@@ -1156,15 +1179,15 @@ func GetApprovalRecords(c *gin.Context) {
|
||||
records := []ApprovalRecordResponse{}
|
||||
for rows.Next() {
|
||||
var record ApprovalRecordResponse
|
||||
if err := rows.StructScan(&record); err != nil {
|
||||
log.Printf("扫描审批记录失败: %v", err)
|
||||
if errScan := rows.StructScan(&record); errScan != nil {
|
||||
log.Printf("扫描审批记录失败: %v", errScan)
|
||||
continue
|
||||
}
|
||||
records = append(records, record)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
log.Printf("遍历审批记录结果集失败: %v", err)
|
||||
if errRows := rows.Err(); errRows != nil {
|
||||
log.Printf("遍历审批记录结果集失败: %v", errRows)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "处理审批记录失败"})
|
||||
return
|
||||
}
|
||||
@@ -1179,27 +1202,27 @@ func GetApprovalRecords(c *gin.Context) {
|
||||
// GetResourceApprovalRecords 获取单个资源的审批记录 - 仅管理员可访问
|
||||
func GetResourceApprovalRecords(c *gin.Context) {
|
||||
// 获取资源ID
|
||||
resourceID, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
log.Printf("无效的资源ID: %v", err)
|
||||
resourceID, errParse := strconv.Atoi(c.Param("id"))
|
||||
if errParse != nil {
|
||||
log.Printf("无效的资源ID: %v", errParse)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的资源ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// 检查资源是否存在
|
||||
var resource models.Resource
|
||||
err = models.DB.Get(&resource, "SELECT * FROM resources WHERE id = ?", resourceID)
|
||||
if err != nil {
|
||||
log.Printf("资源未找到: %v", err)
|
||||
errGet := models.DB.Get(&resource, "SELECT * FROM resources WHERE id = ?", resourceID)
|
||||
if errGet != nil {
|
||||
log.Printf("资源未找到: %v", errGet)
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "资源未找到"})
|
||||
return
|
||||
}
|
||||
|
||||
// 查询该资源的审批记录
|
||||
var records []models.ApprovalRecord
|
||||
err = models.DB.Select(&records, "SELECT * FROM approval_records WHERE resource_id = ? ORDER BY created_at DESC", resourceID)
|
||||
if err != nil {
|
||||
log.Printf("查询资源审批记录失败: %v", err)
|
||||
errSelect := models.DB.Select(&records, "SELECT * FROM approval_records WHERE resource_id = ? ORDER BY created_at DESC", resourceID)
|
||||
if errSelect != nil {
|
||||
log.Printf("查询资源审批记录失败: %v", errSelect)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "查询资源审批记录失败"})
|
||||
return
|
||||
}
|
||||
@@ -1209,4 +1232,4 @@ func GetResourceApprovalRecords(c *gin.Context) {
|
||||
"resource": resource,
|
||||
"records": records,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,6 +560,17 @@ func UpdateResource(c *gin.Context) {
|
||||
log.Printf("处理图片更新,收到 %d 张图片", len(resourceUpdate.Images))
|
||||
// 检查图片是否在临时目录中,如果是则移动到永久目录
|
||||
imagesToMove := make([]string, 0)
|
||||
var posterImageInUpload bool
|
||||
var posterImageOriginalPath string
|
||||
|
||||
// 检查海报图片是否在待上传图片中
|
||||
if resourceUpdate.PosterImage != nil && *resourceUpdate.PosterImage != "" &&
|
||||
strings.Contains(*resourceUpdate.PosterImage, "/assets/uploads/") {
|
||||
posterImageInUpload = true
|
||||
posterImageOriginalPath = *resourceUpdate.PosterImage
|
||||
log.Printf("海报图片在上传图片中: %s", posterImageOriginalPath)
|
||||
}
|
||||
|
||||
for _, img := range resourceUpdate.Images {
|
||||
// 检查图片是否在uploads目录中
|
||||
if strings.Contains(img, "/assets/uploads/") {
|
||||
@@ -579,6 +590,21 @@ func UpdateResource(c *gin.Context) {
|
||||
}
|
||||
log.Printf("图片移动完成,新路径: %v", newImagePaths)
|
||||
|
||||
// 如果海报图片在待移动图片中,更新其路径
|
||||
if posterImageInUpload {
|
||||
// 在移动后的图片中查找对应海报的新路径
|
||||
for i, oldPath := range imagesToMove {
|
||||
if oldPath == posterImageOriginalPath {
|
||||
if i < len(newImagePaths) {
|
||||
newPosterPath := newImagePaths[i]
|
||||
log.Printf("更新海报图片路径: %s -> %s", posterImageOriginalPath, newPosterPath)
|
||||
resource.PosterImage = &newPosterPath
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新图片路径(保留不需要移动的图片)
|
||||
finalImages := make([]string, 0)
|
||||
|
||||
@@ -598,6 +624,19 @@ func UpdateResource(c *gin.Context) {
|
||||
// 发生错误时继续使用原始图片
|
||||
} else {
|
||||
finalImages = webpImages
|
||||
|
||||
// 如果海报图片被转换为WebP,也需要更新海报路径
|
||||
if posterImageInUpload && resource.PosterImage != nil {
|
||||
originalPosterPath := *resource.PosterImage
|
||||
for i, oldPath := range finalImages {
|
||||
if oldPath == originalPosterPath && i < len(webpImages) {
|
||||
webpPosterPath := webpImages[i]
|
||||
log.Printf("更新海报图片WebP路径: %s -> %s", originalPosterPath, webpPosterPath)
|
||||
resource.PosterImage = &webpPosterPath
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource.Images = finalImages
|
||||
@@ -616,33 +655,19 @@ func UpdateResource(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// 处理海报图片更新
|
||||
if resourceUpdate.PosterImage != nil {
|
||||
// 处理海报图片更新,但仅当它不是来自上述已处理的上传图片
|
||||
if resourceUpdate.PosterImage != nil && !strings.Contains(*resourceUpdate.PosterImage, "/assets/uploads/") {
|
||||
log.Printf("处理海报图片更新: %s", *resourceUpdate.PosterImage)
|
||||
if *resourceUpdate.PosterImage != "" {
|
||||
// 检查海报图片是否在临时目录中
|
||||
if strings.Contains(*resourceUpdate.PosterImage, "/assets/uploads/") {
|
||||
log.Printf("海报图片需要移动: %s", *resourceUpdate.PosterImage)
|
||||
// 移动海报图片到永久目录
|
||||
newPosterPath, err := utils.MoveApprovedImage(resourceID, *resourceUpdate.PosterImage)
|
||||
if err != nil {
|
||||
log.Printf("移动海报图片失败: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("移动海报图片失败: %v", err)})
|
||||
return
|
||||
}
|
||||
log.Printf("海报图片移动完成,新路径: %s", newPosterPath)
|
||||
resource.PosterImage = &newPosterPath
|
||||
} else {
|
||||
log.Printf("海报图片无需移动")
|
||||
resource.PosterImage = resourceUpdate.PosterImage
|
||||
}
|
||||
// 无需再次移动已经处理过的上传图片
|
||||
resource.PosterImage = resourceUpdate.PosterImage
|
||||
} else {
|
||||
log.Printf("清除海报图片设置")
|
||||
resource.PosterImage = resourceUpdate.PosterImage
|
||||
}
|
||||
updated = true
|
||||
} else {
|
||||
log.Printf("未更新海报图片")
|
||||
log.Printf("海报图片已在图片处理逻辑中处理或未更新")
|
||||
}
|
||||
|
||||
if resourceUpdate.Links != nil {
|
||||
|
||||
@@ -4,13 +4,13 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"dongman/internal/utils"
|
||||
)
|
||||
|
||||
// DB 是全局数据库连接
|
||||
@@ -75,16 +75,10 @@ CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
||||
|
||||
// InitDB 初始化数据库连接
|
||||
func InitDB() (*sqlx.DB, error) {
|
||||
// 获取当前工作目录
|
||||
workDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("获取工作目录失败: %w", err)
|
||||
}
|
||||
|
||||
// 数据库文件路径
|
||||
dbPath := filepath.Join(workDir, "resource_hub.db")
|
||||
log.Printf("使用数据库: %s", dbPath)
|
||||
|
||||
// 从utils包获取数据库路径
|
||||
dbPath := utils.GetDbPath()
|
||||
log.Printf("连接数据库: %s", dbPath)
|
||||
|
||||
// 连接SQLite数据库
|
||||
db, err := sqlx.Connect("sqlite3", fmt.Sprintf("file:%s?_journal=WAL&_foreign_keys=on", dbPath))
|
||||
if err != nil {
|
||||
@@ -161,15 +155,9 @@ func RestoreImagesPath() error {
|
||||
return fmt.Errorf("查询资源失败: %w", err)
|
||||
}
|
||||
|
||||
// 获取工作目录
|
||||
workDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取工作目录失败: %w", err)
|
||||
}
|
||||
|
||||
// 构建assets目录路径
|
||||
assetsDir := filepath.Join(workDir, "..", "assets")
|
||||
log.Printf("assets目录: %s", assetsDir)
|
||||
// 获取资源目录
|
||||
assetsDir := utils.GetAssetsDir()
|
||||
log.Printf("资源目录: %s", assetsDir)
|
||||
|
||||
// 扫描所有图片文件
|
||||
allImages := make(map[string]string)
|
||||
|
||||
73
gobackend/internal/utils/config.go
Normal file
73
gobackend/internal/utils/config.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var (
|
||||
// 全局配置变量
|
||||
DbPath string
|
||||
AssetsDir string
|
||||
)
|
||||
|
||||
// 初始化配置
|
||||
func init() {
|
||||
// 初始化数据库路径
|
||||
if envPath := os.Getenv("DB_PATH"); envPath != "" {
|
||||
DbPath = envPath
|
||||
log.Printf("使用环境变量指定的数据库路径: %s", DbPath)
|
||||
} else {
|
||||
// 获取当前工作目录
|
||||
workDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Printf("获取工作目录失败: %v,使用默认路径", err)
|
||||
workDir = "."
|
||||
}
|
||||
|
||||
// 使用默认数据库文件路径
|
||||
DbPath = filepath.Join(workDir, "resource_hub.db")
|
||||
log.Printf("使用默认数据库路径: %s", DbPath)
|
||||
}
|
||||
|
||||
// 初始化资源目录
|
||||
if envPath := os.Getenv("ASSETS_PATH"); envPath != "" {
|
||||
AssetsDir = envPath
|
||||
log.Printf("使用环境变量指定的资源目录: %s", AssetsDir)
|
||||
} else {
|
||||
// 获取当前工作目录
|
||||
workDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Printf("获取工作目录失败: %v,使用默认路径", err)
|
||||
workDir = "."
|
||||
}
|
||||
|
||||
// 使用默认资源目录路径
|
||||
AssetsDir = filepath.Join(workDir, "..", "assets")
|
||||
log.Printf("使用默认资源目录: %s", AssetsDir)
|
||||
}
|
||||
|
||||
// 确保目录存在
|
||||
ensureDirExists(filepath.Dir(DbPath))
|
||||
ensureDirExists(AssetsDir)
|
||||
ensureDirExists(filepath.Join(AssetsDir, "uploads"))
|
||||
ensureDirExists(filepath.Join(AssetsDir, "imgs"))
|
||||
}
|
||||
|
||||
// 确保目录存在
|
||||
func ensureDirExists(dir string) {
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
log.Printf("创建目录失败 %s: %v", dir, err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetAssetsDir 获取资源目录路径
|
||||
func GetAssetsDir() string {
|
||||
return AssetsDir
|
||||
}
|
||||
|
||||
// GetDbPath 获取数据库路径
|
||||
func GetDbPath() string {
|
||||
return DbPath
|
||||
}
|
||||
@@ -71,20 +71,14 @@ func SaveUploadedFile(file io.Reader, filename string) (string, error) {
|
||||
return filepath.Join("/assets/uploads", time.Now().Format("20060102"), uniqueFilename), nil
|
||||
}
|
||||
|
||||
// MoveApprovedImages 将图片从uploads目录移动到imgs/resourceID目录
|
||||
// MoveApprovedImages 移动已批准的图片到资源目录
|
||||
func MoveApprovedImages(resourceID int, imagePaths []string) ([]string, error) {
|
||||
if len(imagePaths) == 0 {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
// 获取工作目录
|
||||
workDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("获取工作目录失败: %w", err)
|
||||
}
|
||||
|
||||
// 构建assets目录路径
|
||||
assetsDir := filepath.Join(workDir, "..", "assets")
|
||||
// 获取资源目录
|
||||
assetsDir := GetAssetsDir()
|
||||
|
||||
// 创建目标目录
|
||||
imgsDir := filepath.Join(assetsDir, "imgs", fmt.Sprintf("%d", resourceID))
|
||||
@@ -138,14 +132,8 @@ func MoveApprovedImage(resourceID int, imagePath string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// 获取工作目录
|
||||
workDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("获取工作目录失败: %w", err)
|
||||
}
|
||||
|
||||
// 构建assets目录路径
|
||||
assetsDir := filepath.Join(workDir, "..", "assets")
|
||||
// 获取资源目录
|
||||
assetsDir := GetAssetsDir()
|
||||
|
||||
// 创建目标目录
|
||||
imgsDir := filepath.Join(assetsDir, "imgs", fmt.Sprintf("%d", resourceID))
|
||||
@@ -227,14 +215,8 @@ func moveFile(src, dst string) error {
|
||||
|
||||
// ensureUploadDir 确保上传目录存在
|
||||
func ensureUploadDir() (string, error) {
|
||||
// 获取工作目录
|
||||
workDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("获取工作目录失败: %w", err)
|
||||
}
|
||||
|
||||
// 构建assets目录路径
|
||||
assetsDir := filepath.Join(workDir, "..", "assets")
|
||||
// 获取资源目录
|
||||
assetsDir := GetAssetsDir()
|
||||
|
||||
// 按日期创建上传目录
|
||||
dateDir := time.Now().Format("20060102")
|
||||
|
||||
Reference in New Issue
Block a user