Compare commits

..

No commits in common. "master" and "develop" have entirely different histories.

47 changed files with 994 additions and 68 deletions

4
.env Normal file
View File

@ -0,0 +1,4 @@
# 默认配置
DID_YOU_KNOW=none
PORT=30058
APP_ENV=production

1
.env.production Normal file
View File

@ -0,0 +1 @@
APP_ENV=production

3
.eslintrc.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
extends: require.resolve('@umijs/max/eslint'),
};

35
.gitignore vendored
View File

@ -1,18 +1,17 @@
# Build and Release Folders
bin-debug/
bin-release/
[Oo]bj/
[Bb]in/
# Other files and folders
.settings/
# Executables
*.swf
*.air
*.ipa
*.apk
# Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties`
# should NOT be excluded as they contain compiler settings and other important
# information for Eclipse / Flash Builder.
/node_modules
/.env.local
/.umirc.local.ts
/config/config.local.ts
/src/.umi
/src/.umi-production
/src/.umi-test
/.umi
/.umi-production
/.umi-test
/dist
/.mfsu
.swc
aircraft-carrier-fleet
dist
.idea
pnpm-lock.yaml

32
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,32 @@
stages:
- build
- package
- deploy
cache:
policy: pull
key: '$CI_COMMIT_REF_NAME'
paths:
- node_modules/
build:
image: registry.zhst.com/video-analysis/pnpm4
tags:
- linux
stage: build
script:
- chmod +x ./deploy/build.sh && ./deploy/build.sh
artifacts:
name: '${CI_PROJECT_NAME}_${CI_COMMIT_REF_NAME}_${CI_JOB_NAME}_${CI_PIPELINE_ID}'
paths:
- ./app/public/*
package:
tags:
- linux_shell
stage: package
script:
- chmod +x ./deploy/package.sh && ./deploy/package.sh
dependencies:
- build

4
.husky/commit-msg Normal file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no-install max verify-commit $1

4
.husky/pre-commit Normal file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no-install lint-staged --quiet

17
.lintstagedrc Normal file
View File

@ -0,0 +1,17 @@
{
"*.{md,json}": [
"prettier --cache --write"
],
"*.{js,jsx}": [
"max lint --fix --eslint-only",
"prettier --cache --write"
],
"*.{css,less}": [
"max lint --fix --stylelint-only",
"prettier --cache --write"
],
"*.ts?(x)": [
"max lint --fix --eslint-only",
"prettier --cache --parser=typescript --write"
]
}

2
.npmrc Normal file
View File

@ -0,0 +1,2 @@
registry=https://registry.npmmirror.com/
@zhst:registry="http://10.0.0.77:4874"

3
.prettierignore Normal file
View File

@ -0,0 +1,3 @@
node_modules
.umi
.umi-production

8
.prettierrc Normal file
View File

@ -0,0 +1,8 @@
{
"printWidth": 80,
"singleQuote": true,
"trailingComma": "all",
"proseWrap": "never",
"overrides": [{ "files": ".prettierrc", "options": { "parser": "json" } }],
"plugins": ["prettier-plugin-organize-imports", "prettier-plugin-packagejson"]
}

3
.stylelintrc.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
extends: require.resolve('@umijs/max/stylelint'),
};

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"cSpell.words": [
"qiankun"
]
}

5
Dockerfile Normal file
View File

@ -0,0 +1,5 @@
FROM alpine:latest
ADD ./app/public/ /app/public/
CMD [ "sh", "-c", "while true; do echo zhst-web; sleep 1; done" ]

21
LICENSE
View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2024 dev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,29 +1,5 @@
# micro-app
#### 介绍
微前端架构实例
#### 软件架构
软件架构说明
#### 安装教程
1. xxxx
2. xxxx
3. xxxx
#### 使用说明
1. xxxx
2. xxxx
3. xxxx
#### 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
微前端母项目
# README
`@umijs/max` 模板项目,更多功能参考 [Umi Max 简介](https://umijs.org/docs/max/introduce)

23
config/config.ts Normal file
View File

@ -0,0 +1,23 @@
import { defineConfig } from '@umijs/max';
import routes from './routes';
export default defineConfig({
favicons: ['/assets/logo.jpg'],
access: {},
model: {},
dva: {},
request: {},
initialState: {},
layout: false,
qiankun: {
master: {
prefetch: false,
},
},
mfsu: false,
routes,
npmClient: 'pnpm',
define: {
APP_ENV: process.env.NODE_ENV || 'production',
},
});

28
config/routes/index.ts Normal file
View File

@ -0,0 +1,28 @@
const routes = [
{
name: 'home',
path: '/',
redirect: '/material/home',
},
{
name: 'cabinet',
path: '/cabinet/*',
microApp: 'cabinet',
},
{
name: 'algorithm',
path: '/algorithm/*',
microApp: 'algorithm',
},
{
name: 'video',
path: '/video/*',
microApp: 'video',
},
{
name: '物料库',
path: '/material/*',
microApp: 'material',
},
];
export default routes;

9
deploy/build.sh Executable file
View File

@ -0,0 +1,9 @@
pnpm install
pnpm run build:master
mkdir -p ./app/public/
mv ./dist/* ./app/public/
cat ./app/public/index.html | head -n 7

10
deploy/package.sh Normal file
View File

@ -0,0 +1,10 @@
#! /bin/bash
set -e
export DOCKER_CLI_EXPERIMENTAL=enabled
docker login registry.zhst.com -u zhst -p Zhst666\&
# docker build -t registry.zhst.com/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}:${CI_COMMIT_REF_NAME//\//-}-${CI_PIPELINE_ID} -f Dockerfile .
# docker push registry.zhst.com/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}:${CI_COMMIT_REF_NAME//\//-}-${CI_PIPELINE_ID}
docker buildx build --platform linux/arm64,linux/amd64 -t registry.zhst.com/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}:${CI_COMMIT_REF_NAME//\//-}-${CI_PIPELINE_ID} -f Dockerfile . --push

1
global.d.ts vendored Normal file
View File

@ -0,0 +1 @@
declare const APP_ENV: string;

20
mock/userAPI.ts Normal file
View File

@ -0,0 +1,20 @@
const users = [
{ id: 0, name: 'Umi', nickName: 'U', gender: 'MALE' },
{ id: 1, name: 'Fish', nickName: 'B', gender: 'FEMALE' },
];
export default {
'GET /api/v1/queryUserList': (req: any, res: any) => {
res.json({
success: true,
data: { list: users },
errorCode: 0,
});
},
'PUT /api/v1/user/': (req: any, res: any) => {
res.json({
success: true,
errorCode: 0,
});
},
};

34
package.json Normal file
View File

@ -0,0 +1,34 @@
{
"name": "aircraft-carrier-fleet",
"private": true,
"author": "dev <710328466@qq.com>",
"scripts": {
"build:master": "cross-env APP_ENV=production max build",
"comp": "cross-env max g component",
"dev": "max dev",
"format": "prettier --cache --write .",
"postinstall": "max setup",
"page": "cross-env max g page",
"prepare": "husky install",
"setup": "max setup",
"start": "npm run dev"
},
"dependencies": {
"@ant-design/icons": "^5.3.0",
"@ant-design/pro-components": "^2.6.49",
"@umijs/max": "^4.1.1",
"@zhst/func": "^0.8.1",
"antd": "^5.14.1",
"cross-env": "^7.0.3"
},
"devDependencies": {
"@types/react": "^18.2.57",
"@types/react-dom": "^18.2.19",
"husky": "^9.0.11",
"lint-staged": "^15.2.2",
"prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^3.2.4",
"prettier-plugin-packagejson": "^2.4.11",
"typescript": "^5.3.3"
}
}

10
src/access.ts Normal file
View File

@ -0,0 +1,10 @@
export default (initialState: API.UserInfo) => {
// 在这里按照初始化数据定义项目中的权限,统一管理
// 参考文档 https://umijs.org/docs/max/access
const canSeeAdmin = !!(
initialState && initialState.name !== 'dontHaveAccess'
);
return {
canSeeAdmin,
};
};

12
src/actions/index.ts Normal file
View File

@ -0,0 +1,12 @@
import { useState } from 'react';
export default function useQiankunStateForSlave() {
const [globalState, setGlobalState] = useState<any>({
fatherName: 'zhst',
});
return {
globalState,
setGlobalState,
};
}

68
src/app.ts Normal file
View File

@ -0,0 +1,68 @@
import doRequest from '@/utils/request';
import useFatherAction from './actions';
// 运行时配置
export async function getInitialState(): Promise<{
name: string;
useLogin: boolean;
}> {
return {
name: '主应用',
useLogin: false,
};
}
// 给子应用暴露的方法
export const useQiankunStateForSlave = useFatherAction;
const hostname = location.hostname;
export const qiankun = {
apps: [
{
name: 'cabinet', // 盒子管理
entry:
APP_ENV === 'production'
? `//${hostname}:30068/cabinet/`
: '//localhost:30068/',
props: {},
singular: false,
credentials: true,
},
{
name: 'video', // AI 智能分析仓
entry:
APP_ENV === 'production'
? `//${hostname}:30088/video/`
: '//localhost:30088/',
singular: false,
credentials: true,
},
{
name: 'algorithm', // AI 算法分析
entry:
APP_ENV === 'production'
? `//${hostname}:30078/algorithm/`
: '//localhost:30078/',
singular: false,
credentials: true,
},
{
name: 'material', // 物料库
entry:
APP_ENV === 'production'
? `//${hostname}:30098/material/`
: '//localhost:30098/',
singular: false,
credentials: true,
},
],
lifeCycles: {
// 所有子应用在挂载完成时,打印 props 信息
async afterMount() {
// console.log('子应用已全部加载:', props);
},
},
};
export const request = doRequest;

0
src/assets/.gitkeep Normal file
View File

BIN
src/assets/logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -0,0 +1,4 @@
.title {
margin: 0 auto;
font-weight: 200;
}

View File

@ -0,0 +1,23 @@
import { Layout, Row, Typography } from 'antd';
import React from 'react';
import styles from './Guide.less';
interface Props {
name: string;
}
// 脚手架示例组件
const Guide: React.FC<Props> = (props) => {
const { name } = props;
return (
<Layout>
<Row>
<Typography.Title level={3} className={styles.title}>
使 <strong>{name}</strong>
</Typography.Title>
</Row>
</Layout>
);
};
export default Guide;

View File

@ -0,0 +1,2 @@
import Guide from './Guide';
export default Guide;

0
src/constants/index.ts Normal file
View File

4
src/global.less Normal file
View File

@ -0,0 +1,4 @@
* {
padding: 0;
margin: 0;
}

5
src/layouts/index.less Normal file
View File

@ -0,0 +1,5 @@
.layout {
&_tag {
bottom: 0;
}
}

33
src/layouts/index.tsx Normal file
View File

@ -0,0 +1,33 @@
import { SettingOutlined, ShopOutlined } from '@ant-design/icons';
import { Outlet } from '@umijs/max';
import { FloatButton } from 'antd';
import React from 'react';
import styles from './index.less';
const Layout = () => {
return (
<div className={styles.layout}>
<FloatButton.Group
trigger="click"
type="primary"
style={{ right: 32 }}
icon={<SettingOutlined />}
>
<FloatButton
tooltip="物料库"
onClick={() =>
(location.href = 'http://10.0.0.222:30098/communal-cabinets')
}
/>
<FloatButton
tooltip="组件库"
onClick={() => (location.href = 'http://10.0.0.222')}
/>
<FloatButton tooltip="demo 展示" icon={<ShopOutlined />} />
</FloatButton.Group>
<Outlet />
</div>
);
};
export default Layout;

13
src/models/global.ts Normal file
View File

@ -0,0 +1,13 @@
// 全局共享数据示例
import { DEFAULT_NAME } from '@/constants';
import { useState } from 'react';
const useUser = () => {
const [name, setName] = useState<string>(DEFAULT_NAME);
return {
name,
setName,
};
};
export default useUser;

View File

@ -0,0 +1,21 @@
import { PageContainer } from '@ant-design/pro-components';
import { Access, useAccess } from '@umijs/max';
import { Button } from 'antd';
const AccessPage: React.FC = () => {
const access = useAccess();
return (
<PageContainer
ghost
header={{
title: '权限示例',
}}
>
<Access accessible={access.canSeeAdmin}>
<Button> Admin </Button>
</Access>
</PageContainer>
);
};
export default AccessPage;

View File

@ -0,0 +1,26 @@
import { Modal } from 'antd';
import React, { PropsWithChildren } from 'react';
interface CreateFormProps {
modalVisible: boolean;
onCancel: () => void;
}
const CreateForm: React.FC<PropsWithChildren<CreateFormProps>> = (props) => {
const { modalVisible, onCancel } = props;
return (
<Modal
destroyOnClose
title="新建"
width={420}
open={modalVisible}
onCancel={() => onCancel()}
footer={null}
>
{props.children}
</Modal>
);
};
export default CreateForm;

View File

@ -0,0 +1,138 @@
import {
ProFormDateTimePicker,
ProFormRadio,
ProFormSelect,
ProFormText,
ProFormTextArea,
StepsForm,
} from '@ant-design/pro-components';
import { Modal } from 'antd';
import React from 'react';
export interface FormValueType extends Partial<API.UserInfo> {
target?: string;
template?: string;
type?: string;
time?: string;
frequency?: string;
}
export interface UpdateFormProps {
onCancel: (flag?: boolean, formVals?: FormValueType) => void;
onSubmit: (values: FormValueType) => Promise<void>;
updateModalVisible: boolean;
values: Partial<API.UserInfo>;
}
const UpdateForm: React.FC<UpdateFormProps> = (props) => (
<StepsForm
stepsProps={{
size: 'small',
}}
stepsFormRender={(dom, submitter) => {
return (
<Modal
width={640}
bodyStyle={{ padding: '32px 40px 48px' }}
destroyOnClose
title="规则配置"
open={props.updateModalVisible}
footer={submitter}
onCancel={() => props.onCancel()}
>
{dom}
</Modal>
);
}}
onFinish={props.onSubmit}
>
<StepsForm.StepForm
initialValues={{
name: props.values.name,
nickName: props.values.nickName,
}}
title="基本信息"
>
<ProFormText
width="md"
name="name"
label="规则名称"
rules={[{ required: true, message: '请输入规则名称!' }]}
/>
<ProFormTextArea
name="desc"
width="md"
label="规则描述"
placeholder="请输入至少五个字符"
rules={[
{ required: true, message: '请输入至少五个字符的规则描述!', min: 5 },
]}
/>
</StepsForm.StepForm>
<StepsForm.StepForm
initialValues={{
target: '0',
template: '0',
}}
title="配置规则属性"
>
<ProFormSelect
width="md"
name="target"
label="监控对象"
valueEnum={{
0: '表一',
1: '表二',
}}
/>
<ProFormSelect
width="md"
name="template"
label="规则模板"
valueEnum={{
0: '规则模板一',
1: '规则模板二',
}}
/>
<ProFormRadio.Group
name="type"
width="md"
label="规则类型"
options={[
{
value: '0',
label: '强',
},
{
value: '1',
label: '弱',
},
]}
/>
</StepsForm.StepForm>
<StepsForm.StepForm
initialValues={{
type: '1',
frequency: 'month',
}}
title="设定调度周期"
>
<ProFormDateTimePicker
name="time"
label="开始时间"
rules={[{ required: true, message: '请选择开始时间!' }]}
/>
<ProFormSelect
name="frequency"
label="监控对象"
width="xs"
valueEnum={{
month: '月',
week: '周',
}}
/>
</StepsForm.StepForm>
</StepsForm>
);
export default UpdateForm;

View File

@ -0,0 +1,270 @@
import services from '@/services/demo';
import {
ActionType,
FooterToolbar,
PageContainer,
ProDescriptions,
ProDescriptionsItemProps,
ProTable,
} from '@ant-design/pro-components';
import { Button, Divider, Drawer, message } from 'antd';
import React, { useRef, useState } from 'react';
import CreateForm from './components/CreateForm';
import UpdateForm, { FormValueType } from './components/UpdateForm';
const { addUser, queryUserList, deleteUser, modifyUser } =
services.UserController;
/**
*
* @param fields
*/
const handleAdd = async (fields: API.UserInfo) => {
const hide = message.loading('正在添加');
try {
await addUser({ ...fields });
hide();
message.success('添加成功');
return true;
} catch (error) {
hide();
message.error('添加失败请重试!');
return false;
}
};
/**
*
* @param fields
*/
const handleUpdate = async (fields: FormValueType) => {
const hide = message.loading('正在配置');
try {
await modifyUser(
{
userId: fields.id || '',
},
{
name: fields.name || '',
nickName: fields.nickName || '',
email: fields.email || '',
},
);
hide();
message.success('配置成功');
return true;
} catch (error) {
hide();
message.error('配置失败请重试!');
return false;
}
};
/**
*
* @param selectedRows
*/
const handleRemove = async (selectedRows: API.UserInfo[]) => {
const hide = message.loading('正在删除');
if (!selectedRows) return true;
try {
await deleteUser({
userId: selectedRows.find((row) => row.id)?.id || '',
});
hide();
message.success('删除成功,即将刷新');
return true;
} catch (error) {
hide();
message.error('删除失败,请重试');
return false;
}
};
const TableList: React.FC<unknown> = () => {
const [createModalVisible, handleModalVisible] = useState<boolean>(false);
const [updateModalVisible, handleUpdateModalVisible] =
useState<boolean>(false);
const [stepFormValues, setStepFormValues] = useState({});
const actionRef = useRef<ActionType>();
const [row, setRow] = useState<API.UserInfo>();
const [selectedRowsState, setSelectedRows] = useState<API.UserInfo[]>([]);
const columns: ProDescriptionsItemProps<API.UserInfo>[] = [
{
title: '名称',
dataIndex: 'name',
tip: '名称是唯一的 key',
formItemProps: {
rules: [
{
required: true,
message: '名称为必填项',
},
],
},
},
{
title: '昵称',
dataIndex: 'nickName',
valueType: 'text',
},
{
title: '性别',
dataIndex: 'gender',
hideInForm: true,
valueEnum: {
0: { text: '男', status: 'MALE' },
1: { text: '女', status: 'FEMALE' },
},
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => (
<>
<a
onClick={() => {
handleUpdateModalVisible(true);
setStepFormValues(record);
}}
>
</a>
<Divider type="vertical" />
<a href=""></a>
</>
),
},
];
return (
<PageContainer
header={{
title: 'CRUD 示例',
}}
>
<ProTable<API.UserInfo>
headerTitle="查询表格"
actionRef={actionRef}
rowKey="id"
search={{
labelWidth: 120,
}}
toolBarRender={() => [
<Button
key="1"
type="primary"
onClick={() => handleModalVisible(true)}
>
</Button>,
]}
request={async (params, sorter, filter) => {
const { data, success } = await queryUserList({
...params,
// FIXME: remove @ts-ignore
// @ts-ignore
sorter,
filter,
});
return {
data: data?.list || [],
success,
};
}}
columns={columns}
rowSelection={{
onChange: (_, selectedRows) => setSelectedRows(selectedRows),
}}
/>
{selectedRowsState?.length > 0 && (
<FooterToolbar
extra={
<div>
{' '}
<a style={{ fontWeight: 600 }}>{selectedRowsState.length}</a>{' '}
&nbsp;&nbsp;
</div>
}
>
<Button
onClick={async () => {
await handleRemove(selectedRowsState);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}}
>
</Button>
<Button type="primary"></Button>
</FooterToolbar>
)}
<CreateForm
onCancel={() => handleModalVisible(false)}
modalVisible={createModalVisible}
>
<ProTable<API.UserInfo, API.UserInfo>
onSubmit={async (value) => {
const success = await handleAdd(value);
if (success) {
handleModalVisible(false);
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
rowKey="id"
type="form"
columns={columns}
/>
</CreateForm>
{stepFormValues && Object.keys(stepFormValues).length ? (
<UpdateForm
onSubmit={async (value) => {
const success = await handleUpdate(value);
if (success) {
handleUpdateModalVisible(false);
setStepFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
handleUpdateModalVisible(false);
setStepFormValues({});
}}
updateModalVisible={updateModalVisible}
values={stepFormValues}
/>
) : null}
<Drawer
width={600}
open={!!row}
onClose={() => {
setRow(undefined);
}}
closable={false}
>
{row?.name && (
<ProDescriptions<API.UserInfo>
column={2}
title={row?.name}
request={async () => ({
data: row || {},
})}
params={{
id: row?.name,
}}
columns={columns}
/>
)}
</Drawer>
</PageContainer>
);
};
export default TableList;

View File

@ -0,0 +1,9 @@
import React from 'react';
export default function HomePage() {
return (
<div>
<h2>error</h2>
</div>
);
}

9
src/pages/index.tsx Normal file
View File

@ -0,0 +1,9 @@
import React from 'react';
export default function HomePage() {
return (
<div>
<h2>welcome home !</h2>
</div>
);
}

4
src/utils/constants.ts Normal file
View File

@ -0,0 +1,4 @@
export const API_URL =
APP_ENV === 'production'
? 'http://10.0.0.222:31300'
: 'http://10.0.0.222:31300';

12
src/utils/format.ts Normal file
View File

@ -0,0 +1,12 @@
/**
* url
* @param key
* @param url
*/
export const getValueByUrlParams = (url: string) => {
if (url.indexOf('?') < 0) return;
const _params = new URLSearchParams(url.split('?')[1]);
return _params;
};

86
src/utils/request.ts Normal file
View File

@ -0,0 +1,86 @@
import type { RequestConfig } from '@umijs/max';
import { API_URL } from './constants';
const doRequest: RequestConfig = {
timeout: 1000,
baseURL: API_URL,
errorConfig: {
errorHandler(error, opts) {
console.log('errorHandler', error, opts);
// if (opts?.skipErrorHandler) throw error
// try {
// const { res } = ctx;
// const d = await res.text();
// if (res.status === 401 && store.user.isLogin) {
// store.user.resetLoginState();
// message.warning('登录过期,请重新登录!');
// return;
// }
// const isEmptyRes = d === '' || d.replace(/\s/g,"")=== 'tokenisinvalid'; //有些后端接口成功会返回空 做下兼容
// const body = !isEmptyRes ? JSON.parse(d || '{}') : d;
// const sessionCode = sessionStorage.getItem('zhst_errcode') || '{}'
// const ERROR_CODE = JSON.parse(sessionCode);
// if (Number(res.status) === 200) {
// ctx.res = body;
// } else {
// // 先判断Grpc-Metadata-Errorx-Message
// let errMsg = ERROR_CODE[body.code]?.value || body.message || '您的网络发生异常,无法连接服务器'
// toast && message.error(errMsg || body);
// ctx.res = {
// code: body.code,
// message: errMsg
// };
// }
// } catch (error) {
// if (get(error, 'type') !== 'CustomError') {
// toast && message.error('您的网络发生异常,无法连接服务器');
// }
// throw error;
// }
},
errorThrower(res) {
console.log('res', res);
},
},
// 请求
requestInterceptors: [
// 一个二元组,第一个元素是 request 拦截器,第二个元素是错误处理
[
(url, options) => {
return {
url,
options: {
...options,
headers: {
authorization: 'test',
// ...(refererSuffix ? { zhst_referer: `${baseUrl}${refererSuffix}` } : {}),
},
},
};
},
(error) => {
return Promise.reject(error);
},
],
],
// 返回
responseInterceptors: [
// 一个二元组,第一个元素是 request 拦截器,第二个元素是错误处理
[
(response) => {
if (response.status !== 200) {
throw Error(JSON.stringify(response.data));
}
return response;
},
(error) => {
return Promise.reject(error);
},
],
],
};
export default doRequest;

6
tsconfig.json Normal file
View File

@ -0,0 +1,6 @@
{
"compilerOptions": {
"jsx": "react"
},
"extends": "./src/.umi/tsconfig.json"
}

1
typings.d.ts vendored Normal file
View File

@ -0,0 +1 @@
import '@umijs/max/typings';