index.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. import { PageContainer } from '@ant-design/pro-layout';
  2. import { observer } from '@formily/react';
  3. import { model } from '@formily/reactive';
  4. import { useIntl } from '@@/plugin-locale/localeExports';
  5. import { useDomFullHeight } from '@/hooks';
  6. import { useEffect, useState } from 'react';
  7. import { Empty, PermissionButton } from '@/components';
  8. import { ProColumns } from '@jetlinks/pro-table';
  9. import service from '@/pages/DataCollect/service';
  10. import SearchComponent from '@/components/SearchComponent';
  11. import { Card, Col, Pagination, Row } from 'antd';
  12. import ChannelCard from '@/components/ProTableCard/CardItems/DataCollect/channel';
  13. import { DeleteOutlined, EditOutlined, PlayCircleOutlined, StopOutlined } from '@ant-design/icons';
  14. import { onlyMessage } from '@/utils/util';
  15. import Save from '@/pages/DataCollect/Channel/Save';
  16. import { getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
  17. import useHistory from '@/hooks/route/useHistory';
  18. const ChannelModel = model<{
  19. visible: boolean;
  20. current: Partial<ChannelItem>;
  21. currentPage: number;
  22. }>({
  23. visible: false,
  24. current: {},
  25. currentPage: 0,
  26. });
  27. export default observer(() => {
  28. const intl = useIntl();
  29. const { minHeight } = useDomFullHeight(`.data-collect-channel-card`, 24);
  30. const [param, setParam] = useState({ pageSize: 12, terms: [] });
  31. const { permission } = PermissionButton.usePermission('DataCollect/Channel');
  32. const [loading, setLoading] = useState<boolean>(true);
  33. const [dataSource, setDataSource] = useState<any>({
  34. data: [],
  35. pageSize: 12,
  36. pageIndex: 0,
  37. total: 0,
  38. });
  39. const history = useHistory();
  40. const columns: ProColumns<ChannelItem>[] = [
  41. {
  42. title: '通道名称',
  43. dataIndex: 'name',
  44. },
  45. {
  46. title: '通讯协议',
  47. dataIndex: 'provider',
  48. valueType: 'select',
  49. valueEnum: {
  50. OPC_UA: {
  51. text: 'OPC_UA',
  52. status: 'OPC_UA',
  53. },
  54. MODBUS_TCP: {
  55. text: 'MODBUS_TCP',
  56. status: 'MODBUS_TCP',
  57. },
  58. },
  59. },
  60. {
  61. title: '状态',
  62. dataIndex: 'state',
  63. valueType: 'select',
  64. valueEnum: {
  65. enabled: {
  66. text: '正常',
  67. status: 'enabled',
  68. },
  69. disabled: {
  70. text: '禁用',
  71. status: 'disabled',
  72. },
  73. },
  74. },
  75. {
  76. title: '运行状态',
  77. dataIndex: 'runningState',
  78. valueType: 'select',
  79. valueEnum: {
  80. running: {
  81. text: '运行中',
  82. status: 'running',
  83. },
  84. partialError: {
  85. text: '部分错误',
  86. status: 'partialError',
  87. },
  88. failed: {
  89. text: '错误',
  90. status: 'failed',
  91. },
  92. // stopped: {
  93. // text: '已停止',
  94. // status: 'stopped',
  95. // },
  96. },
  97. },
  98. {
  99. title: '说明',
  100. dataIndex: 'description',
  101. },
  102. ];
  103. const handleSearch = (params: any) => {
  104. setLoading(true);
  105. setParam(params);
  106. service
  107. .queryChannel({ ...params, sorts: [{ name: 'createTime', order: 'desc' }] })
  108. .then((resp) => {
  109. if (resp.status === 200) {
  110. setDataSource(resp.result);
  111. }
  112. setLoading(false);
  113. });
  114. };
  115. useEffect(() => {
  116. handleSearch(param);
  117. }, []);
  118. const getState = (record: Partial<ChannelItem>) => {
  119. if (record) {
  120. if (record?.state?.value === 'enabled') {
  121. return { ...record?.runningState };
  122. } else {
  123. return {
  124. text: '禁用',
  125. value: 'disabled',
  126. };
  127. }
  128. } else {
  129. return {};
  130. }
  131. };
  132. const onPageChange = (page: number, size: number) => {
  133. if (ChannelModel.currentPage === size) {
  134. handleSearch({
  135. ...param,
  136. pageIndex: page - 1,
  137. pageSize: size,
  138. });
  139. } else {
  140. ChannelModel.currentPage = size;
  141. handleSearch({
  142. ...param,
  143. pageIndex: 0,
  144. pageSize: size,
  145. });
  146. }
  147. };
  148. return (
  149. <PageContainer>
  150. <SearchComponent<ChannelItem>
  151. field={columns}
  152. target="data-collect-channel"
  153. onSearch={(data) => {
  154. const dt = {
  155. pageSize: 12,
  156. terms: [...data?.terms],
  157. };
  158. handleSearch(dt);
  159. }}
  160. />
  161. <Card
  162. loading={loading}
  163. bordered={false}
  164. style={{ position: 'relative', minHeight }}
  165. className={'data-collect-channel-card'}
  166. >
  167. <div style={{ width: '100%', display: 'flex', justifyContent: 'flex-start' }}>
  168. <PermissionButton
  169. isPermission={permission.add}
  170. onClick={() => {
  171. ChannelModel.visible = true;
  172. ChannelModel.current = {};
  173. }}
  174. key="button"
  175. type="primary"
  176. >
  177. 新增通道
  178. </PermissionButton>
  179. </div>
  180. <div style={{ height: '100%', paddingBottom: 48 }}>
  181. {dataSource?.data.length > 0 ? (
  182. <Row gutter={[24, 24]} style={{ marginTop: 10 }}>
  183. {(dataSource?.data || []).map((record: any) => (
  184. <Col key={record.id} span={8}>
  185. <ChannelCard
  186. {...record}
  187. state={getState(record)}
  188. actions={[
  189. <PermissionButton
  190. type={'link'}
  191. onClick={() => {
  192. ChannelModel.current = record;
  193. ChannelModel.visible = true;
  194. }}
  195. key={'edit'}
  196. isPermission={permission.update}
  197. >
  198. <EditOutlined />
  199. {intl.formatMessage({
  200. id: 'pages.data.option.edit',
  201. defaultMessage: '编辑',
  202. })}
  203. </PermissionButton>,
  204. <PermissionButton
  205. key={'action'}
  206. type={'link'}
  207. style={{ padding: 0 }}
  208. isPermission={permission.action}
  209. popConfirm={{
  210. title: intl.formatMessage({
  211. id: `pages.data.option.${
  212. record?.state?.value !== 'disabled' ? 'disabled' : 'enabled'
  213. }.tips`,
  214. defaultMessage: '确认禁用?',
  215. }),
  216. onConfirm: async () => {
  217. const resp =
  218. record?.state?.value !== 'disabled'
  219. ? await service.updateChannel(record.id, {
  220. state: 'disabled',
  221. runningState: 'stopped',
  222. })
  223. : await service.updateChannel(record.id, {
  224. state: 'enabled',
  225. runningState: 'running',
  226. });
  227. if (resp.status === 200) {
  228. onlyMessage('操作成功!');
  229. handleSearch(param);
  230. } else {
  231. onlyMessage('操作失败!', 'error');
  232. }
  233. },
  234. }}
  235. >
  236. {record?.state?.value !== 'disabled' ? (
  237. <StopOutlined />
  238. ) : (
  239. <PlayCircleOutlined />
  240. )}
  241. {intl.formatMessage({
  242. id: `pages.data.option.${
  243. record?.state?.value !== 'disabled' ? 'disabled' : 'enabled'
  244. }`,
  245. defaultMessage: record?.state?.value !== 'disabled' ? '禁用' : '启用',
  246. })}
  247. </PermissionButton>,
  248. <PermissionButton
  249. key="delete"
  250. isPermission={permission.delete}
  251. type={'link'}
  252. style={{ padding: 0 }}
  253. disabled={record?.state?.value !== 'disabled'}
  254. tooltip={
  255. record?.state?.value !== 'disabled'
  256. ? {
  257. title: '正常的通道不能删除',
  258. }
  259. : undefined
  260. }
  261. popConfirm={{
  262. title: '该操作将会删除下属采集器与点位,确定删除?',
  263. placement: 'topRight',
  264. onConfirm: async () => {
  265. await service.removeChannel(record.id);
  266. handleSearch(param);
  267. onlyMessage(
  268. intl.formatMessage({
  269. id: 'pages.data.option.success',
  270. defaultMessage: '操作成功!',
  271. }),
  272. );
  273. },
  274. }}
  275. >
  276. <DeleteOutlined />
  277. </PermissionButton>,
  278. ]}
  279. onClick={() => {
  280. const url = getMenuPathByCode(MENUS_CODE['DataCollect/Collector']);
  281. history.push(url, { channelId: record.id });
  282. }}
  283. />
  284. </Col>
  285. ))}
  286. </Row>
  287. ) : (
  288. <div style={{ height: minHeight - 150 }}>
  289. <Empty />
  290. </div>
  291. )}
  292. </div>
  293. {dataSource?.data?.length > 0 && (
  294. <div
  295. style={{
  296. display: 'flex',
  297. justifyContent: 'flex-end',
  298. position: 'absolute',
  299. width: '100%',
  300. bottom: 10,
  301. right: '2%',
  302. }}
  303. >
  304. <Pagination
  305. showSizeChanger
  306. size="small"
  307. className={'pro-table-card-pagination'}
  308. total={dataSource?.total || 0}
  309. current={dataSource?.pageIndex + 1}
  310. onChange={(page, size) => {
  311. onPageChange(page, size);
  312. }}
  313. onShowSizeChange={(current, size) => {
  314. handleSearch({
  315. ...param,
  316. pageIndex: 1,
  317. pageSize: size,
  318. });
  319. }}
  320. pageSizeOptions={[12, 24, 48, 96]}
  321. pageSize={dataSource?.pageSize}
  322. showTotal={(num) => {
  323. const minSize = dataSource?.pageIndex * dataSource?.pageSize + 1;
  324. const MaxSize = (dataSource?.pageIndex + 1) * dataSource?.pageSize;
  325. return `第 ${minSize} - ${MaxSize > num ? num : MaxSize} 条/总共 ${num} 条`;
  326. }}
  327. />
  328. </div>
  329. )}
  330. </Card>
  331. {ChannelModel.visible && (
  332. <Save
  333. data={ChannelModel.current}
  334. close={() => {
  335. ChannelModel.visible = false;
  336. }}
  337. reload={() => {
  338. ChannelModel.visible = false;
  339. handleSearch(param);
  340. }}
  341. />
  342. )}
  343. </PageContainer>
  344. );
  345. });