perf(backend+frontend): 列表API响应体积优化 3.1MB→145KB (↓95.4%)

- 后端: JPQL构造器投影排除LONGTEXT大字段(uploadedImages/videoReferenceImages)
- 后端: DTO层过滤非分镜图类型的base64内联resultUrl
- 前端: 列表缩略图从video改为img loading=lazy,消除172并发请求
- 前端: download函数增加resultUrl懒加载(详情接口兜底)
- 文档: 新增性能优化报告 docs/performance-optimization-report.md
This commit is contained in:
blandarebiter
2026-04-10 18:46:37 +08:00
commit 90b5118e45
280 changed files with 92468 additions and 0 deletions

View File

@@ -0,0 +1,238 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { getOrders, getOrderById, createOrder, updateOrderStatus, cancelOrder, shipOrder, completeOrder } from '@/api/orders'
export const useOrderStore = defineStore('orders', () => {
// 状态
const orders = ref([])
const currentOrder = ref(null)
const loading = ref(false)
const pagination = ref({
page: 0,
size: 10,
total: 0,
totalPages: 0
})
// 获取订单列表
const fetchOrders = async (params = {}) => {
try {
loading.value = true
console.log('OrderStore: 开始获取订单,参数:', params)
const response = await getOrders(params)
console.log('OrderStore: API原始响应:', response)
if (response.success) {
orders.value = response.data.content || response.data
pagination.value = {
page: response.data.number || 0,
size: response.data.size || 10,
total: response.data.totalElements || response.data.length,
totalPages: response.data.totalPages || 1
}
console.log('OrderStore: 处理后的订单数据:', orders.value)
console.log('OrderStore: 分页信息:', pagination.value)
} else {
console.error('OrderStore: API返回失败:', response.message)
}
return response
} catch (error) {
console.error('OrderStore: 获取订单异常:', error)
return { success: false, message: '获取订单列表失败' }
} finally {
loading.value = false
}
}
// 获取订单详情
const fetchOrderById = async (id) => {
try {
loading.value = true
const response = await getOrderById(id)
console.log('OrderStore: 获取订单详情响应:', response)
// axios会将响应包装在response.data中
const responseData = response?.data || response || {}
console.log('OrderStore: 解析后的响应数据:', responseData)
if (responseData.success && responseData.data) {
currentOrder.value = responseData.data
console.log('OrderStore: 设置后的订单详情:', currentOrder.value)
return { success: true, data: responseData.data }
} else if (responseData.success === false) {
console.error('OrderStore: API返回失败:', responseData.message)
return { success: false, message: responseData.message || '获取订单详情失败' }
} else {
// 如果没有success字段尝试直接使用data
if (responseData.id || responseData.orderNumber) {
currentOrder.value = responseData
return { success: true, data: responseData }
} else {
console.error('OrderStore: API返回数据格式错误:', responseData)
return { success: false, message: 'API返回数据格式错误' }
}
}
} catch (error) {
console.error('OrderStore: 获取订单详情异常:', error)
return { success: false, message: error.response?.data?.message || error.message || '获取订单详情失败' }
} finally {
loading.value = false
}
}
// 创建订单
const createNewOrder = async (orderData) => {
try {
loading.value = true
const response = await createOrder(orderData)
if (response.success) {
// 刷新订单列表
await fetchOrders()
}
return response
} catch (error) {
console.error('Create order error:', error)
return { success: false, message: '创建订单失败' }
} finally {
loading.value = false
}
}
// 更新订单状态
const updateOrder = async (id, status, notes) => {
try {
loading.value = true
const response = await updateOrderStatus(id, status, notes)
if (response.success) {
// 更新本地订单状态
const order = orders.value.find(o => o.id === id)
if (order) {
order.status = status
order.updatedAt = new Date().toISOString()
}
// 更新当前订单
if (currentOrder.value && currentOrder.value.id === id) {
currentOrder.value.status = status
currentOrder.value.updatedAt = new Date().toISOString()
}
}
return response
} catch (error) {
console.error('Update order error:', error)
return { success: false, message: '更新订单状态失败' }
} finally {
loading.value = false
}
}
// 取消订单
const cancelOrderById = async (id, reason) => {
try {
loading.value = true
const response = await cancelOrder(id, reason)
if (response.success) {
// 更新本地订单状态
const order = orders.value.find(o => o.id === id)
if (order) {
order.status = 'CANCELLED'
order.cancelledAt = new Date().toISOString()
}
// 更新当前订单
if (currentOrder.value && currentOrder.value.id === id) {
currentOrder.value.status = 'CANCELLED'
currentOrder.value.cancelledAt = new Date().toISOString()
}
}
return response
} catch (error) {
console.error('Cancel order error:', error)
return { success: false, message: '取消订单失败' }
} finally {
loading.value = false
}
}
// 发货
const shipOrderById = async (id, trackingNumber) => {
try {
loading.value = true
const response = await shipOrder(id, trackingNumber)
if (response.success) {
// 更新本地订单状态
const order = orders.value.find(o => o.id === id)
if (order) {
order.status = 'SHIPPED'
order.shippedAt = new Date().toISOString()
}
// 更新当前订单
if (currentOrder.value && currentOrder.value.id === id) {
currentOrder.value.status = 'SHIPPED'
currentOrder.value.shippedAt = new Date().toISOString()
}
}
return response
} catch (error) {
console.error('Ship order error:', error)
return { success: false, message: '发货失败' }
} finally {
loading.value = false
}
}
// 完成订单
const completeOrderById = async (id) => {
try {
loading.value = true
const response = await completeOrder(id)
if (response.success) {
// 更新本地订单状态
const order = orders.value.find(o => o.id === id)
if (order) {
order.status = 'COMPLETED'
order.deliveredAt = new Date().toISOString()
}
// 更新当前订单
if (currentOrder.value && currentOrder.value.id === id) {
currentOrder.value.status = 'COMPLETED'
currentOrder.value.deliveredAt = new Date().toISOString()
}
}
return response
} catch (error) {
console.error('Complete order error:', error)
return { success: false, message: '完成订单失败' }
} finally {
loading.value = false
}
}
return {
// 状态
orders,
currentOrder,
loading,
pagination,
// 方法
fetchOrders,
fetchOrderById,
createNewOrder,
updateOrder,
cancelOrderById,
shipOrderById,
completeOrderById
}
})

