feat(前端):终端绑定镜像、用户

master
shaot 2025-08-12 15:07:41 +08:00
parent a1dbc6a736
commit 7e9be02d61
7 changed files with 198 additions and 131 deletions

View File

@ -23,7 +23,7 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
const [open, setOpen] = useState<boolean>(false);
const [tableData, setTableData] = useState<any[]>([]);
//镜像选择
const [selectedRowKeys, setSelectedRowKeys] = useState<[]>([]);
const [selectedRowKeys, setSelectedRowKeys] = useState<any[]>([]);
const [selectedRows, setSelectedRows] = useState<any[]>([]);
// 已绑定用户列表选择
@ -37,6 +37,7 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
list.push(item);
idList.push(item.id);
});
setTableData(formValue);
setSelectedRowKeys(idList);
setSelectedRows(list);
}
@ -53,7 +54,7 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
// 镜像
(selectedRows || []).forEach((item) => {
list.push({
record_id: item.id,
id: item.id,
image_name: item.image_name,
});
});
@ -74,17 +75,27 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
const handleDelete = (record?: any) => {
if (record) {
// 单个删除
const { record_id } = record || {};
const newData = tableData.filter((item) => item.record_id !== record_id);
const { id } = record || {};
const newData = tableData.filter((item) => item.id !== id);
const ids: any[] = [];
newData.map((item) => ids.push(item.id));
setTableData(newData);
setSelectedRowKeys(ids);
setSelectedRows(newData);
onBindImageChange(newData);
setBindTableKeys([]);
} else {
// 批量删除
const newData = tableData.filter(
(item) => !bindTableKeys.includes(item.record_id),
(item) => !bindTableKeys.includes(item.id),
);
const ids: any[] = [];
newData.map((item) => ids.push(item.id));
setTableData(newData);
setSelectedRowKeys([]);
setSelectedRows([]);
setBindTableKeys([]);
setSelectedRowKeys(ids);
setSelectedRows(newData);
onBindImageChange(newData);
}
};
@ -136,10 +147,20 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
title: '操作',
key: 'action',
width: 150,
align: 'center',
render: (_, record) => (
<Button type="link" onClick={() => handleDelete(record)}>
<Popconfirm
title=""
placement="bottom"
description="请确认是否删除?"
onConfirm={() => handleDelete(record)}
okText="删除"
cancelText="取消"
>
<Button type="link">
</Button>
</Popconfirm>
),
},
];
@ -154,21 +175,23 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
title=""
trigger="click"
open={open}
// onOpenChange={setOpen}
onOpenChange={setOpen}
placement={placement}
>
<div>
<Button
onClick={() => {
setOpen(true);
}}
style={{ marginRight: '15px' }}
// onClick={() => {
// setOpen(true);
// }}
// style={{ marginRight: '15px' }}
>
</Button>
</Popover>
<Popconfirm
title=""
description="删除操作不可逆,请确认是否删除?"
placement="bottomRight"
description="请确认是否删除?"
onConfirm={() => handleDelete()}
disabled={bindTableKeys.length === 0}
okText="删除"
@ -176,15 +199,13 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
>
<Button disabled={bindTableKeys.length === 0}></Button>
</Popconfirm>
</div>
</Popover>
</Space>
<CustomTable
dataSource={tableData}
onDelete={handleDelete}
columns={getColumns()}
scrollY={400}
rowKey="record_id"
rowKey="id"
pagination={false}
rowSelection={{
bindTableKeys,

View File

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
import { ERROR_CODE } from '@/constants/constants';
import { getImageList } from '@/services/terminal';
import { Input, message, Table } from 'antd';
import { Input, message, Table, Tooltip } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import React, { useEffect, useState } from 'react';
import styles from './index.less';
@ -65,7 +65,9 @@ const TablePage: React.FC<TableProps> = ({
{
title: '镜像名称',
dataIndex: 'image_name',
render: (text: any) => <span>{text || ''}</span>,
render: (text) => {
return <Tooltip>{text || '--'}</Tooltip>;
},
},
];
@ -92,7 +94,7 @@ const TablePage: React.FC<TableProps> = ({
onSearch={handleSearch}
enterButton
allowClear
style={{ width: '200px', marginLeft: '10px' }}
style={{ width: '300px', marginLeft: '10px' }}
/>
</div>
@ -102,7 +104,7 @@ const TablePage: React.FC<TableProps> = ({
rowKey="id"
loading={loading}
rowSelection={{
selectedRowKeys,
selectedRowKeys:selectedRowKeys,
preserveSelectedRowKeys: true,
onChange: onUserTableSelect,
}}

View File

@ -2,16 +2,15 @@
import { ERROR_CODE } from '@/constants/constants';
import { getBindImageAdd, getBindImageList } from '@/services/terminal';
import { Button, Form, message, Modal } from 'antd';
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import SelectedTable from '../ImageSelectedTable/index';
import styles from './index.less';
interface UserEditModalProps {
onCancel: () => void;
onOk: (values: any) => void;
onOk: (values?: any) => void;
confirmLoading?: boolean;
dataDetial?: Termial.ModalBaseNode;
selectedOrg?: number;
}
const BindUserModal: React.FC<UserEditModalProps> = ({
@ -20,9 +19,10 @@ const BindUserModal: React.FC<UserEditModalProps> = ({
confirmLoading = false,
dataDetial,
}) => {
const { recordData, visible, selectedOrg } = dataDetial || {};
const { recordData, visible } = dataDetial || {};
const { device_id } = recordData || {};
const [form] = Form.useForm();
const [dataSource, setDataSource] = useState<any[]>([]);
useEffect(() => {
const params = { device_id: device_id };
@ -30,44 +30,61 @@ const BindUserModal: React.FC<UserEditModalProps> = ({
const { code, data = [] } = res || {};
if (code === ERROR_CODE) {
if (data && data.length) {
const initialValues = { image_list: data };
const imageList: any[] = [];
data.forEach((item: any) => {
imageList.push({
id: item.image_id,
image_name: item.image_name,
// current_id: item.id,
});
});
setDataSource(data);
const initialValues = { image_list: imageList };
form.setFieldsValue(initialValues);
}
}
});
}, [visible, form, recordData, selectedOrg]);
}, [visible, form, recordData]);
const onBind = (payload: any) => {
getBindImageAdd(payload).then((res: any) => {
const { code } = res || {};
if (code === ERROR_CODE) {
message.success('绑定成功');
if (onOk) onOk();
} else {
message.error('绑定失败');
}
});
};
const handleOk = async () => {
try {
const values = await form.validateFields();
const { image_list } = values || {};
console.log('image_list=====', image_list);
if (image_list && image_list.length > 0) {
const list: any[] = [];
image_list.forEach((item: any) => {
list.push({
id: item.id,
const obj: any = {
device_id: device_id,
image_id: item.record_id,
});
image_id: item.id,
};
const newData = dataSource.filter(
(record) => record.image_id === item.id,
);
if (newData && newData.length === 1) {
obj.id = newData[0].id;
}
list.push({ ...obj });
});
const payload: any = {
data: list,
};
getBindImageAdd(payload).then((res: any) => {
const { code } = res || {};
if (code === ERROR_CODE) {
message.success('绑定成功');
onOk();
} else {
message.error('绑定失败');
}
});
onBind(payload);
} else {
message.info('请先选择绑定的镜像');
}
console.log('values=====', values);
// onOk(values);
} catch (error) {
message.error('请检查表单字段');
}

View File

@ -24,8 +24,10 @@ const BindUserModal: React.FC<UserEditModalProps> = ({
dataDetial,
}) => {
const { recordData, visible } = dataDetial || {};
const { device_id,device_group_id } = recordData || {};
const { device_id, device_group_id } = recordData || {};
const [orgTreeData, setOrgTreeData] = useState<User.OrganizationNode[]>([]);
const [userDataSource, setUserDataSource] = useState<any[]>([]);
// const [groupDataSource, setGroupDataSource] = useState<any[]>([]);
const [form] = Form.useForm();
const getGroupList = async () => {
@ -57,7 +59,6 @@ const BindUserModal: React.FC<UserEditModalProps> = ({
if (!device_id) return;
const payload = { device_id: device_id };
getBindUserList(payload).then((res: any) => {
console.log('res========', res);
const { code, data = [] } = res || {};
if (code === ERROR_CODE) {
if (data && data.length > 0) {
@ -65,54 +66,34 @@ const BindUserModal: React.FC<UserEditModalProps> = ({
data.map((item: any) => {
const { type, user_id, user_name, user_group_id, user_group_name } =
item || {};
const obj: any = { ...item };
delete obj.id;
if (type === 1) {
list.push({ record_id: user_id, name: user_name, ...item });
list.push({
table_id: `user_${user_id}`,
id: user_id,
name: user_name,
user_name: user_name,
type: type,
});
} else {
list.push({
record_id: user_group_id,
table_id: `group_${user_group_id}`,
id: user_group_id,
name: user_group_name,
...item,
type: type,
});
}
});
const initialValues = { user_list: list, status: 1 };
setUserDataSource(data);
const initialValues = { user_list: list };
form.setFieldsValue(initialValues);
}
}
});
}, [visible, form, recordData]);
const handleOk = async () => {
try {
const values = await form.validateFields();
const { user_list = [] } = values || {};
const list: any[] = [];
if (user_list && user_list.length > 0) {
user_list.forEach((item: any) => {
const { record_id, type, id } = item || {};
if (type === 1) {
// 用户
list.push({
user_id: record_id,
id: id,
device_id,
device_group_id,
type: type,
});
} else {
//用户分组
list.push({
user_group_id: record_id,
id: id,
device_id: device_id,
device_group_id,
type: type,
});
}
});
const payload = {
data: list,
};
const onBind = (payload: any) => {
bindUserAdd(payload)
.then((res: any) => {
const { code } = res || {};
@ -124,6 +105,52 @@ const BindUserModal: React.FC<UserEditModalProps> = ({
}
})
.catch(() => {});
};
const handleOk = async () => {
try {
const values = await form.validateFields();
const { user_list = [] } = values || {};
const list: any[] = [];
if (user_list && user_list.length > 0) {
user_list.forEach((item: any) => {
const { type, id } = item || {};
if (type === 1) {
// 用户
const obj: any = {
device_id,
device_group_id,
type: type,
user_id: id,
};
const newData = userDataSource.filter(
(record) => record.user_id === item.id && record.type === 1,
);
if (newData && newData.length === 1) {
obj.id = newData[0].id;
}
list.push(obj);
} else {
//用户分组
const obj: any = {
device_id,
device_group_id,
type: type,
user_group_id: id,
};
const newData = userDataSource.filter(
(record) => record.user_group_id === item.id && record.type === 2,
);
if (newData && newData.length === 1) {
obj.id = newData[0].id;
}
list.push(obj);
}
});
const payload = {
data: list,
};
onBind(payload);
}
} catch (error) {
message.error('请检查表单字段');

View File

@ -134,7 +134,7 @@ const UserEditModal: React.FC<UserEditModalProps> = ({
<Form.Item
name="device_type"
label="终端类型"
rules={[{ required: true, message: '请输入终端型号' }]}
rules={[{ required: false, message: '请输入终端型号' }]}
>
<Select options={DEVICE_TYPE_OPTIONS} />
</Form.Item>

View File

@ -2,7 +2,7 @@
import CustomTree from '@/pages/components/customTree';
import { TeamOutlined } from '@ant-design/icons';
import type { PopoverProps } from 'antd';
import { Alert, Button, Popconfirm, Popover, Space, Tabs } from 'antd';
import { Alert, Button, Popconfirm, Popover, Space, Tabs,Tooltip } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import React, { useEffect, useState } from 'react';
import SelectConponents from '../selectConponents';
@ -38,7 +38,6 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
const [bindTableKeys, setBindTableKeys] = useState<any[]>([]);
useEffect(() => {
console.log('formValue==========', formValue);
const userList: any = [];
const groupList: any = [];
const userId: any = [];
@ -47,10 +46,10 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
formValue.forEach((item: any) => {
if (item.type === 1) {
userList.push(item);
userId.push(item.record_id);
userId.push(item.id);
} else {
groupList.push(item);
groupId.push(item.record_id);
groupId.push(item.id);
}
});
setTableData(formValue);
@ -61,11 +60,7 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
}
}, [formValue]);
// const onOrgSelect = (selectedKeys: React.Key[], info: any) => {};
const onCheckChange = (keys: any[], info: any) => {
// const { checkedNodes } = info;
console.log('info=========', info);
setCheckedKeys(keys);
setCheckedRow(info);
};
@ -83,17 +78,19 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
// 用户
(selectedRows || []).forEach((item) => {
list.push({
record_id: item.id,
id: item.id,
name: item.user_name,
type: 1,
table_id: `user_${item.id}`,
});
});
// 用户组
(checkedRow || []).forEach((item) => {
list.push({
record_id: item.id,
id: item.id,
name: item.name,
type: 2,
table_id: `group_${item.id}`,
});
});
setTableData(list);
@ -102,34 +99,30 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
};
const onUserTableSelect = (keys: any[], row: any[]) => {
console.log('selectedRowKeys changed: ', keys);
console.log('selectedRowKeys rows: ', row);
setSelectedRowKeys(keys as any);
setSelectedRows(row);
};
const onSelectChange = (keys: any[]) => {
console.log('selectedRowKeys changed: ', keys);
setBindTableKeys(keys as any);
};
const handleDelete = (record?: any) => {
console.log('record=====handleDelete', record);
if (record) {
// 单个删除
const { record_id } = record || {};
const newData = tableData.filter((item) => item.record_id !== record_id);
const { table_id } = record || {};
const newData = tableData.filter((item) => item.table_id !== table_id);
setTableData(newData);
setBindTableKeys([]);
if (onBindUserChange) onBindUserChange(newData);
} else {
// 批量删除
const newData = tableData.filter(
(item) => !bindTableKeys.includes(item.record_id),
(item) => !bindTableKeys.includes(item.table_id),
);
setTableData(newData);
setBindTableKeys([]);
if (onBindUserChange) onBindUserChange(newData);
setSelectedRowKeys([]);
setSelectedRows([]);
}
};
@ -140,17 +133,24 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
dataIndex: 'order',
key: 'order',
width: 80,
align: 'center',
render: (_, record, index) => <span>{index + 1}</span>,
},
{
title: '名称',
dataIndex: 'name',
key: 'name',
align: 'center',
render: (text) => {
return <Tooltip>{text || '--'}</Tooltip>;
},
},
{
title: '类型',
dataIndex: 'type',
key: 'type',
align: 'center',
width: 220,
render: (text) => (
<span>{text == 1 ? '用户' : text == 2 ? '用户组' : ''}</span>
),
@ -158,10 +158,19 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
{
title: '操作',
key: 'action',
width: 180,
align: 'center',
render: (_, record) => (
<Button type="link" onClick={() => handleDelete(record)}>
</Button>
<Popconfirm
title=""
placement="bottom"
description="请确认是否删除?"
onConfirm={() => handleDelete(record)}
okText="删除"
cancelText="取消"
>
<Button type="link"></Button>
</Popconfirm>
),
},
];
@ -229,21 +238,15 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
title=""
trigger="click"
open={open}
// onOpenChange={setOpen}
onOpenChange={setOpen}
placement={placement}
>
<div>
<Button
onClick={() => {
setOpen(true);
}}
style={{ marginRight: '15px' }}
>
</Button>
<Button></Button>
</Popover>
<Popconfirm
title=""
description="删除操作不可逆,请确认是否删除?"
placement="bottomRight"
description="请确认是否删除?"
onConfirm={() => handleDelete()}
disabled={bindTableKeys.length === 0}
okText="删除"
@ -251,14 +254,12 @@ const SelectedTable: React.FC<SelectedTableProps> = (props) => {
>
<Button disabled={bindTableKeys.length === 0}></Button>
</Popconfirm>
</div>
</Popover>
</Space>
<CustomTable
dataSource={tableData}
onDelete={handleDelete}
scrollY={400}
rowKey="record_id"
rowKey="table_id"
pagination={false}
columns={getColumns()}
rowSelection={{

View File

@ -23,7 +23,6 @@ const DeletableTable: React.FC<DeletableTableProps> = (props) => {
scrollY = 400,
...restProps
} = props;
console.log("datasource=====",dataSource);
// const getColumns = (): ColumnsType<any> => {
// const columns: ColumnsType<any> = [
// {