feat: 添加应用版本管理功能;生成 version.json 文件并更新环境变量配置
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
VITE_API_URL=http://192.168.1.3:9528
|
VITE_API_URL=http://192.168.1.3:9528
|
||||||
VITE_TRADINGVIEW_LIBRARY_URL=http://192.168.1.5:6173
|
VITE_TRADINGVIEW_LIBRARY_URL=http://192.168.1.5:6173
|
||||||
VITE_TRADINGVIEW_DATA_API_URL=https://demo-feed-data.tradingview.com
|
VITE_TRADINGVIEW_DATA_API_URL=https://demo-feed-data.tradingview.com
|
||||||
VITE_APP_VERSION=0.0.1
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
VITE_API_URL=http://192.168.1.3:9527
|
VITE_API_URL=http://192.168.1.3:9527
|
||||||
VITE_TRADINGVIEW_LIBRARY_URL=http://192.168.1.5:6173
|
VITE_TRADINGVIEW_LIBRARY_URL=http://192.168.1.5:6173
|
||||||
VITE_TRADINGVIEW_DATA_API_URL=https://demo-feed-data.tradingview.com
|
VITE_TRADINGVIEW_DATA_API_URL=https://demo-feed-data.tradingview.com
|
||||||
VITE_APP_VERSION=0.0.1
|
|
||||||
474
VERSION_MANAGEMENT.md
Normal file
474
VERSION_MANAGEMENT.md
Normal file
@@ -0,0 +1,474 @@
|
|||||||
|
# 版本管理方案
|
||||||
|
|
||||||
|
## 🎯 问题
|
||||||
|
|
||||||
|
前端每次更新版本,后端也需要手动同步版本信息,容易出错且效率低。
|
||||||
|
|
||||||
|
## ✅ 解决方案
|
||||||
|
|
||||||
|
### 方案一:自动生成 version.json(已实现)⭐⭐⭐
|
||||||
|
|
||||||
|
前端打包时自动生成 `version.json` 文件,后端可以直接读取。
|
||||||
|
|
||||||
|
#### 工作流程
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 开发者修改 package.json 中的 version
|
||||||
|
↓
|
||||||
|
2. 运行 pnpm run build
|
||||||
|
↓
|
||||||
|
3. Vite 自动读取 package.json 版本
|
||||||
|
↓
|
||||||
|
4. 构建完成后生成 dist/version.json
|
||||||
|
↓
|
||||||
|
5. 部署到服务器
|
||||||
|
↓
|
||||||
|
6. 后端通过 HTTP 请求获取前端版本
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 生成的 version.json 格式
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "0.0.1",
|
||||||
|
"buildTime": "2025-12-30T10:30:00.000Z",
|
||||||
|
"gitCommit": "abc123",
|
||||||
|
"environment": "production"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 后端获取版本的方式
|
||||||
|
|
||||||
|
**方式 1:直接读取静态文件(推荐)**
|
||||||
|
|
||||||
|
如果前端部署在 Nginx/CDN,后端可以直接访问:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl https://your-domain.com/version.json
|
||||||
|
```
|
||||||
|
|
||||||
|
后端 API 实现示例:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Node.js / Elysia 示例
|
||||||
|
app.get('/api/app/version', async (ctx) => {
|
||||||
|
// 从前端静态资源读取版本
|
||||||
|
const response = await fetch('https://your-frontend-domain.com/version.json')
|
||||||
|
const frontendVersion = await response.json()
|
||||||
|
|
||||||
|
const { platform, currentVersion } = ctx.query
|
||||||
|
|
||||||
|
return {
|
||||||
|
version: frontendVersion.version,
|
||||||
|
forceUpdate: compareVersion(currentVersion, frontendVersion.version) < 0,
|
||||||
|
updateMessage: '修复了一些问题',
|
||||||
|
updateUrl: platform === 'ios'
|
||||||
|
? 'https://apps.apple.com/app/xxx'
|
||||||
|
: 'https://play.google.com/store/apps/details?id=xxx',
|
||||||
|
minSupportVersion: '0.0.1',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**方式 2:部署时同步到后端**
|
||||||
|
|
||||||
|
在 CI/CD 中,部署前端时自动同步 version.json 到后端:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# GitHub Actions / GitLab CI 示例
|
||||||
|
- name: Deploy Frontend
|
||||||
|
run: |
|
||||||
|
pnpm run build
|
||||||
|
# 上传到前端服务器
|
||||||
|
rsync -avz dist/ user@frontend-server:/var/www/html/
|
||||||
|
# 同时将 version.json 复制到后端
|
||||||
|
scp dist/version.json user@backend-server:/app/frontend-version.json
|
||||||
|
```
|
||||||
|
|
||||||
|
后端直接读取本地文件:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import fs from 'fs'
|
||||||
|
|
||||||
|
app.get('/api/app/version', async (ctx) => {
|
||||||
|
const versionFile = fs.readFileSync('/app/frontend-version.json', 'utf-8')
|
||||||
|
const { version } = JSON.parse(versionFile)
|
||||||
|
|
||||||
|
return {
|
||||||
|
version,
|
||||||
|
forceUpdate: false,
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 使用步骤
|
||||||
|
|
||||||
|
### 1. 修改版本号
|
||||||
|
|
||||||
|
只需修改 `package.json` 中的 `version` 字段:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "1.2.3" // 只改这里
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 构建项目
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
构建完成后会在 `dist/` 目录生成 `version.json`:
|
||||||
|
|
||||||
|
```
|
||||||
|
dist/
|
||||||
|
├── index.html
|
||||||
|
├── assets/
|
||||||
|
└── version.json ← 自动生成
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 部署
|
||||||
|
|
||||||
|
将整个 `dist/` 目录部署到服务器,`version.json` 会一起部署。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 原生应用版本同步
|
||||||
|
|
||||||
|
### iOS (Xcode)
|
||||||
|
|
||||||
|
修改 `ios/App/App/Info.plist`:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.2.3</string> <!-- 与 package.json 保持一致 -->
|
||||||
|
```
|
||||||
|
|
||||||
|
### Android (build.gradle)
|
||||||
|
|
||||||
|
修改 `android/app/build.gradle`:
|
||||||
|
|
||||||
|
```gradle
|
||||||
|
versionName "1.2.3" // 与 package.json 保持一致
|
||||||
|
```
|
||||||
|
|
||||||
|
### 自动化脚本(可选)
|
||||||
|
|
||||||
|
创建 `scripts/sync-version.js`:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
#!/usr/bin/env node
|
||||||
|
import fs from 'fs'
|
||||||
|
import { execSync } from 'child_process'
|
||||||
|
|
||||||
|
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf-8'))
|
||||||
|
const version = packageJson.version
|
||||||
|
|
||||||
|
console.log(`Syncing version ${version} to native projects...`)
|
||||||
|
|
||||||
|
// iOS
|
||||||
|
const infoPlist = './ios/App/App/Info.plist'
|
||||||
|
let plistContent = fs.readFileSync(infoPlist, 'utf-8')
|
||||||
|
plistContent = plistContent.replace(
|
||||||
|
/<key>CFBundleShortVersionString<\/key>\s*<string>.*?<\/string>/,
|
||||||
|
`<key>CFBundleShortVersionString</key>\n\t<string>${version}</string>`
|
||||||
|
)
|
||||||
|
fs.writeFileSync(infoPlist, plistContent)
|
||||||
|
|
||||||
|
// Android (需要安装 gradle 解析库或手动更新)
|
||||||
|
console.log('Please manually update android/app/build.gradle versionName')
|
||||||
|
|
||||||
|
console.log('✓ Version synced!')
|
||||||
|
```
|
||||||
|
|
||||||
|
在 `package.json` 中添加脚本:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"version:sync": "node scripts/sync-version.js",
|
||||||
|
"build:ios": "npm run version:sync && ionic cap sync ios",
|
||||||
|
"build:android": "npm run version:sync && ionic cap sync android"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 版本号规范
|
||||||
|
|
||||||
|
遵循**语义化版本 (Semantic Versioning)**:
|
||||||
|
|
||||||
|
```
|
||||||
|
主版本号.次版本号.修订号
|
||||||
|
↓ ↓ ↓
|
||||||
|
1 . 2 . 3
|
||||||
|
|
||||||
|
- 主版本号:不兼容的 API 修改
|
||||||
|
- 次版本号:向下兼容的功能新增
|
||||||
|
- 修订号:向下兼容的问题修正
|
||||||
|
```
|
||||||
|
|
||||||
|
### 版本更新示例
|
||||||
|
|
||||||
|
- `0.0.1` → `0.0.2` - 修复 bug
|
||||||
|
- `0.0.2` → `0.1.0` - 新增功能
|
||||||
|
- `0.1.0` → `1.0.0` - 重大更新
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 CI/CD 集成
|
||||||
|
|
||||||
|
### GitHub Actions 示例
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: Build and Deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '18'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: pnpm run build
|
||||||
|
env:
|
||||||
|
NODE_ENV: production
|
||||||
|
|
||||||
|
- name: Deploy to server
|
||||||
|
run: |
|
||||||
|
rsync -avz dist/ user@server:/var/www/html/
|
||||||
|
|
||||||
|
- name: Notify backend
|
||||||
|
run: |
|
||||||
|
curl -X POST https://your-backend.com/api/webhook/frontend-deployed \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"version": "'$(node -p "require('./package.json').version")'"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 方案对比
|
||||||
|
|
||||||
|
| 方案 | 优点 | 缺点 | 推荐度 |
|
||||||
|
|-----|------|------|--------|
|
||||||
|
| **自动生成 version.json** | 完全自动化、前后端解耦 | 需要后端额外请求 | ⭐⭐⭐⭐⭐ |
|
||||||
|
| 手动同步 | 简单直接 | 容易忘记、出错 | ⭐ |
|
||||||
|
| 共享配置文件 | 统一管理 | 需要 Monorepo | ⭐⭐⭐ |
|
||||||
|
| 环境变量 | 灵活 | 部署时需手动设置 | ⭐⭐ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ 总结
|
||||||
|
|
||||||
|
1. **前端**:只需修改 `package.json` 的 `version` 字段
|
||||||
|
2. **构建**:运行 `pnpm run build` 自动生成 `version.json`
|
||||||
|
3. **后端**:通过 HTTP 请求或读取文件获取版本信息
|
||||||
|
4. **原生应用**:可选使用脚本自动同步版本号
|
||||||
|
|
||||||
|
**一次配置,永久受益!** 🎉
|
||||||
|
|
||||||
|
|
||||||
|
## 后端 API 实现示例 - 版本检查接口
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { Elysia, t } from 'elysia'
|
||||||
|
|
||||||
|
// 版本比较工具函数
|
||||||
|
function compareVersion(version1: string, version2: string): number {
|
||||||
|
const v1Parts = version1.split('.').map(Number)
|
||||||
|
const v2Parts = version2.split('.').map(Number)
|
||||||
|
const maxLength = Math.max(v1Parts.length, v2Parts.length)
|
||||||
|
|
||||||
|
for (let i = 0; i < maxLength; i++) {
|
||||||
|
const v1Part = v1Parts[i] || 0
|
||||||
|
const v2Part = v2Parts[i] || 0
|
||||||
|
|
||||||
|
if (v1Part < v2Part) return -1
|
||||||
|
if (v1Part > v2Part) return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方案一:从前端静态资源读取版本(推荐)
|
||||||
|
async function getFrontendVersionFromURL(): Promise<{
|
||||||
|
version: string
|
||||||
|
buildTime: string
|
||||||
|
gitCommit: string
|
||||||
|
environment: string
|
||||||
|
}> {
|
||||||
|
const response = await fetch('https://your-frontend-domain.com/version.json')
|
||||||
|
return await response.json()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方案二:从本地文件读取(适用于前后端部署在同一服务器)
|
||||||
|
import fs from 'fs'
|
||||||
|
|
||||||
|
function getFrontendVersionFromFile(): {
|
||||||
|
version: string
|
||||||
|
buildTime: string
|
||||||
|
gitCommit: string
|
||||||
|
environment: string
|
||||||
|
} {
|
||||||
|
const content = fs.readFileSync('/app/frontend-version.json', 'utf-8')
|
||||||
|
return JSON.parse(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用商店链接配置
|
||||||
|
const APP_STORE_URLS = {
|
||||||
|
ios: 'https://apps.apple.com/app/id123456789',
|
||||||
|
android: 'https://play.google.com/store/apps/details?id=riwa.ionic.app',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 版本策略配置(可存储在数据库)
|
||||||
|
const VERSION_POLICIES = {
|
||||||
|
minSupportVersion: '0.0.1', // 最低支持版本
|
||||||
|
forceUpdateVersions: ['0.0.1'], // 需要强制更新的版本列表
|
||||||
|
updateMessages: {
|
||||||
|
'zh-CN': '修复了一些问题并优化了性能',
|
||||||
|
'en-US': 'Bug fixes and performance improvements',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Elysia 路由定义
|
||||||
|
const app = new Elysia()
|
||||||
|
.get(
|
||||||
|
'/api/app/version',
|
||||||
|
async ({ query, headers }) => {
|
||||||
|
const { platform, currentVersion } = query
|
||||||
|
const lang = headers['accept-language']?.split(',')[0] || 'en-US'
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 获取前端版本信息
|
||||||
|
const frontendVersion = await getFrontendVersionFromURL()
|
||||||
|
// 或使用本地文件: const frontendVersion = getFrontendVersionFromFile()
|
||||||
|
|
||||||
|
// 判断是否需要更新
|
||||||
|
const hasUpdate = compareVersion(currentVersion, frontendVersion.version) < 0
|
||||||
|
|
||||||
|
// 判断是否强制更新
|
||||||
|
let forceUpdate = VERSION_POLICIES.forceUpdateVersions.includes(currentVersion)
|
||||||
|
|
||||||
|
// 检查是否低于最低支持版本
|
||||||
|
if (compareVersion(currentVersion, VERSION_POLICIES.minSupportVersion) < 0) {
|
||||||
|
forceUpdate = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取更新链接
|
||||||
|
const updateUrl = platform === 'ios'
|
||||||
|
? APP_STORE_URLS.ios
|
||||||
|
: platform === 'android'
|
||||||
|
? APP_STORE_URLS.android
|
||||||
|
: ''
|
||||||
|
|
||||||
|
// 获取更新说明(多语言)
|
||||||
|
const updateMessage = VERSION_POLICIES.updateMessages[lang]
|
||||||
|
|| VERSION_POLICIES.updateMessages['en-US']
|
||||||
|
|
||||||
|
return {
|
||||||
|
version: frontendVersion.version,
|
||||||
|
buildNumber: parseInt(frontendVersion.version.replace(/\./g, '')),
|
||||||
|
buildTime: frontendVersion.buildTime,
|
||||||
|
gitCommit: frontendVersion.gitCommit,
|
||||||
|
forceUpdate,
|
||||||
|
updateMessage,
|
||||||
|
updateUrl,
|
||||||
|
minSupportVersion: VERSION_POLICIES.minSupportVersion,
|
||||||
|
releaseNotes: [
|
||||||
|
'修复了已知问题',
|
||||||
|
'优化了应用性能',
|
||||||
|
'改进了用户界面',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to get frontend version:', error)
|
||||||
|
|
||||||
|
// 降级处理:返回当前版本,不强制更新
|
||||||
|
return {
|
||||||
|
version: currentVersion,
|
||||||
|
forceUpdate: false,
|
||||||
|
updateMessage: '',
|
||||||
|
updateUrl: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: t.Object({
|
||||||
|
platform: t.Union([t.Literal('ios'), t.Literal('android'), t.Literal('web')]),
|
||||||
|
currentVersion: t.String(),
|
||||||
|
}),
|
||||||
|
response: t.Object({
|
||||||
|
version: t.String(),
|
||||||
|
buildNumber: t.Optional(t.Number()),
|
||||||
|
buildTime: t.Optional(t.String()),
|
||||||
|
gitCommit: t.Optional(t.String()),
|
||||||
|
forceUpdate: t.Boolean(),
|
||||||
|
updateMessage: t.Optional(t.String()),
|
||||||
|
updateUrl: t.Optional(t.String()),
|
||||||
|
minSupportVersion: t.Optional(t.String()),
|
||||||
|
releaseNotes: t.Optional(t.Array(t.String())),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default app
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用示例:
|
||||||
|
*
|
||||||
|
* 1. 启动后端服务
|
||||||
|
* 2. 前端请求:GET /api/app/version?platform=ios¤tVersion=0.0.1
|
||||||
|
* 3. 后端响应:
|
||||||
|
* {
|
||||||
|
* "version": "0.0.2",
|
||||||
|
* "buildTime": "2025-12-30T11:42:43.425Z",
|
||||||
|
* "forceUpdate": false,
|
||||||
|
* "updateMessage": "修复了一些问题并优化了性能",
|
||||||
|
* "updateUrl": "https://apps.apple.com/app/id123456789",
|
||||||
|
* "minSupportVersion": "0.0.1"
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据库存储方案(可选)
|
||||||
|
*
|
||||||
|
* 如果需要更灵活的版本策略管理,可以将配置存储在数据库:
|
||||||
|
*
|
||||||
|
* CREATE TABLE app_versions (
|
||||||
|
* id SERIAL PRIMARY KEY,
|
||||||
|
* platform VARCHAR(20) NOT NULL,
|
||||||
|
* version VARCHAR(20) NOT NULL,
|
||||||
|
* min_support_version VARCHAR(20),
|
||||||
|
* force_update BOOLEAN DEFAULT FALSE,
|
||||||
|
* update_message_zh TEXT,
|
||||||
|
* update_message_en TEXT,
|
||||||
|
* update_url TEXT,
|
||||||
|
* release_notes JSONB,
|
||||||
|
* created_at TIMESTAMP DEFAULT NOW()
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
* 然后从数据库查询版本策略:
|
||||||
|
* const policy = await db.query(
|
||||||
|
* 'SELECT * FROM app_versions WHERE platform = $1 ORDER BY created_at DESC LIMIT 1',
|
||||||
|
* [platform]
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
|
||||||
|
```
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"run:ios": "ionic capacitor run ios -l --external",
|
"run:ios": "ionic capacitor run ios -l --external",
|
||||||
"run:android": "ionic capacitor run android -l --external",
|
"run:android": "ionic capacitor run android -l --external",
|
||||||
"proxy": "ionic config set -g proxy http://192.168.1.36:9527",
|
"proxy": "ionic config set -g proxy http://192.168.1.3:9527",
|
||||||
"test:e2e": "cypress run",
|
"test:e2e": "cypress run",
|
||||||
"test:unit": "vitest",
|
"test:unit": "vitest",
|
||||||
"lint": "eslint",
|
"lint": "eslint",
|
||||||
@@ -81,6 +81,7 @@
|
|||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"eslint-plugin-format": "^1.1.0",
|
"eslint-plugin-format": "^1.1.0",
|
||||||
"eslint-plugin-vue": "^10.6.2",
|
"eslint-plugin-vue": "^10.6.2",
|
||||||
|
"jiti": "^2.6.1",
|
||||||
"jsdom": "^27.3.0",
|
"jsdom": "^27.3.0",
|
||||||
"lint-staged": "^16.2.7",
|
"lint-staged": "^16.2.7",
|
||||||
"simple-git-hooks": "^2.13.1",
|
"simple-git-hooks": "^2.13.1",
|
||||||
|
|||||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -195,6 +195,9 @@ importers:
|
|||||||
eslint-plugin-vue:
|
eslint-plugin-vue:
|
||||||
specifier: ^10.6.2
|
specifier: ^10.6.2
|
||||||
version: 10.6.2(@stylistic/eslint-plugin@5.6.1(eslint@9.39.1(jiti@2.6.1)))(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.1(jiti@2.6.1)))
|
version: 10.6.2(@stylistic/eslint-plugin@5.6.1(eslint@9.39.1(jiti@2.6.1)))(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.1(jiti@2.6.1)))
|
||||||
|
jiti:
|
||||||
|
specifier: ^2.6.1
|
||||||
|
version: 2.6.1
|
||||||
jsdom:
|
jsdom:
|
||||||
specifier: ^27.3.0
|
specifier: ^27.3.0
|
||||||
version: 27.3.0(postcss@8.5.6)
|
version: 27.3.0(postcss@8.5.6)
|
||||||
|
|||||||
25
scripts/build.ts
Normal file
25
scripts/build.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
import process from "node:process";
|
||||||
|
|
||||||
|
export interface VersionPluginOptions {
|
||||||
|
version: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateVersion(options: VersionPluginOptions) {
|
||||||
|
return {
|
||||||
|
name: "generate-version",
|
||||||
|
closeBundle() {
|
||||||
|
const versionInfo = {
|
||||||
|
version: options.version,
|
||||||
|
buildTime: new Date().toISOString(),
|
||||||
|
environment: process.env.NODE_ENV,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 写入到 dist 目录
|
||||||
|
const distPath = path.resolve(process.cwd(), "dist/version.json");
|
||||||
|
fs.writeFileSync(distPath, JSON.stringify(versionInfo, null, 2));
|
||||||
|
console.log(`✓ Generated version.json: ${options.version}`);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -58,8 +58,8 @@ export function useAppUpdate() {
|
|||||||
return appInfo.version;
|
return appInfo.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Web 平台从环境变量或 package.json 获取
|
// Web 平台从编译时注入的全局变量获取(来自 package.json)
|
||||||
return import.meta.env.VITE_APP_VERSION;
|
return __APP_VERSION__;
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error("获取当前版本失败:", error);
|
console.error("获取当前版本失败:", error);
|
||||||
|
|||||||
@@ -10,5 +10,5 @@
|
|||||||
},
|
},
|
||||||
"allowSyntheticDefaultImports": true
|
"allowSyntheticDefaultImports": true
|
||||||
},
|
},
|
||||||
"include": ["vite.config.ts", "tailwind.config.ts"]
|
"include": ["vite.config.ts", "tailwind.config.ts", "scripts/**/*.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
3
types/env.d.ts
vendored
3
types/env.d.ts
vendored
@@ -12,9 +12,10 @@ interface ImportMetaEnv {
|
|||||||
readonly VITE_API_URL: string;
|
readonly VITE_API_URL: string;
|
||||||
readonly VITE_TRADINGVIEW_LIBRARY_URL: string;
|
readonly VITE_TRADINGVIEW_LIBRARY_URL: string;
|
||||||
readonly VITE_TRADINGVIEW_DATA_API_URL: string;
|
readonly VITE_TRADINGVIEW_DATA_API_URL: string;
|
||||||
readonly VITE_APP_VERSION: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
readonly env: ImportMetaEnv;
|
readonly env: ImportMetaEnv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare const __APP_VERSION__: string;
|
||||||
|
|||||||
12
vault.md
12
vault.md
@@ -1,12 +0,0 @@
|
|||||||
open float Y 开盘价 每一个纬度(例如天纬度,就是一天的第一笔成交价格)的第一笔成交价格
|
|
||||||
high float Y 最高价
|
|
||||||
low float Y 最低价
|
|
||||||
close float Y 收盘价
|
|
||||||
settle float Y 结算价 每一个纬度(某一个时间段之内的金额总和 / 交易量)
|
|
||||||
|
|
||||||
接口
|
|
||||||
代币化分类接口
|
|
||||||
代币化列表接口
|
|
||||||
代币化详情接口
|
|
||||||
代币化数据接口
|
|
||||||
买卖接口
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import fs from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import process from "node:process";
|
import process from "node:process";
|
||||||
import tailwindcss from "@tailwindcss/vite";
|
import tailwindcss from "@tailwindcss/vite";
|
||||||
@@ -11,9 +12,13 @@ import icons from "unplugin-icons/vite";
|
|||||||
import { IonicResolver } from "unplugin-vue-components/resolvers";
|
import { IonicResolver } from "unplugin-vue-components/resolvers";
|
||||||
import components from "unplugin-vue-components/vite";
|
import components from "unplugin-vue-components/vite";
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
|
import { generateVersion } from "./scripts/build";
|
||||||
|
|
||||||
dotenv.config({ path: `.env.${process.env.NODE_ENV}` });
|
dotenv.config({ path: `.env.${process.env.NODE_ENV}` });
|
||||||
|
|
||||||
|
const packageJson = JSON.parse(fs.readFileSync("./package.json", "utf-8"));
|
||||||
|
const appVersion = packageJson.version;
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
@@ -34,9 +39,12 @@ export default defineConfig({
|
|||||||
directoryAsNamespace: true,
|
directoryAsNamespace: true,
|
||||||
resolvers: [IonicResolver(), iconsResolver({ prefix: "i" })],
|
resolvers: [IonicResolver(), iconsResolver({ prefix: "i" })],
|
||||||
}),
|
}),
|
||||||
|
generateVersion({
|
||||||
|
version: appVersion,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
define: {
|
define: {
|
||||||
APP_VERSION: JSON.stringify(process.env.VITE_APP_VERSION || "0.0.1"),
|
__APP_VERSION__: JSON.stringify(appVersion),
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
|||||||
Reference in New Issue
Block a user