ソースを参照

feat: 升降机列表

touchitvoid 3 年 前
コミット
d0e2c1e56c

+ 12 - 7
.idea/workspace.xml

@@ -2,13 +2,14 @@
 <project version="4">
   <component name="ChangeListManager">
     <list default="true" id="e134edf7-cd39-4d8a-9fa6-b64c2a732b8a" name="Default Changelist" comment="">
-      <change afterPath="$PROJECT_DIR$/src/pages/hard/static/stripes.png" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/pages/lift/components/bindChanle/index.tsx" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/pages/lift/data.d.ts" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/pages/lift/hook.ts" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/src/pages/lift/index.tsx" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/src/config/menuConfig.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/config/menuConfig.tsx" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/src/pages/hard/components/3d-component.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/hard/components/3d-component.tsx" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/pages/hard/hooks.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/hard/hooks.ts" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/pages/hard/index.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/hard/index.scss" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/pages/hard/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/hard/index.tsx" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/pages/index/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/index/index.tsx" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/src/router/config.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/router/config.tsx" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -47,7 +48,7 @@
     <property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
     <property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
     <property name="WebServerToolWindowFactoryState" value="false" />
-    <property name="last_opened_file_path" value="$PROJECT_DIR$/src/pages/head-mast" />
+    <property name="last_opened_file_path" value="$PROJECT_DIR$/src/pages" />
     <property name="nodejs_package_manager_path" value="yarn" />
     <property name="settings.editor.selected.configurable" value="preferences.pluginManager" />
     <property name="ts.external.directory.path" value="$PROJECT_DIR$/node_modules/typescript/lib" />
@@ -55,6 +56,7 @@
   </component>
   <component name="RecentsManager">
     <key name="CopyFile.RECENT_KEYS">
+      <recent name="$PROJECT_DIR$/src/pages" />
       <recent name="$PROJECT_DIR$/src/pages/head-mast" />
     </key>
     <key name="MoveFile.RECENT_KEYS">
@@ -102,7 +104,10 @@
       <workItem from="1626491883422" duration="73000" />
       <workItem from="1626609758940" duration="2000" />
       <workItem from="1626675361566" duration="5472000" />
-      <workItem from="1626749325308" duration="15512000" />
+      <workItem from="1626749325308" duration="15672000" />
+      <workItem from="1626862210324" duration="128000" />
+      <workItem from="1626862703158" duration="507000" />
+      <workItem from="1626934065732" duration="4486000" />
     </task>
     <servers />
   </component>

+ 6 - 0
src/config/menuConfig.tsx

@@ -246,6 +246,12 @@ const adminMenuConfig = [
         path: '/admin/device/headMast',
         icon: '',
       },
+      {
+        title: '升降机设备',
+        key: '/device/lift',
+        path: '/admin/device/lift',
+        icon: '',
+      },
       {
         title: '视频监控',
         key: '/device/videos',

+ 2 - 2
src/pages/hard/components/3d-component.tsx

@@ -135,9 +135,9 @@ const ThreeComponent: React.FC<ThreeComponentProps> = (props) => {
     })
     initThree(spriteList, rootEle, setLoadProcess)
   }, [props.baseData.base])
