feat: 友链/书库/移动端导航/排行榜等多模块功能
新增模块: - 友链(friendlink)后端处理 + 前端管理页与友链板 - 书库(library):导入、章节、封面、阅读页、横竖版自适应 AdaptiveCoverSlot - 顶栏导航(header_nav)配置与 MobileTabBar/MobileRailDrawers 移动端抽屉 - 排行榜 service 测试、站点页面测试、时间线发布(timeline_release) 其它改动: - 后端 handlers/services 全量小幅调整 - 前端组件、库函数、URL/品牌/站点 URL 工具更新 - Lightbox 图片、MdEntries 条目卡、coverColor 派生色相等前端能力
This commit is contained in:
@@ -585,6 +585,35 @@ func (s *UploadService) CopyBackgroundFromMedia(userID, attachmentID uint) (stri
|
||||
return s.SaveBackground(f)
|
||||
}
|
||||
|
||||
// CopyImageFromMedia 把当前用户媒体库里的一张图复制一份新插图(落 uploads/images 并记一条本人附件)
|
||||
// 用于书籍封面等长期引用场景:与原图解耦,原图删除后副本仍可用
|
||||
func (s *UploadService) CopyImageFromMedia(userID, attachmentID uint) (*model.Attachment, error) {
|
||||
var att model.Attachment
|
||||
if err := s.db.Where("id = ? AND user_id = ?", attachmentID, userID).First(&att).Error; err != nil {
|
||||
return nil, errors.New("图片不存在或不属于你")
|
||||
}
|
||||
if strings.HasPrefix(att.URL, "/api/media/") && s.ops != nil {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
r, _, e := s.ops.OpenObject(ctx, RemoteObjectID(att.URL), true)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
defer r.Close()
|
||||
return s.SaveImage(userID, r)
|
||||
}
|
||||
abs, ok := s.safeUploadPath(att.URL)
|
||||
if !ok {
|
||||
return nil, errors.New("无效的图片地址")
|
||||
}
|
||||
f, err := os.Open(abs)
|
||||
if err != nil {
|
||||
return nil, errors.New("读取图片失败")
|
||||
}
|
||||
defer f.Close()
|
||||
return s.SaveImage(userID, f)
|
||||
}
|
||||
|
||||
// BackgroundFileExists 确认 URL 对应文件在 backgrounds 目录内
|
||||
func (s *UploadService) BackgroundFileExists(url string) bool {
|
||||
rel := BgRelPath(url)
|
||||
|
||||
Reference in New Issue
Block a user