182
frontend/src/stores/user.js Normal file
View File

@@ -0,0 +1,182 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { login, register, logout, getCurrentUser } from '@/api/auth'
export const useUserStore = defineStore('user', () => {
// 状态 - 从 localStorage 尝试恢复用户信息
const user = ref(null)
const token = ref(null)
const loading = ref(false)
const initialized = ref(false)
try {
const cachedUser = localStorage.getItem('user')
const cachedToken = localStorage.getItem('token')
if (cachedUser && cachedToken) {
user.value = JSON.parse(cachedUser)
token.value = cachedToken
}
} catch (_) {
// ignore localStorage parse errors
}
// 计算属性
const isAuthenticated = computed(() => !!user.value)
const isAdmin = computed(() => user.value?.role === 'ROLE_ADMIN' || user.value?.role === 'ROLE_SUPER_ADMIN')
const isSuperAdmin = computed(() => user.value?.role === 'ROLE_SUPER_ADMIN')
const username = computed(() => user.value?.username || '')
// 可用积分(总积分 - 冻结积分)
const availablePoints = computed(() => {
if (!user.value) return 0
const total = user.value.points || 0
const frozen = user.value.frozenPoints || 0
return Math.max(0, total - frozen)
})
// 登录
const loginUser = async (credentials) => {
try {
loading.value = true
const response = await login(credentials)
if (response.success) {
// 使用JWT认证保存token和用户信息
user.value = response.data.user
token.value = response.data.token
// 保存到localStorage关闭浏览器后仍保持登录
localStorage.setItem('token', response.data.token)
localStorage.setItem('user', JSON.stringify(user.value))
return { success: true }
} else {
return { success: false, message: response.message }
}
} catch (error) {
console.error('Login error:', error)
return { success: false, message: '登录失败,请检查网络连接' }
} finally {
loading.value = false
}
}
// 注册
const registerUser = async (userData) => {
try {
loading.value = true
const response = await register(userData)
if (response.success) {
return { success: true, message: '注册成功,请登录' }
} else {
return { success: false, message: response.message }
}
} catch (error) {
console.error('Register error:', error)
return { success: false, message: '注册失败,请检查网络连接' }
} finally {
loading.value = false
}
}
// 登出
const logoutUser = async () => {
try {
// JWT无状态直接清除localStorage即可
token.value = null
user.value = null
localStorage.removeItem('token')
localStorage.removeItem('user')
} catch (error) {
console.error('Logout error:', error)
}
}
// 获取当前用户信息
const fetchCurrentUser = async () => {
try {
const response = await getCurrentUser()
// 统一使用 response.data 格式
const data = response.data || response
if (data.success) {
user.value = data.data
localStorage.setItem('user', JSON.stringify(user.value))
} else {
console.warn('获取用户信息失败:', data.message)
// 不要立即清除用户数据,保持当前登录状态
// 只在明确的401/认证失败时才由axios拦截器处理登出
}
} catch (error) {
console.error('Fetch user error:', error)
// 请求失败时不强制清除,保持现有本地态
}
}
// 清除用户数据
const clearUserData = () => {
token.value = null
user.value = null
// 清除 localStorage 中的用户数据
localStorage.removeItem('token')
localStorage.removeItem('user')
}
// 初始化
const init = async () => {
if (initialized.value) {
return
}
// 从 localStorage 恢复用户状态
const savedToken = localStorage.getItem('token')
const savedUser = localStorage.getItem('user')
console.log('Store init - savedToken:', savedToken ? savedToken.substring(0, 30) + '...' : 'null')
if (savedToken && savedUser) {
try {
token.value = savedToken
user.value = JSON.parse(savedUser)
console.log('恢复用户状态:', user.value?.username)
// 刷新用户信息(确保角色等信息是最新的)
await fetchCurrentUser()
} catch (error) {
console.error('Failed to restore user state:', error)
clearUserData()
}
}
initialized.value = true
}
// 重置初始化状态(登录成功后调用)
const resetInitialized = () => {
initialized.value = false
}
return {
// 状态
user,
token,
loading,
// 计算属性
isAuthenticated,
isAdmin,
isSuperAdmin,
username,
availablePoints,
// 方法
loginUser,
registerUser,
logoutUser,
fetchCurrentUser,
clearUserData,
init,
initialized,
resetInitialized
}
})