Jelajahi Sumber

feat: 物联卡

wzyyy 3 tahun lalu
induk
melakukan
f5b10b996d

+ 4 - 4
config/proxy.ts

@@ -9,16 +9,16 @@
 export default {
   dev: {
     '/api': {
-      // target: 'http://192.168.32.28:8844/',
-      // ws: 'ws://192.168.32.28:8844/',
+      target: 'http://192.168.32.28:8844/',
+      ws: 'ws://192.168.32.28:8844/',
       // 开发环境
       // target: 'http://120.79.18.123:8844/',
       // ws: 'ws://120.79.18.123:8844/',
       // 测试环境
       // target: 'http://120.77.179.54:8844/',
       // ws: 'ws://120.77.179.54:8844/',
-      target: 'http://192.168.32.65:8844/',
-      ws: 'ws://192.168.32.65:8844/',
+      // target: 'http://192.168.32.65:8844/',
+      // ws: 'ws://192.168.32.65:8844/',
       //v2环境
       // ws: 'ws://47.109.52.230:8844',
       // target: 'http://47.109.52.230:8844',

+ 60 - 0
src/pages/home/components/CardStatics.tsx

@@ -0,0 +1,60 @@
+import Title from '@/pages/home/components/Title';
+import React from 'react';
+import './index.less';
+
+type StatisticsItem = {
+  name: string;
+  value: number | string;
+  children: React.ReactNode | string;
+  permission?: any;
+  node?: any;
+};
+
+interface StatisticsProps {
+  extra?: React.ReactNode | string;
+  style?: any;
+  height?: any;
+  data: StatisticsItem[];
+  title: string;
+}
+
+const defaultImage = require('/public/images/home/top-1.png');
+
+const CardStatistics = (props: StatisticsProps) => {
+  return (
+    <div className={'home-statistics'} style={{ height: props.height }}>
+      <Title title={props.title} extra={props.extra} />
+      <div className={'home-statistics-body'} style={props.style}>
+        {props.data.map((item) => (
+          <div className={'home-guide-item'} key={item.name}>
+            <div className={'item-english'}>{item.name}</div>
+            {item.node ? (
+              <div style={{ display: 'flex', marginTop: 15, width: '60%' }}>
+                {item.node.map((i: any) => (
+                  <div style={{ marginRight: 7 }}>
+                    <div style={{ fontSize: '14px', fontWeight: 'bold' }}>{i.value}</div>
+                    <div className={`state ${i.className}`}>{i.name}</div>
+                  </div>
+                ))}
+              </div>
+            ) : (
+              <div className={'item-title'}>{item.permission ? item.permission : item.value}</div>
+            )}
+
+            {typeof item.children === 'string' ? (
+              <div className={`item-index`}>
+                <img src={item.children || defaultImage} />
+              </div>
+            ) : (
+              <div className={'item-index-echarts'} style={{ height: 75, width: 110 }}>
+                {item.children}
+              </div>
+            )}
+          </div>
+        ))}
+      </div>
+    </div>
+  );
+};
+
+export default CardStatistics;

+ 23 - 0
src/pages/home/components/index.less

@@ -26,6 +26,29 @@
   background: linear-gradient(135.62deg, #f6f7fd 22.27%, rgba(255, 255, 255, 0.86) 91.82%);
   border-radius: 2px;
   box-shadow: 0 4px 18px #efefef;
+  .state {
+    position: relative;
+    padding-left: 8px;
+    &::before {
+      position: absolute;
+      top: 7px;
+      left: 0;
+      display: inline-block;
+      width: 6px;
+      height: 6px;
+      margin-right: 2px;
+      content: '';
+    }
+    &.normal::before {
+      background: #85a5ff;
+    }
+    &.notActive::before {
+      background: #f29b55;
+    }
+    &.stopped::before {
+      background: #c4c4c4;
+    }
+  }
 
   &.pointer {
     cursor: pointer;

+ 217 - 3
src/pages/iot-card/Home/index.tsx

@@ -1,4 +1,218 @@
-const Home = () => {
-  return <>首页</>;
+import { PageContainer } from '@ant-design/pro-layout';
+import { Col, message, Row } from 'antd';
+import { PermissionButton } from '@/components';
+import { getMenuPathByCode } from '@/utils/menu';
+import useHistory from '@/hooks/route/useHistory';
+import { useEffect, useRef, useState } from 'react';
+import { Body, Guide } from '@/pages/home/components';
+import CardStatistics from '@/pages/home/components/CardStatics';
+import Echarts from '@/components/DashBoard/echarts';
+import { EChartsOption } from 'echarts';
+import moment from 'moment';
+import Service from './service';
+
+export const service = new Service('');
+
+export default () => {
+  const dashBoardUrl = getMenuPathByCode('iot-card/Dashboard');
+  const platformUrl = getMenuPathByCode('iot-card/Platform/Detail');
+  const recordUrl = getMenuPathByCode('iot-card/Record');
+  const cardUrl = getMenuPathByCode('iot-card/CardManagement');
+
+  const [options, setOptions] = useState<EChartsOption>({});
+  const [cardOptions, setCardOptions] = useState<EChartsOption>({});
+  const currentSource = useRef(0);
+  const pieChartData = useRef([
+    {
+      key: 'using',
+      name: '正常',
+      value: 0,
+      className: 'normal',
+    },
+    {
+      key: 'toBeActivated',
+      name: '未激活',
+      value: 0,
+      className: 'notActive',
+    },
+    {
+      key: 'deactivate',
+      name: '停用',
+      value: 0,
+      className: 'stopped',
+    },
+  ]);
+
+  const { permission: paltformPermission } = PermissionButton.usePermission('iot-card/Platform');
+
+  const history = useHistory();
+
+  //昨日流量
+  const getTodayFlow = async () => {
+    const beginTime = moment().subtract(1, 'days').startOf('day').valueOf();
+    const endTime = moment().subtract(1, 'days').endOf('day').valueOf();
+    const res = await service.queryFlow(beginTime, endTime, { orderBy: 'date' });
+    if (res.status === 200) {
+      res.result.map((item: any) => {
+        currentSource.current += parseFloat(item.value.toFixed(2));
+      });
+    }
+  };
+
+  //15天流量
+  const get15DaysTrafficConsumption = async () => {
+    const beginTime = moment().subtract(15, 'days').startOf('day').valueOf();
+    const endTime = moment().subtract(1, 'days').endOf('day').valueOf();
+    const resp = await service.queryFlow(beginTime, endTime, { orderBy: 'date' });
+    if (resp.status === 200) {
+      setOptions({
+        tooltip: {},
+        xAxis: {
+          show: false,
+          data: resp.result.map((item: any) => item.date).reverse(),
+        },
+        yAxis: {
+          show: false,
+        },
+        series: [
+          {
+            name: '流量消耗',
+            type: 'bar',
+            color: '#FACD89',
+            // barWidth: '5%', // 设单柱状置宽度
+            showBackground: true, //设置柱状的背景虚拟
+            data: resp.result.map((m: any) => parseFloat(m.value.toFixed(2))).reverse(),
+          },
+        ],
+      });
+    }
+  };
+  //获取物联卡状态数据
+  const getStateCard = async () => {
+    Promise.all(
+      pieChartData.current.map((item) => {
+        const params = {
+          terms: [
+            {
+              terms: [
+                {
+                  column: 'cardStateType',
+                  termType: 'eq',
+                  value: item.key,
+                },
+              ],
+            },
+          ],
+        };
+        return service.list(params);
+      }),
+    ).then((res) => {
+      res.forEach((item, index) => {
+        if (item && item.status === 200) {
+          pieChartData.current[index].value = item.result.total;
+        }
+      });
+      setCardOptions({
+        tooltip: {
+          trigger: 'item',
+          formatter: '{b}: {c} ({d}%)',
+        },
+        color: ['#85a5ff', '#f29b55', '#c4c4c4'],
+        series: [
+          {
+            name: '',
+            type: 'pie',
+            avoidLabelOverlap: true, //是否启用防止标签重叠策略
+            radius: ['50%', '90%'],
+            center: ['50%', '50%'],
+            itemStyle: {
+              borderColor: 'rgba(255,255,255,1)',
+              borderWidth: 2,
+            },
+            label: {
+              show: false,
+            },
+            data: pieChartData.current,
+          },
+        ],
+      });
+    });
+  };
+
+  const guideList = [
+    {
+      key: 'EQUIPMENT',
+      name: '平台对接',
+      english: 'STEP1',
+      auth: !!paltformPermission.update,
+      url: platformUrl,
+    },
+    {
+      key: 'SCREEN',
+      name: '物联卡管理',
+      english: 'STEP2',
+      auth: !!cardUrl,
+      url: cardUrl,
+      param: { save: true },
+    },
+    {
+      key: 'CASCADE',
+      name: '操作记录',
+      english: 'STEP3',
+      auth: !!recordUrl,
+      url: recordUrl,
+    },
+  ];
+
+  useEffect(() => {
+    getTodayFlow();
+    get15DaysTrafficConsumption();
+    getStateCard();
+  }, []);
+
+  return (
+    <PageContainer>
+      <Row gutter={24}>
+        <Col span={14}>
+          <Guide title={'物联卡引导'} data={guideList} />
+        </Col>
+        <Col span={10}>
+          <CardStatistics
+            title={'基础统计'}
+            data={[
+              {
+                name: '昨日流量统计',
+                value: `${currentSource.current}M`,
+                children: <Echarts options={options} />,
+              },
+              {
+                name: '物联卡',
+                value: 0,
+                node: pieChartData.current,
+                children: <Echarts options={cardOptions} />,
+              },
+            ]}
+            extra={
+              <div style={{ fontSize: 14, fontWeight: 400 }}>
+                <a
+                  onClick={() => {
+                    if (!!dashBoardUrl) {
+                      history.push(`${dashBoardUrl}`);
+                    } else {
+                      message.warning('暂无权限,请联系管理员');
+                    }
+                  }}
+                >
+                  详情
+                </a>
+              </div>
+            }
+          />
+        </Col>
+        <Col span={24}>
+          <Body title={'平台架构图'} english={'PLATFORM ARCHITECTURE DIAGRAM'} />
+        </Col>
+      </Row>
+    </PageContainer>
+  );
 };
-export default Home;

+ 21 - 0
src/pages/iot-card/Home/service.ts

@@ -0,0 +1,21 @@
+import { request } from 'umi';
+import SystemConst from '@/utils/const';
+import BaseService from '@/utils/BaseService';
+
+class Service extends BaseService<any> {
+  queryFlow = (beginTime: any, endTime: any, data: any) =>
+    request(`${SystemConst.API_BASE}/network/flow/_query/${beginTime}/${endTime}`, {
+      method: 'POST',
+      data,
+    });
+  queryState = (status: any) =>
+    request(`${SystemConst.API_BASE}/network/card/${status}/state/_count`, {
+      method: 'GET',
+    });
+  list = (data: any) =>
+    request(`${SystemConst.API_BASE}/network/card/_query`, {
+      method: 'POST',
+      data,
+    });
+}
+export default Service;

+ 259 - 11
src/pages/iot-card/Platform/Detail/index.tsx

@@ -1,19 +1,20 @@
 import { RadioCard, TitleComponent } from '@/components';
 import { PageContainer } from '@ant-design/pro-layout';
 import { Form, FormButtonGroup, FormGrid, FormItem, Input } from '@formily/antd';
-import { createForm, onFormInit } from '@formily/core';
+import { createForm, Field, onFieldReact, onFormInit } from '@formily/core';
 import { createSchemaField, observer } from '@formily/react';
 import { Button, Card, Col, Row } from 'antd';
-import { useEffect, useMemo } from 'react';
+import { useEffect, useMemo, useState } from 'react';
 import { useParams } from 'umi';
-import { useAsyncDataSource } from '@/utils/util';
-// import './index.less';
-import { service } from '@/pages/Northbound/AliCloud';
+import { onlyMessage, useAsyncDataSource } from '@/utils/util';
+import { service } from '../index';
 import { useModel } from '@@/plugin-model/useModel';
+import Doc from '../doc';
 
 const Detail = observer(() => {
   const params = useParams<{ id: string }>();
   const { initialState } = useModel('@@initialState');
+  const [docType, setDocType] = useState('');
 
   const form = useMemo(
     () =>
@@ -23,7 +24,14 @@ const Detail = observer(() => {
           onFormInit(async (form1) => {
             if (params.id === ':id') return;
             const resp = await service.detail(params.id);
-            form1.setInitialValues(resp.result);
+            if (resp.status === 200) {
+              form1.setValues(resp.result);
+            }
+          });
+          onFieldReact('operatorName', (field) => {
+            const value = (field as Field).value;
+            setDocType(value);
+            // console.log(value)
           });
         },
       }),
@@ -49,13 +57,13 @@ const Detail = observer(() => {
         'x-decorator-props': {
           gridSpan: 1,
         },
-        default: 'onelink',
+        default: params.id === ':id' ? 'onelink' : undefined,
         'x-component-props': {
           model: 'singular',
           itemStyle: {
             display: 'flex',
             flexDirection: 'column',
-            justifyContent: 'center',
+            justifyContent: 'space-around',
             minWidth: '130px',
           },
           options: [
@@ -106,7 +114,235 @@ const Detail = observer(() => {
           },
         ],
       },
-      description: {
+      onelink: {
+        type: 'void',
+        'x-reactions': {
+          dependencies: ['.operatorName'],
+          fulfill: {
+            state: {
+              visible: '{{$deps[0] ==="onelink"}}',
+            },
+          },
+        },
+        properties: {
+          config: {
+            type: 'object',
+            properties: {
+              appId: {
+                type: 'string',
+                title: 'App ID',
+                required: true,
+                'x-decorator': 'FormItem',
+                'x-component': 'Input',
+                'x-component-props': {
+                  placeholder: '请输入App ID',
+                },
+                'x-validator': [
+                  {
+                    max: 64,
+                    message: '最多可输入64个字符',
+                  },
+                  {
+                    required: true,
+                    message: '请输入App ID',
+                  },
+                ],
+              },
+              passWord: {
+                type: 'string',
+                title: 'Password',
+                required: true,
+                'x-decorator': 'FormItem',
+                'x-component': 'Input',
+                'x-component-props': {
+                  placeholder: '请输入Password',
+                },
+                'x-validator': [
+                  {
+                    max: 64,
+                    message: '最多可输入64个字符',
+                  },
+                  {
+                    required: true,
+                    message: '请输入App ID',
+                  },
+                ],
+              },
+              apiAddr: {
+                type: 'string',
+                title: '接口地址',
+                required: true,
+                'x-decorator': 'FormItem',
+                'x-component': 'Input',
+                'x-component-props': {
+                  placeholder: '请输入接口地址',
+                },
+                'x-validator': [
+                  {
+                    max: 64,
+                    message: '最多可输入64个字符',
+                  },
+                  {
+                    required: true,
+                    message: '请输入接口地址',
+                  },
+                ],
+              },
+            },
+          },
+        },
+      },
+      ctwing: {
+        type: 'void',
+        'x-reactions': {
+          dependencies: ['.operatorName'],
+          fulfill: {
+            state: {
+              visible: '{{$deps[0] ==="ctwing"}}',
+            },
+          },
+        },
+
+        properties: {
+          config: {
+            type: 'object',
+            properties: {
+              userId: {
+                type: 'string',
+                title: '用户id',
+                required: true,
+                'x-decorator': 'FormItem',
+                'x-component': 'Input',
+                'x-component-props': {
+                  placeholder: '请输入用户id',
+                },
+                'x-validator': [
+                  {
+                    max: 64,
+                    message: '最多可输入64个字符',
+                  },
+                  {
+                    required: true,
+                    message: '请输入用户id',
+                  },
+                ],
+              },
+              passWord: {
+                type: 'string',
+                title: 'Password',
+                required: true,
+                'x-decorator': 'FormItem',
+                'x-component': 'Input',
+                'x-component-props': {
+                  placeholder: '请输入Password',
+                },
+                'x-validator': [
+                  {
+                    required: true,
+                    message: '请输入Password',
+                  },
+                ],
+              },
+              secretKey: {
+                type: 'string',
+                title: 'secretKey',
+                required: true,
+                'x-decorator': 'FormItem',
+                'x-component': 'Input',
+                'x-component-props': {
+                  placeholder: '请输入secretKey',
+                },
+                'x-validator': [
+                  {
+                    max: 64,
+                    message: '最多可输入64个字符',
+                  },
+                  {
+                    required: true,
+                    message: '请输入secretKey',
+                  },
+                ],
+              },
+            },
+          },
+        },
+      },
+      unicom: {
+        type: 'void',
+        'x-reactions': {
+          dependencies: ['.operatorName'],
+          fulfill: {
+            state: {
+              visible: '{{$deps[0] ==="unicom"}}',
+            },
+          },
+        },
+
+        properties: {
+          config: {
+            type: 'object',
+            properties: {
+              appId: {
+                type: 'string',
+                title: 'App ID',
+                required: true,
+                'x-decorator': 'FormItem',
+                'x-component': 'Input',
+                'x-component-props': {
+                  placeholder: '请输入App ID',
+                },
+                'x-validator': [
+                  {
+                    max: 64,
+                    message: '最多可输入64个字符',
+                  },
+                  {
+                    required: true,
+                    message: '请输入App ID',
+                  },
+                ],
+              },
+              appSecret: {
+                type: 'string',
+                title: 'App Secret',
+                required: true,
+                'x-decorator': 'FormItem',
+                'x-component': 'Input',
+                'x-component-props': {
+                  placeholder: '请输入App Secret',
+                },
+                'x-validator': [
+                  {
+                    required: true,
+                    message: '请输入App Secret',
+                  },
+                ],
+              },
+              openId: {
+                type: 'string',
+                title: '创建者ID',
+                required: true,
+                'x-decorator': 'FormItem',
+                'x-component': 'Input',
+                'x-component-props': {
+                  placeholder: '请输入创建者ID',
+                },
+                'x-validator': [
+                  {
+                    max: 64,
+                    message: '最多可输入64个字符',
+                  },
+                  {
+                    required: true,
+                    message: '请输入创建者ID',
+                  },
+                ],
+              },
+            },
+          },
+        },
+      },
+      explain: {
         title: '说明',
         'x-component': 'Input.TextArea',
         'x-decorator': 'FormItem',
@@ -116,12 +352,22 @@ const Detail = observer(() => {
           maxLength: 200,
           placeholder: '请输入说明',
         },
+        'x-validator': [
+          {
+            max: 200,
+            message: '最多可输入200个字符',
+          },
+        ],
       },
     },
   };
 
   const handleSave = async () => {
     const data: any = await form.submit();
+    const res: any = params.id === ':id' ? await service.save(data) : await service.update(data);
+    if (res.status === 200) {
+      onlyMessage('保存成功');
+    }
     console.log(data);
   };
 
@@ -139,7 +385,7 @@ const Detail = observer(() => {
     <PageContainer>
       <Card>
         <Row gutter={24}>
-          <Col span={12}>
+          <Col span={14}>
             <TitleComponent data={'详情'} />
             <Form form={form} layout="vertical">
               <SchemaField
@@ -157,7 +403,9 @@ const Detail = observer(() => {
               </FormButtonGroup.Sticky>
             </Form>
           </Col>
-          <Col span={12} className="aliyun"></Col>
+          <Col span={10}>
+            <Doc type={docType} />
+          </Col>
         </Row>
       </Card>
     </PageContainer>

+ 35 - 0
src/pages/iot-card/Platform/doc/index.less

@@ -0,0 +1,35 @@
+.doc {
+  height: 1000px;
+  padding: 24px;
+  overflow-y: auto;
+  color: rgba(#000, 0.8);
+  font-size: 14px;
+  background-color: #fafafa;
+
+  .url {
+    padding: 8px 16px;
+    color: #2f54eb;
+    background-color: rgba(#a7bdf7, 0.2);
+  }
+
+  h1 {
+    margin: 16px 0;
+    color: rgba(#000, 0.85);
+    font-weight: bold;
+    font-size: 14px;
+
+    &:first-child {
+      margin-top: 0;
+    }
+  }
+
+  h2 {
+    margin: 6px 0;
+    color: rgba(0, 0, 0, 0.8);
+    font-size: 14px;
+  }
+
+  .image {
+    margin: 16px 0;
+  }
+}

+ 161 - 0
src/pages/iot-card/Platform/doc/index.tsx

@@ -0,0 +1,161 @@
+import './index.less';
+import { Image } from 'antd';
+interface Props {
+  type: 'onelink' | 'ctwing' | 'unicom' | any;
+}
+
+const Doc = (props: Props) => {
+  const { type } = props;
+
+  return (
+    <>
+      {type === 'onelink' && (
+        <div className="doc">
+          <div className="url">
+            中国移动物联卡能力开放平台:
+            <a
+              style={{ wordBreak: 'break-all' }}
+              href="https://api.iot.10086.cn/api/index.html#/login"
+              target={'_blank'}
+              rel="noreferrer"
+            >
+              https://api.iot.10086.cn/api/index.html#/login
+            </a>
+          </div>
+          <h1>1.概述</h1>
+          <p>平台对接通过API的方式与三方系统进行数据对接,为物联卡的管理提供数据交互支持。</p>
+          <h1>2.配置说明</h1>
+          <h2>1、APP ID</h2>
+          <p>
+            第三方应用唯一标识,中国移动物联网全网管理员在 OneLink
+            能力开放平台上分配并展示给集团客户。
+            <br />
+            获取路径:“中移物联卡能力开放平台”--“个人中心”--“客户信息”--“接入信息”
+          </p>
+          <div className={'image'}>
+            <Image width="100%" src={require('/public/images/iot-card/onelink-appid.png')} />
+          </div>
+          <h2>2、Password</h2>
+          <p>
+            API 接入秘钥,由中国移动物联网提供,集团客户从“OneLink 能力开放平台”获取。
+            <br />
+            获取路径:“中移物联卡能力开放平台”--“个人中心”--“客户信息”--“接入信息”
+          </p>
+          <div className={'image'}>
+            <Image width="100%" src={require('/public/images/iot-card/onelink-pass.png')} />
+          </div>
+          <h2>3、接口地址</h2>
+          <p>
+            https://api.iot.10086.cn/v5/ec/get/token
+            <br />
+            token后缀请根据实际情况填写
+            <br />
+            示例:https://api.iot.10086.cn/v5/authService?appid=xxx&password=xxx&transid=xxx
+          </p>
+        </div>
+      )}
+
+      {type === 'ctwing' && (
+        <div className="doc">
+          <div className="url">
+            5G连接管理平台:
+            <a
+              style={{ wordBreak: 'break-all' }}
+              href="https://cmp.ctwing.cn:4821/login"
+              target={'_blank'}
+              rel="noreferrer"
+            >
+              https://cmp.ctwing.cn:4821/login
+            </a>
+          </div>
+          <div>
+            <h1>1.概述</h1>
+            <p>平台对接通过API的方式与三方系统进行数据对接,为物联卡的管理提供数据交互支持。</p>
+            <h1>2.配置说明</h1>
+            <h2>1、用户 id</h2>
+            <p>
+              5G连接管理平台用户的唯一标识,用于身份识别。
+              <br />
+              获取路径:“5G连接管理平台”--“能力开放”--“API网关账号管理”
+            </p>
+            <div className={'image'}>
+              <Image width="100%" src={require('/public/images/iot-card/ctwing-id.png')} />
+            </div>
+
+            <h2>2、密码</h2>
+            <p>
+              用户id经加密之后的密码。
+              <br />
+              获取路径:“5G连接管理平台”--“能力开放”--“API网关账号管理”
+            </p>
+            <div className={'image'}>
+              <Image width="100%" src={require('/public/images/iot-card/ctwing-pass.png')} />
+            </div>
+
+            <h2>3、secretKey</h2>
+            <p>
+              APP secret唯一秘钥。
+              <br />
+              获取路径:“5G连接管理平台”--“能力开放”--“API网关账号管理”
+            </p>
+            <div className={'image'}>
+              <Image width="100%" src={require('/public/images/iot-card/ctwing-secret.png')} />
+            </div>
+          </div>
+        </div>
+      )}
+      {type === 'unicom' && (
+        <div className="doc">
+          <div className="url">
+            雁飞智连CMP平台:
+            <a
+              style={{ wordBreak: 'break-all' }}
+              href="  https://cmp.10646.cn/webframe/login"
+              target={'_blank'}
+              rel="noreferrer"
+            >
+              https://cmp.10646.cn/webframe/login
+            </a>
+          </div>
+
+          <div>
+            <h1>1.概述</h1>
+            <p>平台对接通过API的方式与三方系统进行数据对接,为物联卡的管理提供数据交互支持。</p>
+            <h1>2.配置说明</h1>
+            <h2>1、APP ID</h2>
+            <p>
+              第三方应用唯一标识。
+              <br />
+              获取路径:“雁飞智连CMP平台”--“我的应用”--“应用列表”
+            </p>
+            <div className={'image'}>
+              <Image width="100%" src={require('/public/images/iot-card/unicom-id.png')} />
+            </div>
+
+            <h2>2、App Secret</h2>
+            <p>
+              API 接入秘钥。
+              <br />
+              获取路径:“雁飞智连CMP平台”--“我的应用”--“应用列表”
+            </p>
+            <div className={'image'}>
+              <Image width="100%" src={require('/public/images/iot-card/unicom-secret.png')} />
+            </div>
+
+            <h2>3、创建者ID</h2>
+            <p>
+              接口参数中的 OpenId。
+              <br />
+              获取路径:“雁飞智连CMP平台”--“我的应用”--“应用列表”
+              <br />
+            </p>
+            <div className={'image'}>
+              <Image width="100%" src={require('/public/images/iot-card/unicom-openid.png')} />
+            </div>
+          </div>
+        </div>
+      )}
+    </>
+  );
+};
+export default Doc;

+ 6 - 3
src/pages/iot-card/Platform/index.tsx

@@ -17,7 +17,7 @@ import { useRef, useState } from 'react';
 import Service from './service';
 import { useHistory } from '@/hooks';
 
-export const service = new Service('network/card/platfrom');
+export const service = new Service('network/card/platform');
 
 const Platform = () => {
   const { minHeight } = useDomFullHeight(`.record`, 24);
@@ -95,7 +95,10 @@ const Platform = () => {
         <PermissionButton
           isPermission={true}
           key="edit"
-          onClick={() => {}}
+          onClick={() => {
+            const url = `${getMenuPathByParams(MENUS_CODE['iot-card/Platform/Detail'], record.id)}`;
+            history.push(url);
+          }}
           type={'link'}
           style={{ padding: 0 }}
           tooltip={{
@@ -138,7 +141,7 @@ const Platform = () => {
         <PermissionButton
           isPermission={true}
           tooltip={{
-            title: record.state.value !== 'enabled' ? '删除' : '请先禁用该协议,再删除',
+            title: record.state.value !== 'enabled' ? '删除' : '请先禁用再删除',
           }}
           style={{ padding: 0 }}
           disabled={record.state.value === 'enabled'}

+ 19 - 1
src/pages/iot-card/Recharge/index.tsx

@@ -31,6 +31,25 @@ const Recharge = () => {
       title: '支付方式',
       dataIndex: 'paymentType',
       ellipsis: true,
+      valueType: 'select',
+      valueEnum: {
+        ALIPAY_WAP: {
+          text: '支付宝手机网站支付',
+          status: 'ALIPAY_WAP',
+        },
+        ALIPAY_WEB: {
+          text: '支付宝网页及时到账支付',
+          status: 'ALIPAY_WEB',
+        },
+        WEIXIN_JSAPI: {
+          text: '微信公众号支付',
+          status: 'WEIXIN_JSAPI',
+        },
+        WEIXIN_NATIVE: {
+          text: '微信扫码支付',
+          status: 'WEIXIN_NATIVE',
+        },
+      },
     },
     {
       title: '订单号',
@@ -127,7 +146,6 @@ const Recharge = () => {
       />
       {visible && (
         <TopUp
-          data={{}}
           close={() => {
             setVisible(false);
             actionRef.current?.reload();

+ 11 - 3
src/pages/iot-card/Recharge/topUp.tsx

@@ -3,14 +3,13 @@ import { createSchemaField } from '@formily/react';
 import { Form, FormGrid, FormItem, Input, Select, NumberPicker } from '@formily/antd';
 import type { ISchema } from '@formily/json-schema';
 import { Modal } from '@/components';
-// import { onlyMessage } from '@/utils/util';
+import { onlyMessage } from '@/utils/util';
 import { ExclamationCircleOutlined } from '@ant-design/icons';
 import { action } from '@formily/reactive';
 import { service } from './index';
 import { PaymentMethod } from '../data';
 
 interface Props {
-  data: any;
   close: () => void;
 }
 
@@ -172,7 +171,16 @@ const TopUp = (props: Props) => {
 
   const save = async () => {
     const value = await form.submit<any>();
-    console.log(value);
+    const res: any = await service.recharge(value);
+    if (res.status === 200) {
+      if (res.result === '失败') {
+        onlyMessage('缴费失败', 'error');
+        props.close();
+      } else {
+        window.open(res.result);
+        props.close();
+      }
+    }
   };
 
   return (

+ 1 - 1
src/pages/iot-card/Record/index.tsx

@@ -57,7 +57,7 @@ const Record = () => {
         columnEmptyText={''}
         tableStyle={{ minHeight }}
         request={async (params) =>
-          service.getList({ ...params, sorts: [{ name: 'createTime', order: 'desc' }] })
+          service.getList({ ...params, sorts: [{ name: 'time', order: 'desc' }] })
         }
       />
     </PageContainer>