@quansitech/antd-admin 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/components/Column/Cascader.tsx +79 -0
  2. package/components/Column/File.tsx +168 -0
  3. package/components/Column/Image.tsx +77 -0
  4. package/components/Column/Readonly/Cascader.tsx +51 -0
  5. package/components/Column/Readonly/File.tsx +54 -0
  6. package/components/Column/Readonly/Image.tsx +78 -0
  7. package/components/Column/Readonly/Option.tsx +58 -0
  8. package/components/Column/Readonly/types.d.ts +9 -0
  9. package/components/Column/Ueditor.tsx +314 -0
  10. package/components/Column/types.d.ts +29 -0
  11. package/components/Form/Action/Button.tsx +125 -0
  12. package/components/Form/Action/types.d.ts +5 -0
  13. package/components/Form/Actions.tsx +35 -0
  14. package/components/Form.tsx +171 -0
  15. package/components/FormContext.ts +8 -0
  16. package/components/Layout.tsx +237 -0
  17. package/components/LayoutContext.ts +26 -0
  18. package/components/ModalContext.ts +16 -0
  19. package/components/Table/Action/Button.tsx +89 -0
  20. package/components/Table/Action/StartEditable.tsx +59 -0
  21. package/components/Table/Action/types.d.ts +7 -0
  22. package/components/Table/Option/Link.tsx +68 -0
  23. package/components/Table/Option/types.d.ts +5 -0
  24. package/components/Table/ToolbarActions.tsx +39 -0
  25. package/components/Table.scss +7 -0
  26. package/components/Table.tsx +279 -0
  27. package/components/TableContext.ts +14 -0
  28. package/components/Tabs.tsx +72 -0
  29. package/components/types.d.ts +0 -0
  30. package/lib/container.ts +82 -0
  31. package/lib/customRule.ts +10 -0
  32. package/lib/global.ts +11 -0
  33. package/lib/helpers.tsx +150 -0
  34. package/lib/http.ts +74 -0
  35. package/lib/schemaHandler.ts +122 -0
  36. package/lib/upload.ts +177 -0
  37. package/package.json +35 -0
  38. package/readme.md +128 -0
@@ -0,0 +1,279 @@
1
+ import React, {lazy, Suspense, useContext, useEffect, useRef, useState} from "react";
2
+ import {
3
+ ActionType,
4
+ FormInstance,
5
+ ProColumnType,
6
+ ProSkeleton,
7
+ ProTable,
8
+ ProTableProps
9
+ } from "@ant-design/pro-components";
10
+ import type {SortOrder} from "antd/lib/table/interface";
11
+ import {TablePaginationConfig} from "antd/es/table";
12
+ import isArray from "lodash/isArray"
13
+ import upperFirst from "lodash/upperFirst"
14
+ import {TableContext} from "./TableContext";
15
+ import ToolbarActions from "./Table/ToolbarActions";
16
+ import container from "../lib/container";
17
+ import {TableActionProps} from "./Table/Action/types";
18
+ import http from "../lib/http";
19
+ import {Spin} from "antd";
20
+ import "./Table.scss"
21
+ import {ModalContext} from "./ModalContext";
22
+ import cloneDeep from "lodash/cloneDeep";
23
+ import uniqueId from "lodash/uniqueId";
24
+ import {commonHandler} from "../lib/schemaHandler";
25
+
26
+ export type TableProps = ProTableProps<any, any> & {
27
+ columns: ProColumnType[],
28
+ dataSource: any[],
29
+ pagination: TablePaginationConfig & {
30
+ paramName?: string,
31
+ },
32
+ rowKey: string,
33
+ defaultSearchValue?: Record<string, any>,
34
+ actions: TableActionProps[],
35
+ searchUrl: string,
36
+ search?: boolean,
37
+ }
38
+
39
+ export default function (props: TableProps) {
40
+
41
+
42
+ const request = async (params: Record<string, any> & {
43
+ pageSize: number,
44
+ current: number
45
+ }, sort: Record<string, SortOrder>, filter: Record<string, (string | number)[] | null>) => {
46
+ setLoading(true)
47
+ const data: Record<string, any> = {
48
+ ...params,
49
+ ...filter,
50
+ sort,
51
+ }
52
+ if (props.pagination) {
53
+ data[props.pagination.paramName || 'page'] = data.current
54
+ delete data.current
55
+ delete data.pageSize
56
+ }
57
+
58
+ setEditableKeys([])
59
+ setEditableValues([])
60
+
61
+ try {
62
+ const res = await http.get(props.searchUrl, {
63
+ params: data,
64
+ headers: {
65
+ 'X-Table-Search': '1'
66
+ }
67
+ })
68
+
69
+ if (res.data.pagination) {
70
+ setPagination({
71
+ ...res.data.pagination,
72
+ current: params.current,
73
+ })
74
+ }
75
+ return {
76
+ data: res.data.dataSource || [],
77
+ success: true,
78
+ }
79
+ } finally {
80
+ setLoading(false)
81
+ }
82
+ }
83
+
84
+ const formRef = useRef<FormInstance>()
85
+ const actionRef = useRef<ActionType>()
86
+ const [editableKeys, setEditableKeys] = useState<React.Key[]>(() => [])
87
+ const [columns, setColumns] = useState<ProColumnType[]>([])
88
+ const [selectedRows, setSelectedRows] = useState<any[]>([])
89
+ const [editableValues, setEditableValues] = useState<Record<string, any>[]>([])
90
+ const [loading, setLoading] = useState(false)
91
+ const [initialized, setInitialized] = useState(false)
92
+ const [pagination, setPagination] = useState<TablePaginationConfig>()
93
+ const [dataSource, setDataSource] = useState<any[]>([])
94
+ const [sticky, setSticky] = useState<TableProps['sticky']>(true)
95
+
96
+ const modalContext = useContext(ModalContext)
97
+
98
+ useEffect(() => {
99
+ setPagination(props.pagination as TablePaginationConfig || false)
100
+ setDataSource(postData(props.dataSource))
101
+
102
+ // 重新定义列
103
+ setColumns(cloneDeep(props.columns)?.map((c: ProColumnType) => {
104
+ c.key = c.dataIndex as string
105
+
106
+ // 列render
107
+ const renderComponent = 'Column.Readonly.' + upperFirst(c.valueType as string)
108
+ if (container.check(renderComponent)) {
109
+ const Component = lazy(container.get(renderComponent))
110
+ c.render = (dom, record, _, action) =>
111
+ <Suspense fallback={<Spin/>}>
112
+ <Component {...c}
113
+ key={c.title as string}
114
+ record={record}
115
+ ></Component>
116
+ </Suspense>
117
+ }
118
+
119
+ // 列查询及编辑render
120
+ const formItemComponent = 'Column.' + upperFirst(c.valueType as string)
121
+ if (container.check(formItemComponent)) {
122
+ const Component = lazy(container.get(formItemComponent))
123
+ c.renderFormItem = (schema, config, form) => (
124
+ <Suspense fallback={<Spin/>}>
125
+ <Component config={config}
126
+ form={form}
127
+ schema={schema}
128
+ fieldProps={c.fieldProps}
129
+ key={c.title as string}
130
+ ></Component>
131
+ </Suspense>
132
+ )
133
+ }
134
+
135
+ if (props.defaultSearchValue?.[c.dataIndex as string] !== undefined) {
136
+ c.initialValue = props.defaultSearchValue[c.dataIndex as string]
137
+ }
138
+
139
+ commonHandler(c)
140
+ if (container.schemaHandler[c.valueType as string]) {
141
+ return container.schemaHandler[c.valueType as string](c) as ProColumnType
142
+ }
143
+
144
+ return c
145
+ }))
146
+
147
+ setLoading(false)
148
+ setInitialized(true)
149
+
150
+ if (!modalContext.inModal) {
151
+ setSticky({
152
+ offsetHeader: document.querySelector('.ant-layout-header')?.clientHeight || 56,
153
+ })
154
+ }
155
+
156
+ }, []);
157
+
158
+ const postData = (data: any[]) => {
159
+ if (!isArray(data)) {
160
+ return data
161
+ }
162
+
163
+ props.columns.map(column => {
164
+ switch (column.valueType) {
165
+ case 'dateTime':
166
+ data = data.map(row => {
167
+ const v = row[column.dataIndex]
168
+ if (parseInt(v) == v && v < 4102444800) {
169
+ row[column.dataIndex] *= 1000
170
+ }
171
+ return row
172
+ })
173
+ break;
174
+ }
175
+ })
176
+
177
+ return data.map(row => {
178
+ if (typeof row[props.rowKey] === 'undefined') {
179
+ row[props.rowKey] = uniqueId('row_')
180
+ }
181
+ return row
182
+ })
183
+ }
184
+
185
+
186
+ return <>
187
+ <TableContext.Provider value={{
188
+ getTableProps: () => props,
189
+ getEditedValues: () => editableValues,
190
+ editableKeys: editableKeys,
191
+ actionRef: actionRef.current,
192
+ formRef: formRef.current,
193
+ }}>
194
+ {!initialized && <ProSkeleton type={"list"} list={2}></ProSkeleton>}
195
+ <ProTable rowKey={props.rowKey}
196
+ style={{display: initialized ? 'block' : 'none'}}
197
+ tableClassName={'qs-antd-table'}
198
+ columns={columns}
199
+ onDataSourceChange={setDataSource}
200
+ dataSource={dataSource}
201
+ pagination={pagination}
202
+ loading={loading}
203
+ scroll={{x: true}}
204
+ postData={postData}
205
+ sticky={sticky}
206
+ form={{
207
+ onValuesChange(changedValues) {
208
+ const key = Object.keys(changedValues)[0]
209
+ const c = columns.find(c => c.dataIndex === key) as ProColumnType & {
210
+ searchOnChange: boolean
211
+ }
212
+ if (!c) {
213
+ return
214
+ }
215
+ // 是否立即搜索
216
+ if (c.searchOnChange) {
217
+ formRef.current?.submit()
218
+ }
219
+ }
220
+ }}
221
+ rowSelection={props.rowSelection && {
222
+ alwaysShowAlert: false,
223
+ selectedRowKeys: selectedRows.map(item => item[props.rowKey]),
224
+ onSelect(record, selected) {
225
+ if (selected) {
226
+ setSelectedRows([...selectedRows, record])
227
+ } else {
228
+ setSelectedRows(selectedRows.filter(item => item[props.rowKey] !== record[props.rowKey]))
229
+ }
230
+ },
231
+ onChange(selectedRowKeys, newSelectedRows, info) {
232
+ switch (info.type) {
233
+ case 'all':
234
+ if (newSelectedRows.length) {
235
+ setSelectedRows([
236
+ ...selectedRows,
237
+ ...newSelectedRows.filter(item => !selectedRows.find(s => s[props.rowKey] == item[props.rowKey]))
238
+ ])
239
+ } else {
240
+ setSelectedRows(selectedRows.filter(item => !props.dataSource.find(dr => dr[props.rowKey] == item[props.rowKey])))
241
+ }
242
+ break;
243
+ case 'none':
244
+ setSelectedRows([])
245
+ break;
246
+ }
247
+ },
248
+ }}
249
+ toolbar={{
250
+ filter: true,
251
+ }}
252
+ toolBarRender={(action) => [
253
+ <ToolbarActions key={'actions'} actions={props.actions}
254
+ selectedRows={selectedRows}></ToolbarActions>
255
+ ]}
256
+ editable={{
257
+ type: 'multiple',
258
+ editableKeys: editableKeys,
259
+ onChange: setEditableKeys,
260
+ onValuesChange(record) {
261
+ setEditableValues([
262
+ ...editableValues.filter(item => item[props.rowKey] !== record[props.rowKey]),
263
+ record
264
+ ])
265
+ }
266
+ }}
267
+ cardBordered
268
+ manualRequest={true}
269
+ request={request}
270
+ formRef={formRef}
271
+ actionRef={actionRef}
272
+ search={props.search}
273
+ dateFormatter={props.dateFormatter}
274
+ ></ProTable>
275
+
276
+ </TableContext.Provider>
277
+ </>
278
+ }
279
+
@@ -0,0 +1,14 @@
1
+ import React, {createContext} from "react";
2
+ import {ActionType} from "@ant-design/pro-components";
3
+ import {TableProps} from "./Table";
4
+ import {FormInstance} from "antd/lib/form";
5
+
6
+ type TableContextValue = {
7
+ getTableProps: () => TableProps,
8
+ getEditedValues: () => Record<string, any>[],
9
+ editableKeys: React.Key[],
10
+ actionRef?: ActionType,
11
+ formRef?: FormInstance,
12
+ }
13
+
14
+ export const TableContext = createContext({} as TableContextValue)
@@ -0,0 +1,72 @@
1
+ import {Tabs} from "antd";
2
+ import {lazy, Suspense, useEffect, useState} from "react";
3
+ import type {Tab} from 'rc-tabs/lib/interface';
4
+ import container from "../lib/container";
5
+ import {routerNavigateTo} from "../lib/helpers";
6
+ import upperFirst from "lodash/upperFirst";
7
+ import {ProSkeleton} from "@ant-design/pro-components";
8
+
9
+ type TabProps = {
10
+ title: string,
11
+ url?: string,
12
+ pane?: {
13
+ component: 'form' | 'table',
14
+ props: any,
15
+ }
16
+ }
17
+
18
+ export type TabsPageType = {
19
+ tabs: Record<string, TabProps>,
20
+ defaultActiveKey?: string,
21
+ }
22
+
23
+ export default function (props: TabsPageType) {
24
+ const [items, setItems] = useState<Tab[]>([]);
25
+ const [activeKey, setActiveKey] = useState<string>();
26
+
27
+ useEffect(() => {
28
+ setActiveKey(props.defaultActiveKey || Object.keys(props.tabs)[0])
29
+
30
+ setItems(Object.keys(props.tabs).map(key => {
31
+ const t = props.tabs[key]
32
+
33
+ if (!t.pane) {
34
+ return {
35
+ key,
36
+ label: t.title,
37
+ children: <>
38
+ <ProSkeleton list={2}></ProSkeleton>
39
+ </>
40
+ }
41
+ }
42
+
43
+ const Component = lazy(() => container.get('Tab.Pane.' + upperFirst(t.pane?.component)))
44
+
45
+ return {
46
+ key,
47
+ label: t.title,
48
+ children: <>
49
+ <Suspense>
50
+ <Component {...t.pane.props}></Component>
51
+ </Suspense>
52
+ </>
53
+ }
54
+ }))
55
+ }, []);
56
+
57
+ const onChange = (key: string) => {
58
+ setActiveKey(key)
59
+
60
+ const tab = props.tabs[key]
61
+ if (tab.url) {
62
+ routerNavigateTo(tab.url)
63
+ }
64
+ }
65
+
66
+ return <>
67
+ <Tabs items={items}
68
+ onChange={onChange}
69
+ activeKey={activeKey}
70
+ ></Tabs>
71
+ </>
72
+ }
File without changes
@@ -0,0 +1,82 @@
1
+ import {schemaHandler} from "./schemaHandler";
2
+
3
+ const components: Record<string, any> = {}
4
+
5
+ const container = {
6
+ register(name: string, componentLoader: any) {
7
+ if (this.check(name)) {
8
+ throw new Error(`Component ${name} already registered`)
9
+ }
10
+ components[name] = componentLoader
11
+ },
12
+ get(name: string) {
13
+ if (!this.check(name)) {
14
+ throw new Error(`Component ${name} is not registered`)
15
+ }
16
+ return components[name]
17
+ },
18
+ check(name: string) {
19
+ return !!components[name]
20
+ },
21
+ schemaHandler,
22
+ };
23
+
24
+ function autoRegister(prefix: string, components: Record<string, () => Promise<any>>) {
25
+ for (const [key, value] of Object.entries(components)) {
26
+ const name = key.split('/').pop()?.split('.').shift()
27
+ container.register(prefix + name, value)
28
+ }
29
+ }
30
+
31
+ // -------- 通用 -----------
32
+ {
33
+ const columnRender = import.meta.glob('../components/Column/*.tsx')
34
+ autoRegister('Column.', columnRender)
35
+
36
+ // readonly render
37
+ const columnReadonlyRender = import.meta.glob('../components/Column/Readonly/*.tsx')
38
+ autoRegister('Column.Readonly.', columnReadonlyRender)
39
+ }
40
+
41
+ // -------- 弹窗 -----------
42
+ {
43
+ container.register('Modal.Table', import('../components/Table'))
44
+ container.register('Modal.Form', import('../components/Form'))
45
+ }
46
+
47
+ // -------- Tabs -----------
48
+ {
49
+ container.register('Tab.Pane.Table', import('../components/Table'))
50
+ container.register('Tab.Pane.Form', import('../components/Form'))
51
+ }
52
+
53
+ // -------- 表格 -----------
54
+ {
55
+ // options render
56
+ const optionsRender = import.meta.glob('../components/Table/Option/*.tsx')
57
+ autoRegister('Table.Option.', optionsRender)
58
+
59
+ // action render
60
+ const actionRender = import.meta.glob('../components/Table/Action/*.tsx')
61
+ autoRegister('Table.Action.', actionRender)
62
+ }
63
+
64
+ // -------- 表单 -----------
65
+ {
66
+
67
+ // formAction render
68
+ const formActionRender = import.meta.glob('../components/Form/Action/*.tsx')
69
+ autoRegister('Form.Action.', formActionRender)
70
+ }
71
+
72
+
73
+ ;((globalThis: any) => {
74
+ if (globalThis.$qsContainer) {
75
+ return;
76
+ }
77
+
78
+ globalThis.$qsContainer = container
79
+
80
+ })(window)
81
+
82
+ export default container
@@ -0,0 +1,10 @@
1
+ import {RuleObject, StoreValue} from "rc-field-form/lib/interface";
2
+
3
+ const customRule: Record<string, (rule: RuleObject, value: StoreValue, callback: (error?: string) => void) => any> = {
4
+ notInEnum(rule, value) {
5
+ return !rule.enum?.includes(value);
6
+
7
+ }
8
+ }
9
+
10
+ export default customRule
package/lib/global.ts ADDED
@@ -0,0 +1,11 @@
1
+ import {MessageInstance} from "antd/es/message/interface";
2
+ import {ModalStaticFunctions} from "antd/es/modal/confirm";
3
+ import {NotificationInstance} from "antd/es/notification/interface";
4
+
5
+ const global = {} as {
6
+ message: MessageInstance,
7
+ modal: Omit<ModalStaticFunctions, 'warn'>,
8
+ notification: NotificationInstance,
9
+ }
10
+
11
+ export default global
@@ -0,0 +1,150 @@
1
+ import {router} from "@inertiajs/react";
2
+ import {VisitOptions} from "@inertiajs/core/types/types";
3
+ import Schema from '@rc-component/async-validator';
4
+ import {Rules, ValidateError, ValidateFieldsError, Values} from "@rc-component/async-validator/lib/interface";
5
+ import {Spin} from "antd";
6
+ import http from "./http";
7
+ import container from "./container";
8
+ import upperFirst from "lodash/upperFirst";
9
+ import {lazy, Suspense} from "react";
10
+ import global from "./global";
11
+ import {ModalContext} from "../components/ModalContext";
12
+
13
+ export function replaceUrl(url: string, params: any) {
14
+ return url.replace(/__([\w]+)__/g, (match, key) => {
15
+ return params[key] || match;
16
+ })
17
+ }
18
+
19
+ export function replaceParams(params: Record<string, any>, data: Record<string, any>) {
20
+ if (typeof params !== 'object') {
21
+ return params;
22
+ }
23
+ const res = Object.assign({}, params);
24
+ Object.keys(params).forEach(key => {
25
+ if (typeof params[key] === 'string') {
26
+ const m = params[key].match(/^__(\w+)__$/)
27
+ if (m) {
28
+ res[key] = data[m[1]];
29
+ }
30
+ }
31
+ })
32
+ return res;
33
+ }
34
+
35
+ export function routerNavigateTo(url: string, config?: VisitOptions) {
36
+ return router.visit(url, {
37
+ ...config,
38
+ })
39
+ }
40
+
41
+ export function handleRules(dataRules: Rules, data: any) {
42
+ return new Promise(resolve => {
43
+ const validator = new Schema(dataRules);
44
+ validator.validate(data, (errors: ValidateError[] | null, fields: ValidateFieldsError | Values) => {
45
+ if (errors) {
46
+ resolve(false);
47
+ return;
48
+ }
49
+ resolve(true);
50
+ })
51
+
52
+ })
53
+
54
+ }
55
+
56
+ export async function asyncFilter(arr: any[], predicate: (item: any) => PromiseLike<any>) {
57
+ return await Promise.all(arr.map(predicate))
58
+ .then((results) => arr.filter((_v, index) => results[index]))
59
+ }
60
+
61
+ export function modalShow(type: string, props: any) {
62
+
63
+ }
64
+
65
+ export function filterObjectKeys(obj: Record<string, any>, keysToKeep: string[]) {
66
+ if (typeof obj !== 'object' || !obj) {
67
+ return obj;
68
+ }
69
+ return Object.keys(obj)
70
+ .filter(key => !keysToKeep.includes(key))
71
+ .reduce((newObj, key) => {
72
+ newObj[key] = obj[key];
73
+ return newObj;
74
+ }, {} as Record<string, any>);
75
+ }
76
+
77
+
78
+ export function createScript(url: string) {
79
+ let scriptTags = window.document.querySelectorAll('script')
80
+ let len = scriptTags.length
81
+ let i = 0
82
+ let _url = window.location.origin + url
83
+ return new Promise((resolve, reject) => {
84
+ for (i = 0; i < len; i++) {
85
+ var src = scriptTags[i].src
86
+ if (src && src === _url) {
87
+ scriptTags[i].parentElement?.removeChild(scriptTags[i])
88
+ }
89
+ }
90
+
91
+ let node = document.createElement('script')
92
+ node.src = url
93
+ node.onload = resolve
94
+ document.body.appendChild(node)
95
+ })
96
+ }
97
+
98
+ export async function modal(options: ModalOptions) {
99
+ let props = options.content.props
100
+ if (options.content.url) {
101
+ const res = await http({
102
+ method: 'get',
103
+ url: options.content.url,
104
+ headers: {
105
+ 'X-Modal': '1',
106
+ }
107
+ })
108
+ if (typeof res.data === 'string') {
109
+ throw new Error('modal response is not vail')
110
+ }
111
+ props = res.data
112
+ }
113
+ if (!props) {
114
+ throw new Error('modal props is empty')
115
+ }
116
+ const Component = lazy(() => container.get('Modal.' + upperFirst(options.content.type)))
117
+
118
+ let afterClose = () => {
119
+ }
120
+ const modal = global.modal.info({
121
+ ...options,
122
+ closable: true,
123
+ icon: null,
124
+ destroyOnClose: true,
125
+ footer: null,
126
+ content: (
127
+ <Suspense fallback={<Spin/>}>
128
+ <ModalContext.Provider value={{
129
+ inModal: true,
130
+ closeModal: () => {
131
+ modal?.destroy()
132
+ },
133
+ contexts: options.contexts,
134
+ setAfterClose(callback: () => void) {
135
+ afterClose = callback
136
+ }
137
+ }}>
138
+ <Component {...props} />
139
+ </ModalContext.Provider>
140
+ </Suspense>
141
+ ),
142
+ afterClose: () => {
143
+ afterClose && afterClose()
144
+ },
145
+ })
146
+ return {
147
+ destroy: modal.destroy,
148
+ update: modal.update,
149
+ }
150
+ }
package/lib/http.ts ADDED
@@ -0,0 +1,74 @@
1
+ import axios, {AxiosError} from "axios";
2
+ import {routerNavigateTo} from "./helpers";
3
+ import global from "./global";
4
+
5
+ /**
6
+ * fetchOptions.noHandle 成功时不处理 url 和 info
7
+ */
8
+
9
+ const http = axios.create({})
10
+
11
+ http.interceptors.request.use(config => {
12
+ config.headers['Accept'] = 'application/json'
13
+ // 设置异步模式
14
+ config.headers['X-Requested-With'] = 'XMLHttpRequest'
15
+ return config
16
+ })
17
+
18
+ http.interceptors.response.use(response => {
19
+ const checkInfo = (data: { status?: number, info?: string }) => {
20
+ if (!data?.info) {
21
+ return false
22
+ }
23
+ switch (data.status) {
24
+ case 0:
25
+ global.notification.warning({
26
+ message: data.info
27
+ })
28
+ break
29
+ default:
30
+ global.notification.success({
31
+ message: data.info
32
+ })
33
+ }
34
+ return true
35
+ }
36
+
37
+ if (response.config.fetchOptions?.noHandle) {
38
+ return response
39
+ }
40
+ const showInfo = checkInfo(response.data)
41
+
42
+ if (response.data.url) {
43
+ setTimeout(() => {
44
+ routerNavigateTo(response.data.url)
45
+ }, showInfo ? 2000 : 0)
46
+ }
47
+ if (response.data.status == 0) {
48
+ return Promise.reject(response.data.info)
49
+ }
50
+ return response
51
+ }, error => {
52
+ if (error instanceof AxiosError) {
53
+ if (error.response?.headers['content-type'].includes('application/json')) {
54
+ global.notification.error({
55
+ message: error.response?.data?.info || '请求错误,请稍候重试'
56
+ })
57
+ } else if (error.response?.headers['content-type'].includes('text/html')) {
58
+ const parser = new DOMParser;
59
+ const doc = parser.parseFromString(error.response?.data, 'text/html');
60
+ const title = doc.querySelector('title')?.textContent;
61
+
62
+ global.notification.error({
63
+ message: title || '请求错误,请稍候重试'
64
+ })
65
+ }
66
+ } else {
67
+ global.notification.error({
68
+ message: '请求错误,请稍候重试'
69
+ })
70
+ }
71
+ return Promise.reject(error)
72
+ })
73
+
74
+ export default http