Browse Source

feat: 重构构建部署流程并优化登录页

- 重构构建和部署流程,使用新的版本发布脚本
- 在登录页显示当前版本号并调整布局
- 添加新的构建信息插件生成版本信息
- 新增测试环境部署脚本
- 更新README文档说明新的流程
liujia 2 tháng trước cách đây
mục cha
commit
36b249d885
9 tập tin đã thay đổi với 154 bổ sung55 xóa
  1. 13 45
      README.md
  2. 11 0
      components.d.ts
  3. 5 4
      package.json
  4. 28 0
      scripts/build-info-plugin.ts
  5. 71 0
      scripts/deploy.ps1
  6. 13 0
      scripts/release-message.js
  7. 3 3
      src/stores/user.ts
  8. 8 3
      src/views/login/index.vue
  9. 2 0
      vite.config.ts

+ 13 - 45
README.md

@@ -4,63 +4,31 @@ nodejs 20.19.0
 pnpm 10.12.4
 ```
 
-## 本地开发
+## 开发阶段
 ```bash
   npm run dev # 启动研发环境
   npm run dev:test # 启动测试环境
   npm run dev:pro # 启动生产环境
 ```
 
-## 构建说明
-项目提供了多种构建方式,分别适用于不同的场景:
+## 版本发布
+用于发布版本,自动生成版本tag, 如:`v0.0.2`
 ```bash
-  # 构建生产环境
-  npm run build # 不生成tag分支与版本文件
-  # 以下脚本都会生成tag分支与版本文件
-  npm run build:test # 构建测试环境
-  npm run build:pro # 构建生成环境
-  npm run build:tag:test # 基于特定tag 构建测试环境
-  npm run build:tag:pro # 基于特定tag 构建生产环境
+  npm run release
 ```
 
-### 1、测试构建
-用于日常开发测试,自动生成带时间戳的测试版本tag,如:`test-202508061340`
-```bash
-  npm run build:test
-```
-* 执行该命令会:
-  * 自动生成格式为 `test-YYYYMMDDHHmm` 的tag
-  * 在dist目录下生成包含版本信息的 `version.json` 文件
-  * 不会修改 `package.json` 中的版本号
 
-### 2、发布构建
-用于发布正式版本,自动生成带版本号的tag,如:`publish-v0.0.2`
+## 构建阶段
 ```bash
-  npm run build:pro
+  npm run build:dev # 构建研发环境
+  npm run build:test # 构建测试环境 
+  npm run build # 构建生产环境
 ```
-* 执行该命令会:
-  * 自动生成格式为 `publish-vX.X.X` 的tag
-  * 在dist目录下生成包含版本信息的 `version.json` 文件
-  * 会更新 `package.json` 中的版本号
-
-
-### 3、基于特定tag构建
-用于基于已有的tag进行构建,用于重新构建特定tag版本的代码
-```bash
-  npm run build:tag:test # 基于特定tag 构建测试环境
-  npm run build:tag:pro # 基于特定tag 构建生产环境
-```
-
-### 4、构建注意事项
-1. 确保在执行构建命令前已提交所有更改
-2. 发布构建会修改 `package.json` 中的版本号,请确保有相应的权限
-3. 基于指定 `tag` 版本构建会切换工作目录到指定 `tag` 分支,构建完成后会自动切换回原分支,若切换失败则需手动切换回原分支
-4. 所有构建命令都会自动创建对应的 `git tag`,用于版本追踪,仅打包构建除外
-5. 构建完成后,建议手动检查 `dist` 目录下的文件,确保无误
 
-### 5、仅打包构建
-适用于仅打包,不生成 `tag` 的场景
+## 部署阶段
+> 说明:目前仅测试环境需要手动部署,研发与生产环境使用jenkins自动部署
 ```bash
