feat: 添加构建时间信息和相关功能
This commit is contained in:
@@ -12,7 +12,7 @@ APP_BASE_URL=https://bai-api.blv-oa.com
|
|||||||
|
|
||||||
# Database Configuration (Pocketbase)
|
# Database Configuration (Pocketbase)
|
||||||
POCKETBASE_API_URL=https://bai-api.blv-oa.com/pb/
|
POCKETBASE_API_URL=https://bai-api.blv-oa.com/pb/
|
||||||
POCKETBASE_AUTH_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJfcGJfdXNlcnNfYXV0aF8iLCJleHAiOjE3NzQzNjEzMzIsImlkIjoiazQ0aHI5MW90bnBydG10IiwicmVmcmVzaGFibGUiOmZhbHNlLCJ0eXBlIjoiYXV0aCJ9.qm4E6xYrDbEpAfdxZnHHRZs_EqiwHgDIIwSBz2k90Nk
|
POCKETBASE_AUTH_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJwYmNfMzE0MjYzNTgyMyIsImV4cCI6MTc3NDEwMTc4NiwiaWQiOiJmcnl2dG1qNnlwcHlmMXAiLCJyZWZyZXNoYWJsZSI6ZmFsc2UsInR5cGUiOiJhdXRoIn0.67DCKhqRQYF3ClPU_9mBgON_9ZDEy-NzqTeS50rGGZo
|
||||||
|
|
||||||
# WeChat Configuration
|
# WeChat Configuration
|
||||||
WECHAT_APPID=wx3bd7a7b19679da7a
|
WECHAT_APPID=wx3bd7a7b19679da7a
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const rootDir = path.resolve(__dirname, '..')
|
|||||||
const distDir = path.join(rootDir, 'dist')
|
const distDir = path.join(rootDir, 'dist')
|
||||||
const sourceDirs = ['src', 'spec']
|
const sourceDirs = ['src', 'spec']
|
||||||
const sourceFiles = ['package.json', 'package-lock.json', '.env', 'eslint.config.js']
|
const sourceFiles = ['package.json', 'package-lock.json', '.env', 'eslint.config.js']
|
||||||
|
const buildInfoPath = path.join(distDir, 'build-info.json')
|
||||||
|
|
||||||
function ensureCleanDir(dirPath) {
|
function ensureCleanDir(dirPath) {
|
||||||
fs.rmSync(dirPath, { recursive: true, force: true })
|
fs.rmSync(dirPath, { recursive: true, force: true })
|
||||||
@@ -46,6 +47,17 @@ function build() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
buildInfoPath,
|
||||||
|
JSON.stringify(
|
||||||
|
{
|
||||||
|
buildTime: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
console.log('Build completed. Deployable files generated in dist/.')
|
console.log('Build completed. Deployable files generated in dist/.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,11 @@ components:
|
|||||||
status:
|
status:
|
||||||
type: string
|
type: string
|
||||||
example: success
|
example: success
|
||||||
|
build_time:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
description: 最近一次构建时间;开发模式下若未执行构建则可能为空
|
||||||
|
format: date-time
|
||||||
WechatProfileRequest:
|
WechatProfileRequest:
|
||||||
type: object
|
type: object
|
||||||
required: [users_name, users_phone_code, users_picture]
|
required: [users_name, users_phone_code, users_picture]
|
||||||
@@ -197,7 +202,7 @@ paths:
|
|||||||
post:
|
post:
|
||||||
tags: [系统]
|
tags: [系统]
|
||||||
summary: Test endpoint
|
summary: Test endpoint
|
||||||
description: Returns a hello world message
|
description: Returns a hello world message and build time
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Successful response
|
description: Successful response
|
||||||
|
|||||||
@@ -1,23 +1,29 @@
|
|||||||
const express = require('express')
|
const express = require('express')
|
||||||
const { success } = require('../utils/response')
|
const { success } = require('../utils/response')
|
||||||
|
const { getBuildTimestamp } = require('../utils/buildInfo')
|
||||||
const wechatRoutes = require('./wechatRoutes')
|
const wechatRoutes = require('./wechatRoutes')
|
||||||
|
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
|
|
||||||
router.post('/test-helloworld', (req, res) => {
|
function respondHelloWorld(req, res) {
|
||||||
return success(res, '请求成功', {
|
return success(res, '请求成功', {
|
||||||
message: 'Hello, World!',
|
message: 'Hello, World!',
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
status: 'success',
|
status: 'success',
|
||||||
|
build_time: getBuildTimestamp(),
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
|
||||||
router.post('/health', (req, res) => {
|
function respondHealth(req, res) {
|
||||||
return success(res, '服务运行正常', {
|
return success(res, '服务运行正常', {
|
||||||
status: 'healthy',
|
status: 'healthy',
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
|
||||||
|
router.post('/test-helloworld', respondHelloWorld)
|
||||||
|
|
||||||
|
router.post('/health', respondHealth)
|
||||||
|
|
||||||
router.use('/wechat', wechatRoutes)
|
router.use('/wechat', wechatRoutes)
|
||||||
|
|
||||||
|
|||||||
30
back-end/src/utils/buildInfo.js
Normal file
30
back-end/src/utils/buildInfo.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
function getBuildInfoFilePath() {
|
||||||
|
return path.resolve(__dirname, '..', '..', 'build-info.json')
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBuildTimestamp() {
|
||||||
|
if (process.env.BUILD_TIME) {
|
||||||
|
return process.env.BUILD_TIME
|
||||||
|
}
|
||||||
|
|
||||||
|
const filePath = getBuildInfoFilePath()
|
||||||
|
|
||||||
|
if (!fs.existsSync(filePath)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const content = fs.readFileSync(filePath, 'utf8')
|
||||||
|
const payload = JSON.parse(content)
|
||||||
|
return payload.buildTime || null
|
||||||
|
} catch {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getBuildTimestamp,
|
||||||
|
}
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
const test = require('node:test')
|
const test = require('node:test')
|
||||||
const assert = require('node:assert/strict')
|
const assert = require('node:assert/strict')
|
||||||
const request = require('supertest')
|
const request = require('supertest')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
const env = require('../../src/config/env')
|
const env = require('../../src/config/env')
|
||||||
const { createApp } = require('../../src/index')
|
const { createApp } = require('../../src/index')
|
||||||
const userService = require('../../src/services/userService')
|
const userService = require('../../src/services/userService')
|
||||||
|
|
||||||
test('POST /api/health 返回统一结构', async () => {
|
const buildInfoPath = path.resolve(__dirname, '..', '..', 'build-info.json')
|
||||||
|
|
||||||
|
test('POST /api/health 仍返回统一结构', async () => {
|
||||||
const app = createApp()
|
const app = createApp()
|
||||||
const response = await request(app).post('/api/health').send({})
|
const response = await request(app).post('/api/health').send({})
|
||||||
|
|
||||||
@@ -16,6 +20,36 @@ test('POST /api/health 返回统一结构', async () => {
|
|||||||
assert.equal(response.body.data.status, 'healthy')
|
assert.equal(response.body.data.status, 'healthy')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('POST /api/test-helloworld 返回统一结构和构建时间', async (t) => {
|
||||||
|
const app = createApp()
|
||||||
|
const buildTime = '2026-03-20T08:00:00.000Z'
|
||||||
|
|
||||||
|
fs.writeFileSync(buildInfoPath, JSON.stringify({ buildTime }, null, 2))
|
||||||
|
|
||||||
|
t.after(() => {
|
||||||
|
if (fs.existsSync(buildInfoPath)) {
|
||||||
|
fs.rmSync(buildInfoPath)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await request(app).post('/api/test-helloworld').send({})
|
||||||
|
|
||||||
|
assert.equal(response.status, 200)
|
||||||
|
assert.equal(response.body.code, 200)
|
||||||
|
assert.equal(response.body.msg, '请求成功')
|
||||||
|
assert.equal(response.body.data.message, 'Hello, World!')
|
||||||
|
assert.equal(response.body.data.build_time, buildTime)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('GET /api/test-helloworld 返回 404', async () => {
|
||||||
|
const app = createApp()
|
||||||
|
const response = await request(app).get('/api/test-helloworld')
|
||||||
|
|
||||||
|
assert.equal(response.status, 404)
|
||||||
|
assert.equal(response.body.code, 404)
|
||||||
|
assert.equal(response.body.msg, 'Route not found')
|
||||||
|
})
|
||||||
|
|
||||||
test('POST /api/test-helloworld 返回统一结构', async () => {
|
test('POST /api/test-helloworld 返回统一结构', async () => {
|
||||||
const app = createApp()
|
const app = createApp()
|
||||||
const response = await request(app).post('/api/test-helloworld').send({})
|
const response = await request(app).post('/api/test-helloworld').send({})
|
||||||
@@ -24,6 +58,7 @@ test('POST /api/test-helloworld 返回统一结构', async () => {
|
|||||||
assert.equal(response.body.code, 200)
|
assert.equal(response.body.code, 200)
|
||||||
assert.equal(response.body.msg, '请求成功')
|
assert.equal(response.body.msg, '请求成功')
|
||||||
assert.equal(response.body.data.message, 'Hello, World!')
|
assert.equal(response.body.data.message, 'Hello, World!')
|
||||||
|
assert.ok(Object.prototype.hasOwnProperty.call(response.body.data, 'build_time'))
|
||||||
})
|
})
|
||||||
|
|
||||||
test('未匹配路由返回统一 404', async () => {
|
test('未匹配路由返回统一 404', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user