2026-07-31 16:53:07 +08:00
|
|
|
param(
|
|
|
|
|
[Parameter(Mandatory = $true)][string]$ImagePath,
|
|
|
|
|
[Parameter(Mandatory = $true)][string]$StorageRoot,
|
|
|
|
|
[Parameter(Mandatory = $true)][UInt64]$TenantId,
|
|
|
|
|
[Parameter(Mandatory = $true)][UInt64]$QualificationId,
|
|
|
|
|
[Parameter(Mandatory = $true)][string]$OldDocumentUrl,
|
|
|
|
|
[string]$OutputDirectory = ".\reports\qualification-migration"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
|
$source = (Resolve-Path -LiteralPath $ImagePath).Path
|
|
|
|
|
$file = Get-Item -LiteralPath $source
|
|
|
|
|
if ($file.Length -le 0 -or $file.Length -gt 5MB) {
|
|
|
|
|
throw "资质图片必须大于 0 字节且不超过 5 MB。"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$bytes = [System.IO.File]::ReadAllBytes($source)
|
|
|
|
|
$isJpeg = $bytes.Length -ge 3 -and $bytes[0] -eq 0xFF -and $bytes[1] -eq 0xD8 -and $bytes[2] -eq 0xFF
|
|
|
|
|
$pngSignature = [byte[]](0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A)
|
|
|
|
|
$isPng = $bytes.Length -ge 8
|
|
|
|
|
for ($index = 0; $isPng -and $index -lt $pngSignature.Length; $index++) {
|
|
|
|
|
$isPng = $bytes[$index] -eq $pngSignature[$index]
|
|
|
|
|
}
|
|
|
|
|
if (-not $isJpeg -and -not $isPng) {
|
|
|
|
|
throw "资质文件签名不是有效的 JPG 或 PNG。"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$extension = if ($isPng) { ".png" } else { ".jpg" }
|
|
|
|
|
$fileName = "{0}{1}" -f ([guid]::NewGuid().ToString()), $extension
|
|
|
|
|
$qualificationDirectory = Join-Path (Join-Path $StorageRoot "qualifications") $TenantId
|
|
|
|
|
$target = Join-Path $qualificationDirectory $fileName
|
|
|
|
|
New-Item -ItemType Directory -Force -Path $qualificationDirectory | Out-Null
|
|
|
|
|
Copy-Item -LiteralPath $source -Destination $target -ErrorAction Stop
|
|
|
|
|
|
|
|
|
|
$sourceHash = (Get-FileHash -Algorithm SHA256 -LiteralPath $source).Hash
|
|
|
|
|
$targetHash = (Get-FileHash -Algorithm SHA256 -LiteralPath $target).Hash
|
|
|
|
|
if ($sourceHash -ne $targetHash) {
|
|
|
|
|
Remove-Item -LiteralPath $target -Force
|
|
|
|
|
throw "复制后的文件校验和不一致,迁移已终止并清理目标文件。"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$newUrl = "/api/merchant/v1/files/qualifications/$fileName"
|
|
|
|
|
$escapedOldUrl = $OldDocumentUrl.Replace("'", "''")
|
|
|
|
|
$escapedNewUrl = $newUrl.Replace("'", "''")
|
|
|
|
|
$output = [System.IO.Path]::GetFullPath($OutputDirectory)
|
|
|
|
|
New-Item -ItemType Directory -Force -Path $output | Out-Null
|
|
|
|
|
|
|
|
|
|
$forwardSql = @"
|
|
|
|
|
START TRANSACTION;
|
|
|
|
|
UPDATE baiyue_iam.iam_tenant_qualification
|
|
|
|
|
SET document_url = '$escapedNewUrl'
|
|
|
|
|
WHERE id = $QualificationId
|
|
|
|
|
AND tenant_id = $TenantId
|
|
|
|
|
AND document_url = '$escapedOldUrl'
|
|
|
|
|
AND deleted = 0;
|
2026-07-31 18:10:32 +08:00
|
|
|
SELECT ROW_COUNT() AS affected_rows;
|
|
|
|
|
-- 仅当 affected_rows = 1 且平台预览校验成功时,由执行人员显式 COMMIT;否则 ROLLBACK 并删除:$target
|
2026-07-31 16:53:07 +08:00
|
|
|
"@
|
|
|
|
|
$rollbackSql = @"
|
|
|
|
|
START TRANSACTION;
|
|
|
|
|
UPDATE baiyue_iam.iam_tenant_qualification
|
|
|
|
|
SET document_url = '$escapedOldUrl'
|
|
|
|
|
WHERE id = $QualificationId
|
|
|
|
|
AND tenant_id = $TenantId
|
|
|
|
|
AND document_url = '$escapedNewUrl'
|
|
|
|
|
AND deleted = 0;
|
2026-07-31 18:10:32 +08:00
|
|
|
SELECT ROW_COUNT() AS affected_rows;
|
|
|
|
|
-- 仅当 affected_rows = 1 且旧文件可用时,由执行人员显式 COMMIT;否则 ROLLBACK。
|
2026-07-31 16:53:07 +08:00
|
|
|
"@
|
|
|
|
|
|
|
|
|
|
$forwardPath = Join-Path $output "qualification-$QualificationId-forward.sql"
|
|
|
|
|
$rollbackPath = Join-Path $output "qualification-$QualificationId-rollback.sql"
|
|
|
|
|
[System.IO.File]::WriteAllText($forwardPath, $forwardSql, [System.Text.UTF8Encoding]::new($false))
|
|
|
|
|
[System.IO.File]::WriteAllText($rollbackPath, $rollbackSql, [System.Text.UTF8Encoding]::new($false))
|
|
|
|
|
|
|
|
|
|
[pscustomobject]@{
|
|
|
|
|
TenantId = $TenantId
|
|
|
|
|
QualificationId = $QualificationId
|
|
|
|
|
DocumentUrl = $newUrl
|
|
|
|
|
PhysicalFile = $target
|
|
|
|
|
Sha256 = $targetHash
|
|
|
|
|
ForwardSql = $forwardPath
|
|
|
|
|
RollbackSql = $rollbackPath
|
|
|
|
|
MerchantPreview = $newUrl
|
|
|
|
|
PlatformPreview = "/api/platform/v1/files/qualifications/$TenantId/$fileName"
|
|
|
|
|
}
|