1. 生产模块按工序拆分为两个一级菜单 - 生产-前缫(落丝记录)、生产-后缫(纤度检验、黑板检验) - 旧的「生产管理」(/prod) 目录及子菜单由种子自动清理,页面组件与权限标识保持不变 - 消息中心跳转路径、首页快捷入口路径同步更新 2. 职工管理独立为一级菜单(原挂在「基础数据」目录下),并清理历史子菜单 3. 修复侧边栏菜单展开卡顿(基础数据等子项较多的目录尤其明显) - 去掉 Element Plus 的 height 过渡动画(会逐帧重排全部子项) - 收起时改用 height:0 + visibility:hidden 而非 display:none,子项提前完成布局 - 菜单区独立滚动并预留滚动条宽度(scrollbar-gutter),消除展开时的横向抖动 - 菜单项增加 contain 布局隔离,淡入动画改为容器级 4. 修复页面首次打开重复请求 - 分页组件挂载时会触发一次 current-change,页码未变化时不再重复加载(18 个页面) - 职工管理去掉 onMounted 与默认选中部门的重复加载 - 工种管理、原料庄口的注册表下拉由按 key 多次请求改为一次全量拉取 5. 后端增加前端静态托管与 SPA 路由回退,支持 IIS 单站点部署(前后端同源) 6. 新增部署脚本 deploy-iis.ps1(首次部署)与 update-iis.ps1(更新发布)
112 lines
5.4 KiB
PowerShell
112 lines
5.4 KiB
PowerShell
# ============================================================
|
||
# 将「智慧缫丝系统」(f9-web-ai-test) 发布到本机 IIS
|
||
# - 自动安装 ASP.NET Core Hosting Bundle(IIS 托管 .NET 8 必需)
|
||
# - 创建应用池 / 站点 / 目录权限,并做一次自检
|
||
# 必须以【管理员身份】运行
|
||
# ============================================================
|
||
$ErrorActionPreference = 'Stop'
|
||
|
||
# 全过程写入日志文件,便于提权窗口关闭后回看
|
||
$logDir = Join-Path $PSScriptRoot '_runlog'
|
||
New-Item -ItemType Directory -Force -Path $logDir | Out-Null
|
||
try { Start-Transcript -Path (Join-Path $logDir 'deploy-iis.log') -Force -ErrorAction Stop | Out-Null } catch { }
|
||
|
||
$publishDir = 'C:\Users\32453\CodeBuddy\20260825142915\publish'
|
||
$siteName = 'F9WebAiTest'
|
||
$appPoolName = 'F9WebAiTest'
|
||
$preferredPort = 80
|
||
$ancmPath = 'C:\Program Files\IIS\Asp.Net Core Module\V2\aspnetcorev2.dll'
|
||
$hostingBundle = 'https://builds.dotnet.microsoft.com/dotnet/aspnetcore/Runtime/8.0.21/dotnet-hosting-8.0.21-win.exe'
|
||
$installer = Join-Path $env:TEMP 'dotnet-hosting-8.0.21-win.exe'
|
||
|
||
function Info($m) { Write-Host "[部署] $m" -ForegroundColor Cyan }
|
||
function Warn($m) { Write-Host "[警告] $m" -ForegroundColor Yellow }
|
||
|
||
# ---------- 0. 前置校验 ----------
|
||
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||
throw '请以管理员身份运行本脚本'
|
||
}
|
||
if (-not (Test-Path $publishDir)) { throw "发布目录不存在:$publishDir" }
|
||
if (-not (Test-Path (Join-Path $publishDir 'wwwroot\index.html'))) { throw "前端产物缺失:$publishDir\wwwroot\index.html" }
|
||
if (-not (Test-Path (Join-Path $publishDir 'F9WebAiTest.Api.dll'))) { throw "后端产物缺失:$publishDir\F9WebAiTest.Api.dll" }
|
||
if (-not (Test-Path 'C:\Windows\System32\inetsrv\appcmd.exe')) { throw '本机未安装 IIS,请先启用 IIS 功能' }
|
||
|
||
Import-Module WebAdministration
|
||
|
||
# ---------- 1. ASP.NET Core Hosting Bundle ----------
|
||
if (-not (Test-Path $ancmPath)) {
|
||
Info '未检测到 AspNetCoreModuleV2,开始下载 Hosting Bundle 8.0.21 ...'
|
||
Invoke-WebRequest -Uri $hostingBundle -OutFile $installer -UseBasicParsing
|
||
Info '下载完成,静默安装中(约 1-2 分钟)...'
|
||
Start-Process -FilePath $installer -ArgumentList '/install', '/quiet', '/norestart' -Wait
|
||
if (-not (Test-Path $ancmPath)) { throw 'Hosting Bundle 安装失败,请手动安装后重试' }
|
||
Info '安装完成,重启 IIS 使模块生效 ...'
|
||
& iisreset /noforce | Out-Null
|
||
} else {
|
||
Info 'AspNetCoreModuleV2 已安装,跳过'
|
||
}
|
||
|
||
# ---------- 2. 选择端口 ----------
|
||
$port = $preferredPort
|
||
$occupied = netstat -ano | Select-String 'LISTENING' | Select-String ":$port\s"
|
||
if ($occupied) {
|
||
$port = 8080
|
||
Warn "端口 $preferredPort 已被占用,改用 $port"
|
||
}
|
||
|
||
# ---------- 3. 应用池(无托管代码,与 .NET Core 应用匹配)----------
|
||
if (Test-Path "IIS:\AppPools\$appPoolName") {
|
||
Info "应用池 $appPoolName 已存在,更新配置"
|
||
} else {
|
||
New-WebAppPool -Name $appPoolName | Out-Null
|
||
Info "已创建应用池 $appPoolName"
|
||
}
|
||
Set-ItemProperty "IIS:\AppPools\$appPoolName" -Name managedRuntimeVersion -Value ''
|
||
Set-ItemProperty "IIS:\AppPools\$appPoolName" -Name startMode -Value 'AlwaysRunning'
|
||
|
||
# ---------- 4. 站点 ----------
|
||
if (Test-Path "IIS:\Sites\$siteName") {
|
||
Info "站点 $siteName 已存在,更新物理路径与应用池"
|
||
Set-ItemProperty "IIS:\Sites\$siteName" -Name physicalPath -Value $publishDir
|
||
Set-ItemProperty "IIS:\Sites\$siteName" -Name applicationPool -Value $appPoolName
|
||
if (-not (Get-WebBinding -Name $siteName -Protocol http -Port $port -ErrorAction SilentlyContinue)) {
|
||
New-WebBinding -Name $siteName -Protocol http -Port $port -IPAddress '*'
|
||
Info "已补充绑定 http://*:$port"
|
||
}
|
||
} else {
|
||
New-Website -Name $siteName -PhysicalPath $publishDir -Port $port -ApplicationPool $appPoolName -Force | Out-Null
|
||
Info "已创建站点 $siteName"
|
||
}
|
||
|
||
# ---------- 5. 目录权限(应用池身份需读写:SQLite 库文件、日志)----------
|
||
$aclUser = "IIS AppPool\$appPoolName"
|
||
& icacls $publishDir /grant "${aclUser}:(OI)(CI)M" /T /Q | Out-Null
|
||
Info "已授予 $aclUser 读写权限"
|
||
|
||
# ---------- 6. 启动 ----------
|
||
if ((Get-WebAppPoolState -Name $appPoolName).Value -ne 'Started') { Start-WebAppPool -Name $appPoolName }
|
||
if ((Get-Website -Name $siteName).State -ne 'Started') { Start-Website -Name $siteName }
|
||
Start-Sleep -Seconds 4
|
||
|
||
# ---------- 7. 自检 ----------
|
||
$url = "http://localhost:$port/"
|
||
Info '开始自检 ...'
|
||
try {
|
||
$r = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 40
|
||
Info "首页:HTTP $($r.StatusCode)(前端已托管)"
|
||
} catch {
|
||
Warn "首页访问失败:$($_.Exception.Message)"
|
||
Warn "如为 500,请查看 事件查看器 → Windows 日志 → 应用程序,或打开 $publishDir\web.config 把 stdoutLogEnabled 改为 true 后重试"
|
||
}
|
||
try {
|
||
$login = Invoke-RestMethod -Uri "${url}api/auth/login" -Method Post -ContentType 'application/json' `
|
||
-Body '{"userName":"admin","password":"123456"}' -TimeoutSec 40
|
||
Info "登录接口:code=$($login.code) $($login.message)"
|
||
} catch {
|
||
Warn "登录接口调用失败:$($_.Exception.Message)"
|
||
}
|
||
|
||
Write-Host ''
|
||
Info "部署完成,访问地址:$url"
|
||
Info "API 文档:${url}swagger 默认账号:admin / 123456"
|