-  npm run build
+  # npm run deploy # 部署生产环境
+  npm run deploy:test # 部署测试环境
+  # npm run deploy:dev # 部署研发环境
 ```
-* 执行该命令后,仅会打包生成 `dist` 目录,不会生成 `tag`,也不会修改 `package.json` 中的版本号

+ 11 - 0
components.d.ts

@@ -12,10 +12,12 @@ declare module 'vue' {
     AButton: typeof import('ant-design-vue/es')['Button']
     ACascader: typeof import('ant-design-vue/es')['Cascader']
     AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider']
+    ADrawer: typeof import('ant-design-vue/es')['Drawer']
     ADropdown: typeof import('ant-design-vue/es')['Dropdown']
     AForm: typeof import('ant-design-vue/es')['Form']
     AFormItem: typeof import('ant-design-vue/es')['FormItem']
     AInput: typeof import('ant-design-vue/es')['Input']
+    AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
     AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
     ALayout: typeof import('ant-design-vue/es')['Layout']
     ALayoutContent: typeof import('ant-design-vue/es')['LayoutContent']
@@ -27,11 +29,20 @@ declare module 'vue' {
     AModal: typeof import('ant-design-vue/es')['Modal']
     APageHeader: typeof import('ant-design-vue/es')['PageHeader']
     APagination: typeof import('ant-design-vue/es')['Pagination']
+    ARadioButton: typeof import('ant-design-vue/es')['RadioButton']
+    ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
     ARangePicker: typeof import('ant-design-vue/es')['RangePicker']
     ASelect: typeof import('ant-design-vue/es')['Select']
+    ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
+    ASkeleton: typeof import('ant-design-vue/es')['Skeleton']
     ASpace: typeof import('ant-design-vue/es')['Space']
+    ASpin: typeof import('ant-design-vue/es')['Spin']
+    ASwitch: typeof import('ant-design-vue/es')['Switch']
     ATable: typeof import('ant-design-vue/es')['Table']
+    ATag: typeof import('ant-design-vue/es')['Tag']
     ATooltip: typeof import('ant-design-vue/es')['Tooltip']
+    ATree: typeof import('ant-design-vue/es')['Tree']
+    AUploadDragger: typeof import('ant-design-vue/es')['UploadDragger']
     BaseCard: typeof import('./src/components/baseCard/index.vue')['default']
     BasePagination: typeof import('./src/components/basePagination/index.vue')['default']
     BaseWeather: typeof import('./src/components/baseWeather/index.vue')['default']

+ 5 - 4
package.json

@@ -7,11 +7,12 @@
     "dev": "vite --host --mode development --port 3000",
     "dev:test": "vite --host --mode test --port 4000",
     "dev:pro": "vite --host --mode production --port 5000",
+    "build:dev": "vite build --mode development",
+    "build:test": "vite build --mode test",
     "build": "vite build",
-    "build:test": "node version-script.js test",
-    "build:publish": "node version-script.js publish",
-    "build:tag:test": "node version-script.js test-by-tag",
-    "build:tag:pro": "node version-script.js pro-by-tag",
+    "bump": "npm version patch -m \"new version published: v%s\"",
+    "release": "npm run bump && git push && git push --tags && node scripts/release-message.js",
+    "deploy:test": "pwsh -ExecutionPolicy Bypass -File scripts/deploy.ps1",
     "preview": "vite preview",
     "type-check": "vue-tsc --build",
     "lint": "eslint . --fix",

+ 28 - 0
scripts/build-info-plugin.ts

@@ -0,0 +1,28 @@
+import fs from 'fs'
+import path from 'path'
+import { execSync } from 'child_process'
+import type { Plugin } from 'vite'
+import { formatDateTime } from '../src/utils'
+
+export default function buildInfoPlugin(mode: string): Plugin {
+  return {
+    name: 'build-info-plugin',
+    closeBundle() {
+      const pkg = JSON.parse(fs.readFileSync('./package.json', 'utf-8'))
+
+      const buildInfo = {
+        version: pkg.version,
+        buildTime: formatDateTime(new Date()),
+        branch: execSync('git rev-parse --abbrev-ref HEAD').toString().trim(),
+        commitHash: execSync('git rev-parse --short HEAD').toString().trim(),
+        env: mode,
+      }
+
+      const outDir = path.resolve(process.cwd(), 'dist')
+      fs.writeFileSync(path.join(outDir, 'version.json'), JSON.stringify(buildInfo, null, 2))
+
+      console.log('\x1b[36m📦 已生成 version.json\x1b[0m')
+      console.log(buildInfo)
+    },
+  }
+}

+ 71 - 0
scripts/deploy.ps1

@@ -0,0 +1,71 @@
+# 前端部署脚本
+# 日期:2025-08-07
+
+# ========== 🛠️ 配置参数 ==========
+$sourceDir = "D:\project\ln-web\dist"
+$remoteUser = "liujia"
+$remoteIP = "43.137.10.199"
+$remotePath = "/work/web/dist" # 实际路径  /work/web/dist
+$sshPort = 22
+
+# === 准备文件 ===
+$timestamp = Get-Date -Format "yyyyMMddHHmmss"
+$zipPath = "D:\project\dist-$timestamp.zip"
+
+Write-Host "`n🗜️ 正在压缩 dist..." -ForegroundColor Cyan
+Compress-Archive -Path "$sourceDir\*" -DestinationPath $zipPath -CompressionLevel Optimal
+$zipSizeMB = [math]::Round((Get-Item $zipPath).Length / 1MB, 2)
+
+Write-Host "`n🚀 上传压缩包到服务器 ($zipSizeMB MB)..." -ForegroundColor Cyan
+scp -P $sshPort $zipPath "${remoteUser}@${remoteIP}:~/dist-latest.zip"
+
+# === 生成远程 bash 部署脚本 ===
+$remoteScript = @'
+#!/bin/bash
+set -e
+
+timestamp={0}
+tmpdir="/tmp/dist-temp-$timestamp"
+
+echo "📁 创建临时目录 $tmpdir"
+mkdir -p "$tmpdir"
+
+echo "📦 解压上传文件"
+unzip -qo ~/dist-latest.zip -d "$tmpdir"
+
+echo "🔒 设置 root 权限"
+sudo chown -R root:root "$tmpdir"
+
+if [ -d "{1}" ]; then
+  echo "🕐 备份旧目录"
+  sudo mv "{1}" "{1}-backup-$timestamp"
+fi
+
+echo "🚀 替换新目录"
+sudo mv "$tmpdir" "{1}"
+
+echo "🧹 删除压缩包"
+rm ~/dist-latest.zip
+
+echo "✅ 远程部署完成: {1} 替换成功"
+'@ -f $timestamp, $remotePath
+
+
+# === 写入为 LF 格式(避免 \r 问题)===
+$localScriptPath = "D:\project\deploy-temp.sh"
+$remoteScriptLF = $remoteScript -replace "`r", ""
+Set-Content -Path $localScriptPath -Value $remoteScriptLF -Encoding UTF8
+
+# === 上传并执行远程脚本 ===
+Write-Host "`n📤 上传远程部署脚本..." -ForegroundColor Cyan
+scp -P $sshPort $localScriptPath "${remoteUser}@${remoteIP}:~/deploy-temp.sh"
+
+Write-Host "`n📦 正在服务器上原子部署 ..." -ForegroundColor Cyan
+ssh -p $sshPort ${remoteUser}@${remoteIP} "bash ~/deploy-temp.sh"
+
+# === 清理 ===
+Write-Host "`n🧹 清理临时文件..." -ForegroundColor DarkGray
+ssh -p $sshPort ${remoteUser}@${remoteIP} 'rm ~/deploy-temp.sh'
+Remove-Item $zipPath, $localScriptPath -Force -ErrorAction SilentlyContinue
+
+Write-Host "`n✅ 部署完成,压缩包大小:$zipSizeMB MB" -ForegroundColor Green

