Commit c5c01f69 authored by 前端-钟卫鹏's avatar 前端-钟卫鹏

merge

parents 57866842 3fcaf2ac
...@@ -3,4 +3,23 @@ ...@@ -3,4 +3,23 @@
### 为数商云&醒电构建项目提供react脚手架模板 ### 为数商云&醒电构建项目提供react脚手架模板
- god页面模板, 依赖于[umi](https://umijs.org/), 更多配置可以查看 - god页面模板, 依赖于[umi](https://umijs.org/), 更多配置可以查看
- god组件库[文档](http://10.0.0.22:8080/) - god组件库[文档](http://10.0.0.22:8080/)
\ No newline at end of file
### 项目运行请先执行 scripts:build
可获取项目所需配置, 在/src/constants/cacheConfig.ts
### 全局引入的文件
- /src/global
- /styles/theme.less 默认可使用其中的less变量
- /config/index.ts 全局变量配置文件
### scripts 所需依赖
- gulp 流程工具
- chalk 控制台样式控制工具
- fs-extra 扩展fs模块
- ora 控制台加载中样式
## 开发注意事项
1. 样式
- 全局样式需写在src/global/global.less下, 涉及到color, size之类的属性尽量变量化 并且储存在/styles/theme.less中
\ No newline at end of file
{
"global": {
"logo": "",
"countryList": [
{
"name": "简体中文-ZH",
"key": "cn",
"icon": ""
},
{
"name": "English-EN",
"key": "en",
"icon": ""
},
{
"name": "日本語-JP",
"key": "jp",
"icon": ""
},
{
"name": "한국어-KO",
"key": "ko",
"icon": ""
}
]
}
}
\ No newline at end of file
...@@ -42,8 +42,12 @@ export default defineConfig({ ...@@ -42,8 +42,12 @@ export default defineConfig({
cssLoader: { cssLoader: {
localsConvention: 'camelCase', // 将style中的class由 .foo-body 转化为fooBody调用 localsConvention: 'camelCase', // 将style中的class由 .foo-body 转化为fooBody调用
}, },
cssModulesTypescriptLoader: { lessLoader: {
mode: 'emit' // 所有less文件都会引入的变量
modifyVars: {
// 或者可以通过 less 文件覆盖(文件路径为绝对路径)
'hack': `true; @import "~@/global/styles/theme.less";`
}
}, },
dynamicImport: { dynamicImport: {
loading: '@/components/Loading' loading: '@/components/Loading'
......
export default { export default {
'/api': { '/api': {
'target': 'http://jsonplaceholder.typicode.com/', 'target': 'http://10.0.0.129:8100/',
'changeOrigin': true, 'changeOrigin': true,
'pathRewrite': { '^/api' : '' }, 'pathRewrite': { '^/api' : '' },
} }
......
const mockData = {
message: '',
code: 1000,
data: {
global: {
logo: '',
countryList: [
{
name: '简体中文-ZH',
key: 'cn',
icon: ''
},
{
name: 'English-EN',
key: 'en',
icon: ''
},
{
name: '日本語-JP',
key: 'jp',
icon: ''
},
{
name: '한국어-KO',
key: 'ko',
icon: ''
}
]
}
}
}
exports.fetchConfig = async () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(mockData)
}, 2* 1000)
})
}
\ No newline at end of file
{
"global": {
"hi": 1
}
}
\ No newline at end of file
{ {
"name": "god-template", "name": "god-template",
"scripts": { "scripts": {
"scripts:build": "node scripts/run",
"start:analyze": "ANALYZE=1 umi dev", "start:analyze": "ANALYZE=1 umi dev",
"start": "umi dev", "start": "umi dev",
"build": "umi build", "build": "umi build",
...@@ -32,5 +33,12 @@ ...@@ -32,5 +33,12 @@
"react-dom": "^16.12.0", "react-dom": "^16.12.0",
"umi": "^3.2.0", "umi": "^3.2.0",
"yorkie": "^2.0.0" "yorkie": "^2.0.0"
},
"devDependencies": {
"chalk": "^4.1.0",
"fs-extra": "^9.0.1",
"gulp": "^4.0.2",
"json2ts": "^0.0.7",
"ora": "^4.0.4"
} }
} }
const path = require('path')
const Logs = require('./utils/log')
const fse = require('fs-extra')
const Type = require('./utils/type')
const fetchConfig = require('../demo').fetchConfig
const gulp = require('gulp')
const json2ts = require('json2ts')
const rootPath = '../';
const outputPath = path.resolve(__dirname, rootPath, 'config/base.config.json')
const outputDts = path.resolve(__dirname, rootPath, 'src/global/config/global.d.ts')
Logs.start('gulp start')
gulp.task('start', gulp.series(done => {
getAsyncConfig(done)
}))
/**
* 生成对应json文件
*/
function genarateBaseJson(obj, done) {
if (Type.isObject(obj)) {
fse.ensureFile(outputPath).then(() => {
fse.writeJson(outputPath, obj).then(() => {
Logs.success('\nstart genarate config json')
Logs.success('write success')
Logs.stop('Configuration has arrived locally', 'success')
genarateDtsFile(JSON.stringify(obj), done)
}).catch(err => {
Logs.error(err)
done()
})
})
} else {
Logs.error('!!!!!! value is not a object !!!!!')
Logs.error(`here is your value, the type is ${typeof obj}`)
console.log(obj)
Logs.stop('Append error!!!', 'fail')
done()
}
}
function genarateDtsFile(json, done) {
const dtsResult = json2ts.convert(json)
fse.outputFile(outputDts, dtsResult).then(() => {
done()
})
}
/**
* 异步获取远程配置
* @todo
*/
async function getAsyncConfig(done) {
const data = await fetchConfig()
genarateBaseJson(data.data, done)
}
\ No newline at end of file
const gulp = require('gulp')
function runTask(toRun) {
const metadata = { task: toRun };
// Gulp >= 4.0.0 (doesn't support events)
const taskInstance = gulp.task(toRun);
if (taskInstance === undefined) {
gulp.emit('task_not_found', metadata);
return;
}
const start = process.hrtime();
gulp.emit('task_start', metadata);
try {
taskInstance.apply(gulp);
metadata.hrDuration = process.hrtime(start);
gulp.emit('task_stop', metadata);
gulp.emit('stop');
} catch (err) {
err.hrDuration = process.hrtime(start);
err.task = metadata.task;
gulp.emit('task_err', err);
}
}
require('./gulpfile')
runTask('start')
\ No newline at end of file
const chalk = require('chalk')
const ora = require('ora')
const spinner = ora('Loading remote configuration')
const log = console.log
const Logs = {
success(msg) {
log(chalk.green(msg))
},
error(msg) {
log(chalk.red(msg))
},
start() {
spinner.start()
},
stop(msg, type) {
const instance = spinner.stop()
type === 'success' ? instance.succeed(msg) : instance.fail(msg)
}
}
module.exports = Logs
\ No newline at end of file
const Type = {
isObject(data) {
return Object.prototype.toString.call(data) === '[object Object]'
}
}
module.exports = Type
\ No newline at end of file
...@@ -2,8 +2,11 @@ import { IRoutes } from '.'; ...@@ -2,8 +2,11 @@ import { IRoutes } from '.';
import { history, RequestConfig } from 'umi'; import { history, RequestConfig } from 'umi';
import React from 'react' import React from 'react'
import MobxProvider from './store' import MobxProvider from './store'
<<<<<<< HEAD
import 'mobx-react-lite/batchingForReactDom' import 'mobx-react-lite/batchingForReactDom'
import './global.less' import './global.less'
=======
>>>>>>> 3fcaf2ac8432e3e511d10c3073e59eb1aa99a368
let extraRoutes: never[] = [] let extraRoutes: never[] = []
...@@ -70,7 +73,7 @@ let extraRoutes: never[] = [] ...@@ -70,7 +73,7 @@ let extraRoutes: never[] = []
* @param {*} container * @param {*} container
* @returns * @returns
*/ */
export function rootContainer(container) { export function rootContainer(container: any) {
return React.createElement(MobxProvider, null, container); return React.createElement(MobxProvider, null, container);
} }
...@@ -97,3 +100,17 @@ export function rootContainer(container) { ...@@ -97,3 +100,17 @@ export function rootContainer(container) {
// requestInterceptors: [], // requestInterceptors: [],
// responseInterceptors: [] // responseInterceptors: []
// } // }
<<<<<<< HEAD
=======
/**
* @description 初始化配置数据 https://umijs.org/zh-CN/plugins/plugin-initial-state#%E4%BB%8B%E7%BB%8D
* @author xjm
* @date 2020-06-10
* @export
*/
// export async function getInitialState():Promise<{menu: {title: string, logo: string}}> {
// return globalConfig
// }
>>>>>>> 3fcaf2ac8432e3e511d10c3073e59eb1aa99a368
.listCard {
margin-top: 41px;
.header {
display: flex;
align-items: center;
height: 38px;
border-bottom: 1px solid #F4F5F7;
margin-bottom: 24px;
&::before {
content: "";
width: 2px;
height: 16px;
background: @primary-color;
margin-right: 6px;
}
}
}
\ No newline at end of file
import React from 'react';
import styles from './index.less';
export interface ListCardProps {
title?: React.ReactNode,
}
const ListCard: React.FC<ListCardProps> = (props) => {
return (
<div className={styles.listCard}>
<div className={styles.header}>{props.title}</div>
{ props.children }
</div>
)
}
ListCard.defaultProps = {
title: 'header'
}
export default ListCard
\ No newline at end of file
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'link': string;
}
export const cssExports: CssExports;
export default cssExports;
export interface CountryList {
name: string;
key: string;
icon: string;
}
export interface Global {
logo: string;
countryList: CountryList[];
}
export interface RootObject {
global: Global;
}
\ No newline at end of file
/**
*
* **********
* 脚本注入全局配置
*
* **********
*/
import SELF_CONFIG from '../../../config/base.config.json'
import { RootObject } from './global'
export const GlobalConfig: RootObject = SELF_CONFIG
/********************************** 布局 ******************************************/
@import './mixins/layout.less';
@makeCenters: text, block, flex, flexAlign, flexJustify, absolute, fixed, margin;
@makeCentersLen: length(@makeCenters);
.loopCenter(@list, @i: 1, @val: extract(@list, @i)) when (@i < @makeCentersLen + 1) {
.center-@{val} {
.make-center(@val);
}
.loopCenter(@list, @i + 1)
};
.loopCenter(@makeCenters);
// antd default
h1, h2, h3, h4, h5, h6 {
color: #6B778C;
}
.@{prefix}-margin_content {
.center-margin;
width: 1190px;
}
.@{prefix}-content1024 {
.center-margin;
width: 1024px;
}
/**
* @description 布局类
* @author xjm
*/
// ------------ 容器container ------------
.make-container(@pad-x: @padding-lg) {
width: 100%;
.make-center(block);
}
.make-container(@pad-x) when not (@pad-x = none) {
padding-left: @pad-x;
padding-right: @pad-x;
}
// ------------ 居中相关 center ------------
.make-center(@type:text) {}
.make-center(@type) when (@type = text) {
text-align: center;
}
.make-center(@type) when (@type = margin) {
margin-left: auto;
margin-right: auto;
}
.make-center(@type) when (@type = block) {
.make-center(center);
display: block;
}
.make-center(@type) when (@type = flex) {
display: flex;
justify-content: center;
align-items: center;
}
.make-center(@type) when (@type = flexAlign) {
display: flex;
align-items: center;
}
.make-center(@type) when (@type = flexJustify) {
display: flex;
justify-content: center;
}
.make-center(@type) when (@type = absolute), (@type = fixed) {
position: @type;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
...@@ -2,20 +2,21 @@ export interface IRoutes { ...@@ -2,20 +2,21 @@ export interface IRoutes {
routes: [] routes: []
} }
/** /**
* @todo
* @description 定义请求成功的接口模型 * @description 定义请求成功的接口模型
* @author xjm * @author xjm
* @date 2020-05-25 * @date 2020-06-01
* @export * @export
* @interface IRequest * @interface IRequestSuccess
* @template T data类型, 无法指定时可传入any
*/ */
export interface IRequest { export interface IRequestSuccess<T> {
code: number,
data: T,
message: string,
time: number
} }
/** /**
* @todo * @todo
* @description 定义请求失败时的接口模型 * @description 定义请求失败时的接口模型
...@@ -24,6 +25,9 @@ export interface IRequest { ...@@ -24,6 +25,9 @@ export interface IRequest {
* @export * @export
* @interface IRequestError * @interface IRequestError
*/ */
export interface IRequestError { export interface IRequestError extends Error {
data?: any,
message: string,
time?: number
}
}
\ No newline at end of file
...@@ -27,21 +27,4 @@ const UserHeader:React.FC<UserHeaderProps> = (props) => { ...@@ -27,21 +27,4 @@ const UserHeader:React.FC<UserHeaderProps> = (props) => {
) )
} }
UserHeader.defaultProps = {
// 开发环境下的替代logo
logo: require('../../../mockStatic/logo.png'),
countryList: [
{
name: '中国',
key: 'China',
icon: require('../../../mockStatic/china.png')
},
{
name: '美国',
key: 'US',
icon: require('../../../mockStatic/us.png')
}
]
}
export default UserHeader export default UserHeader
\ No newline at end of file
@import '~@/styles/theme.less';
.@{prefix}-margin_content { .@{prefix}-margin_content {
width: 1190px; width: 1190px;
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
// footer // footer
.@{prefix}-user-footer { .@{prefix}-user-footer {
padding-top: 32px; padding: 32px 0;
font-size: 14px; font-size: 14px;
color: #97A0AF; color: #97A0AF;
text-align: center; text-align: center;
......
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'fixed': string;
'lingxi-business-logo': string;
'lingxi-business-margin_content': string;
'lingxi-business-user-bg': string;
'lingxi-business-user-footer': string;
'lingxi-business-user-header': string;
'lingxi-business-user-layout': string;
'lingxiBusinessLogo': string;
'lingxiBusinessMarginContent': string;
'lingxiBusinessUserBg': string;
'lingxiBusinessUserFooter': string;
'lingxiBusinessUserHeader': string;
'lingxiBusinessUserLayout': string;
}
export const cssExports: CssExports;
export default cssExports;
import React from 'react';
import styles from '../index.less';
import { Radio } from 'antd';
export interface ButtonListProps {
size?: 'default' | 'large',
group: {value: string, text?: React.ReactNode, key: string}[]
}
const ButtonList: React.FC<ButtonListProps> = (props) => {
return (
<div className={styles.margin320}>
<Radio.Group>
{
props.group.map(v => <Radio.Button value={v.value} key={v.key} className={props.size === 'default' ? styles.default : styles.large}>{v.text}</Radio.Button>)
}
</Radio.Group>
</div>
)
}
ButtonList.defaultProps = {
size: 'default'
}
export default ButtonList
\ No newline at end of file
...@@ -8,10 +8,15 @@ import { ...@@ -8,10 +8,15 @@ import {
import styles from '../index.less' import styles from '../index.less'
const LoginWrap: React.FC = () => { const LoginWrap: React.FC = () => {
<<<<<<< HEAD
const [validFrame, setValidFrame] = useState(false) const [validFrame, setValidFrame] = useState(false)
const [validButton, setValidButton] = useState(false) const [validButton, setValidButton] = useState(false)
const finish = (value) => { const finish = (value) => {
=======
const isValied = true
const finish = (value: any) => {
>>>>>>> 3fcaf2ac8432e3e511d10c3073e59eb1aa99a368
console.log(value) console.log(value)
} }
return ( return (
......
@import '~@/global.less'; @import '~@/global/styles/global.less';
.login-item { .login-item {
flex: 1; flex: 1;
...@@ -86,7 +86,8 @@ ...@@ -86,7 +86,8 @@
.registerBox { .registerBox {
width: 100%; width: 100%;
//height: 700px; min-height: 700px;
padding-bottom: 40px;
background: #fff; background: #fff;
padding-bottom: 40px; padding-bottom: 40px;
} }
...@@ -98,8 +99,11 @@ ...@@ -98,8 +99,11 @@
display: flex; display: flex;
align-items: center; align-items: center;
} }
.formBoxStep1 { .formBoxStep1 {
width: 320px; width: 320px;
.form-box {
width: 340px;
margin: 40px auto 0; margin: 40px auto 0;
} }
...@@ -185,3 +189,44 @@ ...@@ -185,3 +189,44 @@
margin: 0 auto; margin: 0 auto;
} }
} }
=======
.agreement {
font-size: 12px;
}
.checkTypes {
width: 702px;
margin: 0 auto;
}
.margin320 {
width: 320px;
margin-left: auto;
margin-right: auto;
display: block;
}
.default {
width: 148px;
margin-right: 24px;
margin-bottom: 16px;
text-align: center;
height: 32px;
line-height: 32px;
&:nth-child(2n) {
margin-right: 0;
}
}
.large {
width: 320px;
margin-bottom: 24px;
text-align: center;
height: 48px;
line-height: 48px;
}
.btnCenter {
width: 320px;
margin-left: auto;
margin-right: auto;
display: block;
}
>>>>>>> 3fcaf2ac8432e3e511d10c3073e59eb1aa99a368
import React, { useState } from 'react'; import React, { useState } from 'react';
import globalStyles from '@/global.less'; import globalStyles from '@/global/styles/global.less';
import styles from './index.less' import styles from './index.less'
import cx from 'classnames'; import cx from 'classnames';
import { Row, Col, Form, Input, Button, Space } from 'antd'; import { Row, Col, Form, Input, Button, Space } from 'antd';
......
...@@ -5,7 +5,7 @@ import { ...@@ -5,7 +5,7 @@ import {
QuestionCircleOutlined QuestionCircleOutlined
} from '@ant-design/icons'; } from '@ant-design/icons';
import styles from './index.less' import styles from './index.less'
import globalStyles from '@/global.less' import globalStyles from '@/global/styles/global.less'
import cx from 'classnames' import cx from 'classnames'
import { FormPage } from 'god' import { FormPage } from 'god'
import { IFormControllers, IFormButtonTypes } from 'god/dist/src/form-page' import { IFormControllers, IFormButtonTypes } from 'god/dist/src/form-page'
...@@ -94,7 +94,7 @@ const registerForm: IFormControllers[] = [ ...@@ -94,7 +94,7 @@ const registerForm: IFormControllers[] = [
} }
}, },
{ {
type: 'CheckBox', type: 'Agreement',
name: 'readme', name: 'readme',
span: 24, span: 24,
labelCol: { labelCol: {
...@@ -120,14 +120,14 @@ const registerButtons: IFormButtonTypes[] = [ ...@@ -120,14 +120,14 @@ const registerButtons: IFormButtonTypes[] = [
} }
] ]
let timeChange; // 定时器 let timeChange: any; // 定时器
const UserRegistry = () => { const UserRegistry = () => {
const [identityForm1] = Form.useForm(); const [identityForm1] = Form.useForm();
const [licenseForm] = Form.useForm(); const [licenseForm] = Form.useForm();
const [current, setCurrent] = useState(1.1) const [current, setCurrent] = useState(1.1)
const handleOneSubmit = (values) => { const handleOneSubmit = (values: any) => {
console.log(values, 'values') console.log(values, 'values')
if(values.phone) setCurrent(1) if(values.phone) setCurrent(1)
} }
...@@ -136,16 +136,16 @@ const UserRegistry = () => { ...@@ -136,16 +136,16 @@ const UserRegistry = () => {
history.push('/user/login') history.push('/user/login')
} }
const onChange = (value) => { const onChange = (value: any) => {
console.log(value.target.value,'value') console.log(value.target.value,'value')
} }
const handleSecondSubmit = (values) => { const handleSecondSubmit = (values: any) => {
console.log(values,'values') console.log(values,'values')
setCurrent(1.1) setCurrent(1.1)
} }
const handleLicenseSubmit = (values) => { const handleLicenseSubmit = (values: any) => {
console.log(values, 'values') console.log(values, 'values')
setCurrent(2) setCurrent(2)
} }
...@@ -170,7 +170,7 @@ const UserRegistry = () => { ...@@ -170,7 +170,7 @@ const UserRegistry = () => {
timeChange = setInterval(() => setTime(t => --t), 1000) timeChange = setInterval(() => setTime(t => --t), 1000)
} }
const normFile = e => { const normFile = (e: any) => {
console.log('上传Upload 事件:', e); console.log('上传Upload 事件:', e);
if (Array.isArray(e)) { if (Array.isArray(e)) {
return e; return e;
...@@ -178,7 +178,7 @@ const UserRegistry = () => { ...@@ -178,7 +178,7 @@ const UserRegistry = () => {
return e && e.fileList; return e && e.fileList;
} }
const checkoutFile = (rule, value) => { const checkoutFile = (rule: any, value: any) => {
if(value && value.length){ if(value && value.length){
let length = value.length let length = value.length
let obj = value[length-1] let obj = value[length-1]
...@@ -193,7 +193,7 @@ const UserRegistry = () => { ...@@ -193,7 +193,7 @@ const UserRegistry = () => {
} }
} }
const beforeUpload = (file) => { const beforeUpload = (file: any) => {
const isLt5M = file.size / 1024 / 1024 < 5; const isLt5M = file.size / 1024 / 1024 < 5;
if (!isLt5M) { if (!isLt5M) {
message.error('附件大小不能超过5M!'); message.error('附件大小不能超过5M!');
...@@ -208,7 +208,7 @@ const UserRegistry = () => { ...@@ -208,7 +208,7 @@ const UserRegistry = () => {
<div className={styles.registerBox}> <div className={styles.registerBox}>
<Steps current={current} className={styles.stepWrap} size='small'> <Steps current={current} className={styles.stepWrap} size='small'>
{ {
stepList.map(v => <Step title={v.title} key={v.key}/>) stepList.map((v,i) => <Step title={v.title} key={v.key} onClick={() => {setCurrent(i)}}/>)
} }
</Steps> </Steps>
{ {
......
declare namespace API { declare namespace API {
export interface currentUser {
name?: string;
age?: number;
}
} }
\ No newline at end of file
import BaseService from "../baseService";
const mockData = () => {
return new Promise(resolve => {
setTimeout(() => {
resolve({
data: 10,
success: true
})
}, 2000)
})
}
class AccountController extends BaseService {
constructor() {
super()
}
async add() {
try {
const data = await mockData()
return data
} catch(err) {
return err
}
}
async delete() {
}
async update() {
}
async getList() {
}
}
export default new AccountController()
\ No newline at end of file
/**
* @todo
* @description 公共请求方法
* @author xjm
* @date 2020-05-25
* @class BaseService
*/
class BaseService {
protected success(data) {
return Promise.resolve(data)
}
protected error(err) {
return Promise.reject(err)
}
}
export default BaseService
\ No newline at end of file
// 用于表格数据时的模型定义
export interface ApiListData<T> {
data: T[],
totalCount: number
}
\ No newline at end of file
import AccountCtroller from './account'
const Services = {
AccountCtroller
}
export default Services
\ No newline at end of file
declare namespace MemberApi {
interface RegisterBasicModel {
phone: string;
smsCode: string;
password: string;
email: string;
}
interface RegisterBasicDTO {
id: number
}
}
\ No newline at end of file
import request from '@/utils/request';
const prefix = '/member/merchant'
/**
* @description 用户基础注册接口
* @param {MemberApi.RegisterBasicModel} params
*/
export async function postMemberRegister(params: MemberApi.RegisterBasicModel) {
return request<MemberApi.RegisterBasicDTO>('/member/register/basic', {
prefix,
method: 'post',
data: params
})
}
...@@ -7,7 +7,16 @@ function isObject(obj: any) { ...@@ -7,7 +7,16 @@ function isObject(obj: any) {
return Object.prototype.toString.call(obj) === '[object Object]' return Object.prototype.toString.call(obj) === '[object Object]'
} }
export function omit(obj: any, arr: string[]) {
const tempObj = {...obj}
for (let i = 0; i < arr.length; i++) {
delete tempObj[arr[i]]
}
return tempObj
}
export default { export default {
isArray, isArray,
isObject isObject,
omit
} }
\ No newline at end of file
import { extend } from 'umi-request'; import { extend, ResponseError, OnionOptions, RequestOptionsInit, ResponseInterceptor, OnionMiddleware, Context, RequestMethod } from 'umi-request';
import responseCode from '@/constants/responseCode' import responseCode from '@/constants/responseCode'
import { IRequestError, IRequestSuccess } from '..';
import { message } from 'antd'
export type CtlType = 'none' | 'message'
// 根前缀请求路径
const basePrefix = '/api'
export interface IApiRequest extends RequestOptionsInit {
ctlType?: CtlType
// 可以用于扩展请求配置
extendsOptions?: RequestOptionsInit
}
/** /**
* *
* umi-request文档 https://github.com/umijs/umi-request/blob/master/README_zh-CN.md * umi-request文档 https://github.com/umijs/umi-request/blob/master/README_zh-CN.md
* *
*/ */
type httpStatus = {
[key: number]: string
}
const errorMessage: httpStatus = {
400: "发出的请求有错误,服务器没有进行新建或修改数据的操作。",
401: "用户没有权限(令牌、用户名、密码错误)。",
403: "用户得到授权,但是访问是被禁止的。",
404: "发出的请求针对的是不存在的记录,服务器没有进行操作。",
406: "请求的格式不可得。",
410: "请求的资源被永久删除,且不会再得到的。",
422: "当创建一个对象时,发生一个验证错误。",
500: "服务器发生错误,请检查服务器。",
502: "网关错误。",
503: "服务不可用,服务器暂时过载或维护。",
504: "网关超时。",
};
const errorHandler = (error: ResponseError):IRequestError => {
const { response } = error
// http状态码非200的错误处理
const messageText = errorMessage[response.status]
if (response) {
message.error('http请求错误: ' + response.status + '->' + messageText, 3)
}
// throw可令响应promise走catch, 如需走resolve需直接return
throw {
message: messageText,
...error
}
}
const defaultHeaders = {
'Content-Type': 'Application/json'
}
/** /**
* 配置request请求时的默认参数, 底层使用fetch进行请求 * 配置request请求时的默认参数, 底层使用fetch进行请求
*/ */
const request = extend({ const baseRequest = extend({
timeout: 30 * 1000, timeout: 30 * 1000,
headers: defaultHeaders,
credentials: 'include', // 默认请求是否带上cookie credentials: 'include', // 默认请求是否带上cookie
errorHandler
});
// 请求拦截器
baseRequest.interceptors.request.use((url: string, options: RequestOptionsInit):{ url: string, options: RequestOptionsInit } => {
return {
// 前缀如果已经带上api, 跳过自动补前缀
url: url.startsWith('/api') ? url : basePrefix + url,
options,
};
});
// 响应拦截器
baseRequest.interceptors.response.use((response: Response, options: RequestOptionsInit) => {
return response;
}); });
export default request; // 请求中间件
\ No newline at end of file baseRequest.use(async (ctx: Context, next: () => void) => {
await next()
})
/**
* 公共请求层
*/
class ApiRequest {
createRequest <T>(url: string, options: IApiRequest = { ctlType: 'none' }): Promise<IRequestSuccess<T>> {
return new Promise((resolve, reject) => {
baseRequest<IRequestSuccess<T>>(url, options).then(res => {
if (res.code === 1000) {
options.ctlType === 'message' && message.success(res.message)
resolve(res)
} else {
message.error(res.message)
}
}).catch((err: IRequestError) => {
// http错误处理, 直接透传
reject(err)
})
})
}
}
export default new ApiRequest().createRequest;
\ No newline at end of file
export function isString(str):str is string { export function isString(str: any):str is string {
return typeof str === 'string' return typeof str === 'string'
} }
\ No newline at end of file
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
"moduleResolution": "node", "moduleResolution": "node",
"importHelpers": true, "importHelpers": true,
"jsx": "react", "jsx": "react",
"noImplicitAny": false,
"esModuleInterop": true, "esModuleInterop": true,
"sourceMap": true, "sourceMap": true,
"baseUrl": "./", "baseUrl": "./",
......
declare module '*.css'; declare module '*.css';
declare module '*.less'; declare module '*.less';
declare module "*.png"; declare module "*.png";
declare module "classnames";
declare module "*.json";
declare module '*.svg' { declare module '*.svg' {
export function ReactComponent(props: React.SVGProps<SVGSVGElement>): React.ReactElement export function ReactComponent(props: React.SVGProps<SVGSVGElement>): React.ReactElement
const url: string const url: string
export default url export default url
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment