feat: 修复 Redis 超时问题、固定小程序端口、新增人生事件模块及优化多个页面

- 修复 Redis 超时:添加 commons-pool2 依赖,启用 Lettuce 连接池,超时提升至 15s
- 固定 mini-program H5 端口为 5175,避免与 web 项目端口冲突
- 新增人生事件(life-event)模块:表单和详情页面
- 新增 EpicScript 灵感接口(Controller/Service/DTO)
- 优化登录、引导、主页、记录、剧本详情等多个页面
- 优化服务管理脚本和 Nginx 配置

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-10 11:38:35 +08:00
parent 507d1ebdab
commit 60c63850ee
36 changed files with 4545 additions and 3043 deletions
+86 -62
View File
@@ -1,11 +1,42 @@
import { getEnvValue, isDev } from '../config/env.js'
import { getEnvValue, getConfig } from '../config/env.js'
const API_BASE_URL = getEnvValue('API_BASE_URL')
/**
* 请求拦截处理
* 自动添加 token 到请求头
*/
const AUTH_PATH_PREFIX = '/auth/'
const isAuthPath = (path = '') => path.startsWith(AUTH_PATH_PREFIX)
const createRequestError = (message, meta = {}) => {
const error = new Error(message || 'Request failed')
Object.assign(error, meta)
return error
}
const clearAuthStorage = () => {
uni.removeStorageSync('access_token')
uni.removeStorageSync('refresh_token')
}
const logApi = (level, label, payload, force = false) => {
const debug = getEnvValue('DEBUG')
if (!debug && !force) return
const logger = level === 'error' ? console.error : console.log
logger(`[API] ${label}`, payload)
}
export const logRuntimeEnv = (source = 'startup') => {
const config = getConfig()
console.log('[ENV] runtime', {
source,
rawEnv: import.meta.env.VITE_APP_ENV,
mode: import.meta.env.MODE,
apiBaseUrl: config.API_BASE_URL,
wsUrl: config.WS_URL,
debug: config.DEBUG,
platform: typeof uni !== 'undefined' ? uni.getSystemInfoSync?.()?.platform : 'unknown'
})
}
const getHeaders = () => {
const token = uni.getStorageSync('access_token')
const headers = {
@@ -17,81 +48,82 @@ const getHeaders = () => {
return headers
}
/**
* 统一请求方法
* @param {Object} options - 请求配置
* @returns {Promise} 请求 Promise
*/
const request = (options) => {
const debug = getEnvValue('DEBUG')
const method = options.method || 'GET'
const fullUrl = `${API_BASE_URL}${options.url}`
const forceLog = isAuthPath(options.url)
// 请求日志
if (debug) {
console.log('[API Request]', {
method: options.method || 'GET',
url: fullUrl,
path: options.url,
env: import.meta.env.VITE_APP_ENV
})
}
logApi('log', 'request', {
method,
url: fullUrl,
path: options.url,
env: import.meta.env.VITE_APP_ENV || import.meta.env.MODE
}, forceLog)
return new Promise((resolve, reject) => {
uni.request({
url: fullUrl,
method: options.method || 'GET',
method,
data: options.data,
header: getHeaders(),
timeout: 30000,
success: (res) => {
const { data, statusCode } = res
const success = statusCode >= 200 && statusCode < 300 && (data?.code === 200 || data?.code === 0)
// 响应日志
if (debug) {
console.log('[API Response]', {
path: options.url,
status: statusCode,
code: data?.code,
success: data?.code === 200 || data?.code === 0
})
}
logApi('log', 'response', {
path: options.url,
status: statusCode,
code: data?.code,
success
}, forceLog || statusCode >= 400)
// 处理 401 未授权
if (statusCode === 401) {
uni.removeStorageSync('access_token')
uni.removeStorageSync('refresh_token')
uni.redirectTo({ url: '/pages/login/index' })
reject(new Error('登录已过期,请重新登录'))
if (!forceLog) {
clearAuthStorage()
uni.reLaunch({ url: '/pages/login/index' })
}
reject(createRequestError('Login expired, please login again', {
statusCode,
code: data?.code,
path: options.url,
isAuthRejected: true
}))
return
}
// 后端返回格式:{ code, message, data }
if (data.code === 200 || data.code === 0) {
if (success) {
resolve(data)
} else {
reject(new Error(data.message || '请求失败'))
return
}
reject(createRequestError(data?.message || 'Request failed', {
statusCode,
code: data?.code,
path: options.url,
response: data,
isAuthRejected: statusCode === 403 || data?.code === 401 || data?.code === 403
}))
},
fail: (err) => {
// 错误日志
if (debug) {
console.error('[API Error]', {
path: options.url,
error: err.errMsg,
env: import.meta.env.VITE_APP_ENV
})
}
reject(new Error(err.errMsg || '网络错误'))
logApi('error', 'fail', {
path: options.url,
url: fullUrl,
error: err.errMsg,
env: import.meta.env.VITE_APP_ENV || import.meta.env.MODE
}, true)
reject(createRequestError(err.errMsg || 'Network request failed', {
path: options.url,
isNetworkError: true,
originalError: err
}))
}
})
})
}
/**
* GET 请求
*/
export const get = (url, params = {}) => {
// 构建查询字符串
const queryString = Object.keys(params)
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
.join('&')
@@ -100,23 +132,14 @@ export const get = (url, params = {}) => {
return request({ url: fullUrl, method: 'GET' })
}
/**
* POST 请求
*/
export const post = (url, data = {}) => {
return request({ url, method: 'POST', data })
}
/**
* PUT 请求
*/
export const put = (url, data = {}) => {
return request({ url, method: 'PUT', data })
}
/**
* DELETE 请求
*/
export const del = (url, params = {}) => {
const queryString = Object.keys(params)
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
@@ -130,5 +153,6 @@ export default {
get,
post,
put,
del
del,
logRuntimeEnv
}