feat: 媒体库添加手动色情标记功能,默认分页改为10条
This commit is contained in:
@@ -89,6 +89,15 @@
|
|||||||
<span v-else class="muted">-</span>
|
<span v-else class="muted">-</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column label="色情标记" width="100" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-switch
|
||||||
|
:value="scope.row.manualNsfw === 'Y'"
|
||||||
|
active-color="#F56C6C"
|
||||||
|
@change="handleManualNsfwChange(scope.row)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="codec" label="编码" width="120" align="center">
|
<el-table-column prop="codec" label="编码" width="120" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span class="muted" v-if="!scope.row.codec">-</span>
|
<span class="muted" v-if="!scope.row.codec">-</span>
|
||||||
@@ -157,7 +166,7 @@ export default {
|
|||||||
formatOptions: [],
|
formatOptions: [],
|
||||||
query: {
|
query: {
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 20,
|
pageSize: 10,
|
||||||
mediaType: '',
|
mediaType: '',
|
||||||
orientation: '',
|
orientation: '',
|
||||||
resolution: '',
|
resolution: '',
|
||||||
@@ -240,6 +249,15 @@ export default {
|
|||||||
d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) +
|
d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) +
|
||||||
' ' + pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + pad(d.getSeconds())
|
' ' + pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + pad(d.getSeconds())
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
async handleManualNsfwChange(row) {
|
||||||
|
const newValue = row.manualNsfw === 'Y' ? 'N' : 'Y'
|
||||||
|
try {
|
||||||
|
await request.put(`/api/media/${row.id}/manual-nsfw`, { value: newValue })
|
||||||
|
row.manualNsfw = newValue
|
||||||
|
} catch (e) {
|
||||||
|
// 拦截器已提示
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,6 +137,34 @@ func (c *MediaController) Preview(ctx *gin.Context) {
|
|||||||
ctx.File(path)
|
ctx.File(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateManualNsfw 处理 PUT /api/media/:id/manual-nsfw:更新手动色情标记。
|
||||||
|
func (c *MediaController) UpdateManualNsfw(ctx *gin.Context) {
|
||||||
|
idStr := ctx.Param("id")
|
||||||
|
var id int64
|
||||||
|
if _, err := fmt.Sscanf(idStr, "%d", &id); err != nil || id <= 0 {
|
||||||
|
Error(ctx, http.StatusBadRequest, "无效的 ID")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var req struct {
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||||
|
Error(ctx, http.StatusBadRequest, "请求参数错误:"+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if req.Value != "Y" && req.Value != "N" {
|
||||||
|
Error(ctx, http.StatusBadRequest, "值必须是 Y 或 N")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.store.UpdateManualNsfw(id, req.Value); err != nil {
|
||||||
|
Error(ctx, http.StatusInternalServerError, "更新失败:"+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Success(ctx, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// toMediaView 给一条数据库记录补上展示用的派生字段。
|
// toMediaView 给一条数据库记录补上展示用的派生字段。
|
||||||
func toMediaView(m store.MediaInfo) mediaView {
|
func toMediaView(m store.MediaInfo) mediaView {
|
||||||
v := mediaView{MediaInfo: m}
|
v := mediaView{MediaInfo: m}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ func NewRouter(st *store.Store) *gin.Engine {
|
|||||||
apiGroup.POST("/media/list", mc.List)
|
apiGroup.POST("/media/list", mc.List)
|
||||||
apiGroup.POST("/media/stats", mc.Stats)
|
apiGroup.POST("/media/stats", mc.Stats)
|
||||||
apiGroup.GET("/media/preview", mc.Preview)
|
apiGroup.GET("/media/preview", mc.Preview)
|
||||||
|
apiGroup.PUT("/media/:id/manual-nsfw", mc.UpdateManualNsfw)
|
||||||
|
|
||||||
// 扫描整理(开始 / 中止 / 移动 / 查进度 / 实时进度)
|
// 扫描整理(开始 / 中止 / 移动 / 查进度 / 实时进度)
|
||||||
sc := NewScanController(service.NewScanService(st))
|
sc := NewScanController(service.NewScanService(st))
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ type MediaInfo struct {
|
|||||||
TailMd5 string `xorm:"char(32) index('idx_fp') 'tail_md5'" json:"tailMd5"` // 文件尾 256KB 的 MD5(指纹用)
|
TailMd5 string `xorm:"char(32) index('idx_fp') 'tail_md5'" json:"tailMd5"` // 文件尾 256KB 的 MD5(指纹用)
|
||||||
NsfwScore float64 `xorm:"real 'nsfw_score'" json:"nsfwScore"` // NSFW 检测分 0~1(0 表示未检测或非图片)
|
NsfwScore float64 `xorm:"real 'nsfw_score'" json:"nsfwScore"` // NSFW 检测分 0~1(0 表示未检测或非图片)
|
||||||
NsfwThreshold float64 `xorm:"real 'nsfw_threshold'" json:"nsfwThreshold"` // NSFW 判定阈值
|
NsfwThreshold float64 `xorm:"real 'nsfw_threshold'" json:"nsfwThreshold"` // NSFW 判定阈值
|
||||||
|
ManualNsfw string `xorm:"varchar(1) 'manual_nsfw'" json:"manualNsfw"` // 手动标记是否色情:Y/N,默认 N
|
||||||
CreatedAt time.Time `xorm:"created 'created_at'" json:"createdAt"` // 首次入库时间
|
CreatedAt time.Time `xorm:"created 'created_at'" json:"createdAt"` // 首次入库时间
|
||||||
UpdatedAt time.Time `xorm:"updated 'updated_at'" json:"updatedAt"` // 最近更新时间
|
UpdatedAt time.Time `xorm:"updated 'updated_at'" json:"updatedAt"` // 最近更新时间
|
||||||
}
|
}
|
||||||
@@ -219,6 +220,15 @@ func (s *Store) UpdateMediaFilePaths(moved map[string]string) error {
|
|||||||
return sess.Commit()
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateManualNsfw 更新单条记录的手动色情标记。
|
||||||
|
func (s *Store) UpdateManualNsfw(id int64, value string) error {
|
||||||
|
if s == nil || s.engine == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, err := s.engine.ID(id).Update(&MediaInfo{ManualNsfw: value})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// ============================ 媒体记录的新增/更新 ============================
|
// ============================ 媒体记录的新增/更新 ============================
|
||||||
|
|
||||||
// SaveMedia 保存/更新一条媒体记录:按 MD5 找,有就更新,没有就新增。
|
// SaveMedia 保存/更新一条媒体记录:按 MD5 找,有就更新,没有就新增。
|
||||||
|
|||||||
Reference in New Issue
Block a user