import { useState, useMemo, useEffect, useRef } from 'react' import { useNavigate, useLocation } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { DatePicker, Input, Toast, Dialog, TextArea, Selector } from 'antd-mobile' import { AddOutline, DeleteOutline } from 'antd-mobile-icons' import dayjs from 'dayjs' import { businessTripApi, userApi } from '../../services/api' import { useUserStore } from '@/stores/user' import styles from './apply.module.css' interface ItineraryItem { startTime: Date | null endTime: Date | null departure: string destination: string transport: string tripType: 'oneway' | 'roundtrip' | '' remark: string } interface ApproverItem { id: number name: string avatar?: string position?: string } // 计算时长(天数) const calculateDuration = (start: Date | null, end: Date | null): number => { if (!start || !end) return 0 const startDate = dayjs(start) const endDate = dayjs(end) return endDate.diff(startDate, 'day') + 1 } // 格式化时长显示 const formatDuration = (days: number): string => { if (days <= 0) return '' return `${days}天` } // 行程类型选项 const tripTypeOptions = [ { label: '单程', value: 'oneway' }, { label: '往返', value: 'roundtrip' }, ] // 交通工具选项 const transportOptions = [ { label: '飞机', value: '飞机' }, { label: '高铁', value: '高铁' }, { label: '火车', value: '火车' }, { label: '自驾', value: '自驾' }, { label: '其他', value: '其他' }, ] export default function BusinessTripApply() { const { t } = useTranslation() const navigate = useNavigate() const location = useLocation() const [reason, setReason] = useState('') const [itineraries, setItineraries] = useState([ { startTime: null, endTime: null, departure: '', destination: '', transport: '', tripType: '' as 'oneway' | 'roundtrip' | '', remark: '' } ]) const [approvers, setApprovers] = useState([]) const [ccUsers, setCcUsers] = useState([]) const [defaultLoaded, setDefaultLoaded] = useState(false) // 手动保存草稿的函数 const saveDraft = () => { const draftData = { reason, itineraries, } sessionStorage.setItem('businessTripDraft', JSON.stringify(draftData)) console.log('💾 Manually saved draft:', { reason, itineraries }) } // DatePicker 可见性状态 const [datePickerVisible, setDatePickerVisible] = useState<{ index: number field: 'startTime' | 'endTime' } | null>(null) // 使用 ref 来跟踪是否已经恢复过草稿 const hasRestoredRef = useRef(false) // 统一处理:草稿恢复、默认审批人加载、选择页面返回 const initRef = useRef(false) useEffect(() => { const fromSelection = location.state?.fromSelection console.log('📍 Page init:', { fromSelection, locationState: location.state, initRef: initRef.current }) // 1. 从选择页面返回:恢复所有数据(草稿 + 人员) if (fromSelection) { console.log('🔄 Returning from selection page') // 恢复草稿数据 const draftData = sessionStorage.getItem('businessTripDraft') if (draftData) { const draft = JSON.parse(draftData) setReason(draft.reason || '') // 将日期字符串转换回 Date 对象 const restoredItineraries = (draft.itineraries || [{ startTime: null, endTime: null, departure: '', destination: '', transport: '', tripType: '' as 'oneway' | 'roundtrip' | '', remark: '' }]).map((item: any) => ({ ...item, startTime: item.startTime ? new Date(item.startTime) : null, endTime: item.endTime ? new Date(item.endTime) : null, })) setItineraries(restoredItineraries) console.log('✅ Restored draft') } // 恢复人员数据 const approversData = sessionStorage.getItem('selectedApprovers') if (approversData) { setApprovers(JSON.parse(approversData)) console.log('✅ Restored approvers') } else { setApprovers([]) } const ccData = sessionStorage.getItem('selectedCc') if (ccData) { setCcUsers(JSON.parse(ccData)) console.log('✅ Restored CC') } else { setCcUsers([]) } return } // 2. 非首次进入且已初始化过:跳过 if (initRef.current) { console.log('⏭️ Already initialized, skipping') return } initRef.current = true // 3. 从列表页新建申请:清除旧数据,加载默认配置 console.log('🆕 New application - clearing old data and loading defaults') sessionStorage.removeItem('businessTripDraft') sessionStorage.removeItem('selectedApprovers') sessionStorage.removeItem('selectedCc') setReason('') setItineraries([{ startTime: null, endTime: null, departure: '', destination: '', transport: '', tripType: '' as 'oneway' | 'roundtrip' | '', remark: '' }]) setApprovers([]) setCcUsers([]) // 4. 加载默认审批人和抄送人 const loadDefaultApprovers = async () => { console.log('📡 Calling API...') try { const defaultData = await businessTripApi.getDefaultApprovers() console.log('✅ API Response:', defaultData) if (defaultData.approvers && defaultData.approvers.length > 0) { console.log('✅ Setting approvers:', defaultData.approvers) setApprovers(defaultData.approvers) sessionStorage.setItem('selectedApprovers', JSON.stringify(defaultData.approvers)) } if (defaultData.cc_users && defaultData.cc_users.length > 0) { console.log('✅ Setting cc_users:', defaultData.cc_users) setCcUsers(defaultData.cc_users) sessionStorage.setItem('selectedCc', JSON.stringify(defaultData.cc_users)) } } catch (error: any) { console.error('❌ Failed to load default approvers:', error.message) } } loadDefaultApprovers() }, [location.state?.fromSelection]) // 计算总时长(累加所有行程的天数) const totalDuration = useMemo(() => { let total = 0 itineraries.forEach(item => { const duration = calculateDuration(item.startTime, item.endTime) total += duration }) return total }, [itineraries]) const handleAddItinerary = () => { const newItineraries = [...itineraries, { startTime: null, endTime: null, departure: '', destination: '', transport: '', tripType: '' as 'oneway' | 'roundtrip' | '', remark: '' }] setItineraries(newItineraries) saveDraft() } const handleRemoveItinerary = (index: number) => { if (itineraries.length === 1) { Toast.show('至少保留一条行程') return } const newItineraries = itineraries.filter((_, i) => i !== index) setItineraries(newItineraries) saveDraft() } const handleUpdateItinerary = (index: number, field: keyof ItineraryItem, value: any) => { const updated = [...itineraries] updated[index] = { ...updated[index], [field]: value } setItineraries(updated) saveDraft() } const handleSelectApprovers = () => { console.log('🚀 Navigating to select approvers') saveDraft() // 导航前保存草稿 navigate('/business-trip/apply/select-approver', { state: { selected: approvers, type: 'approver' } }) } const handleSelectCc = () => { console.log('🚀 Navigating to select CC') saveDraft() // 导航前保存草稿 navigate('/business-trip/apply/select-cc', { state: { selected: ccUsers, type: 'cc' } }) } const handleSave = async () => { // 移除当前焦点,避免按钮保持高亮状态 if (document.activeElement instanceof HTMLElement) { document.activeElement.blur() } try { // 验证必填字段 if (!reason.trim()) { Toast.show(t('businessTrip.pleaseEnterReason')) return } const hasValidItinerary = itineraries.some(item => item.startTime && item.destination.trim()) if (!hasValidItinerary) { Toast.show('请至少填写一条完整行程') return } // 准备行程数据 const itineraryData = itineraries .filter(item => item.startTime) // 只保存有开始时间的行程 .map(item => ({ start_time: dayjs(item.startTime).format('YYYY-MM-DD HH:mm:ss'), end_time: item.endTime ? dayjs(item.endTime).format('YYYY-MM-DD HH:mm:ss') : '', departure: item.departure || '', destination: item.destination || '', transport: item.transport || '', trip_type: item.tripType || 'oneway', remark: item.remark || '', })) await businessTripApi.create({ reason, itineraries: itineraryData, }) // 保存成功后清除 sessionStorage sessionStorage.removeItem('selectedApprovers') sessionStorage.removeItem('selectedCc') sessionStorage.removeItem('businessTripDraft') Toast.show('草稿已保存') navigate('/approval') } catch (error: any) { Toast.show(error.message || '保存失败') } } const handleSubmit = () => { // 移除当前焦点,避免按钮保持高亮状态 if (document.activeElement instanceof HTMLElement) { document.activeElement.blur() } if (!reason.trim()) { Toast.show(t('businessTrip.pleaseEnterReason')) return } const hasValidItinerary = itineraries.some(item => item.startTime && item.destination.trim()) if (!hasValidItinerary) { Toast.show('请至少填写一条完整行程') return } if (approvers.length === 0) { Toast.show('请选择审批人') return } Dialog.confirm({ content: t('businessTrip.confirmSubmit'), confirmText: '确认', cancelText: '取消', onConfirm: async () => { try { // 准备行程数据 const itineraryData = itineraries .filter(item => item.startTime) // 只保存有开始时间的行程 .map(item => ({ start_time: dayjs(item.startTime).format('YYYY-MM-DD HH:mm:ss'), end_time: item.endTime ? dayjs(item.endTime).format('YYYY-MM-DD HH:mm:ss') : '', departure: item.departure || '', destination: item.destination || '', transport: item.transport || '', trip_type: item.tripType || 'oneway', remark: item.remark || '', })) // 先创建草稿 const result = await businessTripApi.create({ reason, itineraries: itineraryData, }) // 再提交 await businessTripApi.submit( result.id, approvers.map(a => a.id), ccUsers.map(u => u.id) ) // 提交成功后清除 sessionStorage sessionStorage.removeItem('selectedApprovers') sessionStorage.removeItem('selectedCc') sessionStorage.removeItem('businessTripDraft') Toast.show(t('businessTrip.submitSuccess')) navigate('/approval') } catch (error: any) { Toast.show(error.message || '提交失败') } } }) } return (