index.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. import { PageContainer } from '@ant-design/pro-layout';
  2. import type { ProtocolItem } from '@/pages/link/Protocol/typings';
  3. import { useEffect, useRef } from 'react';
  4. import type { ActionType, ProColumns } from '@jetlinks/pro-table';
  5. import { Badge, Button, message, Popconfirm, Tooltip } from 'antd';
  6. import { CheckCircleOutlined, DeleteOutlined, EditOutlined, StopOutlined } from '@ant-design/icons';
  7. import BaseCrud from '@/components/BaseCrud';
  8. import { useIntl } from '@@/plugin-locale/localeExports';
  9. import type { ISchema } from '@formily/json-schema';
  10. import { CurdModel } from '@/components/BaseCrud/model';
  11. import Service from '@/pages/link/Protocol/service';
  12. import { onFormValuesChange, registerValidateRules } from '@formily/core';
  13. import { Store } from 'jetlinks-store';
  14. import { useLocation } from 'umi';
  15. import SystemConst from '@/utils/const';
  16. export const service = new Service('protocol');
  17. const Protocol = () => {
  18. const intl = useIntl();
  19. const actionRef = useRef<ActionType>();
  20. const modifyState = async (id: string, type: 'deploy' | 'un-deploy') => {
  21. const resp = await service.modifyState(id, type);
  22. if (resp.status === 200) {
  23. message.success('插件发布成功!');
  24. } else {
  25. message.error('插件发布失败!');
  26. }
  27. actionRef.current?.reload();
  28. };
  29. const columns: ProColumns<ProtocolItem>[] = [
  30. {
  31. dataIndex: 'id',
  32. title: 'ID',
  33. sorter: true,
  34. ellipsis: true,
  35. defaultSortOrder: 'ascend',
  36. },
  37. {
  38. dataIndex: 'name',
  39. ellipsis: true,
  40. title: intl.formatMessage({
  41. id: 'pages.table.name',
  42. defaultMessage: '名称',
  43. }),
  44. },
  45. {
  46. dataIndex: 'type',
  47. title: '类型',
  48. ellipsis: true,
  49. },
  50. {
  51. dataIndex: 'state',
  52. title: '状态',
  53. renderText: (text) => (
  54. <Badge color={text !== 1 ? 'red' : 'green'} text={text !== 1 ? '未发布' : '已发布'} />
  55. ),
  56. },
  57. {
  58. dataIndex: 'description',
  59. ellipsis: true,
  60. title: '说明',
  61. },
  62. {
  63. title: intl.formatMessage({
  64. id: 'pages.data.option',
  65. defaultMessage: '操作',
  66. }),
  67. valueType: 'option',
  68. width: 200,
  69. render: (text, record) => [
  70. <a
  71. key="edit"
  72. onClick={() => {
  73. CurdModel.update(record);
  74. CurdModel.model = 'edit';
  75. }}
  76. >
  77. <Tooltip
  78. title={intl.formatMessage({
  79. id: 'pages.data.option.edit',
  80. defaultMessage: '编辑',
  81. })}
  82. >
  83. <EditOutlined />
  84. </Tooltip>
  85. </a>,
  86. record.state !== 1 && (
  87. <a key="publish">
  88. <Popconfirm title="确认发布?" onConfirm={() => modifyState(record.id, 'deploy')}>
  89. <Tooltip title="发布">
  90. <CheckCircleOutlined />
  91. </Tooltip>
  92. </Popconfirm>
  93. </a>
  94. ),
  95. record.state === 1 && (
  96. <a key="reload">
  97. <Popconfirm title="确认撤销?" onConfirm={() => modifyState(record.id, 'un-deploy')}>
  98. <Tooltip title="撤销">
  99. <StopOutlined />
  100. </Tooltip>
  101. </Popconfirm>
  102. </a>
  103. ),
  104. <Tooltip
  105. key="delete"
  106. title={
  107. record.state !== 1
  108. ? intl.formatMessage({
  109. id: 'pages.data.option.remove',
  110. defaultMessage: '删除',
  111. })
  112. : '请先禁用该组件,再删除。'
  113. }
  114. >
  115. <Button style={{ padding: 0 }} key="delete" type="link" disabled={record.state === 1}>
  116. <Popconfirm
  117. title={intl.formatMessage({
  118. id: 'pages.data.option.remove.tips',
  119. defaultMessage: '确认删除?',
  120. })}
  121. onConfirm={async () => {
  122. await service.remove(record.id);
  123. message.success(
  124. intl.formatMessage({
  125. id: 'pages.data.option.success',
  126. defaultMessage: '操作成功!',
  127. }),
  128. );
  129. actionRef.current?.reload();
  130. }}
  131. >
  132. <Tooltip
  133. title={intl.formatMessage({
  134. id: 'pages.data.option.remove',
  135. defaultMessage: '删除',
  136. })}
  137. >
  138. <DeleteOutlined />
  139. </Tooltip>
  140. </Popconfirm>
  141. </Button>
  142. </Tooltip>,
  143. ],
  144. },
  145. ];
  146. registerValidateRules({
  147. validateId(value) {
  148. if (!value) return '';
  149. const reg = new RegExp('^[0-9a-zA-Z_\\\\-]+$');
  150. return reg.exec(value) ? '' : 'ID只能由数字、26个英文字母或者下划线组成';
  151. },
  152. });
  153. const schema: ISchema = {
  154. type: 'object',
  155. properties: {
  156. layout: {
  157. type: 'void',
  158. 'x-component': 'FormGrid',
  159. 'x-component-props': {
  160. maxColumns: 1,
  161. minColumns: 1,
  162. },
  163. properties: {
  164. id: {
  165. title: 'ID',
  166. 'x-component': 'Input',
  167. 'x-decorator': 'FormItem',
  168. 'x-decorator-props': {
  169. gridSpan: 1,
  170. },
  171. 'x-validator': [
  172. {
  173. required: true,
  174. message: '请输入ID',
  175. },
  176. {
  177. max: 64,
  178. message: '最多可输入64个字符',
  179. },
  180. {
  181. validateId: true,
  182. message: 'ID只能由数字、26个英文字母或者下划线组成',
  183. },
  184. {
  185. triggerType: 'onBlur',
  186. validator: (value: string) => {
  187. if (!value) return;
  188. return new Promise((resolve) => {
  189. service
  190. .validator(value)
  191. .then((resp) => {
  192. if (!!resp?.result) {
  193. resolve('ID已存在');
  194. } else {
  195. resolve('');
  196. }
  197. })
  198. .catch(() => '验证失败!');
  199. });
  200. },
  201. },
  202. ],
  203. },
  204. name: {
  205. title: '名称',
  206. 'x-component': 'Input',
  207. 'x-decorator': 'FormItem',
  208. 'x-decorator-props': {
  209. gridSpan: 1,
  210. },
  211. 'x-validator': [
  212. {
  213. required: true,
  214. message: '请输入名称',
  215. },
  216. {
  217. max: 64,
  218. message: '最多可输入64个字符',
  219. },
  220. ],
  221. },
  222. type: {
  223. title: '类型',
  224. 'x-component': 'Select',
  225. 'x-decorator': 'FormItem',
  226. 'x-decorator-props': {
  227. tooltip: <div>jar:上传协议jar包,文件格式支持.jar或.zip</div>,
  228. },
  229. 'x-validator': [
  230. {
  231. required: true,
  232. message: '请选择类型',
  233. },
  234. ],
  235. enum: [
  236. { label: 'jar', value: 'jar' },
  237. { label: 'local', value: 'local' },
  238. // { label: 'script', value: 'script' },
  239. ],
  240. },
  241. configuration: {
  242. type: 'object',
  243. properties: {
  244. location: {
  245. title: '文件地址',
  246. 'x-decorator': 'FormItem',
  247. 'x-visible': false,
  248. 'x-decorator-props': {
  249. tooltip: (
  250. <div>
  251. local:填写本地协议编译目录绝对地址,如:d:/workspace/protocol/target/classes
  252. </div>
  253. ),
  254. },
  255. 'x-validator': [
  256. {
  257. required: true,
  258. message: '请输入文件地址',
  259. },
  260. ],
  261. 'x-reactions': {
  262. dependencies: ['..type'],
  263. fulfill: {
  264. state: {
  265. visible: '{{["jar","local"].includes($deps[0])}}',
  266. componentType: '{{$deps[0]==="jar"?"FileUpload":"Input"}}',
  267. componentProps: '{{$deps[0]==="jar"?{type:"file", accept: ".jar, .zip"}:{}}}',
  268. },
  269. },
  270. },
  271. },
  272. // provider: {
  273. // title: '类名',
  274. // 'x-component': 'Input',
  275. // 'x-decorator': 'FormItem',
  276. // 'x-visible': false,
  277. // 'x-validator': [
  278. // {
  279. // required: true,
  280. // message: '请选择类名',
  281. // },
  282. // ],
  283. // 'x-reactions': {
  284. // dependencies: ['..type'],
  285. // fulfill: {
  286. // state: {
  287. // visible: '{{["jar","local"].includes($deps[0])}}',
  288. // },
  289. // },
  290. // },
  291. // },
  292. },
  293. },
  294. description: {
  295. title: '说明',
  296. 'x-component': 'Input.TextArea',
  297. 'x-decorator': 'FormItem',
  298. 'x-component-props': {
  299. rows: 3,
  300. showCount: true,
  301. maxLength: 200,
  302. },
  303. },
  304. },
  305. },
  306. },
  307. };
  308. const location = useLocation();
  309. useEffect(() => {
  310. if ((location as any).query?.save === 'true') {
  311. CurdModel.add();
  312. }
  313. const subscription = Store.subscribe(SystemConst.BASE_UPDATE_DATA, (data) => {
  314. if ((window as any).onTabSaveSuccess) {
  315. (window as any).onTabSaveSuccess(data);
  316. setTimeout(() => window.close(), 300);
  317. }
  318. });
  319. return () => subscription.unsubscribe();
  320. }, []);
  321. return (
  322. <PageContainer>
  323. <BaseCrud
  324. columns={columns}
  325. service={service}
  326. title={'插件管理'}
  327. search={false}
  328. modelConfig={{ width: '550px' }}
  329. schema={schema}
  330. actionRef={actionRef}
  331. formEffect={() => {
  332. onFormValuesChange((form) => {
  333. form.setFieldState('id', (state) => {
  334. state.disabled = CurdModel.model === 'edit';
  335. });
  336. });
  337. }}
  338. footer={
  339. <>
  340. <Button onClick={CurdModel.close}>取消</Button>
  341. <Button
  342. type="primary"
  343. onClick={() => {
  344. Store.set('save-data', true);
  345. }}
  346. >
  347. 保存
  348. </Button>
  349. <Button
  350. type="primary"
  351. onClick={() => {
  352. Store.set('save-data', async (data: any) => {
  353. // 获取到的保存的数据
  354. if (data.id) {
  355. await modifyState(data.id, 'deploy');
  356. }
  357. });
  358. }}
  359. >
  360. 保存并发布
  361. </Button>
  362. </>
  363. }
  364. />
  365. {/* {visible && <Debug data={current} close={() => setVisible(!visible)} />} */}
  366. </PageContainer>
  367. );
  368. };
  369. export default Protocol;