wzyyy 3 роки тому
батько
коміт
90f2aa7091

+ 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:8850/',
+      // ws: 'ws://192.168.32.65:8850/',
       //v2环境
       // ws: 'ws://47.109.52.230:8844',
       // target: 'http://47.109.52.230:8844',

+ 144 - 0
src/pages/iot-card/CardManagement/SaveModal.tsx

@@ -0,0 +1,144 @@
+import { Form, Input, message, Modal, Select } from 'antd';
+import { useEffect } from 'react';
+
+import { service } from './index';
+import { useRequest } from 'ahooks';
+import { OperatorList, TypeList } from '@/pages/iot-card/data';
+
+type SaveType = {
+  type: 'add' | 'edit';
+  data?: any;
+  onCancel: () => void;
+  onOk: () => void;
+};
+
+const Save = (props: SaveType) => {
+  const [form] = Form.useForm();
+
+  const { data: platformList, run: platformRun } = useRequest(service.queryPlatformNoPage, {
+    manual: false,
+    formatResult(result) {
+      return result.data;
+    },
+  });
+
+  useEffect(() => {
+    platformRun({
+      sorts: [{ order: 'desc' }],
+      terms: [{ column: 'state', value: 'enabled' }],
+    });
+    // if (props.type === 'edit' && form) {
+    //   form.setFieldsValue(props.data)
+    // }
+  }, []);
+
+  const submit = async () => {
+    const formData = await form.validateFields();
+    if (formData) {
+      const resp =
+        props.type === 'add' ? await service.save(formData) : await service.update(formData);
+
+      if (resp.status === 200) {
+        message.success('操作成功');
+        props?.onOk();
+      }
+    }
+  };
+  return (
+    <Modal
+      title={props.type === 'add' ? '新增' : '编辑'}
+      visible={true}
+      width={600}
+      onCancel={props.onCancel}
+      onOk={submit}
+    >
+      <Form
+        form={form}
+        labelCol={{
+          style: { width: 100 },
+        }}
+        layout={'vertical'}
+      >
+        <Form.Item
+          label={'卡号'}
+          name={'id'}
+          required
+          rules={[
+            { required: true, message: '请输入卡号' },
+            { max: 64, message: '最多可输入64个字符' },
+          ]}
+        >
+          <Input placeholder={'请输入卡号'} disabled={props.type === 'edit'} />
+        </Form.Item>
+        <Form.Item
+          label={'ICCID'}
+          name={'iccId'}
+          required
+          rules={[
+            { required: true, message: '请输入ICCID' },
+            { max: 64, message: '最多可输入64个字符' },
+          ]}
+        >
+          <Input placeholder={'请输入ICCID'} disabled={props.type === 'edit'} />
+        </Form.Item>
+        <Form.Item
+          label={'平台对接'}
+          name={'platformConfigId'}
+          required
+          rules={[{ required: true, message: '请选择平台对接' }]}
+        >
+          <Select
+            showSearch
+            placeholder={'请选择平台对接'}
+            disabled={props.type === 'edit'}
+            fieldNames={{ label: 'name', value: 'id' }}
+            options={platformList}
+            filterOption={(input, option) => {
+              if (option?.name) {
+                return option.name.includes(input);
+              }
+              return false;
+            }}
+          />
+        </Form.Item>
+        <Form.Item label={'运营商'} name={'operatorName'}>
+          <Select
+            showSearch
+            placeholder={'请选择运营商'}
+            options={OperatorList}
+            filterOption={(input, option) => {
+              if (option?.label) {
+                return option.label.includes(input);
+              }
+              return false;
+            }}
+          />
+        </Form.Item>
+        <Form.Item
+          label={'类型'}
+          name={'cardType'}
+          required
+          rules={[{ required: true, message: '请选择类型' }]}
+        >
+          <Select
+            showSearch
+            placeholder={'请选择类型'}
+            disabled={props.type === 'edit'}
+            options={TypeList}
+            filterOption={(input, option) => {
+              if (option?.label) {
+                return option.label.includes(input);
+              }
+              return false;
+            }}
+          />
+        </Form.Item>
+        <Form.Item label={'说明'} name={'describe'}>
+          <Input.TextArea showCount maxLength={200} placeholder="请输入说明" />
+        </Form.Item>
+      </Form>
+    </Modal>
+  );
+};
+
+export default Save;

