You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@inlong.apache.org by do...@apache.org on 2021/07/13 04:38:22 UTC

[incubator-inlong] 02/10: feat(issue): issue completed

This is an automated email from the ASF dual-hosted git repository.

dockerzhang pushed a commit to branch new-web-client
in repository https://gitbox.apache.org/repos/asf/incubator-inlong.git

commit 84931199b839fa9a9e26190f02932e5a3c1e4abf
Author: zakwu <12...@qq.com>
AuthorDate: Tue Jun 16 18:14:07 2020 +0800

    feat(issue): issue completed
---
 web/package-lock.json                      | 26 ++++----
 web/package.json                           |  4 +-
 web/src/components/Breadcrumb/index.tsx    | 11 +++-
 web/src/components/Layout/index.less       | 10 ++++
 web/src/configs/menus/index.tsx            |  7 +++
 web/src/hooks/index.ts                     | 38 +++++++++++-
 web/src/pages/Issue/consumeGroupDetail.tsx | 95 ++++++++++++++++++++++++++++++
 web/src/pages/Issue/index.less             |  2 -
 web/src/pages/Issue/index.tsx              | 90 ++++++++++++++++++++++++++--
 web/src/router.tsx                         | 12 +++-
 web/src/routes/index.tsx                   |  5 +-
 web/src/setupProxy.js                      |  5 +-
 12 files changed, 282 insertions(+), 23 deletions(-)