+ 13 - 0
scripts/release-message.js

@@ -0,0 +1,13 @@
+#!/usr/bin/env node
+import pkg from '../package.json' assert { type: 'json' }
+
+const version = pkg.version
+
+console.log('\x1b[36m=========================\x1b[0m')
+console.log('\x1b[32m🎉 发布成功!\x1b[0m')
+console.log(`\x1b[33m📦 版本号:v${version}\x1b[0m`)
+console.log('\x1b[35m⚙️  打包命令:\x1b[0m')
+console.log('\x1b[34m  * 开发环境:npm run build:dev\x1b[0m')
+console.log('\x1b[34m  * 测试环境:npm run build:test\x1b[0m')
+console.log('\x1b[34m  * 生产环境:npm run build:pro or npm run build\x1b[0m')
+console.log('\x1b[36m=========================\x1b[0m')

+ 3 - 3
src/stores/user.ts

@@ -100,9 +100,9 @@ export const useUserStore = defineStore(
       if (router.currentRoute.value.name === 'login') return
       router.push({
         name: 'login',
-        query: {
-          redirect: redirectPath,
-        },
+        // query: {
+        //   redirect: redirectPath,
+        // },
       })
     }
 

+ 8 - 3
src/views/login/index.vue

@@ -35,7 +35,10 @@
           </a-form>
           <a-button type="primary" block :loading="sbumitLoading" @click="login">登录</a-button>
         </div>
-        <div class="footer"> 合肥雷能信息技术有限公司 </div>
+        <div class="footer">
+          <span>合肥雷能信息技术有限公司</span>
+          <span>&nbsp;&nbsp;版本号:{{ version }}</span>
+        </div>
       </div>
     </div>
   </div>
@@ -51,6 +54,7 @@ defineOptions({
 })
 
 const userStore = useUserStore()
+const version = __APP_VERSION__
 
 interface FormState {
   account: string
@@ -114,7 +118,7 @@ const login = () => {
   }
 
   .loginCard {
-    width: 750px;
+    width: 800px;
     height: 500px;
     background-color: #fff;
     border-radius: 10px;
@@ -134,7 +138,8 @@ const login = () => {
       }
     }
     .contant {
-      width: 40%;
+      width: 45%;
+      min-width: 350px;
       height: 100%;
       padding: 20px;
       display: flex;

+ 2 - 0
vite.config.ts

@@ -7,6 +7,7 @@ import Components from 'unplugin-vue-components/vite'
 import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'
 import { readFileSync } from 'fs'
 import { formatDateTime } from './src/utils'
+import buildInfoPlugin from './scripts/build-info-plugin'
 
 // https://vite.dev/config/
 export default defineConfig(({ mode }) => {
@@ -24,6 +25,7 @@ export default defineConfig(({ mode }) => {
     plugins: [
       vue(),
       vueDevTools(),
+      buildInfoPlugin(mode),
       Components({
         resolvers: [
           AntDesignVueResolver({