docs: 整理项目问题文档,修复审批列表数据混乱
- 新增 PROJECT_ISSUES.md 统一管理所有问题和解决方案 - 精简 CLAUDE.md,移除重复的问题记录部分 - 修复审批列表数据混乱问题(React 18 StrictMode + 状态管理) - 修复首次加载不显示数据问题(requestIdRef 清理时机) - 修复页码初始值错误(hasMore 默认值) - 修复后端响应序列化问题(Eloquent 模型转数组) - 添加审批人和抄送人重复校验 - 修复双 header 问题 - 调整申请页面 padding-bottom Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@ export default function MobileLayout() {
|
||||
const location = useLocation()
|
||||
const mainRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const showHeader = location.pathname !== '/login'
|
||||
const showHeader = false // 所有页面都不显示 Header
|
||||
const showTabBar = false // 暂时隐藏底部 Tab
|
||||
|
||||
// 路由变化时滚动到顶部
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { List, Card, Tag, Tabs, PullToRefresh, InfiniteScroll } from 'antd-mobile'
|
||||
@@ -49,17 +49,42 @@ export default function ApprovalList() {
|
||||
const [activeTab, setActiveTab] = useState<'my' | 'pending' | 'approved'>('my')
|
||||
const [list, setList] = useState<ApprovalItem[]>([])
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [hasMore, setHasMore] = useState(true)
|
||||
const [hasMore, setHasMore] = useState(false) // 改为 false,避免挂载时立即触发加载更多
|
||||
const [page, setPage] = useState(1)
|
||||
const currentTabRef = useRef(activeTab) // 用于追踪当前有效的 tab
|
||||
const loadingRef = useRef(false) // 用于同步追踪 loading 状态
|
||||
const requestIdRef = useRef<string | null>(null) // 用于追踪当前请求 ID
|
||||
const mountedRef = useRef(true) // 组件挂载时立即设为 true
|
||||
|
||||
// 更新 ref 当 activeTab 变化时
|
||||
useEffect(() => {
|
||||
currentTabRef.current = activeTab
|
||||
}, [activeTab])
|
||||
|
||||
// 加载数据 - 接收 tab 参数避免使用旧的 activeTab
|
||||
const loadData = async (pageNum: number = 1, isRefresh: boolean = false, tab?: string) => {
|
||||
if (loading) return
|
||||
// 使用 ref 检查 loading,避免 React 18 StrictMode 双重调用
|
||||
if (loadingRef.current) {
|
||||
console.log('⏸️ Request blocked - already loading')
|
||||
return
|
||||
}
|
||||
|
||||
// 使用传入的 tab 参数,如果没有则使用当前 activeTab
|
||||
const currentTab = tab || activeTab
|
||||
console.log('🔍 Loading approval list:', { currentTab, activeTab, tab, pageNum, isRefresh })
|
||||
const requestId = `${currentTab}-${pageNum}-${Date.now()}`
|
||||
requestIdRef.current = requestId
|
||||
|
||||
console.log('🔍 Loading approval list START:', {
|
||||
requestId,
|
||||
currentTab,
|
||||
activeTab,
|
||||
tab,
|
||||
pageNum,
|
||||
isRefresh,
|
||||
currentTabRef: currentTabRef.current
|
||||
})
|
||||
|
||||
loadingRef.current = true
|
||||
setLoading(true)
|
||||
try {
|
||||
const result = await approvalApi.getList({
|
||||
@@ -68,21 +93,36 @@ export default function ApprovalList() {
|
||||
page_size: 20,
|
||||
})
|
||||
|
||||
console.log('📦 API response:', { type: currentTab, count: result?.list?.length, result })
|
||||
console.log('📦 API response received:', {
|
||||
requestId,
|
||||
type: currentTab,
|
||||
count: result?.list?.length,
|
||||
currentTabRefNow: currentTabRef.current
|
||||
})
|
||||
|
||||
// 检查是否是最新的请求
|
||||
if (requestIdRef.current !== requestId) {
|
||||
console.log('⏭️ Skipping outdated response:', { requestId, latestRequestId: requestIdRef.current })
|
||||
return
|
||||
}
|
||||
|
||||
console.log('📦 API response validated - processing data')
|
||||
|
||||
const newList = result?.list || []
|
||||
|
||||
if (isRefresh || pageNum === 1) {
|
||||
// 只在当前 tab 与请求的 tab 一致时才更新数据
|
||||
if (currentTabRef.current === currentTab) {
|
||||
console.log('✅ Updating list for tab:', currentTab, 'items:', newList.length)
|
||||
setList(newList)
|
||||
setHasMore(newList.length >= 20)
|
||||
setPage(pageNum)
|
||||
} else {
|
||||
setList([...list, ...newList])
|
||||
console.log('⏭️ Skipping update - tab changed from', currentTab, 'to', currentTabRef.current)
|
||||
}
|
||||
|
||||
setHasMore(newList.length >= 20)
|
||||
setPage(pageNum)
|
||||
} catch (error: any) {
|
||||
console.error('Failed to load approvals:', error)
|
||||
} finally {
|
||||
loadingRef.current = false
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
@@ -90,6 +130,7 @@ export default function ApprovalList() {
|
||||
// 切换标签
|
||||
const handleTabChange = (key: string) => {
|
||||
console.log('🔄 Tab changing from', activeTab, 'to', key)
|
||||
currentTabRef.current = key as 'my' | 'pending' | 'approved' // 立即更新 ref
|
||||
setActiveTab(key as 'my' | 'pending' | 'approved')
|
||||
setList([])
|
||||
setHasMore(true)
|
||||
@@ -100,17 +141,26 @@ export default function ApprovalList() {
|
||||
|
||||
// 刷新
|
||||
const handleRefresh = async () => {
|
||||
await loadData(1, true)
|
||||
await loadData(1, true, activeTab)
|
||||
}
|
||||
|
||||
// 加载更多
|
||||
const handleLoadMore = async () => {
|
||||
await loadData(page + 1, false)
|
||||
await loadData(page + 1, false, activeTab)
|
||||
}
|
||||
|
||||
// 初始加载
|
||||
useEffect(() => {
|
||||
mountedRef.current = true
|
||||
// 强制使用页码 1,忽略当前 page 状态
|
||||
console.log('🚀 Initial load effect, forcing page=1')
|
||||
loadData(1, true)
|
||||
|
||||
return () => {
|
||||
console.log('🧹 Cleanup function called')
|
||||
mountedRef.current = false
|
||||
// 不清空 requestIdRef,让异步请求能够正常完成处理
|
||||
}
|
||||
}, [])
|
||||
|
||||
// 查看详情
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
padding: 12px;
|
||||
padding-bottom: 80px;
|
||||
padding-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.form {
|
||||
|
||||
@@ -96,8 +96,23 @@ export const businessTripApi = {
|
||||
|
||||
// ========== 审批 API ==========
|
||||
export const approvalApi = {
|
||||
getList: (params: { type?: string; page?: number; page_size?: number }) =>
|
||||
api.get('/approval/list', { params }),
|
||||
getList: (params: { type?: string; page?: number; page_size?: number }) => {
|
||||
console.log('🚀 API Request approval/list:', params)
|
||||
return api.get('/approval/list', { params })
|
||||
.then(res => {
|
||||
console.log('✅ API Response approval/list:', {
|
||||
requestParams: params,
|
||||
responseData: res,
|
||||
listCount: res?.list?.length,
|
||||
listIds: res?.list?.map((item: any) => ({ id: item.id, title: item.title, status: item.status }))
|
||||
})
|
||||
return res
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('❌ API Error approval/list:', err)
|
||||
throw err
|
||||
})
|
||||
},
|
||||
|
||||
getDetail: (id: number) => api.get(`/approval/detail/${id}`),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user