diff --git a/web/package-lock.json b/web/package-lock.json
index 8eba5d6..9ee94d4 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -2812,8 +2812,8 @@
     },
     "@umijs/use-request": {
       "version": "1.4.3",
-      "resolved": "https://registry.npmjs.org/@umijs/use-request/-/use-request-1.4.3.tgz",
-      "integrity": "sha512-aH4GCdRnMCaaciygdN0KtCDQdBBh1KyiNUAgYDPX8Y4brmbymEpJViX1FU4isOTbV34WlbkWTiBpR9HIi2ciNQ==",
+      "resolved": "http://r.tnpm.oa.com/@umijs/use-request/download/@umijs/use-request-1.4.3.tgz",
+      "integrity": "sha1-vF+txMsH15brNfCYONahXLEoAvc=",
       "requires": {
         "lodash.debounce": "^4.0.8",
         "lodash.throttle": "^4.1.1",
@@ -6548,7 +6548,7 @@
     },
     "encoding": {
       "version": "0.1.12",
-      "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
+      "resolved": "http://r.tnpm.oa.com/encoding/download/encoding-0.1.12.tgz",
       "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
       "requires": {
         "iconv-lite": "~0.4.13"
@@ -9795,7 +9795,7 @@
     },
     "isomorphic-fetch": {
       "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
+      "resolved": "http://r.tnpm.oa.com/isomorphic-fetch/download/isomorphic-fetch-2.2.1.tgz",
       "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
       "requires": {
         "node-fetch": "^1.0.1",
@@ -11172,7 +11172,7 @@
     },
     "lodash.debounce": {
       "version": "4.0.8",
-      "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+      "resolved": "http://r.tnpm.oa.com/lodash.debounce/download/lodash.debounce-4.0.8.tgz",
       "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
     },
     "lodash.flow": {
@@ -11225,7 +11225,7 @@
     },
     "lodash.throttle": {
       "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
+      "resolved": "http://r.tnpm.oa.com/lodash.throttle/download/lodash.throttle-4.1.1.tgz",
       "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
     },
     "lodash.uniq": {
@@ -12259,8 +12259,8 @@
     },
     "node-fetch": {
       "version": "1.7.3",
-      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
-      "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
+      "resolved": "http://r.tnpm.oa.com/node-fetch/download/node-fetch-1.7.3.tgz",
+      "integrity": "sha1-mA9vcthSEaU0fGsrwYxbhMPrR+8=",
       "requires": {
         "encoding": "^0.1.11",
         "is-stream": "^1.0.1"
@@ -18628,8 +18628,8 @@
     },
     "umi-request": {
       "version": "1.3.3",
-      "resolved": "https://registry.npmjs.org/umi-request/-/umi-request-1.3.3.tgz",
-      "integrity": "sha512-TRf5x11OJ/9VBi2ZzCJGg/ZFs6KXxpZg1hV0/9oYa9d4YZtQ62Gk6djbonYoMFkyw7fMcxRh8ayPe4YG/gCNeg==",
+      "resolved": "http://r.tnpm.oa.com/umi-request/download/umi-request-1.3.3.tgz",
+      "integrity": "sha1-nwU6O798jol2XKjjwBGPHLhIHxE=",
       "requires": {
         "isomorphic-fetch": "^2.2.1",
         "qs": "^6.9.1"
@@ -18940,6 +18940,12 @@
       "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
       "dev": true
     },
+    "use-immer": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/use-immer/-/use-immer-0.4.0.tgz",
+      "integrity": "sha512-mxx4jbRRc1/56geSc3VHx8gg3FvlzUpQPfVNJXtU1NRK/iTdK0pV3k3YPi7iFUcCM8YJ6/0dUBENyuk3WO/gxw==",
+      "dev": true
+    },
     "use-json-comparison": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/use-json-comparison/-/use-json-comparison-1.0.5.tgz",
diff --git a/web/package.json b/web/package.json
index 688553c..5b8fefc 100644
--- a/web/package.json
+++ b/web/package.json
@@ -8,6 +8,7 @@
     "@reactseed/use-redux": "^0.0.3",
     "@reactseed/use-request": "^0.0.2",
     "@types/lodash": "^4.14.155",
+    "@umijs/use-request": "^1.4.3",
     "antd": "^4.2.2",
     "immer": "^6.0.9",
     "lodash": "^4.17.15",
@@ -103,6 +104,7 @@
     "stylelint": "^13.3.3",
     "stylelint-config-prettier": "^8.0.1",
     "stylelint-config-standard": "^20.0.0",
-    "typescript": "~3.8.3"
+    "typescript": "~3.8.3",
+    "use-immer": "^0.4.0"
   }
 }
diff --git a/web/src/components/Breadcrumb/index.tsx b/web/src/components/Breadcrumb/index.tsx
index 3aee452..4d41369 100644
--- a/web/src/components/Breadcrumb/index.tsx
+++ b/web/src/components/Breadcrumb/index.tsx
@@ -7,11 +7,12 @@ import { Breadcrumb } from 'antd';
 
 export interface BreadcrumbProps {
   breadcrumbMap?: Map<string, import('@umijs/route-utils').MenuDataItem>;
+  appendParams?: string;
 }
 
 const BasicLayout: React.FC<BreadcrumbProps> = props => {
   const location = useLocation();
-  const { breadcrumbMap } = props;
+  const { breadcrumbMap, appendParams } = props;
 
   const pathSnippets = location.pathname.split('/').filter(i => i);
   const breadcrumbItems = pathSnippets.map((_, index) => {
@@ -21,6 +22,14 @@ const BasicLayout: React.FC<BreadcrumbProps> = props => {
         breadcrumbNameMap[t.pro_layout_parentKeys.join('/') + t.key] = t.name;
       });
     const url = `/${pathSnippets.slice(0, index + 1).join('/')}`;
+    if (appendParams && index === pathSnippets.length - 1) {
+      return (
+        <Breadcrumb.Item key={url}>
+          <Link to={url}>{appendParams}</Link>
+        </Breadcrumb.Item>
+      );
+    }
+
     return (
       <Breadcrumb.Item key={url}>
         <Link to={url}>{breadcrumbNameMap[url]}</Link>
diff --git a/web/src/components/Layout/index.less b/web/src/components/Layout/index.less
index ef8b6fd..9811a7d 100644
--- a/web/src/components/Layout/index.less
+++ b/web/src/components/Layout/index.less
@@ -9,3 +9,13 @@
 .header-span {
   float: left;
 }
+
+// global css
+.main-container {
+  background: #fff;
+  padding: 20px;
+}
+
+.search-wrapper {
+  margin-bottom: 20px;
+}
\ No newline at end of file
diff --git a/web/src/configs/menus/index.tsx b/web/src/configs/menus/index.tsx
index 9899708..140f583 100644
--- a/web/src/configs/menus/index.tsx
+++ b/web/src/configs/menus/index.tsx
@@ -16,6 +16,13 @@ const menus: Route[] = [
     path: '/issue',
     name: '分发查询',
     icon: <NodeExpandOutlined />,
+    hideChildrenInMenu: true,
+    children: [
+      {
+        path: '/:id',
+        name: '消费组详情',
+      },
+    ],
   },
   {
     name: '配置管理',
diff --git a/web/src/hooks/index.ts b/web/src/hooks/index.ts
index d6bb0cd..6ce8168 100644
--- a/web/src/hooks/index.ts
+++ b/web/src/hooks/index.ts
@@ -1,5 +1,41 @@
 import { useHistory, useLocation } from 'react-router-dom';
-import useRequest from '@reactseed/use-request';
+import useRequest, { axios } from '@reactseed/use-request';
 import useRedux from '@reactseed/use-redux';
+import { message } from 'antd';
 
+interface DataProps {
+  data: any;
+  errorCode: number;
+  errMsg: number;
+  result: boolean;
+}
+// handler for old type interface
+axios.interceptors.request.use(
+  config => {
+    const urlArr = (config.url as any).split('/');
+    config.url = '/webapi.htm';
+    config.params = config.params || {};
+    config.params['type'] = urlArr[2];
+    config.params['method'] = urlArr[3];
+
+    return config;
+  },
+  function(error) {
+    return Promise.reject(error);
+  }
+);
+
+axios.interceptors.response.use(
+  ({ data }) => {
+    if (data.errCode !== 0) {
+      message.error(data.errMsg);
+      return Promise.reject(data);
+    }
+
+    return data || [];
+  },
+  function(error) {
+    return Promise.reject(error);
+  }
+);
 export { useHistory, useLocation, useRequest, useRedux };
diff --git a/web/src/pages/Issue/consumeGroupDetail.tsx b/web/src/pages/Issue/consumeGroupDetail.tsx
new file mode 100644
index 0000000..9e54f42
--- /dev/null
+++ b/web/src/pages/Issue/consumeGroupDetail.tsx
@@ -0,0 +1,95 @@
+import React, { useContext } from 'react';
+import GlobalContext from '@/context/globalContext';
+import Breadcrumb from '@/components/Breadcrumb';
+import Table from '@/components/Tablex';
+import { Form, Input, Button, Spin } from 'antd';
+import { useImmer } from 'use-immer';
+import './index.less';
+import { useRequest } from '@/hooks';
+import { useParams } from 'react-router-dom';
+
+declare type ConsumeGroupData = any[];
+interface ConsumeGroupQueryData {
+  consumeGroup: string;
+}
+
+// column config
+const columns = [
+  {
+    title: '消费者ID',
+    dataIndex: 'consumerId',
+  },
+  {
+    title: '消费Topic',
+    dataIndex: 'topicName',
+  },
+  {
+    title: 'broker地址',
+    dataIndex: 'brokerAddr',
+  },
+  {
+    title: '分区ID',
+    dataIndex: 'partId',
+  },
+];
+
+const queryUser = (data: ConsumeGroupQueryData) => ({
+  url: '/api/op_query/admin_query_consume_group_detail',
+  data: data,
+});
+
+const ConsumeGroupDetail: React.FC = () => {
+  const { id } = useParams();
+  const { breadMap } = useContext(GlobalContext);
+  const [form] = Form.useForm();
+  const [formValues, updateFormValues] = useImmer<any>({});
+  const { data, loading, run } = useRequest<any, ConsumeGroupData>(
+    () =>
+      queryUser({
+        consumeGroup: id,
+      }),
+    {
+      formatResult: data => {
+        const d = data[0];
+        return {
+          list: d.parInfo.map((t: any) => ({
+            consumerId: d.consumerId,
+            ...t,
+          })),
+        };
+      },
+    }
+  );
+
+  const onValuesChange = (p: any) => {
+    updateFormValues(d => {
+      Object.assign(d, p);
+    });
+  };
+  const onSearch = () => {
+    run(formValues);
+  };
+
+  const onReset = () => {
+    form.resetFields();
+    run({});
+  };
+
+  return (
+    <Spin spinning={loading}>
+      <Breadcrumb
+        breadcrumbMap={breadMap}
+        appendParams={`消费组详情(${id})`}
+      ></Breadcrumb>
+      <div className="main-container">
+        <Table
+          columns={columns}
+          dataSource={data?.list}
+          rowKey="brokerAddr"
+        ></Table>
+      </div>
+    </Spin>
+  );
+};
+
+export default ConsumeGroupDetail;
diff --git a/web/src/pages/Issue/index.less b/web/src/pages/Issue/index.less
index c15c7a7..e69de29 100644
--- a/web/src/pages/Issue/index.less
+++ b/web/src/pages/Issue/index.less
@@ -1,2 +0,0 @@
-.home__container {
-}
diff --git a/web/src/pages/Issue/index.tsx b/web/src/pages/Issue/index.tsx
index 3128c5e..bfedf64 100644
--- a/web/src/pages/Issue/index.tsx
+++ b/web/src/pages/Issue/index.tsx
@@ -1,15 +1,97 @@
 import React, { useContext } from 'react';
-import './index.less';
 import GlobalContext from '@/context/globalContext';
 import Breadcrumb from '@/components/Breadcrumb';
+import Table from '@/components/Tablex';
+import { Form, Input, Button, Spin } from 'antd';
+import { useImmer } from 'use-immer';
+import './index.less';
+import { useRequest } from '@/hooks';
+import { Link } from 'react-router-dom';
+
+declare type IssueData = any[];
+interface IssueQueryData {
+  topicName?: string;
+  consumeGroup?: string;
+}
+
+// column config
+const columns = [
+  {
+    title: '消费组',
+    dataIndex: 'consumeGroup',
+    render: (t: Array<any>) => <Link to={'/issue/' + t}>{t}</Link>,
+  },
+  {
+    title: '消费Topic',
+    dataIndex: 'topicSet',
+    render: (t: Array<any>) => {
+      return t.join(',');
+    },
+  },
+  {
+    title: '消费分区',
+    dataIndex: 'consumerNum',
+  },
+];
+
+const queryUser = (data: IssueQueryData) => ({
+  url: '/api/op_query/admin_query_sub_info',
+  data: data,
+});
 
 const Issue: React.FC = () => {
   const { breadMap } = useContext(GlobalContext);
+  const [form] = Form.useForm();
+  const [formValues, updateFormValues] = useImmer<any>({});
+  const { data, loading, run } = useRequest<any, IssueData>(queryUser, {});
+
+  const onValuesChange = (p: any) => {
+    updateFormValues(d => {
+      Object.assign(d, p);
+    });
+  };
+  const onSearch = () => {
+    run(formValues);
+  };
+
+  const onReset = () => {
+    form.resetFields();
+    run({});
+  };
+
   return (
-    <div className="home__container">
+    <Spin spinning={loading}>
       <Breadcrumb breadcrumbMap={breadMap}></Breadcrumb>
-      <div>我打野的</div>
-    </div>
+      <div className="main-container">
+        <div className="search-wrapper">
+          <Form form={form} layout={'inline'} onValuesChange={onValuesChange}>
+            <Form.Item label="Topic 名称" name="topicName">
+              <Input placeholder="" />
+            </Form.Item>
+            <Form.Item label="消费组" name="consumeGroup">
+              <Input placeholder="" />
+            </Form.Item>
+            <Form.Item>
+              <Button
+                type="primary"
+                onClick={onSearch}
+                style={{ margin: '0 20px' }}
+              >
+                查询
+              </Button>
+              <Button type="default" onClick={onReset}>
+                重置
+              </Button>
+            </Form.Item>
+          </Form>
+        </div>
+        <Table
+          columns={columns}
+          dataSource={data}
+          rowKey="consumeGroup"
+        ></Table>
+      </div>
+    </Spin>
   );
 };
 
diff --git a/web/src/router.tsx b/web/src/router.tsx
index eaf2a50..1b6a6e9 100644
--- a/web/src/router.tsx
+++ b/web/src/router.tsx
@@ -1,5 +1,10 @@
 import React, { Suspense, lazy, useState } from 'react';
-import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
+import {
+  BrowserRouter as Router,
+  Switch,
+  Route,
+  Redirect,
+} from 'react-router-dom';
 import { PageLoading } from '@ant-design/pro-layout';
 import { hot } from 'react-hot-loader/root';
 import { Layout } from '@/components';
@@ -31,6 +36,11 @@ const App = () => {
                 />
               ))}
             </Switch>
+            <Route
+              exact
+              path="/"
+              render={() => <Redirect to="/issue" push />}
+            />
           </Suspense>
         </Layout>
       </Router>
diff --git a/web/src/routes/index.tsx b/web/src/routes/index.tsx
index 00a7ce0..032a633 100644
--- a/web/src/routes/index.tsx
+++ b/web/src/routes/index.tsx
@@ -2,9 +2,12 @@ import { RouteProps } from '@/typings';
 
 const routes: RouteProps[] = [
   {
+    path: '/issue/:id',
+    component: () => import('@/pages/Issue/consumeGroupDetail'),
+  },
+  {
     path: '/issue',
     component: () => import('@/pages/Issue'),
-    exact: true,
   },
   {
     path: '/hello',
diff --git a/web/src/setupProxy.js b/web/src/setupProxy.js
index a60f2c8..3496dd6 100644
--- a/web/src/setupProxy.js
+++ b/web/src/setupProxy.js
@@ -3,8 +3,9 @@ const { createProxyMiddleware } = require('http-proxy-middleware');
 
 module.exports = function(app) {
   app.use(
-    createProxyMiddleware('/api', {
-      target: 'https://api.github.com',
+    createProxyMiddleware('/webapi.htm', {
+      // target: 'http://10.224.148.145:8080',
+      target: 'http://10.215.131.92:8080',
       changeOrigin: true,
       ws: true,
     })