/* eslint-disable no-empty-pattern */
import React, { useEffect, useState, useCallback } from 'react'
import {
Button,
Card,
Form,
Row,
Col,
message,
Skeleton,
DatePicker,
} from 'antd' // 移除Select,新增UserSelect
import {
ProFormSelect,
ProFormText,
ProForm,
ProFormDatePicker,
} from '@ant-design/pro-components'
import styled from '@emotion/styled'
import NiceModal from '@ebay/nice-modal-react'
import People from './setPeople'
import Time from './setTime'
import dayjs from 'dayjs'
import {
usePlanOne,
useAddPlan,
usePlanTrack,
useEditPlan,
} from '@/query/patrol-plan'
import { useNavigate, useSearchParams } from 'react-router-dom'
import { UserSelect } from '@repo/base' // 导入UserSelect组件
// 样式组件保持不变
const StyledTitle = styled('div')(({}) => ({
color: '#4683dd',
background: '#f5f8fd',
padding: '10px 20px',
position: 'relative',
':before': {
content: '""',
width: '4px',
height: '20px',
background: '#3874cb',
position: 'absolute',
top: '50%',
left: 0,
transform: 'translateY(-50%)',
},
}))
const StyledBox = styled('div')(({}) => ({
border: '1px solid #ccc',
borderRadius: '10px',
padding: '30px',
marginTop: '20px',
}))
const StyledButtonBox = styled('div')(({}) => ({
marginBottom: '30px',
}))
const StyledTable = styled('div')(({}) => ({
// border: '1px solid #f1f1f1',
}))
const StyledTr = styled('div')(({}) => ({
border: '1px solid #ccc',
}))
const StyledFirstTd = styled('div')(({}) => ({
width: '120px',
background: '#d7d7d7',
paddingTop: '10px',
paddingBottom: '10px',
paddingLeft: '10px',
paddingRight: '10px',
textAlign: 'center',
color: '#4683dd',
}))
const StyledTd = styled('div')(({}) => ({
width: '120px',
height: '54px',
background: '#fff',
paddingTop: '10px',
paddingBottom: '10px',
paddingLeft: '10px',
paddingRight: '10px',
textAlign: 'center',
borderTop: '1px solid #f1f1f1',
borderBottom: '1px solid #f1f1f1',
color: '#4683dd',
}))
export default function Component() {
const [searchParams] = useSearchParams()
const id = searchParams.get('id')?.split(',')[0]
const disabled = Boolean(Number(searchParams.get('disabled')?.split(',')[0]))
const isCopy = searchParams.get('isCopy')?.split(',')[0]
const actionRef = React.useRef()
const [form] = ProForm.useForm()
const [list, setList] = useState([])
const { data: formData, isLoading: isLoadingFormData } = usePlanOne({ id })
const [timeArr, setTimeArr] = useState([])
const [isDis, setIsDis] = useState(false)
const [month, setMonth] = useState('')
const { mutateAsync: runAdd } = useAddPlan({})
const { mutateAsync: update } = useEditPlan({})
const navigate = useNavigate()
const { data: trackData, isLoading: isLoadingTrack } = usePlanTrack({})
const [trackOption, setTrack] = useState([])
const [selectedUsers, setSelectedUsers] = useState({}) // 存储已选用户信息(userId -> 用户详情)
// 初始化路线数据
useEffect(() => {
if (trackData) {
setTrack(
trackData.map(v => ({
label: v.name,
value: v.id,
}))
)
}
}, [trackData])
// 合并新旧数据逻辑(保持不变)
const mergeWithExistingData = (newData, oldData) => {
if (!oldData || oldData.length === 0) return newData
return newData.map(group =>
group.map(newItem => {
const oldItem = oldData
.flatMap(g => g)
.find(item => item.day === newItem.day)
return oldItem
? {
...newItem,
...timeArr.reduce((acc, _, index) => {
const personKey = `person${index + 1}`
if (oldItem[personKey] !== undefined)
acc[personKey] = oldItem[personKey]
return acc
}, {}),
}
: newItem
})
)
}
// 初始化日期列表(保持不变)
const initDay = useCallback(
(time = '') => {
if (!time) {
setList([])
return
}
try {
const date = new Date(time)
if (isNaN(date.getTime())) throw new Error('无效日期')
const year = date.getFullYear()
const monthNum = date.getMonth()
const days = new Date(year, monthNum + 1, 0).getDate()
const daysList = Array.from({ length: days }, (_, i) => i + 1)
const newData = daysList.reduce((acc, day, index) => {
if (index % 10 === 0) acc.push([])
acc[acc.length - 1].push({
day,
...timeArr.reduce((itemAcc, _, i) => {
itemAcc[`person${i + 1}`] = ''
return itemAcc
}, {}),
})
return acc
}, [])
setList(mergeWithExistingData(newData, list))
} catch (error) {
console.error('日期初始化错误:', error)
setList([])
}
},
[timeArr, list, mergeWithExistingData]
)
// 人员选择逻辑(保持不变:仅存储userId,显示依赖selectedUsers)
const choosePeople = (groupIndex, itemIndex, personKey, value, userInfo) => {
// 存储选中的用户详情(用于显示label)
if (value && userInfo) {
setSelectedUsers(prev => ({
...prev,
[value]: userInfo, // key: userId, value: 用户完整信息
}))
}
// 更新list中的人员ID
setList(prevList => {
return prevList.map((group, gIndex) =>
gIndex === groupIndex
? group.map((item, iIndex) =>
iIndex === itemIndex ? { ...item, [personKey]: value } : item
)
: group
)
})
}
// 日期选择变化逻辑(保持不变)
const handleDateChange = value => {
const selectedMonth = dayjs(value).format('YYYY-MM')
setMonth(selectedMonth)
initDay(selectedMonth)
}
// 初始化详情数据(适配UserSelect:存储用户详情到selectedUsers)
useEffect(() => {
if (!formData || isLoadingFormData) return
// 重置状态
setTimeArr([])
setList([])
setSelectedUsers({}) // 重置已选用户
// 表单字段初始化
form.setFieldValue('trackId', formData?.trackId)
form.setFieldValue('planMonth', dayjs(formData.planMonth, 'YYYY-MM'))
form.setFieldValue('remark', formData?.remark)
if (formData.bizPatrolPlanDetailList?.length > 0) {
// 提取时间列表
const uniqueTimes = [
...new Set(
formData.bizPatrolPlanDetailList.map(item =>
item.planDetailTime.split(' ')[1].slice(0, 5)
)
),
].sort()
setTimeArr(uniqueTimes.map(time => ({ time })))
// 初始化月份和日期列表
const planMonth = formData.planMonth
setMonth(planMonth)
initDay(planMonth)
// 判断禁用状态
const currentMonth = dayjs().format('YYYY-MM')
const isDisabled =
new Date(currentMonth).getTime() >= new Date(planMonth).getTime()
if (isCopy != 1) {
setIsDis(isDisabled)
}
// 初始化已选用户(从formData提取用户详情)
const initSelectedUsers = {}
formData.bizPatrolPlanDetailList.forEach(item => {
if (item.userId && item.userName) {
initSelectedUsers[item.userId] = {
id: item.userId,
realName: item.userName,
...item, // 保留其他用户信息
}
}
})
setSelectedUsers(initSelectedUsers)
// 填充人员配置到list
setTimeout(() => {
const uniqueTimesMap = uniqueTimes.reduce((acc, time, index) => {
acc[time] = index
return acc
}, {})
const personConfigMap = {}
formData.bizPatrolPlanDetailList.forEach(item => {
const [datePart, timePart] = item.planDetailTime.split(' ')
const day = parseInt(datePart.split('-')[2])
const time = timePart.slice(0, 5)
const timeIndex = uniqueTimesMap[time]
if (timeIndex !== -1) {
personConfigMap[day] = {
...personConfigMap[day],
[`person${timeIndex + 1}`]: item.userId,
}
}
})
setList(prevList =>
prevList.map(group =>
group.map(item => ({
...item,
...personConfigMap[item.day],
}))
)
)
}, 100)
}
}, [formData, isLoadingFormData, form, id, isCopy, initDay])
// timeArr更新后重新初始化日期列表(保持不变)
useEffect(() => {
if (month && timeArr.length > 0) {
initDay(month)
}
}, [month, timeArr, initDay])
const labelCol = { span: 4 }
// 初次加载显示骨架屏(保持不变)
if (isLoadingFormData || isLoadingTrack) {
return (
<Card style={{ paddingTop: '24px', minHeight: '500px' }}>
<Skeleton active paragraph={{ rows: 5 }} />
</Card>
)
}
return (
<Card
style={{
paddingTop: '24px',
}}
>
<ProForm
layout="horizontal"
form={form}
onFinish={async values => {
values.planMonth = dayjs(values.planMonth).format('YYYY-MM')
// 构建提交数据(保持不变:仅传递userId)
const scheduleData = list.flatMap(group =>
group.flatMap(item =>
timeArr.map((timeItem, i) => ({
userId: item[`person${i + 1}`], // 仅传递userId
planDetailTime: `${values.planMonth}-${String(item.day).padStart(2, '0')} ${timeItem.time}:00`,
}))
)
)
try {
if (id) {
await (isCopy === '1' ? runAdd : update)({
...values,
bizPatrolPlanDetailList: scheduleData,
patrolTime: timeArr.map(v => v.time).join(','),
id: isCopy === '1' ? undefined : id,
})
message.success('修改成功!')
} else {
await runAdd({
...values,
bizPatrolPlanDetailList: scheduleData,
patrolTime: timeArr.map(v => v.time).join(','),
})
message.success('添加成功!')
}
navigate(-1)
} catch (error) {
message.error('操作失败,请重试')
console.error('保存失败:', error)
}
}}
submitter={false}
actionRef={actionRef}
>
{/* 路线名称、计划月份、备注表单(保持不变) */}
<Row>
<Col span={8}>
<ProFormSelect
label="路线名称"
disabled={disabled || isDis}
readonly={disabled}
name="trackId"
required
options={trackOption}
formItemProps={{ labelCol }}
/>
</Col>
<Col span={8} offset={2}>
{disabled ? (
<ProFormDatePicker
fieldProps={{
picker: 'month',
format: 'YYYY-MM',
}}
name="planMonth"
label="计划月份"
readonly
/>
) : (
<Form.Item
label="计划月份"
name="planMonth"
required
labelCol={{ span: 4 }}
>
<DatePicker
onChange={handleDateChange}
picker="month"
disabled={disabled || isDis}
placeholder="请选择计划月份"
/>
</Form.Item>
)}
</Col>
</Row>
<Row>
<Col span={8}>
<ProFormText
label="备注"
name="remark"
readonly={disabled}
formItemProps={{ labelCol }}
/>
</Col>
</Row>
{/* 计划安排表格(核心:Select替换为UserSelect) */}
<StyledTitle>计划安排</StyledTitle>
<StyledBox>
<StyledButtonBox>
{disabled ? (
<>
<Button type="text" disabled>
配置时间
</Button>
<Button type="text" disabled>
配置人员
</Button>
</>
) : (
<>
<Button
disabled={disabled}
size="middle"
onClick={() => {
if (!month) {
message.warning('请选择月份!')
return
}
NiceModal.show(Time, {
id: '',
timeArr,
onOk: value => setTimeArr(value.map(time => ({ time }))),
})
}}
>
配置时间
</Button>
<Button
disabled={disabled}
type="default"
style={{ marginLeft: '20px' }}
onClick={() => {
if (timeArr.length === 0) {
message.warning('请先配置时间!')
return
}
NiceModal.show(People, {
id: '',
timeArr,
month,
onOk: ({ dateRange, personConfig }) => {
const [startDay, endDay] = dateRange.map(str =>
parseInt(str.split('-')[2])
)
// 1. 存储配置的用户详情到selectedUsers
const newSelectedUsers = { ...selectedUsers }
personConfig.forEach(config => {
if (config.person && config.userInfo) {
newSelectedUsers[config.person] = config.userInfo
}
})
setSelectedUsers(newSelectedUsers)
// 2. 更新list中的人员ID
setList(prevList =>
prevList.map(group =>
group.map(item =>
item.day >= startDay && item.day <= endDay
? {
...item,
...personConfig.reduce((acc, config) => {
const timeIndex = timeArr.findIndex(
t => t.time === config.time
)
if (timeIndex !== -1 && config.person) {
acc[`person${timeIndex + 1}`] =
config.person
}
return acc
}, {}),
}
: item
)
)
)
},
})
}}
>
配置人员
</Button>
</>
)}
</StyledButtonBox>
<StyledTable>
{list.length === 0 ? (
<div style={{ textAlign: 'center', padding: '50px' }}>
{month ? '暂无计划安排,请配置时间和人员' : '请先选择计划月份'}
</div>
) : (
list.map((v, index) => (
<div style={{ display: 'flex' }} key={index}>
<StyledTr>
<StyledFirstTd>时间</StyledFirstTd>
{timeArr.map((timeItem, timeIndex) => (
<StyledTd key={timeIndex}>{timeItem.time}</StyledTd>
))}
</StyledTr>
{v.map((n, Nindex) => (
<StyledTr key={Nindex}>
<StyledFirstTd>{n.day}日</StyledFirstTd>
{timeArr.map((timeItem, i) => {
const personId = n[`person${i + 1}`]
// 从selectedUsers获取用户label(适配UserSelect选择结果)
const currentLabel = personId
? selectedUsers[personId]?.realName || '未安排'
: '未安排'
return (
<StyledTd key={i}>
{disabled ? (
// 禁用时显示人员名称
<div style={{ color: '#333' }}>
{currentLabel}
</div>
) : (
// 启用时显示UserSelect(替换原Select)
<UserSelect
style={{ width: '100px' }}
showSearch
allowClear
placeholder="请选择人员"
disabled={disabled}
// UserSelect选择后触发:传递userId和完整用户信息
onSelect={(value, option) => {
choosePeople(
index,
Nindex,
`person${i + 1}`,
value, // userId
option // 完整用户信息(含realName、id等)
)
}}
// 初始值:仅传递userId(UserSelect内部会匹配显示label)
value={personId || undefined}
/>
)}
</StyledTd>
)
})}
</StyledTr>
))}
</div>
))
)}
</StyledTable>
</StyledBox>
{/* 取消/确定按钮(保持不变) */}
<div
style={{
display: 'flex',
justifyContent: 'flex-end',
marginTop: '20px',
}}
>
<Button
type="default"
htmlType="reset"
onClick={() => {
navigate(-1)
}}
>
取消
</Button>
{!disabled ? (
<Button
type="primary"
style={{
marginLeft: '20px',
}}
htmlType="submit"
>
确定
</Button>
) : (
''
)}
</div>
</ProForm>
</Card>
)
}
点击设置人员,onOk返回的数据格式为0
:
label
:
"曾军"
person
:
"b04fa22bc35243da803a9cacb9873b37"
time
:
"08:00"
userInfo
:
account
:
"zengj"
email
:
"zengj@fiberhome.com"
employeeNo
:
"0210990847"
id
:
"b04fa22bc35243da803a9cacb9873b37"
myAccountNonExpired
:
true
myAccountNonLocked
:
"true"
myAccountNonLocked_dicName
:
"未锁定"
myCredentialsNonExpired
:
true
myEnabled
:
true
orgId
:
"32a63cce0b884ebd94f9390d1f516677"
orgName
:
"高管"
realName
:
"曾军"
status
:
"active"
status_dicName
:
"启用"
treeLevelId
:
"8d8abd2050ed468d98681f98246d0107/4953b174581c471b894ac8eedf36e838/32a63cce0b884ebd94f9390d1f516677"
treeLevelName
:
"烽火科技集团/烽火通信科技股份有限公司/高管"
username
:
"zengj,处理一下页面回显的问题
最新发布