-
+  // 进度条
   const LoadComponent = () => {
-    // 刻度
+    // 计算刻度
     const sign = [5, 25, 50, 75, 100].find(p => p >= loadProcess)
     return (
       <div className='load-process'>

+ 65 - 0
src/pages/lift/components/bindChanle/index.tsx

@@ -0,0 +1,65 @@
+import { useEffect, useCallback } from 'react';
+import { Modal, Form, Select } from 'antd';
+import { useUnBindChanles } from '../../../../hooks/video';
+
+interface Iprops {
+	onOk?: (values: { channel_id: number }) => void;
+	visible?: boolean;
+	onCancle?: () => void;
+	loading?: boolean;
+}
+const bindChanleModal: React.FC<Iprops> = ({
+	onOk,
+	visible,
+	onCancle,
+	loading,
+}) => {
+	const [form] = Form.useForm();
+	const {
+		state: chanleListState,
+		request: requestChanleList,
+	} = useUnBindChanles();
+	useEffect(() => {
+		requestChanleList();
+	}, []);
+	useEffect(() => {
+		form && form.resetFields();
+	}, [visible]);
+	const handleOK = useCallback(() => {
+		form
+			.validateFields()
+			.then((data: any) => {
+				onOk && onOk(data);
+			})
+			.catch((error) => {});
+	}, [onOk, form]);
+	return (
+		<Modal
+			title='绑定摄像头'
+			visible={visible}
+			onOk={handleOK}
+			okButtonProps={{ loading }}
+			onCancel={onCancle}>
+			<Form form={form}>
+				<Form.Item
+					name='channel_id'
+					required
+					rules={[{ required: true, message: '请选择摄像头' }]}
+					label='摄像头'
+					children={
+						<Select
+							loading={chanleListState.loading}
+							showSearch={false}
+							placeholder='请输入摄像头'
+							options={chanleListState.dataSource.map((element) => {
+								return {
+									label: element.name,
+									value: element.id,
+								};
+							})}></Select>
+					}></Form.Item>
+			</Form>
+		</Modal>
+	);
+};
+export default bindChanleModal;

+ 0 - 0
src/pages/lift/data.d.ts


+ 65 - 0
src/pages/lift/hook.ts

@@ -0,0 +1,65 @@
+import { useState } from 'react';
+import Request from '../../utils/request';
+export interface DustRecordProps {
+	id: number;
+	name: string;
+	batch: string;
+	provider_name: string;
+	created_time: string;
+	approve_time: string;
+	state: keyof typeof DustState;
+	channel_id: number;
+	status: keyof typeof StatusConfig;
+	type_code: number;
+}
+export const DustState = {
+	0: '离线',
+	1: '在线',
+};
+
+export enum DustStatus {
+	'wait',
+	'agree',
+	'Refuse',
+}
+export const StatusConfig = {
+	[DustStatus.wait]: '待确认',
+	[DustStatus.agree]: '已确认',
+	[DustStatus.Refuse]: '非本项目',
+};
+/**
+ * @description 扬尘设备列表
+ */
+export const useLiftList = () => {
+	const [state, setState] = useState<{
+		loading: boolean;
+		dataSource: DustRecordProps[];
+		total: number;
+		current: number;
+	}>({
+		loading: false,
+		dataSource: [],
+		total: 0,
+		current: 1,
+	});
+	const request = (params: { page: number }) => {
+		setState((preState) => ({ ...preState, loading: true }));
+		return Request.sendRequest({
+			url: '/v1/device/lift_list',
+			params,
+		})
+			.then((data: any) => {
+				setState((preState) => ({
+					...preState,
+					...data,
+					loading: false,
+					dataSource: data.list,
+				}));
+			})
+			.catch((error) => {
+				setState((preState) => ({ ...preState, loading: false }));
+				return Promise.reject(error);
+			});
+	};
+	return { state, request } as const;
+};

+ 279 - 0
src/pages/lift/index.tsx

@@ -0,0 +1,279 @@
+import { useEffect, useCallback, useState, useRef } from 'react';
+import {
+	Button,
+	Table,
+	Modal,
+	Radio,
+	Space,
+	PageHeader,
+	message,
+	Badge,
+	Typography,
+} from 'antd';
+import { ColumnProps } from 'antd/lib/table';
+import {
+	useLiftList,
+	DustRecordProps,
+	DustState,
+	DustStatus,
+  StatusConfig,
+} from './hook';
+import {
+	useBindChanle,
+	useUnBindChanle,
+	usPutDevice,
+} from '../../hooks/device';
+
+const { Text } = Typography;
+
+import BindChanleModal from './components/bindChanle';
+const device: React.FC = () => {
+	const ApplyStatus = useRef(true);
+	const [modalState, setModalState] = useState<{
+		visible: boolean;
+		values?: DustRecordProps;
+	}>({
+		visible: false,
+	});
+	const [searchState, changeSearchState] = useState({ page: 1 });
+	const { state: dustListState, request: requestDustList } = useLiftList();
+	const { state: bindState, request: requestBindChanle } = useBindChanle();
+	const { state: revokeState, request: requestRevoke } = useUnBindChanle();
+	const { state: putState, request: requestPutDevice } = usPutDevice();
+	const [state, setState] = useState<{ reviewStatue: boolean }>({
+		reviewStatue: true,
+	});
+	useEffect(() => {
+		requestDustList(searchState);
+	}, [searchState]);
+
+	const colums: ColumnProps<DustRecordProps>[] = [
+		{
+			title: '供应商',
+			dataIndex: 'provider_name',
+			key: 'provider_name',
+		},
+		{
+			title: '设备名',
+			dataIndex: 'name',
+			key: 'name',
+		},
+		{
+			title: '批次',
+			dataIndex: 'batch',
+			key: 'batch',
+		},
+		{
+			title: '设备唯一编码',
+			dataIndex: 'sn',
+			key: 'sn',
+		},
+		/*{
+			title: '设备密钥',
+			width: 130,
+			dataIndex: 'key',
+			key: 'key',
+		},*/
+		{
+			title: '申请时间',
+			dataIndex: 'created_time',
+			key: 'created_time',
+		},
+		{
+			title: '审批时间',
+			dataIndex: 'approve_time',
+			key: 'approve_time',
+		},
+		{
+			title: '状态',
+			dataIndex: 'state',
+			key: 'state',
+			render: (dataIndex) => {
+				const online = dataIndex === 1;
+				return (
+					<>
+						<Badge status={online ? 'success' : 'error'}/>
+						<Text type={online ? 'success' : 'secondary'}>
+							{DustState[dataIndex as 0 | 1]}
+						</Text>
+					</>
+				);
+			},
+			//render: (_, record) => DustState[record.state],
+		},
+		{
+			title: '确认状态',
+			dataIndex: 'status',
+			key: 'status',
+			render: (_, record) => StatusConfig[record.status],
+		},
+		{
+			title: '操作',
+			render: (record) => {
+				return (
+					<Space>
+						<Button
+							type={record.status === DustStatus.wait ? 'primary' : 'default'}
+							disabled={record.status !== DustStatus.wait}
+							size='small'
+							onClick={() => handleConfirm(record)}>
+							审核
+						</Button>
+						{/*{!!record.channel_id ? (*/}
+						{/*	<Button*/}
+						{/*		size='small'*/}
+						{/*		danger*/}
+						{/*		onClick={() => handleRevokeChanle(record)}>*/}
+						{/*		解绑摄像头*/}
+						{/*	</Button>*/}
+						{/*) : (*/}
+						{/*	<Button*/}
+						{/*		size='small'*/}
+						{/*		onClick={() => {*/}
+						{/*			setModalState((preState) => ({*/}
+						{/*				...preState,*/}
+						{/*				visible: true,*/}
+						{/*				values: record,*/}
+						{/*			}));*/}
+						{/*		}}>*/}
+						{/*		绑定摄像头*/}
+						{/*	</Button>*/}
+						{/*)}*/}
+					</Space>
+				);
+			},
+		},
+	];
+	/**
+	 * @description 审批设备
+	 * @param record
+	 */
+	const handleConfirm = useCallback(
+		(record: DustRecordProps) => {
+			Modal.confirm({
+				title: '审核',
+				content: (
+					<div>
+						<Space>
+							确认是否为当前项目设备:
+							<Radio.Group
+								defaultValue={true}
+								onChange={(event) => {
+									console.log(event.target.value);
+									ApplyStatus.current = event.target.value;
+								}}>
+								<Radio value={true}>通过</Radio>
+								<Radio value={false}>拒绝</Radio>
+							</Radio.Group>
+						</Space>
+					</div>
+				),
+				okText: '确认',
+				cancelText: '取消',
+				onOk: () => {
+					return requestPutDevice({
+						id: record.id,
+						device_code: record.type_code,
+						status: ApplyStatus.current,
+					})
+						.then(() => {
+							requestDustList(searchState);
+							message.success('操作成功');
+						})
+						.catch((error) => {
+							message.error(error.message);
+						})
+						.finally(() => {
+							ApplyStatus.current = true;
+						});
+				},
+				onCancel() {
+					ApplyStatus.current = true;
+				},
+			});
+		},
+		[Modal]
+	);
+
+	/**
+	 * @description 绑定摄像头
+	 */
+	const handleBindChanle = useCallback(
+		(data) => {
+			requestBindChanle({
+				...data,
+				device_id: modalState.values?.id,
+				device_code: modalState.values?.type_code,
+			})
+				.then(() => {
+					message.success('绑定摄像头成功');
+					requestDustList(searchState);
+					setModalState((preState) => ({
+						...preState,
+						visible: false,
+						values: undefined,
+					}));
+				})
+				.catch((error) => {
+					message.error(error.message);
+				});
+		},
+		[modalState.values, message, requestDustList]
+	);
+	/**
+	 * @description 解绑摄像头
+	 */
+	const handleRevokeChanle = useCallback(
+		(record: DustRecordProps) => {
+			Modal.confirm({
+				title: '确认解绑摄像头',
+				okText: '确认',
+				cancelText: '取消',
+				okButtonProps: {
+					loading: revokeState.loading,
+				},
+				onOk: () => {
+					return requestRevoke({
+						device_id: record.id,
+						device_code: record.type_code,
+					})
+						.then(() => {
+							requestDustList(searchState);
+							message.success('解绑成功');
+						})
+						.catch((error) => {
+							message.error(error.message);
+						});
+				},
+			});
+		},
+		[requestDustList, message]
+	);
+	return (
+		<div>
+			<PageHeader title='升降机设备'/>
+			<Table
+				rowKey={(record) => record.id}
+				columns={colums}
+				pagination={{
+					current: dustListState.current,
+					total: dustListState.total,
+					showQuickJumper: false,
+					showSizeChanger: false,
+					hideOnSinglePage: true,
+					onChange: (page) =>
+						changeSearchState((preState) => ({ ...preState, page })),
+				}}
+				loading={dustListState.loading}
+				dataSource={dustListState.dataSource}/>
+			<BindChanleModal
+				loading={bindState.loading}
+				visible={modalState.visible}
+				onCancle={() => {
+					setModalState((preState) => ({ ...preState, visible: false }));
+				}}
+				onOk={handleBindChanle}/>
+		</div>
+	);
+};
+export default device;

+ 6 - 0
src/router/config.tsx

@@ -18,6 +18,7 @@ const projectPlan = lazy(() => import('../pages/projectPlan'));
 const projectRender = lazy(() => import('../pages/admin-renderings'));
 
 const dust = lazy(() => import('../pages/dust'));
+const lift = lazy(() => import('../pages/lift'));
 const headMast = lazy(() => import('../pages/head-mast'));
 
 const videoDevice = lazy(() => import('../pages/device-video'));
@@ -133,6 +134,11 @@ export const routerConfig = [
 				exact: true,
 				component: wrapperLoading(headMast),
 			},
+      {
+				path: '/admin/device/lift',
+				exact: true,
+				component: wrapperLoading(lift),
+			},
 			{
 				path: '/admin/device/accessController',
 				exact: true,