Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ __pycache__/
# Swagger 文档由 swag init 在构建阶段自动生成(代码即文档,不入 git)
/swagger-ui/swagger.json
/docs/
重构.md
3 changes: 2 additions & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ COPY --from=backend /out/dockerCopilot ./dockerCopilot
COPY etc/. ./etc
COPY start.sh ./start.sh

RUN apk add --no-cache tzdata \
# 安装时区数据、Docker CLI 和 Compose 插件(用于执行 docker compose 命令)
RUN apk add --no-cache tzdata docker-cli docker-cli-compose \
&& chmod +x start.sh \
&& chmod +x dockerCopilot

Expand Down
53 changes: 37 additions & 16 deletions dockercopilot.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,25 +96,17 @@ func main() {
sched.Start()
defer sched.Stop()

// Ensure data directory and config exist (Auto-init)
dataDir := "/data/config/image"
if err := os.MkdirAll(dataDir, 0755); err != nil {
// Ensure data directory and config exist (Auto-init),路径统一引用 config 常量
if err := os.MkdirAll(config.LegacyImageDir, 0755); err != nil {
logx.Errorf("Failed to create data directory: %v", err)
}
// 持久化图标目录:favicon 自动抓取下载与手动上传统一存放
if err := os.MkdirAll("/data/images", 0755); err != nil {
if err := os.MkdirAll(config.ImagesDir, 0755); err != nil {
logx.Errorf("Failed to create images directory: %v", err)
}

imageLogosPath := "/data/config/imageLogos.js"
if _, err := os.Stat(imageLogosPath); os.IsNotExist(err) {
defaultConfig := []byte(`// 自定义镜像logo配置
export const customImageLogos = {
};
`)
if err := os.WriteFile(imageLogosPath, defaultConfig, 0644); err != nil {
logx.Errorf("Failed to create default imageLogos.js: %v", err)
}
// 图标配置目录(用于 icons.json)
if err := os.MkdirAll(config.ConfigDir, 0755); err != nil {
logx.Errorf("Failed to create config directory: %v", err)
}

// 首轮镜像更新检查放到后台执行:镜像列表获取和加速器域名探测都可能较慢,
Expand Down Expand Up @@ -178,6 +170,22 @@ export const customImageLogos = {
logx.Info("程序版本" + config.Version)
server.Start()
}

// serveEmbeddedFavicon 返回 DockerCopilot 自身图标。
// 复用前端 logo.png:embed 目录为 front/(见 //go:embed front/*),
// Dockerfile 将前端 dist/ 内容拷入 front/,故 logo.png 的 embed 路径为 front/logo.png。
func serveEmbeddedFavicon(w http.ResponseWriter, r *http.Request) {
data, err := embeddedFront.ReadFile("front/logo.png")
if err != nil {
logx.Errorf("无法读取嵌入的 favicon(front/logo.png): %v", err)
http.Error(w, "Icon not found", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "image/png")
w.Header().Set("Cache-Control", "public, max-age=86400")
_, _ = w.Write(data)
}

func RegisterHandlers(engine *rest.Server) {
frontFS, err := fs.Sub(embeddedFront, "front")
if err != nil {
Expand All @@ -189,9 +197,9 @@ func RegisterHandlers(engine *rest.Server) {
assetsHandler := http.FileServer(http.FS(frontFS))

// Serve custom icons(历史目录,保持兼容)
iconFileServer := http.StripPrefix("/src/config/image/", http.FileServer(http.Dir("/data/config/image")))
iconFileServer := http.StripPrefix("/src/config/image/", http.FileServer(http.Dir(config.LegacyImageDir)))
// 持久化图标目录 /data/images(favicon 自动抓取下载 + 手动上传统一存放)
imagesFileServer := http.StripPrefix("/images/", http.FileServer(http.Dir("/data/images")))
imagesFileServer := http.StripPrefix("/images/", http.FileServer(http.Dir(config.ImagesDir)))
engine.AddRoutes(
[]rest.Route{
{
Expand All @@ -209,6 +217,19 @@ func RegisterHandlers(engine *rest.Server) {
imagesFileServer.ServeHTTP(w, r)
},
},
{
// DockerCopilot 自身的 favicon(浏览器标签页图标)。
// 复用前端 logo.png(embed 路径 front/logo.png,由 Dockerfile 从 dist/ 拷入)。
Method: http.MethodGet,
Path: "/favicon.png",
Handler: serveEmbeddedFavicon,
},
{
// 兼容 /favicon.ico 请求,同样返回 logo.png。
Method: http.MethodGet,
Path: "/favicon.ico",
Handler: serveEmbeddedFavicon,
},
},
)

Expand Down
5 changes: 2 additions & 3 deletions frontend-react/index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="zh-CN" class="h-full">
<head>
<meta charset="UTF-8" />
Expand All @@ -7,13 +7,12 @@
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="Docker Copilot" />
<meta name="apple-mobile-web-app-icon" content="/logo.png" />
<link rel="manifest" href="/manifest.json" />
<link rel="icon" type="image/png" href="/logo.png" />
<link rel="apple-touch-icon" href="/logo.png" />
<meta name="theme-color" content="#0ea5e9" />
<title>Docker Copilot</title>
<meta name="description" content="Docker容器管理平台" />
<meta name="description" content="Docker 容器管理平台" />
</head>
<body class="h-full bg-gray-50 dark:bg-gray-900 transition-colors duration-300">
<div id="root" class="h-full"></div>
Expand Down
28 changes: 19 additions & 9 deletions frontend-react/public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Docker Copilot",
"short_name": "Docker",
"description": "一个简洁、优雅且强大的 Docker 容器管理工具",
"short_name": "DC",
"description": "Docker容器管理平台 - 一键更新、定时任务、Compose编排",
"start_url": "/",
"scope": "/",
"display": "standalone",
Expand All @@ -19,14 +19,24 @@
"src": "/logo.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
"purpose": "any maskable"
}
],
"categories": ["utilities", "productivity"],
"shortcuts": [
{
"name": "容器列表",
"short_name": "容器",
"description": "查看所有容器",
"url": "/",
"icons": [{ "src": "/logo.png", "sizes": "192x192" }]
},
{
"src": "/logo.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
"name": "任务中心",
"short_name": "任务",
"description": "查看后台任务",
"url": "/?open_tasks=1",
"icons": [{ "src": "/logo.png", "sizes": "192x192" }]
}
],
"categories": ["utilities", "productivity"]
]
}
27 changes: 20 additions & 7 deletions frontend-react/src/api/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,17 +199,19 @@ export const imageAPI = {
pruneImages: (ids, force = false, hostId = '') => apiClient.post('/api/images/prune', { ids, force, hostId }),
// 手动触发检测所有镜像更新(异步执行,立即返回)
checkUpdate: () => apiClient.post('/api/images/check-update'),
// 通过 URL 绑定图标到镜像名(无需上传图片)
setIconUrl: (imageName, url) => apiClient.post('/api/icons/url', { imageName, url }),
// 以下图标方法统一为「对象入参」,字段与后端 struct tag 严格对齐(imageName/url/targetType)。
// 通过 URL 绑定图标(无需上传图片)
setIconUrl: ({ imageName, url, targetType = 'image' }) =>
apiClient.post('/api/icons/url', { imageName, url, targetType }),
// 自动抓取站点 favicon 并下载持久化到 /data/images,url 为容器访问地址
fetchIcon: (imageName, url) => apiClient.post('/api/icons/fetch', { imageName, url }),
uploadIcon: (file, imageName, containerName) => {
fetchIcon: ({ imageName, url, targetType = 'image' }) =>
apiClient.post('/api/icons/fetch', { imageName, url, targetType }),
// 上传图标文件:后端读取 formData 字段名固定为 file / imageName / targetType
uploadIcon: ({ file, imageName, targetType = 'image' }) => {
const formData = new FormData()
formData.append('file', file)
formData.append('imageName', imageName)
if (containerName) {
formData.append('containerName', containerName)
}
formData.append('targetType', targetType)
return apiClient.post('/api/icons', formData, {
headers: { 'Content-Type': 'multipart/form-data' }
})
Expand Down Expand Up @@ -264,6 +266,12 @@ export const composeAPI = {
saveConfig: (cfg) => apiClient.put('/api/compose/config', cfg),
// 浏览 DC 自身文件系统目录(目录选择器用);path 为空返回起始目录
browse: (path = '') => apiClient.get('/api/compose/browse', { params: { path } }),
// 创建文件夹
createFolder: (parentPath, folderName) =>
apiClient.post('/api/compose/folder', { parentPath, folderName }),
// 创建 Compose 配置文件
createFile: (parentPath, fileName) =>
apiClient.post('/api/compose/file', { parentPath, fileName }),
}

// 阶段8:favicon 抓取API(按容器暴露端口解析站点图标)
Expand Down Expand Up @@ -352,4 +360,9 @@ export const githubAPI = {
},
}

// 说明:原重复的 iconAPI 已删除,图标相关接口统一收敛到上方 imageAPI
// (getIcons / setIconUrl / fetchIcon / uploadIcon),字段与后端严格对齐。

// 导出 apiClient 供其他组件使用
export { apiClient }
export default apiClient
Binary file removed frontend-react/src/assets/logos/asynqmon.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/audiobookshelf.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/byte-muse.jpg
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/code-server.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/cookiecloud.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/cpa.jpg
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/docker-copilot.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/embyserver.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/flaresolverr.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/fndesk.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/fntv.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/hermes-agent.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/immortal.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/it-tools.webp
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/iyuu.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/jellyfin.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/lobechat.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/lucky.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/mdc-ng.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/media-saber.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/momo.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/moviepilot.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/ms_tmdb.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/mt-photos.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/mysql.png
Binary file not shown.
Binary file removed frontend-react/src/assets/logos/next-chat.png
Diff not rendered.
1 change: 0 additions & 1 deletion frontend-react/src/assets/logos/octopus.svg
Diff not rendered.
Binary file removed frontend-react/src/assets/logos/ollama.png
Diff not rendered.
Binary file removed frontend-react/src/assets/logos/one-api.png
Diff not rendered.
Binary file removed frontend-react/src/assets/logos/one-hub.png
Diff not rendered.
Binary file removed frontend-react/src/assets/logos/openwebui.png
Diff not rendered.
Binary file removed frontend-react/src/assets/logos/pansou.jpg
Diff not rendered.
Binary file removed frontend-react/src/assets/logos/postgres.png
Diff not rendered.
Binary file removed frontend-react/src/assets/logos/qbittorrent.webp
Diff not rendered.
Binary file removed frontend-react/src/assets/logos/qd.png
Diff not rendered.
1 change: 0 additions & 1 deletion frontend-react/src/assets/logos/qinglong.svg
Diff not rendered.
Binary file removed frontend-react/src/assets/logos/redis.png
Diff not rendered.
Loading
Loading