+ 331 - 3
src/pages/iot-card/CardManagement/index.tsx

@@ -1,4 +1,332 @@
-const CardManagement = () => {
-  return <>物联卡管理</>;
+import { PageContainer } from '@ant-design/pro-layout';
+import SearchComponent from '@/components/SearchComponent';
+import { useRef, useState } from 'react';
+import type { ActionType } from '@jetlinks/pro-table';
+import { PermissionButton, ProTableCard } from '@/components';
+import { useIntl } from '@@/plugin-locale/localeExports';
+import type { ProColumns } from '@jetlinks/pro-table';
+import type { CardManagement } from './typing';
+import { Button, Dropdown, Menu } from 'antd';
+import {
+  ExportOutlined,
+  PlusOutlined,
+  ImportOutlined,
+  CheckCircleOutlined,
+} from '@ant-design/icons';
+import SaveModal from './SaveModal';
+import Service from './service';
+
+export const service = new Service('network/card');
+
+const CardManagementNode = () => {
+  const actionRef = useRef<ActionType>();
+  const [searchParams, setSearchParams] = useState<any>({});
+  const [visible, setVisible] = useState<boolean>(false);
+  const [exportVisible, setExportVisible] = useState<boolean>(false); // 导出
+  const [importVisible, setImportVisible] = useState<boolean>(false); // 导入
+  const [current, setCurrent] = useState<Partial<CardManagement>>({});
+  const [bindKeys, setBindKeys] = useState<any[]>([]);
+  const { permission } = PermissionButton.usePermission('device/Instance');
+  const intl = useIntl();
+
+  const columns: ProColumns<CardManagement>[] = [
+    {
+      title: '卡号',
+      dataIndex: 'id',
+      width: 300,
+      ellipsis: true,
+      fixed: 'left',
+    },
+    {
+      title: 'ICCID',
+      dataIndex: 'iccId',
+      ellipsis: true,
+      width: 200,
+    },
+    {
+      title: '绑定设备',
+      dataIndex: 'deviceId',
+      ellipsis: true,
+    },
+    {
+      title: '平台对接',
+      dataIndex: 'platformConfigId',
+    },
+    {
+      title: '运营商',
+      dataIndex: 'operatorName',
+    },
+    {
+      title: '类型',
+      dataIndex: 'cardType',
+    },
+    {
+      title: '总流量',
+      dataIndex: 'totalFlow',
+    },
+    {
+      title: '使用流量',
+      dataIndex: 'usedFlow',
+    },
+    {
+      title: '剩余流量',
+      dataIndex: 'residualFlow',
+    },
+    {
+      title: '激活日期',
+      dataIndex: 'activationDate',
+    },
+    {
+      title: '更新时间',
+      dataIndex: 'updateTime',
+    },
+    {
+      title: '状态',
+      dataIndex: 'cardStateType',
+      valueEnum: {
+        using: {
+          text: '正常',
+          status: 'using',
+        },
+        toBeActivated: {
+          text: '未激活',
+          status: 'using',
+        },
+        deactivate: {
+          text: '停机',
+          status: 'using',
+        },
+      },
+    },
+    {
+      title: '操作',
+      valueType: 'option',
+      width: 120,
+      fixed: 'right',
+      render: (_, record) => {
+        console.log(_, record);
+        return [];
+      },
+    },
+  ];
+
+  console.log(exportVisible, importVisible);
+
+  const menu = (
+    <Menu>
+      <Menu.Item key="1">
+        <PermissionButton
+          isPermission={permission.export}
+          icon={<ExportOutlined />}
+          type="default"
+          onClick={() => {
+            setExportVisible(true);
+          }}
+          style={{ width: '100%' }}
+        >
+          导出
+        </PermissionButton>
+      </Menu.Item>
+      <Menu.Item key="2">
+        <PermissionButton
+          isPermission={permission.import}
+          icon={<ImportOutlined />}
+          type="default"
+          onClick={() => {
+            setImportVisible(true);
+          }}
+          style={{ width: '100%' }}
+        >
+          导入
+        </PermissionButton>
+      </Menu.Item>
+      {bindKeys.length > 0 && (
+        <Menu.Item key="3">
+          <PermissionButton
+            isPermission={permission.action}
+            icon={<CheckCircleOutlined />}
+            type="primary"
+            ghost
+            popConfirm={{
+              title: '确认激活吗?',
+              onConfirm: async () => {},
+            }}
+            style={{ width: '100%' }}
+          >
+            激活
+          </PermissionButton>
+        </Menu.Item>
+      )}
+      {bindKeys.length > 0 && (
+        <Menu.Item key="4">
+          <PermissionButton
+            isPermission={permission.stop}
+            icon={<CheckCircleOutlined />}
+            type="primary"
+            ghost
+            popConfirm={{
+              title: '确认停用吗?',
+              onConfirm: async () => {},
+            }}
+            style={{ width: '100%' }}
+          >
+            停用
+          </PermissionButton>
+        </Menu.Item>
+      )}
+      {bindKeys.length > 0 && (
+        <Menu.Item key="5">
+          <PermissionButton
+            isPermission={permission.restart}
+            icon={<CheckCircleOutlined />}
+            type="primary"
+            ghost
+            popConfirm={{
+              title: '确认复机吗?',
+              onConfirm: async () => {},
+            }}
+            style={{ width: '100%' }}
+          >
+            复机
+          </PermissionButton>
+        </Menu.Item>
+      )}
+      <Menu.Item key="6">
+        <PermissionButton
+          isPermission={permission.sync}
+          icon={<CheckCircleOutlined />}
+          type="primary"
+          ghost
+          popConfirm={{
+            title: '确认同步物联卡状态?',
+            onConfirm: async () => {},
+          }}
+        >
+          同步状态
+        </PermissionButton>
+      </Menu.Item>
+      {bindKeys.length > 0 && (
+        <PermissionButton
+          isPermission={permission.delete}
+          icon={<CheckCircleOutlined />}
+          type="primary"
+          ghost
+          popConfirm={{
+            title: '确认删除吗?',
+            onConfirm: async () => {},
+          }}
+        >
+          批量删除
+        </PermissionButton>
+      )}
+    </Menu>
+  );
+
+  return (
+    <PageContainer>
+      {visible && (
+        <SaveModal
+          type={'add'}
+          onCancel={() => {
+            setVisible(false);
+          }}
+          data={current}
+          onOk={() => {
+            setVisible(false);
+            actionRef.current?.reload();
+          }}
+        />
+      )}
+      <SearchComponent<CardManagement>
+        field={columns}
+        target="iot-card-management"
+        onSearch={(data) => {
+          actionRef.current?.reset?.();
+          setSearchParams(data);
+        }}
+      />
+      <ProTableCard<CardManagement>
+        columns={columns}
+        scroll={{ x: 1366 }}
+        actionRef={actionRef}
+        params={searchParams}
+        options={{ fullScreen: true }}
+        columnEmptyText={''}
+        request={(params) =>
+          service.query({
+            ...params,
+            sorts: [
+              {
+                name: 'createTime',
+                order: 'desc',
+              },
+            ],
+          })
+        }
+        rowKey="id"
+        search={false}
+        tableAlertRender={({ selectedRowKeys }) => <div>已选择 {selectedRowKeys.length} 项</div>}
+        tableAlertOptionRender={() => {
+          return (
+            <a
+              onClick={() => {
+                setBindKeys([]);
+              }}
+            >
+              取消选择
+            </a>
+          );
+        }}
+        pagination={{ pageSize: 10 }}
+        rowSelection={{
+          selectedRowKeys: bindKeys,
+          onChange: (selectedRowKeys) => {
+            setBindKeys(selectedRowKeys);
+          },
+          onSelect: (_, selected) => {
+            if (selected) {
+              // InstanceModel.selectedRows.set(record.id, record?.state?.value);
+            } else {
+              // InstanceModel.selectedRows.delete(record.id);
+            }
+            // setBindKeys([...InstanceModel.selectedRows.keys()]);
+          },
+          onSelectAll: (selected, _, changeRows) => {
+            if (selected) {
+              changeRows.forEach(() => {
+                // InstanceModel.selectedRows.set(item.id, item?.state?.value);
+              });
+            } else {
+              changeRows.forEach(() => {
+                // InstanceModel.selectedRows.delete(item.id);
+              });
+            }
+            // setBindKeys([...InstanceModel.selectedRows.keys()]);
+          },
+        }}
+        headerTitle={[
+          <PermissionButton
+            onClick={() => {
+              setVisible(true);
+              setCurrent({});
+            }}
+            style={{ marginRight: 12 }}
+            isPermission={permission.add}
+            key="button"
+            icon={<PlusOutlined />}
+            type="primary"
+          >
+            {intl.formatMessage({
+              id: 'pages.data.option.add',
+              defaultMessage: '新增',
+            })}
+          </PermissionButton>,
+          <Dropdown key={'more'} overlay={menu} placement="bottom">
+            <Button>批量操作</Button>
+          </Dropdown>,
+        ]}
+      />
+    </PageContainer>
+  );
 };
-export default CardManagement;
+export default CardManagementNode;

+ 74 - 0
src/pages/iot-card/data.ts

@@ -0,0 +1,74 @@
+// 平台类型
+export const PlatformTypeList = [
+  {
+    label: '移动OneLink',
+    value: 'OneLinkPB',
+    imgUrl: require('/public/images/iot-card/onelink.png'),
+  },
+  {
+    label: '电信Ctwing',
+    value: 'CtwingCmp',
+    imgUrl: require('/public/images/iot-card/ctwingcmp.png'),
+  },
+  {
+    label: '联通Unicom',
+    value: 'UnicomCmp',
+    imgUrl: require('/public/images/iot-card/unicom.png'),
+  },
+];
+
+//运营商
+export const OperatorList = [
+  {
+    label: '移动',
+    value: '移动',
+  },
+  {
+    label: '电信',
+    value: '电信',
+  },
+  {
+    label: '联通',
+    value: '联通',
+  },
+];
+
+// 类型
+export const TypeList = [
+  {
+    label: '年卡',
+    value: 'year',
+  },
+  {
+    label: '季卡',
+    value: 'season',
+  },
+  {
+    label: '月卡',
+    value: 'month',
+  },
+  {
+    label: '其他',
+    value: 'other',
+  },
+];
+
+// 支付方式
+export const PaymentMethod = [
+  {
+    label: '支付宝手机网站支付',
+    value: 'ALIPAY_WAP',
+  },
+  {
+    label: '支付宝网页及时到账支付',
+    value: 'ALIPAY_WEB',
+  },
+  {
+    label: '微信公众号支付',
+    value: 'WEIXIN_JSAPI',
+  },
+  {
+    label: '微信扫码支付',
+    value: 'WEIXIN_NATIVE',
+  },
+];

+ 12 - 7
src/pages/notice/Config/Detail/index.tsx

@@ -319,7 +319,12 @@ const Detail = observer(() => {
                 'x-component-props': {
                   placeholder: '请输入webhook',
                 },
-
+                'x-validator': [
+                  {
+                    max: 64,
+                    message: '最多可输入64个字符',
+                  },
+                ],
                 'x-reactions': {
                   dependencies: ['provider'],
                   fulfill: {
@@ -525,12 +530,12 @@ const Detail = observer(() => {
                 },
                 'x-component': 'Input',
                 'x-decorator': 'FormItem',
-                // 'x-validator': [
-                //   {
-                //     max: 64,
-                //     message: '最多可输入64个字符',
-                //   },
-                // ],
+                'x-validator': [
+                  {
+                    max: 64,
+                    message: '最多可输入64个字符',
+                  },
+                ],
               },
               headers: {
                 title: '请求头',

+ 2 - 2
src/pages/oauth/index.tsx

@@ -202,8 +202,8 @@ const Oauth = () => {
         const item = getQueryVariable('internal');
         if (items.redirect_uri) {
           const orgin = items.redirect_uri.split('/').slice(0, 3);
-          const url = `${orgin.join('/')}/%23/${items.redirect_uri?.split('redirect_uri=')[1]}`;
-          redirectUrl = `${items.redirect_uri?.split('redirect_uri=')[0]}?redirect=${url}`;
+          const url = `${orgin.join('/')}/%23/${items.redirect_uri?.split('redirect=')[1]}`;
+          redirectUrl = `${items.redirect_uri?.split('redirect=')[0]}redirect=${url}`;
         }
         getLoginUser({
           ...items,

+ 2 - 0
src/utils/menu/router.ts

@@ -171,6 +171,8 @@ export enum BUTTON_PERMISSION_ENUM {
   'password' = 'password', //重置密码
   'api' = 'api', //查看api
   'manage' = 'manage', //数据源-管理
+  'stop' = 'stop',
+  'restart' = 'restart',
 }
 
 // 调试按钮、通知记录、批量导出、批量导入、选择通道、推送、分配资产、绑定用户对应的ID是啥