diff --git a/.gitignore b/.gitignore index ba8194a..5580a54 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,24 @@ bin frontend/dist frontend/node_modules build/linux/appimage/build -build/windows/nsis/MicrosoftEdgeWebview2Setup.exe \ No newline at end of file +build/windows/nsis/MicrosoftEdgeWebview2Setup.exe + +.DS_Store +node_modules/ +/dist/ +/user-data/ +/log/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +/www +config.yaml + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +.vs/* \ No newline at end of file diff --git a/config/index.go b/config/index.go index 05003b9..7863bcc 100644 --- a/config/index.go +++ b/config/index.go @@ -7,11 +7,12 @@ import ( ) type AppConfig struct { - Port int `yaml:"port"` - WsUrl string `yaml:"wsUrl"` - StunUrl string `yaml:"stunUrl"` - ApiUrl string `yaml:"apiUrl"` - AppName string `yaml:"appName"` + Port int `yaml:"port"` + WsUrl string `yaml:"wsUrl"` + StunUrl string `yaml:"stunUrl"` + ApiUrl string `yaml:"apiUrl"` + AppName string `yaml:"appName"` + SiteFileDir string `yaml:"siteFileDir"` } func LoadConfig() (*AppConfig, error) { diff --git a/frontend/app/components/SiderMenu.vue b/frontend/app/components/SiderMenu.vue index 223ec36..586d7a5 100644 --- a/frontend/app/components/SiderMenu.vue +++ b/frontend/app/components/SiderMenu.vue @@ -8,14 +8,15 @@ 控制台 - + - 整站下载 + 整站下载 + 仿站记录 diff --git a/frontend/app/page/index.vue b/frontend/app/pages/index.vue similarity index 100% rename from frontend/app/page/index.vue rename to frontend/app/pages/index.vue diff --git a/frontend/app/pages/site/download.vue b/frontend/app/pages/site/download.vue new file mode 100644 index 0000000..2bfb420 --- /dev/null +++ b/frontend/app/pages/site/download.vue @@ -0,0 +1,288 @@ + + + + + diff --git a/frontend/app/pages/site/record.vue b/frontend/app/pages/site/record.vue new file mode 100644 index 0000000..f7632d3 --- /dev/null +++ b/frontend/app/pages/site/record.vue @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/frontend/nuxt.config.ts b/frontend/nuxt.config.ts index e8c3d09..c2167f0 100644 --- a/frontend/nuxt.config.ts +++ b/frontend/nuxt.config.ts @@ -1,5 +1,14 @@ // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ + app: { + head: { + title: '仿站小工具', + meta: [ + { name: 'description', content: '这是我的 Nuxt4 应用默认描述' } + ] + }, + baseURL: './' // 确保相对路径,方便打包到 Wails + }, compatibilityDate: '2025-07-15', devtools: { enabled: true }, ssr: false, // 关闭 SSR,改为 CSR @@ -9,9 +18,6 @@ export default defineNuxtConfig({ publicDir: './dist' // 相对 Nuxt3 项目根目录的路径 } }, - app: { - baseURL: './' // 确保相对路径,方便打包到 Wails - }, plugins: [ '~/plugins/ant-design-vue', ], diff --git a/frontend/package.json b/frontend/package.json index 8f6cc74..a8c3a34 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,5 +16,8 @@ "nuxt": "^4.1.2", "vue": "^3.5.21", "vue-router": "^4.5.1" + }, + "devDependencies": { + "sass-embedded": "^1.93.2" } } diff --git a/services/site_service.go b/services/site_service.go index 64cb9b2..1554288 100644 --- a/services/site_service.go +++ b/services/site_service.go @@ -13,6 +13,7 @@ import ( type SiteService struct { BaseDomain string + Port string } type RequestParams struct { @@ -36,9 +37,10 @@ func (s SiteService) GetAllResources(rawURL string) ([]RequestParams, []string) host := parsed.Hostname() if parsed.Port() != "" { host += parsed.Port() + s.Port = parsed.Port() } obj := Browser.GetBrowser(host, &libs.Fingerprint{}) - s.BaseDomain = host + s.BaseDomain = parsed.Hostname() ActiveHref["https://"+host] = struct{}{} // 进入主站 // browser := obj.Browser @@ -171,5 +173,27 @@ func deduplicationRequest(list []RequestParams) []RequestParams { newList = append(newList, v) } } + + return newList +} + +func (s SiteService) DeduplicationRequestByUrl(list []RequestParams) []RequestParams { + var newList []RequestParams + for _, v := range list { + is := true + u, _ := url.Parse(v.URL) + u.RawQuery = "" + for _, l := range newList { + ur, _ := url.Parse(l.URL) + ur.RawQuery = "" + if u.String() == ur.String() && l.Type == v.Type { + is = false + } + } + if is { + newList = append(newList, v) + } + } + return newList } diff --git a/utils/file.go b/utils/file.go new file mode 100644 index 0000000..72831d7 --- /dev/null +++ b/utils/file.go @@ -0,0 +1,117 @@ +package utils + +import ( + "fmt" + "go-site-clone/config" + "io" + "log" + "net/http" + "net/url" + "os" + "path" + "path/filepath" +) + +type File struct{} + +func (*File) Download(uri string) string { + // 解析文件链接及 路径 + u, err := url.Parse(uri) + if err != nil { + return "" + } + host := u.Hostname() + if u.Port() != "" { + host += u.Port() + } + // 获取路径部分 + filePath := u.Path + appConfig, _ := config.LoadConfig() + fp := filepath.Join(appConfig.SiteFileDir, host, filePath) + // 获取文件名 + // fileName := path.Base(filePath) + log.Println("开始下载:", uri) + resp, err := http.Get(uri) + if err != nil { + fmt.Println("下载失败:", err) + return "" + } + defer resp.Body.Close() + // 创建本地文件 + outFile, err := CreateFileWithDirs(fp) + if err != nil { + fmt.Println("文件创建失败:", err) + return "" + } + defer outFile.Close() + // 将响应内容写入文件 + _, err = io.Copy(outFile, resp.Body) + if err != nil { + fmt.Println("写入失败:", err) + return "" + } + fmt.Println("下载完成:", fp) + return fp +} + +func CreateFileWithDirs(filePath string) (*os.File, error) { + // 取出目录部分 + dir := filepath.Dir(filePath) + + // 确保目录存在(递归创建) + if err := os.MkdirAll(dir, os.ModePerm); err != nil { + return nil, fmt.Errorf("创建目录失败: %w", err) + } + + // 创建文件(如果已存在会清空) + f, err := os.Create(filePath) + if err != nil { + return nil, fmt.Errorf("创建文件失败: %w", err) + } + + return f, nil +} + +func (*File) HTMLDownload(uri string) string { + // 解析文件链接及 路径 + u, err := url.Parse(uri) + if err != nil { + return "" + } + host := u.Hostname() + if u.Port() != "" { + host += u.Port() + } + // 获取路径部分 + filePath := u.Path + appConfig, _ := config.LoadConfig() + // 获取文件名 + fileName := path.Base(filePath) + if fileName == "/" || filePath == "" { + filePath = filePath + "/index.html" + } + fp := filepath.Join(appConfig.SiteFileDir, host, filePath) + + log.Println("开始下载:", uri) + resp, err := http.Get(uri) + if err != nil { + fmt.Println("下载失败:", err) + return "" + } + defer resp.Body.Close() + // 创建本地文件 + outFile, err := CreateFileWithDirs(fp) + if err != nil { + fmt.Println("文件创建失败:", err) + return "" + } + defer outFile.Close() + // 将响应内容写入文件 + _, err = io.Copy(outFile, resp.Body) + if err != nil { + fmt.Println("写入失败:", err) + return "" + } + fmt.Println("下载完成:", fp) + return fp +}