From 201c85b1d983b49b66b6293b5c8459a2f20017e9 Mon Sep 17 00:00:00 2001 From: ltx <1006158920@qq.com> Date: Mon, 27 Jul 2026 16:44:06 +0800 Subject: [PATCH] =?UTF-8?q?update:=E6=89=93=E5=8C=85=E4=B8=8A=E4=BC=A0&?= =?UTF-8?q?=E6=9E=B6=E6=9E=84=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OSS-DEPLOY.md | 32 ++++ package.json | 1 + scripts/deploy-oss.ps1 | 137 +++++++++++++++++ src/components/PosterGallery.vue | 190 ++++++++++++++++++++++++ src/components/PurchaseChannels.vue | 42 ++++++ src/components/SiteFooter.vue | 6 +- src/components/SiteHeader.vue | 74 ++++++++- src/components/SportsGroupedSection.vue | 177 ++++++++++++++++++++++ src/components/VenueAddressSection.vue | 63 ++++++++ src/data/page-content.js | 147 +++++++++++++++++- src/data/venue-groups.js | 82 ++++++++++ src/router.js | 43 +++++- src/style.css | 130 ++++++++++++++-- src/views/ContactPage.vue | 75 +--------- src/views/ContentDetailPage.vue | 14 +- src/views/ContentPage.vue | 71 ++++++--- src/views/HomePage.vue | 10 +- src/views/ProductDetailPage.vue | 6 +- 18 files changed, 1171 insertions(+), 129 deletions(-) create mode 100644 OSS-DEPLOY.md create mode 100644 scripts/deploy-oss.ps1 create mode 100644 src/components/PosterGallery.vue create mode 100644 src/components/PurchaseChannels.vue create mode 100644 src/components/SportsGroupedSection.vue create mode 100644 src/components/VenueAddressSection.vue create mode 100644 src/data/venue-groups.js diff --git a/OSS-DEPLOY.md b/OSS-DEPLOY.md new file mode 100644 index 0000000..18d0c9e --- /dev/null +++ b/OSS-DEPLOY.md @@ -0,0 +1,32 @@ +# 阿里云 OSS 发布 + +在项目根目录打开 PowerShell,执行: + +```powershell +npm run deploy:oss +``` + +脚本会自动完成以下操作: + +1. 使用当前时间生成 `static/wwwweb/yyyyMMdd-HHmmss/` 目录。 +2. 执行 Vue/Vite 生产构建。 +3. 改写并检查 OSS 静态资源地址,阻止重复 `https://...https://...` 地址上传。 +4. 上传 JS、CSS、图片等静态资源,并排除 `index.html`。 +5. 验证线上 JS、CSS、Logo 可访问,同时确认 OSS 中不存在 `index.html`。 + +构建完成后,将终端输出的 `Server index` 文件部署到 `www.yuedongsports.com` 服务器。 + +## 前置配置 + +- AccessKey 配置文件:`C:\Users\当前用户\.ossutilconfig` +- ossutil 默认位置:`.tools\ossutil-2.3.0-windows-amd64\ossutil.exe` + +如果路径不同,可以直接调用脚本并传入参数: + +```powershell +powershell -NoProfile -ExecutionPolicy Bypass -File scripts\deploy-oss.ps1 ` + -ConfigFile "D:\secure\.ossutilconfig" ` + -OssutilPath "D:\tools\ossutil.exe" +``` + +仅在网络环境无法执行公网校验时,可增加 `-SkipRemoteVerify`;上传和本地路径检查仍会正常执行。 diff --git a/package.json b/package.json index 74103e5..884ef14 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "dev": "vite", "build": "vite build", "rewrite:oss": "node scripts/rewrite-oss-paths.mjs", + "deploy:oss": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/deploy-oss.ps1", "preview": "vite preview" }, "dependencies": { diff --git a/scripts/deploy-oss.ps1 b/scripts/deploy-oss.ps1 new file mode 100644 index 0000000..994b907 --- /dev/null +++ b/scripts/deploy-oss.ps1 @@ -0,0 +1,137 @@ +[CmdletBinding()] +param( + [string]$Bucket = 'yuedong-wechatapplet', + [string]$Prefix = 'static/wwwweb', + [string]$PublicOrigin = 'https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com', + [string]$ConfigFile = (Join-Path $HOME '.ossutilconfig'), + [string]$OssutilPath = '', + [switch]$SkipRemoteVerify +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$ProjectRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path +$DistDir = Join-Path $ProjectRoot 'dist' +$DefaultOssutil = Join-Path $ProjectRoot '.tools\ossutil-2.3.0-windows-amd64\ossutil.exe' + +if (-not $OssutilPath) { + $OssutilPath = $DefaultOssutil +} + +if (-not (Test-Path -LiteralPath $OssutilPath -PathType Leaf)) { + throw "ossutil not found: $OssutilPath" +} + +if (-not (Test-Path -LiteralPath $ConfigFile -PathType Leaf)) { + throw "OSS config not found: $ConfigFile" +} + +if (-not (Get-Command 'npm.cmd' -ErrorAction SilentlyContinue)) { + throw 'npm.cmd was not found. Install Node.js and reopen PowerShell.' +} + +$Timestamp = Get-Date -Format 'yyyyMMdd-HHmmss' +$CleanOrigin = $PublicOrigin.TrimEnd('/') +$CleanPrefix = $Prefix.Trim('/') +$PublicBase = "$CleanOrigin/$CleanPrefix/$Timestamp/" +$OssTarget = "oss://$Bucket/$CleanPrefix/$Timestamp/" + +Push-Location $ProjectRoot +try { + Write-Host "[1/5] Building production files" -ForegroundColor Cyan + & npm.cmd run build -- "--base=$PublicBase" + if ($LASTEXITCODE -ne 0) { + throw "Vite build failed with exit code $LASTEXITCODE" + } + + Write-Host "[2/5] Rewriting and validating OSS asset paths" -ForegroundColor Cyan + & npm.cmd run rewrite:oss -- $PublicBase + if ($LASTEXITCODE -ne 0) { + throw "OSS path validation failed with exit code $LASTEXITCODE" + } + + $IndexPath = Join-Path $DistDir 'index.html' + $IndexContent = [System.IO.File]::ReadAllText($IndexPath) + $DuplicatePrefix = $PublicBase.TrimEnd('/') + $PublicBase + + if ($IndexContent.Contains($DuplicatePrefix)) { + throw 'The generated index.html contains a duplicated OSS prefix.' + } + + if (-not $IndexContent.Contains($PublicBase)) { + throw 'The generated index.html does not reference the new OSS directory.' + } + + $Files = Get-ChildItem -LiteralPath $DistDir -Recurse -File + $UploadFiles = @($Files | Where-Object { $_.Name -ne 'index.html' }) + $UploadBytes = ($UploadFiles | Measure-Object Length -Sum).Sum + + Write-Host "[3/5] Uploading $($UploadFiles.Count) static files" -ForegroundColor Cyan + Write-Host " Target: $OssTarget" + & $OssutilPath -c $ConfigFile cp "$DistDir\" $OssTarget -r --exclude 'index.html' -f -q --no-progress + if ($LASTEXITCODE -ne 0) { + throw "OSS upload failed with exit code $LASTEXITCODE" + } + + Write-Host '[4/5] Confirming index.html was excluded' -ForegroundColor Cyan + $RemoteIndexUrl = "${PublicBase}index.html?verify=$Timestamp" + try { + $RemoteIndexResponse = Invoke-WebRequest -Uri $RemoteIndexUrl -Method Head -UseBasicParsing + if ($RemoteIndexResponse.StatusCode -eq 200) { + throw 'index.html exists in the new OSS directory, but it must remain on the web server.' + } + } catch { + if (-not $_.Exception.Response) { + throw + } + + $RemoteIndexStatus = [int]$_.Exception.Response.StatusCode + if ($RemoteIndexStatus -ne 404) { + throw "Unable to confirm that index.html was excluded. HTTP status: $RemoteIndexStatus" + } + } + + if (-not $SkipRemoteVerify) { + Write-Host '[5/5] Verifying uploaded JS, CSS, and image URLs' -ForegroundColor Cyan + $ScriptMatch = [regex]::Match($IndexContent, ']+src="([^"]+)"') + $StyleMatch = [regex]::Match($IndexContent, ']+rel="stylesheet"[^>]+href="([^"]+)"') + + if (-not $ScriptMatch.Success -or -not $StyleMatch.Success) { + throw 'Could not locate generated JS or CSS URLs in index.html.' + } + + $CacheBuster = "verify=$Timestamp" + $ScriptUrl = $ScriptMatch.Groups[1].Value + $StyleUrl = $StyleMatch.Groups[1].Value + $ScriptResponse = Invoke-WebRequest -Uri "${ScriptUrl}?$CacheBuster" -UseBasicParsing + $StyleResponse = Invoke-WebRequest -Uri "${StyleUrl}?$CacheBuster" -Method Head -UseBasicParsing + + if ($ScriptResponse.StatusCode -ne 200 -or $StyleResponse.StatusCode -ne 200) { + throw 'The uploaded JS or CSS file is not publicly accessible.' + } + + if ($ScriptResponse.Content.Contains($DuplicatePrefix) -or + $ScriptResponse.Content -match 'https://[^\s"''`]+https://') { + throw 'The uploaded JS contains a duplicated URL.' + } + + $SampleImage = "${PublicBase}site/assets/logo.png" + $ImageResponse = Invoke-WebRequest -Uri "${SampleImage}?$CacheBuster" -Method Head -UseBasicParsing + if ($ImageResponse.StatusCode -ne 200) { + throw 'The uploaded sample image is not publicly accessible.' + } + } else { + Write-Host '[5/5] Remote verification skipped by parameter' -ForegroundColor Yellow + } + + $SizeMiB = [math]::Round($UploadBytes / 1MB, 2) + Write-Host '' + Write-Host 'Deployment completed successfully.' -ForegroundColor Green + Write-Host "OSS directory : $OssTarget" + Write-Host "Public base : $PublicBase" + Write-Host "Uploaded : $($UploadFiles.Count) files / $SizeMiB MiB" + Write-Host "Server index : $IndexPath" +} finally { + Pop-Location +} diff --git a/src/components/PosterGallery.vue b/src/components/PosterGallery.vue new file mode 100644 index 0000000..07c7f07 --- /dev/null +++ b/src/components/PosterGallery.vue @@ -0,0 +1,190 @@ + + + diff --git a/src/components/PurchaseChannels.vue b/src/components/PurchaseChannels.vue new file mode 100644 index 0000000..902f680 --- /dev/null +++ b/src/components/PurchaseChannels.vue @@ -0,0 +1,42 @@ + + + diff --git a/src/components/SiteFooter.vue b/src/components/SiteFooter.vue index d67584b..7f7eac7 100644 --- a/src/components/SiteFooter.vue +++ b/src/components/SiteFooter.vue @@ -4,9 +4,9 @@ diff --git a/src/components/SiteHeader.vue b/src/components/SiteHeader.vue index d20ee07..607a01c 100644 --- a/src/components/SiteHeader.vue +++ b/src/components/SiteHeader.vue @@ -4,8 +4,21 @@ 跃动 YUEDONG