feat(background): 添加删除应用功能

- 添加DELETE /apps/:id API端点用于删除指定应用
- 实现deleteApp函数,支持文件和数据的完整删除
- 在getApps函数中增加文件存在性验证,自动清理无效应用记录
- 优化appsMutex使用,确保并发安全的数据操作
- 添加文件路径验证和错误处理机制

feat(frontend): 实现前端删除应用交互功能

- 将deleteApp函数改为异步处理,支持API调用
- 添加确认对话框提升用户体验
- 实现DELETE请求发送和响应处理
- 添加错误处理和用户反馈提示
- 删除成功后自动刷新应用列表
```
This commit is contained in:
2026-01-07 00:05:16 +08:00
parent 20ccfbc205
commit 8240d8cf94
2 changed files with 110 additions and 5 deletions

View File

@@ -129,6 +129,7 @@ func main() {
{
api.GET("/apps", getApps)
api.POST("/apps", uploadApp)
api.DELETE("/apps/:id", deleteApp) // 添加删除应用的API端点
api.GET("/apps/:id", downloadApp)
api.GET("/apps/:id/", downloadApp) // 处理以/结尾的URL
api.GET("/docs", getDocs) // 新增获取文档的API端点
@@ -143,8 +144,33 @@ func main() {
// 获取App列表
func getApps(c *gin.Context) {
appsMutex.RLock()
defer appsMutex.RUnlock()
appsMutex.Lock()
defer appsMutex.Unlock()
// 验证文件是否存在,如果不存在则从切片中删除
appsToKeep := []App{}
appsChanged := false
for _, app := range apps {
filePath := filepath.Join(filesDir, app.FilePath)
if _, err := os.Stat(filePath); os.IsNotExist(err) {
// 文件不存在跳过这个app即从逻辑上删除它
appsChanged = true
fmt.Printf("文件不存在,从列表中移除: %s, 文件路径: %s\n", app.Name, filePath)
} else {
// 文件存在保留这个app
appsToKeep = append(appsToKeep, app)
}
}
if appsChanged {
// 更新apps切片
apps = appsToKeep
// 保存到文件
if err := saveApps(); err != nil {
fmt.Printf("保存apps.json失败: %v\n", err)
}
}
c.JSON(http.StatusOK, apps)
}
@@ -242,6 +268,57 @@ func downloadApp(c *gin.Context) {
c.FileAttachment(filePath, targetApp.FileName)
}
// 删除指定App
func deleteApp(c *gin.Context) {
// 获取ID
id := c.Param("id")
// 查找App
appsMutex.Lock()
var targetApp *App
targetIndex := -1
for i := range apps {
if apps[i].ID == id {
targetApp = &apps[i]
targetIndex = i
break
}
}
appsMutex.Unlock()
if targetApp == nil {
c.JSON(http.StatusNotFound, gin.H{"success": false, "message": "App不存在"})
return
}
// 构建文件路径
filePath := filepath.Join(filesDir, targetApp.FilePath)
// 删除文件
if err := os.Remove(filePath); err != nil {
if os.IsNotExist(err) {
// 文件不存在,可能已经被删除,继续执行
fmt.Printf("文件已经不存在: %s\n", filePath)
} else {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": "删除文件失败: " + err.Error()})
return
}
}
// 从apps切片中删除该应用
appsMutex.Lock()
apps = append(apps[:targetIndex], apps[targetIndex+1:]...)
appsMutex.Unlock()
// 保存到文件
if err := saveApps(); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": "保存数据失败: " + err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "message": "删除成功"})
}
// 读取文档内容
func readDocFile(docName string) (string, error) {
filePath := filepath.Join(docsDir, docName+".txt")