网关配置的表格添加内网IP的inner_ip字段的筛选条件
This commit is contained in:
@@ -25,7 +25,10 @@ function GatewayConfigContent() {
|
||||
const [initialConfigData, setInitialConfigData] = useState<{ [mac: string]: GatewayConfig[] }>({})
|
||||
// 初始数据是否已加载完成
|
||||
const [isInitialDataLoaded, setIsInitialDataLoaded] = useState(false)
|
||||
// 定义表单验证规则
|
||||
// MAC 地址 - 内网 IP
|
||||
const [gatewayPairs, setGatewayPairs] = useState<{ macaddr: string, inner_ip: string }[]>([])
|
||||
|
||||
// 表单验证规则
|
||||
const filterSchema = z.object({
|
||||
macaddr: z.string().optional(),
|
||||
public: z.string().optional(),
|
||||
@@ -33,10 +36,7 @@ function GatewayConfigContent() {
|
||||
inner_ip: z.string().optional(),
|
||||
user: z.string().optional(),
|
||||
})
|
||||
|
||||
type FilterFormValues = z.infer<typeof filterSchema>
|
||||
|
||||
// 初始化表单
|
||||
const form = useForm<FilterFormValues>({
|
||||
resolver: zodResolver(filterSchema),
|
||||
defaultValues: {
|
||||
@@ -62,6 +62,8 @@ function GatewayConfigContent() {
|
||||
return processedItem
|
||||
})
|
||||
}
|
||||
|
||||
// 获取IP最后一段用于排序
|
||||
const getLastOctet = (ip: string | undefined): number => {
|
||||
if (!ip) return 0
|
||||
const parts = ip.split('.')
|
||||
@@ -70,14 +72,14 @@ function GatewayConfigContent() {
|
||||
return isNaN(last) ? 0 : last
|
||||
}
|
||||
|
||||
// 端口排序函数
|
||||
// 按内网IP排序配置
|
||||
const sortByInnerIp = (a: GatewayConfig, b: GatewayConfig): number => {
|
||||
const lastOctetA = getLastOctet(a.inner_ip)
|
||||
const lastOctetB = getLastOctet(b.inner_ip)
|
||||
return lastOctetA - lastOctetB
|
||||
}
|
||||
|
||||
// 为每个MAC地址获取配置数据的函数
|
||||
// 为单个MAC获取配置数据
|
||||
const fetchConfigForMac = async (mac: string, filters: {
|
||||
mac?: string | undefined
|
||||
public?: string | undefined
|
||||
@@ -90,16 +92,17 @@ function GatewayConfigContent() {
|
||||
const result = await getGatewayConfig(1, queryParams)
|
||||
if (result.success) {
|
||||
const processedData = processCityNames(result.data.items)
|
||||
const sortedData = [...processedData].sort(sortByInnerIp)
|
||||
return sortedData
|
||||
return [...processedData].sort(sortByInnerIp)
|
||||
}
|
||||
return []
|
||||
}
|
||||
catch (error) {
|
||||
console.error(`获取MAC地址 ${mac} 的配置失败:`, error)
|
||||
console.error(`获取MAC ${mac} 配置失败:`, error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
// 本地筛选数据
|
||||
const filterLocalData = (filters: {
|
||||
mac?: string
|
||||
public?: string
|
||||
@@ -108,18 +111,26 @@ function GatewayConfigContent() {
|
||||
inner_ip?: string
|
||||
}) => {
|
||||
const { mac, public: publicIp, city, user, inner_ip } = filters
|
||||
// 筛选MAC地址
|
||||
let filteredMacs = initialMacAddresses
|
||||
let filteredPairs = [...gatewayPairs]
|
||||
|
||||
// 按MAC筛选
|
||||
if (mac) {
|
||||
filteredMacs = filteredMacs.filter(macAddr =>
|
||||
macAddr.toLowerCase().includes(mac.toLowerCase()),
|
||||
filteredPairs = filteredPairs.filter(pair =>
|
||||
pair.macaddr.toLowerCase().includes(mac.toLowerCase()),
|
||||
)
|
||||
}
|
||||
// 筛选每个MAC地址对应的配置数据
|
||||
const filteredConfigs: { [mac: string]: GatewayConfig[] } = {}
|
||||
filteredMacs.forEach((macAddr) => {
|
||||
const configs = initialConfigData[macAddr] || []
|
||||
|
||||
// 按内网IP筛选
|
||||
if (inner_ip) {
|
||||
filteredPairs = filteredPairs.filter(pair =>
|
||||
pair.inner_ip.includes(inner_ip),
|
||||
)
|
||||
}
|
||||
|
||||
// 筛选配置数据
|
||||
const filteredConfigs: { [mac: string]: GatewayConfig[] } = {}
|
||||
filteredPairs.forEach((pair) => {
|
||||
const configs = initialConfigData[pair.macaddr] || []
|
||||
const filtered = configs.filter((config) => {
|
||||
// 按各个字段筛选
|
||||
const matchPublic = !publicIp || (config.public && config.public.includes(publicIp))
|
||||
@@ -128,24 +139,35 @@ function GatewayConfigContent() {
|
||||
const matchInnerIp = !inner_ip || (config.inner_ip && config.inner_ip.includes(inner_ip))
|
||||
return matchPublic && matchCity && matchUser && matchInnerIp
|
||||
})
|
||||
|
||||
if (filtered.length > 0) {
|
||||
filteredConfigs[macAddr] = filtered
|
||||
filteredConfigs[pair.macaddr] = filtered
|
||||
}
|
||||
})
|
||||
return { filteredMacs: Object.keys(filteredConfigs), filteredConfigs }
|
||||
|
||||
// 筛选后按内网IP重新排序,确保表头与列顺序一致
|
||||
const sortedFilteredPairs = filteredPairs
|
||||
.filter(pair => filteredConfigs[pair.macaddr]?.length > 0)
|
||||
.sort((a, b) => {
|
||||
const lastOctetA = getLastOctet(a.inner_ip)
|
||||
const lastOctetB = getLastOctet(b.inner_ip)
|
||||
return lastOctetA - lastOctetB
|
||||
})
|
||||
|
||||
return { filteredPairs: sortedFilteredPairs, filteredConfigs }
|
||||
}
|
||||
|
||||
// 矩阵数据构建函数
|
||||
// 构建矩阵数据
|
||||
const buildMatrixData = async (
|
||||
macList: string[],
|
||||
gatewayPairsList: { macaddr: string, inner_ip: string }[],
|
||||
configData: { [mac: string]: GatewayConfig[] } = {},
|
||||
useLocalData: boolean = false,
|
||||
) => {
|
||||
setLoading(true)
|
||||
try {
|
||||
let macConfigMap: { [mac: string]: GatewayConfig[] } = {}
|
||||
const macList = gatewayPairsList.map(pair => pair.macaddr)
|
||||
|
||||
// 加载配置数据
|
||||
if (useLocalData) {
|
||||
// 使用本地数据
|
||||
macConfigMap = configData
|
||||
@@ -161,96 +183,91 @@ function GatewayConfigContent() {
|
||||
})
|
||||
}
|
||||
|
||||
// 获取所有端口并排序
|
||||
const allPortLines = Array.from(
|
||||
new Set(
|
||||
Object.values(macConfigMap)
|
||||
.flat()
|
||||
.map(item => item.inner_ip)// 获取端口和线路
|
||||
.map(item => item.inner_ip)
|
||||
.filter(Boolean),
|
||||
),
|
||||
)
|
||||
const portLineConfigMap: { [key: string]: GatewayConfig } = {}
|
||||
Object.values(macConfigMap).forEach((configs) => {
|
||||
configs.forEach((config) => {
|
||||
const key = config.inner_ip
|
||||
if (!portLineConfigMap[key]) {
|
||||
portLineConfigMap[key] = config
|
||||
}
|
||||
})
|
||||
})
|
||||
// 按端口号排序
|
||||
const sortedPortLines = allPortLines.sort((a, b) => {
|
||||
).sort((a, b) => {
|
||||
const portA = getLastOctet(a.split('|')[0])
|
||||
const portB = getLastOctet(b.split('|')[0])
|
||||
return portA - portB
|
||||
})
|
||||
|
||||
// 构建矩阵数据
|
||||
const matrix = sortedPortLines.map((portLine) => {
|
||||
// 构建矩阵
|
||||
const matrix = allPortLines.map((portLine) => {
|
||||
const [inner_ip] = portLine.split('|')
|
||||
const config = portLineConfigMap[portLine]
|
||||
const row = { inner_ip: inner_ip || '', devices: {} as { [macaddr: string]: GatewayConfig[] } }
|
||||
|
||||
const row = {
|
||||
inner_ip: inner_ip || '',
|
||||
devices: {} as { [macaddr: string]: GatewayConfig[] },
|
||||
}
|
||||
|
||||
// 为每个MAC地址填充该城市的配置数据
|
||||
macList.forEach((mac) => {
|
||||
const configsForPortLine = macConfigMap[mac]
|
||||
.filter(item => item.inner_ip === inner_ip)
|
||||
// 遍历排序后的网关对,双重校验配置归属
|
||||
gatewayPairsList.forEach((pair) => {
|
||||
const configsForPortLine = macConfigMap[pair.macaddr]
|
||||
.filter(item => item.inner_ip === inner_ip) // 匹配当前行端口
|
||||
.sort(sortByInnerIp)
|
||||
row.devices[mac] = configsForPortLine
|
||||
row.devices[pair.macaddr] = configsForPortLine
|
||||
})
|
||||
|
||||
return row
|
||||
})
|
||||
|
||||
// 更新状态
|
||||
setMatrixData(matrix)
|
||||
setMacAddresses(macList)
|
||||
setGatewayPairs(gatewayPairsList)
|
||||
setCurrentTotal(matrix.length)
|
||||
|
||||
// 计算总记录数
|
||||
const total = Object.values(macConfigMap).reduce((sum, configs) => sum + configs.length, 0)
|
||||
setTotalCount(total)
|
||||
setTotalCount(Object.values(macConfigMap).reduce((sum, configs) => sum + configs.length, 0))
|
||||
console.log('矩阵构建完成:', { 表头列数: gatewayPairsList.length, 矩阵行数: matrix.length })
|
||||
}
|
||||
catch (error) {
|
||||
toast.error('构建矩阵数据失败')
|
||||
console.error('构建矩阵数据错误:', error)
|
||||
console.error('矩阵构建错误:', error)
|
||||
}
|
||||
finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
// 初始化调用
|
||||
|
||||
// 初始化数据
|
||||
useEffect(() => {
|
||||
const initData = async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
// 获取网关基本信息
|
||||
const infoResult = await getGatewayInfo()
|
||||
|
||||
if (!infoResult.success) {
|
||||
throw new Error(infoResult.error || '查询网关信息失败')
|
||||
}
|
||||
if (!infoResult.success) throw new Error(infoResult.error || '查询网关信息失败')
|
||||
setInfoData(infoResult.data)
|
||||
// 获取所有MAC地址
|
||||
const allMacAddresses = Array.from(
|
||||
new Set(infoResult.data.map(item => item.macaddr).filter(Boolean)),
|
||||
).sort() as string[]
|
||||
setInitialMacAddresses(allMacAddresses)
|
||||
setMacAddresses(allMacAddresses)
|
||||
const configPromises = allMacAddresses.map(mac => fetchConfigForMac(mac, {}))
|
||||
const configResults = await Promise.all(configPromises)
|
||||
|
||||
// 构建排序后的网关对(MAC+内网IP)
|
||||
const sortedGatewayPairs = infoResult.data
|
||||
.filter(item => item.macaddr && item.inner_ip)
|
||||
.sort((a, b) => {
|
||||
const lastOctetA = getLastOctet(a.inner_ip)
|
||||
const lastOctetB = getLastOctet(b.inner_ip)
|
||||
return lastOctetA - lastOctetB
|
||||
})
|
||||
.map(item => ({ macaddr: item.macaddr!, inner_ip: item.inner_ip! }))
|
||||
|
||||
// 加载初始配置
|
||||
setGatewayPairs(sortedGatewayPairs)// 表头数据
|
||||
const sortedMacAddresses = sortedGatewayPairs.map(pair => pair.macaddr)
|
||||
|
||||
setInitialMacAddresses(sortedMacAddresses)
|
||||
setMacAddresses(sortedMacAddresses)
|
||||
|
||||
const configPromises = sortedMacAddresses.map(mac => fetchConfigForMac(mac, {}))
|
||||
const configResults = await Promise.all(configPromises)
|
||||
const initialConfig: { [mac: string]: GatewayConfig[] } = {}
|
||||
allMacAddresses.forEach((mac, index) => {
|
||||
sortedMacAddresses.forEach((mac, index) => {
|
||||
initialConfig[mac] = configResults[index] || []
|
||||
})
|
||||
|
||||
setInitialConfigData(initialConfig)
|
||||
setIsInitialDataLoaded(true)
|
||||
// 每个MAC地址调用接口
|
||||
await buildMatrixData(allMacAddresses, initialConfig, true)
|
||||
|
||||
// 构建初始矩阵
|
||||
await buildMatrixData(sortedGatewayPairs, initialConfig, true)
|
||||
}
|
||||
catch (error) {
|
||||
toast.error((error as Error).message || '获取数据失败')
|
||||
@@ -259,11 +276,10 @@ function GatewayConfigContent() {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
initData()
|
||||
}, [])
|
||||
|
||||
// 网关配置数据查询函数(用于表单查询)
|
||||
// 查询数据表单查询
|
||||
const fetchData = async (filters: {
|
||||
mac?: string
|
||||
public?: string
|
||||
@@ -275,34 +291,26 @@ function GatewayConfigContent() {
|
||||
try {
|
||||
// 如果有初始数据,就本地筛选
|
||||
if (isInitialDataLoaded) {
|
||||
const { filteredMacs, filteredConfigs } = filterLocalData(filters)
|
||||
|
||||
// 更新表格数据(扁平化所有配置数据)
|
||||
const allFilteredData = Object.values(filteredConfigs).flat()
|
||||
setData(allFilteredData)
|
||||
setTotalCount(allFilteredData.length)
|
||||
|
||||
// 构建矩阵数据
|
||||
await buildMatrixData(filteredMacs, filteredConfigs, true)
|
||||
const { filteredPairs, filteredConfigs } = filterLocalData(filters)
|
||||
setData(Object.values(filteredConfigs).flat())
|
||||
setTotalCount(Object.values(filteredConfigs).flat().length)
|
||||
await buildMatrixData(filteredPairs, filteredConfigs, true)
|
||||
}
|
||||
else {
|
||||
// 如果没有初始数据,就接口查询
|
||||
const result = await getGatewayConfig(page, filters)
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || '查询网关配置失败')
|
||||
}
|
||||
if (!result.success) throw new Error(result.error || '查询网关配置失败')
|
||||
const processedData = processCityNames(result.data.items)
|
||||
const sortedData = [...processedData].sort(sortByInnerIp)
|
||||
|
||||
setData(sortedData)
|
||||
setTotalCount(result.data.total)
|
||||
|
||||
const filteredMacs = Array.from(
|
||||
new Set(sortedData.map(item => item.edge).filter(Boolean)),
|
||||
).sort() as string[]
|
||||
const filteredMacs = Array.from(new Set(sortedData.map(item => item.edge).filter(Boolean))).sort() as string[]
|
||||
const temporaryGatewayPairs = filteredMacs
|
||||
.map(mac => ({ macaddr: mac, inner_ip: '' }))
|
||||
.sort((a, b) => a.macaddr.localeCompare(b.macaddr))
|
||||
|
||||
await buildMatrixData(filteredMacs, {}, false)
|
||||
await buildMatrixData(temporaryGatewayPairs, {}, false)
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
@@ -313,6 +321,7 @@ function GatewayConfigContent() {
|
||||
}
|
||||
}
|
||||
|
||||
// 提交查询
|
||||
const onSubmit = async (formData: FilterFormValues) => {
|
||||
const filters = {
|
||||
mac: formData.macaddr || '',
|
||||
@@ -382,6 +391,7 @@ function GatewayConfigContent() {
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
<div className="flex gap-6 p-2 items-center justify-between text-sm">
|
||||
<div className="flex gap-2">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -414,15 +424,17 @@ function GatewayConfigContent() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>
|
||||
端口
|
||||
</TableHead>
|
||||
{macAddresses.map((macaddr, index) => (
|
||||
<TableHead className="border-r sticky left-0 bg-white z-10">端口</TableHead>
|
||||
{gatewayPairs.map((pair, index) => (
|
||||
<TableHead key={index} className="border-r">
|
||||
{macaddr}
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="font-medium">{pair.macaddr}</div>
|
||||
<div className="text-xs text-gray-500 mt-1">{pair.inner_ip}</div>
|
||||
</div>
|
||||
</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
@@ -430,33 +442,28 @@ function GatewayConfigContent() {
|
||||
<TableBody>
|
||||
{matrixData.map((row, rowIndex) => (
|
||||
<TableRow key={rowIndex}>
|
||||
<TableCell className="border-r">{row.inner_ip}</TableCell>
|
||||
{macAddresses.map((macaddr, colIndex) => {
|
||||
const configs = row.devices[macaddr] || []
|
||||
<TableCell className="border-r sticky left-0 bg-white z-10">{row.inner_ip}</TableCell>
|
||||
{gatewayPairs.map((pair, colIndex) => {
|
||||
const configs = row.devices[pair.macaddr] || []
|
||||
return (
|
||||
<TableCell key={`${rowIndex}-${colIndex}`} className="border-r">
|
||||
{ configs.length === 0 ? (
|
||||
{configs.length === 0 ? (
|
||||
<div className="text-center">-</div>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{configs.map((item, itemIndex) => {
|
||||
const statusConfig = {
|
||||
ischange: item.ischange === 0
|
||||
? { bg: 'bg-green-100', border: 'border-green-200', text: 'text-green-800', label: '正常' }
|
||||
: { bg: 'bg-yellow-100', border: 'border-yellow-200', text: 'text-yellow-800', label: '更新' },
|
||||
? { bg: 'bg-green-100', text: 'text-green-800', label: '正常' }
|
||||
: { bg: 'bg-yellow-100', text: 'text-yellow-800', label: '更新' },
|
||||
isonline: item.isonline === 0
|
||||
? { bg: 'bg-green-100', border: 'border-green-200', text: 'text-green-800', label: '空闲' }
|
||||
: { bg: 'bg-blue-100', border: 'border-blue-200', text: 'text-blue-800', label: '在用' },
|
||||
? { bg: 'bg-green-100', text: 'text-green-800', label: '空闲' }
|
||||
: { bg: 'bg-blue-100', text: 'text-blue-800', label: '在用' },
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={itemIndex} className="flex flex-col gap-1 transition-shadow">
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-sm font-medium">{item.public || 'N/A'}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-xs font-medium">{item.city || 'N/A'}</span>
|
||||
</div>
|
||||
<div key={itemIndex} className="flex flex-col gap-1">
|
||||
<div className="text-sm font-medium">{item.public || 'N/A'}</div>
|
||||
<div className="text-xs font-medium">{item.city || 'N/A'}</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className={`px-2 py-0.5 rounded text-xs font-medium ${statusConfig.ischange.bg} ${statusConfig.ischange.text}`}>
|
||||
{statusConfig.ischange.label}
|
||||
|
||||
@@ -120,7 +120,6 @@ export default function Gatewayinfo() {
|
||||
setLoading(true)
|
||||
setError('')
|
||||
const result = await getGatewayInfo()
|
||||
console.log(result.data)
|
||||
|
||||
setData(result.data)
|
||||
setFilteredData(result.data) // 初始化时设置filteredData
|
||||
|
||||
@@ -261,7 +261,6 @@ export default function Settings() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="border rounded-lg">
|
||||
<DataTable
|
||||
data={newData}
|
||||
columns={[
|
||||
@@ -291,7 +290,6 @@ export default function Settings() {
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Toaster richColors />
|
||||
</Page>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user