Commit b975ad55 by pangchong

build(deploy): 添加前端自动化编译与远程部署脚本

- 新增 deploy.ps1 脚本,实现 Vue 3 + TypeScript 项目前端自动化构建
- 脚本支持打包 dist 静态资源并压缩为 dist.tar.gz
- 使用 SSH 清理远程服务器旧的部署目录文件
- 通过 SCP 上传压缩包并远程解压部署
- package.json 新增 deploy 命令,调用 PowerShell 脚本实现自动化部署
- CommonModal.vue 移除冗余的 scoped CSS 样式块
- 优化 editor 功能模块,改为遍历 CSSOM 提取完整 CSS 规则
- 修复线上环境离线 HTML 预览时外链样式失效的问题
- 增强样式提取逻辑,兼容跨域和内联 style 标签样式解析
parent f4fa4e6c
# XM-Inspection-Client-2026 前端自动化编译与远程部署脚本
# 兼容 PowerShell 5.1
# 1. 强制控制台及全局默认编码为 UTF-8
$OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$PSDefaultParameterValues['*:Encoding'] = 'utf8'
chcp 65001 | Out-Null
$ServerIP = "124.71.148.16"
$ServerUser = "root"
$RemoteDir = "/mnt/disk2/xml-editor"
function Write-Step {
param(
[string]$Message,
[string]$Color = "Cyan"
)
$timestamp = Get-Date -Format "HH:mm:ss"
Write-Host "[$timestamp] $Message" -ForegroundColor $Color
}
Write-Host "==========================================================" -ForegroundColor Green
Write-Host " xml在线编辑器 自动化部署" -ForegroundColor Green
Write-Host "==========================================================" -ForegroundColor Green
# 步骤 1:本地前端源码编译构建
Write-Step "【步骤 1/5】开始进行前端工程编译构建 (npm run build)..." "Cyan"
Write-Step "--> 正在运行 Vue 3 + TypeScript 编译打包..." "Gray"
npm run build
if ($LASTEXITCODE -ne 0) {
Write-Step "【错误】前端代码构建失败!请检查 TypeScript 或组件编译错误。" "Red"
exit 1
}
Write-Step "--> 前端工程构建成功!已生成 dist 编译产物。" "Green"
# 步骤 2:压缩 dist 静态资源产物
Write-Step "【步骤 2/5】正在打包压缩编译好的 dist 目录静态资源..." "Cyan"
if (Test-Path "dist.tar.gz") {
Remove-Item "dist.tar.gz" -Force
}
tar -czvf dist.tar.gz -C dist .
if ($LASTEXITCODE -ne 0) {
Write-Step "【错误】本地资源压缩失败!" "Red"
exit 1
}
Write-Step "--> 静态资源压缩完成:dist.tar.gz" "Green"
# 步骤 3:清理远程服务器部署目录旧文件
Write-Step "【步骤 3/5】连接远程服务器 ($ServerIP),正在清理远程历史部署目录旧文件..." "Cyan"
Write-Step "--> 执行远程清理指令:mkdir -p + rm -rf" "Gray"
$remoteCleanCmd = "mkdir -p $RemoteDir; rm -rf $RemoteDir/*"
ssh -o StrictHostKeyChecking=no -o BatchMode=yes "${ServerUser}@${ServerIP}" $remoteCleanCmd
if ($LASTEXITCODE -ne 0) {
Write-Step "【错误】远程目录清理失败!请检查 SSH 密钥配置或网络连接。" "Red"
exit 1
}
# 步骤 4:上传静态资源到远程服务器
Write-Step "【步骤 4/5】正在上传压缩包至远程服务器目录 ($RemoteDir)..." "Cyan"
scp -o StrictHostKeyChecking=no -o BatchMode=yes dist.tar.gz "${ServerUser}@${ServerIP}:${RemoteDir}/"
if ($LASTEXITCODE -ne 0) {
Write-Step "【错误】文件上传远程服务器失败!" "Red"
exit 1
}
# 步骤 5:远程解压部署与现场清理
Write-Step "【步骤 5/5】正在远程解压资源文件并更新服务部署环境..." "Cyan"
$remoteDeployCmd = "cd $RemoteDir; tar -xzvf dist.tar.gz > /dev/null 2>&1; rm -f dist.tar.gz"
ssh -o StrictHostKeyChecking=no -o BatchMode=yes "${ServerUser}@${ServerIP}" $remoteDeployCmd
if ($LASTEXITCODE -eq 0) {
# 清理本地临时压缩包
if (Test-Path "dist.tar.gz") {
Remove-Item "dist.tar.gz" -Force
}
Write-Host "==========================================================" -ForegroundColor Green
Write-Step "【完成】项目已成功发布并部署至远程服务器!" "Green"
Write-Step " 远程服务器 IP:$ServerIP" "Yellow"
Write-Step " 远程部署目录:$RemoteDir" "Yellow"
Write-Host "==========================================================" -ForegroundColor Green
}
else {
Write-Step "【错误】远程解压过程发生异常,请连接服务器检查。" "Red"
exit 1
}
\ No newline at end of file
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
"build": "vue-tsc -b && vite build --mode dev", "build": "vue-tsc -b && vite build --mode dev",
"build:xm": "vue-tsc -b && vite build --mode xm", "build:xm": "vue-tsc -b && vite build --mode xm",
"build:bx": "vue-tsc -b && vite build --mode bx", "build:bx": "vue-tsc -b && vite build --mode bx",
"deploy": "powershell -ExecutionPolicy Bypass -File ./deploy.ps1",
"preview": "vite preview", "preview": "vite preview",
"prepare": "husky install", "prepare": "husky install",
"commitlint": "commitlint --config commitlint.config.cjs -e -V", "commitlint": "commitlint --config commitlint.config.cjs -e -V",
......
...@@ -155,20 +155,4 @@ const handleCancel = () => { ...@@ -155,20 +155,4 @@ const handleCancel = () => {
margin: 0 !important; margin: 0 !important;
} }
</style> </style>
<style scoped> <style scoped></style>
:deep(.rule-op) {
@apply text-primary font-bold;
}
:deep(.rule-quantifier) {
@apply text-warning;
}
:deep(.rule-group) {
@apply text-color3;
}
:deep(.rule-element) {
@apply text-success font-semibold;
}
:deep(.rule-pcdata) {
@apply text-danger;
}
</style>
...@@ -244,10 +244,23 @@ export function useEditor() { ...@@ -244,10 +244,23 @@ export function useEditor() {
el.remove() el.remove()
}) })
// 6. 获取当前页面的所有 CSS 样式(含 Tailwind 和 Naive UI 样式) // 6. 获取当前页面的所有 CSS 样式(遍历 CSSOM 提取完整 CSS 规则,防止线上环境 link 外链在离线 HTML 中 404)
const styles = Array.from(document.querySelectorAll('link[rel="stylesheet"], style')) let inlineCss = ''
.map((el) => el.outerHTML) Array.from(document.styleSheets).forEach((sheet) => {
.join('\n') try {
const rules = sheet.cssRules || sheet.rules
if (rules) {
Array.from(rules).forEach((rule) => {
inlineCss += rule.cssText + '\n'
})
}
} catch (e) {
if (sheet.ownerNode && sheet.ownerNode.nodeName === 'STYLE') {
inlineCss += (sheet.ownerNode.textContent || '') + '\n'
}
}
})
const styles = `<style>\n${inlineCss}\n</style>`
return { return {
innerHTML: clone.innerHTML, innerHTML: clone.innerHTML,
...@@ -576,28 +589,23 @@ export function useEditor() { ...@@ -576,28 +589,23 @@ export function useEditor() {
// 提取纯 CSS 文本,不包含 <style> 和 <link> 标签包装 // 提取纯 CSS 文本,不包含 <style> 和 <link> 标签包装
let pureCss = '' let pureCss = ''
// 1. 收集所有 style 标签的文本内容 // 遍历所有样式表提取完整 CSSOM 规则(与 HTML 预览/下载逻辑一致)
document.querySelectorAll('style').forEach((styleEl) => {
pureCss += (styleEl.textContent || '') + '\n'
})
// 2. 收集同源 link 标签的 CSS rules
Array.from(document.styleSheets).forEach((sheet) => { Array.from(document.styleSheets).forEach((sheet) => {
if (sheet.ownerNode && (sheet.ownerNode as HTMLElement).tagName === 'LINK') { try {
try { const rules = sheet.cssRules || sheet.rules
const rules = sheet.cssRules || sheet.rules if (rules) {
if (rules) { Array.from(rules).forEach((rule) => {
Array.from(rules).forEach((rule) => { pureCss += rule.cssText + '\n'
pureCss += rule.cssText + '\n' })
}) }
} } catch (e) {
} catch (e) { if (sheet.ownerNode && sheet.ownerNode.nodeName === 'STYLE') {
// 跨域 link 标签跳过 pureCss += (sheet.ownerNode.textContent || '') + '\n'
} }
} }
}) })
// 3. 加上自定义的 printStyles (不需要 style 标签包起来) // 加上自定义的 printStyles
pureCss += '\n' + printStyles pureCss += '\n' + printStyles
return { return {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment