提交 10aacd61 authored 作者: 王鹏飞's avatar 王鹏飞

chore: init

上级
{
"globals": {
"createRef": true,
"forwardRef": true,
"lazy": true,
"memo": true,
"startTransition": true,
"useCallback": true,
"useContext": true,
"useDebugValue": true,
"useDeferredValue": true,
"useEffect": true,
"useHref": true,
"useId": true,
"useImperativeHandle": true,
"useInRouterContext": true,
"useInsertionEffect": true,
"useLayoutEffect": true,
"useLocation": true,
"useMemo": true,
"useNavigate": true,
"useNavigationType": true,
"useOutlet": true,
"useOutletContext": true,
"useParams": true,
"useReducer": true,
"useRef": true,
"useResolvedPath": true,
"useRoutes": true,
"useState": true,
"useSyncExternalStore": true,
"useTransition": true
}
}
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react-hooks/recommended'],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
'@typescript-eslint/no-explicit-any': 'off',
},
}
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# React + TypeScript + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
## Expanding the ESLint configuration
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
- Configure the top-level `parserOptions` property like this:
```js
export default {
// other rules...
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: ['./tsconfig.json', './tsconfig.node.json'],
tsconfigRootDir: __dirname,
},
}
```
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
const createRef: typeof import('react')['createRef']
const forwardRef: typeof import('react')['forwardRef']
const lazy: typeof import('react')['lazy']
const memo: typeof import('react')['memo']
const startTransition: typeof import('react')['startTransition']
const useCallback: typeof import('react')['useCallback']
const useContext: typeof import('react')['useContext']
const useDebugValue: typeof import('react')['useDebugValue']
const useDeferredValue: typeof import('react')['useDeferredValue']
const useEffect: typeof import('react')['useEffect']
const useHref: typeof import('react-router')['useHref']
const useId: typeof import('react')['useId']
const useImperativeHandle: typeof import('react')['useImperativeHandle']
const useInRouterContext: typeof import('react-router')['useInRouterContext']
const useInsertionEffect: typeof import('react')['useInsertionEffect']
const useLayoutEffect: typeof import('react')['useLayoutEffect']
const useLocation: typeof import('react-router')['useLocation']
const useMemo: typeof import('react')['useMemo']
const useNavigate: typeof import('react-router')['useNavigate']
const useNavigationType: typeof import('react-router')['useNavigationType']
const useOutlet: typeof import('react-router')['useOutlet']
const useOutletContext: typeof import('react-router')['useOutletContext']
const useParams: typeof import('react-router')['useParams']
const useReducer: typeof import('react')['useReducer']
const useRef: typeof import('react')['useRef']
const useResolvedPath: typeof import('react-router')['useResolvedPath']
const useRoutes: typeof import('react-router')['useRoutes']
const useState: typeof import('react')['useState']
const useSyncExternalStore: typeof import('react')['useSyncExternalStore']
const useTransition: typeof import('react')['useTransition']
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="https://webapp-pub.ezijing.com/website/base/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AI数据分析实验室</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "saas-bi",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@ant-design/icons": "^5.6.1",
"@tanstack/react-query": "^5.67.1",
"antd": "^5.24.3",
"axios": "^1.8.1",
"classnames": "^2.5.1",
"lucide-react": "^0.477.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router": "^7.3.0",
"zustand": "^5.0.3"
},
"devDependencies": {
"@types/node": "^22.13.9",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"@vitejs/plugin-react-swc": "^3.5.0",
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6",
"sass-embedded": "^1.85.1",
"typescript": "^5.2.2",
"unplugin-auto-import": "^19.1.1",
"vite": "^5.2.0",
"vite-plugin-mkcert": "^1.17.7"
}
}
body,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
p,
blockquote,
dl,
dt,
dd,
ul,
ol,
li,
pre,
form,
fieldset,
legend,
button,
input,
textarea,
th,
td {
margin: 0;
padding: 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: 100%;
}
ul,
ol,
li {
list-style: none;
}
em,
i {
font-style: normal;
}
strong,
b {
font-weight: normal;
}
img {
border: none;
}
input,
img {
vertical-align: middle;
}
a {
color: inherit;
text-decoration: none;
}
input,
button,
select,
textarea {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
appearance: none;
border: 0;
border-radius: 0;
font: inherit;
}
textarea:focus {
outline: 0;
}
:root {
--main-color: #ba143e;
}
html,
body,
#root {
height: 100%;
}
.app-card {
--ant-color-text-heading: var(--main-color);
--ant-border-radius-lg: 20px;
}
/* .app-card .ant-card-head {
padding: 0;
margin: 0 20px;
} */
import { Suspense } from 'react'
import { Spin } from 'antd'
import { useRoutes } from 'react-router'
import routes from './router/routes'
import './App.css'
const App = () => {
const element = useRoutes(routes)
return (
<Suspense
fallback={
<div
style={{ width: '100%', height: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Spin size="large" />
</div>
}>
{element}
</Suspense>
)
}
export default App
import httpRequest from '@/utils/axios'
// 获取用户信息
export function getUser() {
return httpRequest.get('/api/lab/v1/common/permission/role')
}
// 退出登录
export function logout() {
return httpRequest.get('/api/passport/rest/logout')
}
// 获取oss token
export function getToken() {
return httpRequest.get('/api/usercenter/aliyun/assume-role')
}
// 获取oss signature
export function getSignature() {
return httpRequest.get('/api/usercenter/aliyun/get-signature')
}
// 图片上传
export async function uploadFile(data: Record<string, any>) {
await httpRequest.post(data.host || 'https://webapp-pub.ezijing.com', data, {
withCredentials: false,
headers: { 'Content-Type': 'multipart/form-data' },
})
return data
}
.app-header {
position: sticky;
top: 0;
z-index: 2001;
padding: 0 20px;
display: flex;
align-items: center;
justify-content: space-between;
height: 66px;
background-color: #fff;
.logo {
height: 40px;
img {
height: 100%;
}
}
}
.app-header-left {
display: flex;
align-items: center;
.line {
margin: 0 20px;
height: 30px;
border-left: 2px solid var(--main-color);
}
.app-name {
font-size: 28px;
font-family: Source Han Sans CN;
color: #333;
font-weight: 500;
line-height: 30px;
white-space: nowrap;
}
}
.app-header-nav {
margin: 0 40px;
flex: 1;
height: 100%;
.ant-menu {
--ant-menu-horizontal-line-height: 66px;
--ant-font-size: 16px;
--ant-font-weight: 500;
--ant-menu-active-bar-height: 0;
}
}
.app-header-right {
display: flex;
.user {
height: 40px;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
color: #666;
border-radius: 21px;
padding: 4px;
p {
margin: 0 10px;
}
&:hover {
background-color: rgba(219, 219, 219, 0.23);
box-shadow: 2px 1px 8px 1px #e4e8eb;
}
}
.avatar {
width: 40px;
height: 40px;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 50%;
overflow: hidden;
}
&:hover {
background-color: rgba(60, 64, 67, 0.08);
}
}
}
.app-header-user {
min-width: 256px;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.app-header-user-avatar {
margin-bottom: 6px;
width: 80px;
height: 80px;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.app-header-user-main {
h3 {
color: #202124;
font: 500 16px/22px Helvetica, Arial, sans-serif;
letter-spacing: 0.29px;
margin: 0;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
}
p {
color: #5f6368;
font: 400 14px/19px Helvetica, Arial, sans-serif;
letter-spacing: normal;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
}
}
.app-header-user-buttons {
padding-top: 16px;
}
import { Link, NavLink, useLocation } from 'react-router'
import { Menu, Popover, Button } from 'antd'
import { CaretDownOutlined } from '@ant-design/icons'
import './AppHeader.scss'
export default function AppHeader({ title = 'AI数据分析实验室' }) {
const location = useLocation()
const defaultSelectedKeys = [location.pathname]
const menus = [
{ name: '首页', path: '/' },
{ name: '我的实验', path: '/data' },
]
const items = menus.map((item) => {
return {
label: <NavLink to={item.path}>{item.name}</NavLink>,
key: item.path,
}
})
return (
<div className="app-header">
<div className="app-header-left">
<div className="logo">
<Link to="/">
<img src="https://webapp-pub.ezijing.com/website/base/logo.svg" />
</Link>
</div>
<div className="line"></div>
<h1 className="app-name">
<Link to="/">{title}</Link>
</h1>
</div>
<div className="app-header-nav">
<Menu mode="horizontal" items={items} defaultSelectedKeys={defaultSelectedKeys} />
</div>
<div className="app-header-right">
<Popover
content={
<div className="app-header-user">
<div className="app-header-user-avatar">
<img src="https://webapp-pub.ezijing.com/website/base/images/avatar.svg" />
</div>
<div className="app-header-user-main">
<h3>王鹏飞</h3>
<p>wangpengfei@ezijing.com</p>
</div>
<div className="app-header-user-buttons">
<Button shape="round">退出登录</Button>
</div>
</div>
}>
<div className="user">
<div className="avatar">
<img src="https://webapp-pub.ezijing.com/website/base/images/avatar.svg" />
</div>
<p>王鹏飞</p>
<CaretDownOutlined />
</div>
</Popover>
</div>
</div>
)
}
.app-layout {
min-width: 1000px;
height: 100%;
margin: 0 auto;
background-color: #ecf2f7;
display: flex;
flex-direction: column;
}
.app-layout-container {
// min-height: calc(100vh - 66px);
flex: 1;
// display: flex;
overflow-y: auto;
}
import { Outlet } from 'react-router'
import AppHeader from './AppHeader'
import './AppLayout.scss'
export default function AppLayout() {
return (
<div className="app-layout">
<AppHeader />
<div className="app-layout-container">
<Outlet />
</div>
</div>
)
}
.data-layout {
display: flex;
gap: 20px;
padding-top: 20px;
height: 100%;
box-sizing: border-box;
&.collapsed {
.data-layout-sidebar {
width: auto;
}
}
&-sidebar {
display: flex;
flex-direction: column;
width: 240px;
background-color: #fff;
border-radius: 20px;
&-header {
color: var(--main-color);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24px;
border-bottom: 1px solid #f0f0f0;
height: 56px;
span {
cursor: pointer;
}
}
&-nav {
flex: 1;
padding: 10px 14px;
overflow-x: hidden;
overflow-y: auto;
.ant-menu-css-var {
--ant-menu-collapsed-width: 44px;
--ant-menu-active-bar-border-width: 0;
--ant-menu-sub-menu-item-bg: transparent;
}
.ant-menu-item-icon {
width: 18px;
height: 18px;
}
.ant-menu-item,
.ant-menu-submenu-title {
padding-left: 10px !important;
}
.ant-menu-sub.ant-menu-inline {
width: auto;
margin-left: 23px;
border-left: 1px solid #f0f0f0;
.ant-menu-item {
padding-left: 14px !important;
}
}
}
}
&-container {
flex: 1;
}
}
import { useState } from 'react'
import { Outlet, NavLink, useLocation } from 'react-router'
import {
CircleArrowRight,
CircleArrowLeft,
Database,
SearchCheck,
Filter,
Bolt,
Cone,
ChartArea,
Wallpaper,
} from 'lucide-react'
import { Menu, MenuProps } from 'antd'
import './DataLayout.scss'
type MyMenuItem = {
name: string
path: string
children?: MyMenuItem[]
disabled?: boolean
icon?: React.ReactNode
}
type MenuItem = Required<MenuProps>['items'][number]
export default function DataLayout() {
const [collapsed, setCollapsed] = useState(false)
const toggleCollapsed = () => {
setCollapsed(!collapsed)
}
const location = useLocation()
const selectedKeys = [location.pathname]
const menus: MyMenuItem[] = [
{
icon: <Database />,
name: '数据采集',
path: '/data/write',
children: [
{ name: '我的数据集', path: '/data/write/my' },
{ name: '数据复制', path: '/data/write/copy' },
{ name: '数据导入', path: '/data/write/upload' },
{ name: '数据爬虫', path: '/data/write/crawler' },
{ name: 'API数据采集', path: '/data/write/api' },
{ name: '数据库对接', path: '/data/write/db' },
{ name: '内置数据集管理', path: '/data/write/built' },
],
},
{
icon: <SearchCheck />,
name: '数据理解与探索',
path: '/data/read',
children: [
{ name: '数据理解', path: '/data/read/crawler' },
{ name: '数据探索', path: '/data/read/api' },
],
},
{
icon: <Filter />,
name: '数据预处理',
path: '/data/preprocess',
children: [
{ name: '缺失值处理', path: '/data/preprocess/null' },
{ name: '重复值处理', path: '/data/preprocess/repeat' },
{ name: '过大值处理', path: '/data/preprocess/max' },
{ name: '过小值处理', path: '/data/preprocess/min' },
{ name: '逻辑错误值处理', path: '/data/preprocess/error' },
{ name: '数据拆分', path: '/data/preprocess/split' },
{ name: '数据去空格', path: '/data/preprocess/space' },
{ name: '数据去标点', path: '/data/preprocess/symbol' },
{ name: '数据类型转换', path: '/data/preprocess/type' },
{ name: '数据排序', path: '/data/preprocess/sort' },
{ name: '数据拼接', path: '/data/preprocess/concat' },
],
},
{
icon: <Bolt />,
name: '数据加工',
path: '/data/process',
children: [
{ name: '值映射', path: '/data/process/mapping' },
{ name: '数据分箱', path: '/data/process/binning' },
{ name: '数据分组', path: '/data/process/group' },
{ name: '数据脱敏', path: '/data/process/4' },
{ name: '日期计算', path: '/data/process/date' },
{ name: '文本计算', path: '/data/process/string' },
{ name: '数值计算', path: '/data/process/number' },
{ name: '逻辑计算', path: '/data/process/logic' },
{ name: '数据透视', path: '/data/process/perspective' },
],
},
{
icon: <Cone />,
name: '数据挖掘',
path: '/data/digging',
children: [
{ name: '线性回归', path: '/data/digging/1' },
{ name: '逻辑回归', path: '/data/digging/2' },
{ name: '决策树', path: '/data/digging/3' },
{ name: '随机森林', path: '/data/digging/4' },
{ name: '支持向量机', path: '/data/digging/5' },
{ name: 'K-Means', path: '/data/digging/6' },
{ name: '层次聚类', path: '/data/digging/7' },
{ name: 'Apriori', path: '/data/digging/8' },
{ name: 'FP-Growth', path: '/data/digging/9' },
{ name: 'Holt-Winters', path: '/data/digging/10' },
],
},
{
icon: <ChartArea />,
name: '数据可视化组件',
path: '/data/chart',
children: [
{ name: '柱状图', path: '/data/chart/1' },
{ name: '折线图', path: '/data/chart/2' },
{ name: '饼状图', path: '/data/chart/3' },
{ name: '雷达图', path: '/data/chart/4' },
{ name: '散点图', path: '/data/chart/5' },
{ name: '气泡图', path: '/data/chart/6' },
{ name: '词云', path: '/data/chart/7' },
{ name: '地图', path: '/data/chart/8' },
{ name: '指标卡', path: '/data/chart/9' },
{ name: '漏斗图', path: '/data/chart/10' },
{ name: '直方图', path: '/data/chart/11' },
{ name: '表格', path: '/data/chart/12' },
{ name: '帕累托图', path: '/data/chart/13' },
{ name: '矩形树图', path: '/data/chart/14' },
],
},
{
icon: <Wallpaper />,
name: '数据可视化大屏',
path: '/data/screen',
},
]
const menusToMenuItems = (menus: MyMenuItem[]): MenuItem[] => {
return menus.map((item) => {
if (item.children) {
return {
...item,
label: item.name,
key: item.path,
children: menusToMenuItems(item.children),
}
}
return {
...item,
label: <NavLink to={item.path}>{item.name}</NavLink>,
key: item.path,
}
})
}
const items = menusToMenuItems(menus)
return (
<div className={`data-layout ${collapsed ? 'collapsed' : ''}`}>
<div className="data-layout-sidebar">
<div className="data-layout-sidebar-header">
{collapsed ? '' : <h2>AI数据分析功能区</h2>}
<span onClick={toggleCollapsed}>{collapsed ? <CircleArrowRight /> : <CircleArrowLeft />}</span>
</div>
<div className="data-layout-sidebar-nav">
<Menu items={items} mode="inline" inlineCollapsed={collapsed} selectedKeys={selectedKeys} />
</div>
</div>
<div className="data-layout-container">
<Outlet />
</div>
</div>
)
}
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ConfigProvider } from 'antd'
import App from './App.tsx'
const queryClient = new QueryClient()
const antdTheme = {
cssVar: true,
hashed: false,
token: {
colorPrimary: '#ba143e',
},
}
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<ConfigProvider theme={antdTheme}>
<BrowserRouter>
<App />
</BrowserRouter>
</ConfigProvider>
</QueryClientProvider>
</React.StrictMode>
)
import { Card, Button, Row, Col } from 'antd'
import { Link } from 'react-router'
type CardItem = {
title: string
description: string
path: string
}
export default function DataDashboard() {
const items: CardItem[] = [
{
title: '数据采集',
description: '多源数据采集与结构化导入',
path: '/data/write',
},
{
title: '数据理解与探索',
description: '动态化数据理解与深度模式探索',
path: '/data/read',
},
{
title: '数据预处理',
description: '智能化数据预处理范式',
path: '/data/preprocess',
},
{
title: '数据加工',
description: '‌多模态数据加工架构',
path: '/data/process',
},
{
title: '数据挖掘',
description: '智能数据解析与知识图谱构建‌‌',
path: '/data/digging',
},
{
title: '可视化组件',
description: '‌智能可视化组件',
path: '/data/chart',
},
{
title: '可视化大屏',
description: '‌智能可视化大屏',
path: '/data/screen',
},
]
const CardCardItem = (item: CardItem) => {
return (
<Card title={item.title}>
<p>{item.description}</p>
<br />
<Link to={item.path}>
<Button shape="round">点击进入</Button>
</Link>
</Card>
)
}
return (
<div style={{ margin: '0 80px' }}>
<Row gutter={[40, 40]}>
{items.map((item) => (
<Col span={6} key={item.path}>
{CardCardItem(item)}
</Col>
))}
</Row>
</div>
)
}
import { lazy } from 'react'
import { Navigate, type RouteObject } from 'react-router'
export const routes: RouteObject[] = [
{
path: '/',
Component: lazy(() => import('@/components/layout/AppLayout')),
children: [
{
path: 'data',
Component: lazy(() => import('@/components/layout/DataLayout')),
children: [
{ index: true, element: <Navigate to="dashboard" /> },
{ path: 'dashboard', Component: lazy(() => import('./dashboard/views/Index')) },
{ path: 'write', element: <Navigate to="my" /> },
{ path: 'write/my', Component: lazy(() => import('./write/my/views/Index')) },
{ path: 'write/copy', Component: lazy(() => import('./write/copy/views/Index')) },
{ path: 'write/upload', Component: lazy(() => import('./write/upload/views/Index')) },
{ path: 'write/copy', Component: lazy(() => import('./write/copy/views/Index')) },
],
},
],
},
]
import { Card } from 'antd'
export default function DataWriteUpload() {
return (
<div>
<Card className="app-card" title="数据复制"></Card>
</div>
)
}
import { Card } from 'antd'
export default function DataWriteUpload() {
return (
<div>
<Card className="app-card" title="我的数据集"></Card>
</div>
)
}
import { Card } from 'antd'
export default function DataWriteUpload() {
return (
<div>
<Card className="app-card" title="数据导入"></Card>
</div>
)
}
import { lazy } from 'react'
import type { RouteObject } from 'react-router'
export const routes: RouteObject[] = [
{
path: '/',
Component: lazy(() => import('@/components/layout/AppLayout')),
children: [{ index: true, Component: lazy(() => import('./views/Index')) }],
},
]
function Home() {
return (
<div>
<h1>Home</h1>
</div>
)
}
export default Home
import { Navigate, RouteObject } from 'react-router'
const modules = import.meta.glob('../modules/**/routes.tsx', { eager: true })
// 提取所有模块的路由
const moduleRoutes: RouteObject[] = Object.values(modules)
.map((mod: any) => mod.routes)
.flat()
// 定义路由表
const routes: RouteObject[] = [...moduleRoutes, { path: '*', element: <Navigate to="/data" /> }]
export default routes
import { getUser } from '@/api/base'
import { create } from 'zustand'
export const useUserStore = create((set) => ({
user: null,
getUser: async () => {
const res = await getUser()
set({ user: res.data })
},
}))
import axios from 'axios'
const axiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_URL || 'https://api.example.com',
timeout: 10000,
headers: { 'Content-Type': 'application/json' },
})
axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
console.error('API Error:', error)
return Promise.reject(error)
}
)
export default axiosInstance
/// <reference types="vite/client" />
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"allowJs": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src"]
}
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}
{
"include": ["vite.config.*"],
"compilerOptions": {
"composite": true,
"noEmit": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"allowSyntheticDefaultImports": true,
"strict": true
}
}
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import { fileURLToPath, URL } from 'node:url'
import AutoImport from 'unplugin-auto-import/vite'
import mkcert from 'vite-plugin-mkcert'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
AutoImport({
imports: ['react', 'react-router'],
dts: true,
eslintrc: { enabled: true },
}),
mkcert(),
],
server: {
open: true,
host: 'dev.ezijing.com',
proxy: {
'/api': 'https://saas-dml.ezijing.com',
},
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
})
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论