提交 2ee9f8b1 作者: ZhangLingKun

功能:框架搭建

上级 166357db
node_modules
\ No newline at end of file
{
"root": true,
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:jsx-a11y/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:import/typescript",
"plugin:react/jsx-runtime",
"plugin:prettier/recommended",
"prettier"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"react",
"@typescript-eslint",
"react-hooks"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
"import",
"jsx-a11y",
"react-hooks",
"prettier"
],
"rules": {
"react-hooks/rules-of-hooks": "error", // 检查 Hook 的规则
"react-hooks/exhaustive-deps": "warn" // 检查 effect 的依赖
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}
],
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"prettier/prettier": [
"warn",
{
"endOfLine": "auto",
"singleQuote": true
}
],
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/no-static-element-interactions": "off"
}
}
......@@ -4,7 +4,6 @@
/node_modules
/.pnp
.pnp.js
/.idea
# testing
/coverage
......@@ -18,8 +17,17 @@
.env.development.local
.env.test.local
.env.production.local
.idea
.vscode
.hbuilderx
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
pnpm-lock.yaml*
yarn-lock.yaml*
package-lock.yaml*
#package-lock.json
#yarn.lock
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EslintConfiguration">
<option name="fix-on-save" value="true" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/react-ts.iml" filepath="$PROJECT_DIR$/.idea/react-ts.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
node_modules
yarn.lock
\ No newline at end of file
{
"jsxSingleQuote": true,
"singleQuote": true,
"semi": true,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 100,
"bracketSameLine": false,
"useTabs": false,
"arrowParens": "always",
"endOfLine": "auto"
}
# Getting Started with Create React App
<h1 align='center'>Vite + React + TypeScript + Eslint + Prettier Template ⚡</h1>
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
Create a new project with Vite, React JS, TypeScript, Eslint, Prettier in just 1 second and you don't need to setup anything.
## Available Scripts
#### **Vercel Deploy: https://vite-react-ts-eslint-prettier.vercel.app**
In the project directory, you can run:
![image](https://user-images.githubusercontent.com/70432453/170648662-2ff424b9-74e9-4754-a04d-512fe1496a3b.png)
### `npm start`
## **Some Features 📋**
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
Alias Import
The page will reload if you make edits.\
You will also see any lint errors in the console.
![image](https://user-images.githubusercontent.com/70432453/170644457-ede03cca-44e9-4543-94d3-412c9d317063.png)
### `npm test`
Hook Warning
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
![image](https://user-images.githubusercontent.com/70432453/170638708-23a20ffd-156e-494a-84be-b1e1cfdb5c93.png)
### `npm run build`
Prettier Warning
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
![image](https://user-images.githubusercontent.com/70432453/170639043-24423ed1-73cc-4730-b270-2acea1ae0c74.png)
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!
Etc...
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
## **Using 📦**
### `npm run eject`
1. Clone Template
**Note: this is a one-way operation. Once you `eject`, you can’t go back!**
```
git clone https://github.com/igdev116/vite-react-ts-eslint-prettier.git
```
If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
2. Install Packages
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
```
yarn install
```
You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
3. Start Project
## Learn More
```
yarn dev
```
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
4. If you using git, delete the existing folder .git after cloning (open `git bash` or other terminal)
To learn React, check out the [React documentation](https://reactjs.org/).
```
rm -rf .git
```
## **Options ✍️**
1. Check lint
```
yarn lint
```
2. Fix lint
```
yarn lint:fix
```
3. Check prettier
```
yarn prettier
```
4. Fix prettier
```
yarn prettier:fix
```
5. Fix lint and prettier
```
yarn format
```
html,body{width:100%;height:100%}input::-ms-clear,input::-ms-reveal{display:none}*,*:before,*:after{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:rgba(0,0,0,0)}@-ms-viewport{width:device-width}body{margin:0}[tabindex="-1"]:focus{outline:none}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5em;font-weight:500}p{margin-top:0;margin-bottom:1em}abbr[title],abbr[data-original-title]{-webkit-text-decoration:underline dotted;text-decoration:underline;text-decoration:underline dotted;border-bottom:0;cursor:help}address{margin-bottom:1em;font-style:normal;line-height:inherit}input[type=text],input[type=password],input[type=number],textarea{-webkit-appearance:none}ol,ul,dl{margin-top:0;margin-bottom:1em}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:500}dd{margin-bottom:.5em;margin-left:0}blockquote{margin:0 0 1em}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}pre,code,kbd,samp{font-size:1em;font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace}pre{margin-top:0;margin-bottom:1em;overflow:auto}figure{margin:0 0 1em}img{vertical-align:middle;border-style:none}a,area,button,[role=button],input:not([type="range"]),label,select,summary,textarea{touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75em;padding-bottom:.3em;text-align:left;caption-side:bottom}input,button,select,optgroup,textarea{margin:0;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}button,html [type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{padding:0;border-style:none}input[type=radio],input[type=checkbox]{box-sizing:border-box;padding:0}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;margin:0;padding:0;border:0}legend{display:block;width:100%;max-width:100%;margin-bottom:.5em;padding:0;color:inherit;font-size:1.5em;line-height:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}mark{padding:.2em;background-color:#feffe6}.excel-upload-view{width:100%;height:100%;display:flex;justify-content:center;align-items:center;flex-direction:column}.excel-upload-view .text-blue{color:#1677ff}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#root{position:relative;box-sizing:border-box;width:100%;height:100%;min-height:100vh;min-width:100vw}
This source diff could not be displayed because it is too large. You can view the blob instead.
<?xml version="1.0" encoding="UTF-8"?>
<svg width="256px" height="257px" viewBox="0 0 256 257" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<defs>
<linearGradient x1="-0.828097821%" y1="7.6518539%" x2="57.6359644%" y2="78.4107719%" id="linearGradient-1">
<stop stop-color="#41D1FF" offset="0%"></stop>
<stop stop-color="#BD34FE" offset="100%"></stop>
</linearGradient>
<linearGradient x1="43.3760053%" y1="2.24179788%" x2="50.3158848%" y2="89.0299051%" id="linearGradient-2">
<stop stop-color="#FFEA83" offset="0%"></stop>
<stop stop-color="#FFDD35" offset="8.33333%"></stop>
<stop stop-color="#FFA800" offset="100%"></stop>
</linearGradient>
</defs>
<g>
<path d="M255.152904,37.937763 L134.896865,252.97646 C132.413943,257.416178 126.035075,257.442321 123.5149,253.02417 L0.87443175,37.9584812 C-1.87111536,33.1438084 2.24595371,27.3119153 7.70191187,28.2871109 L128.086639,49.8052023 C128.854587,49.9424525 129.640835,49.9411454 130.408783,49.8012155 L248.276014,28.3179595 C253.713738,27.3268821 257.850198,33.1136134 255.152904,37.937763 Z" fill="url(#linearGradient-1)"></path>
<path d="M185.432401,0.0631038902 L96.4393502,17.500942 C94.9766549,17.7875335 93.8936852,19.0270992 93.8054529,20.5146956 L88.3311293,112.971419 C88.2023755,115.149123 90.2023075,116.839261 92.3277254,116.349082 L117.10466,110.630976 C119.422882,110.096354 121.517582,112.138114 121.041128,114.469407 L113.67994,150.515893 C113.184532,152.941955 115.462232,155.016394 117.831433,154.29681 L133.134834,149.647295 C135.507302,148.927059 137.786963,151.00738 137.285019,153.435402 L125.586724,210.056351 C124.854723,213.598061 129.565674,215.529368 131.530313,212.49287 L132.842687,210.464834 L205.359174,65.745575 C206.573511,63.3224548 204.479465,60.5594769 201.818118,61.0730542 L176.31441,65.9952397 C173.91776,66.4573155 171.878614,64.2253653 172.555061,61.8805431 L189.2009,4.17570253 C189.878001,1.82692623 187.831665,-0.406957894 185.432401,0.0631038902 Z" fill="url(#linearGradient-2)"></path>
</g>
</svg>
\ No newline at end of file
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="./assets/logo-9022d9e8.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>测试</title>
<script type="module" crossorigin src="./assets/index-3f634a8c.js"></script>
<link rel="stylesheet" href="./assets/index-2aad6a17.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/assets/icon/logo.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>测试</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": "react-ts",
"version": "0.1.0",
"name": "vite-react-ts-eslint-prettier",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.11.45",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"axios": "^0.27.2",
"eslint-plugin-react-hooks": "^4.6.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typescript": "^4.7.4",
"web-vitals": "^2.1.4"
},
"version": "0.0.0",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx"
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"lint": "npx eslint src",
"lint:fix": "npm run lint -- --fix",
"prettier": "npx prettier src --check",
"prettier:fix": "npm run prettier -- --write",
"format": "npm run prettier:fix && npm run lint:fix"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
"dependencies": {
"@ant-design/icons": "^5.0.1",
"antd": "^5.4.2",
"dayjs": "^1.11.7",
"localforage": "^1.10.0",
"match-sorter": "^6.3.1",
"pinyin-pro": "^3.14.0",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-router-dom": "^6.10.0",
"sort-by": "^1.2.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.31.0",
"@typescript-eslint/parser": "^5.31.0",
"eslint": "^7.32.0",
"react-router-dom": "^6.3.0"
"@types/react": "^18.0.9",
"@types/react-dom": "^18.0.5",
"@typescript-eslint/eslint-plugin": "^5.26.0",
"@typescript-eslint/parser": "^5.26.0",
"@vitejs/plugin-react": "^1.3.0",
"eslint": "^8.16.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.30.0",
"eslint-plugin-react-hooks": "^4.5.0",
"prettier": "^2.6.2",
"sass": "^1.62.0",
"typescript": "^4.6.3",
"vite": "^4.2.1",
"vite-tsconfig-paths": "^3.5.0"
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
import { Outlet, Link } from "react-router-dom";
import React from 'react';
import { RouterProvider } from 'react-router-dom';
import './assets/style/App.scss';
import { router } from './router';
export default function App() {
return (
<div>
{/*<h1>Bookkeeper</h1>*/}
{/*<nav style={{*/}
{/* borderBottom: "solid 1px",*/}
{/* paddingBottom: "1rem",*/}
{/* }}*/}
{/*>*/}
{/* <Link to="/home">Home</Link> |{" "}*/}
{/* <Link to="/about">About</Link> |{" "}*/}
{/* <Link to="/test">Test</Link>*/}
{/*</nav>*/}
<Outlet />
</div>
);
}
const App = () => (
<>
<RouterProvider router={router} />
</>
);
export default App;
const baseURL = 'https://testapi.sharefly.mmcuav.cn/';
import {commonAPI} from './modules/common/api';
export {baseURL, commonAPI};
import Axios from '../../request';
import {PlatformLogin} from './interface';
export class commonAPI {
//登录接口
static platformLogin(data: PlatformLogin) {
return Axios.post('/userservlet/auth/platformLogin', data);
}
}
export interface PlatformLogin {
accountNo: string;
passWord: string;
}
import axios from 'axios';
// import {baseURL} from './index';
const baseURL = 'https://testapi.sharefly.mmcuav.cn/';
const Axios = axios.create({
baseURL,
timeout: 60000,
});
Axios.interceptors.request.use(
(config: any) => {
const token = false; //此处获取token
if (token) {
config.headers.token = token;
}
return config;
},
error => {
return Promise.reject(error);
},
);
Axios.interceptors.response.use(
response => {
const res = response.data;
if (res.code === '200') {
return Promise.resolve(res);
} else {
console.log('err -->', res);
return Promise.resolve(res);
}
},
error => {
if (error.response) {
console.log(error.response.status, error.response.statusText);
}
return Promise.reject(error);
},
);
export default Axios;
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
<?xml version="1.0" encoding="UTF-8"?>
<svg width="256px" height="257px" viewBox="0 0 256 257" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<defs>
<linearGradient x1="-0.828097821%" y1="7.6518539%" x2="57.6359644%" y2="78.4107719%" id="linearGradient-1">
<stop stop-color="#41D1FF" offset="0%"></stop>
<stop stop-color="#BD34FE" offset="100%"></stop>
</linearGradient>
<linearGradient x1="43.3760053%" y1="2.24179788%" x2="50.3158848%" y2="89.0299051%" id="linearGradient-2">
<stop stop-color="#FFEA83" offset="0%"></stop>
<stop stop-color="#FFDD35" offset="8.33333%"></stop>
<stop stop-color="#FFA800" offset="100%"></stop>
</linearGradient>
</defs>
<g>
<path d="M255.152904,37.937763 L134.896865,252.97646 C132.413943,257.416178 126.035075,257.442321 123.5149,253.02417 L0.87443175,37.9584812 C-1.87111536,33.1438084 2.24595371,27.3119153 7.70191187,28.2871109 L128.086639,49.8052023 C128.854587,49.9424525 129.640835,49.9411454 130.408783,49.8012155 L248.276014,28.3179595 C253.713738,27.3268821 257.850198,33.1136134 255.152904,37.937763 Z" fill="url(#linearGradient-1)"></path>
<path d="M185.432401,0.0631038902 L96.4393502,17.500942 C94.9766549,17.7875335 93.8936852,19.0270992 93.8054529,20.5146956 L88.3311293,112.971419 C88.2023755,115.149123 90.2023075,116.839261 92.3277254,116.349082 L117.10466,110.630976 C119.422882,110.096354 121.517582,112.138114 121.041128,114.469407 L113.67994,150.515893 C113.184532,152.941955 115.462232,155.016394 117.831433,154.29681 L133.134834,149.647295 C135.507302,148.927059 137.786963,151.00738 137.285019,153.435402 L125.586724,210.056351 C124.854723,213.598061 129.565674,215.529368 131.530313,212.49287 L132.842687,210.464834 L205.359174,65.745575 C206.573511,63.3224548 204.479465,60.5594769 201.818118,61.0730542 L176.31441,65.9952397 C173.91776,66.4573155 171.878614,64.2253653 172.555061,61.8805431 L189.2009,4.17570253 C189.878001,1.82692623 187.831665,-0.406957894 185.432401,0.0631038902 Z" fill="url(#linearGradient-2)"></path>
</g>
</svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
\ No newline at end of file
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
#root {
position: relative;
box-sizing: border-box;
width: 100%;
height: 100%;
min-height: 100vh;
min-width: 100vw;
}
// 颜色变量
$color-primary: #f4b700;
$color-primary-hover: #f7c800;
$color-primary-active: #ffcc32;
$color-primary-border: #f4b700;
.brand-select-search-view {
position: relative;
width: 100%;
box-sizing: border-box;
.brand-select-item {
min-height: 50px;
background: #fff;
display: flex;
align-items: center;
justify-content: flex-start;
box-sizing: border-box;
position: relative;
padding: 12px 20px 12px 20px;
border-bottom: 1px solid #f2f4fa;
.item-label {
font-size: 14px;
color: #979aa8;
margin-right: 16px;
min-width: 32px;
}
.item-content {
display: flex;
align-items: center;
justify-content: flex-start;
flex-wrap: wrap;
width: 100%;
.alphabet-list, .select-list {
width: 100%;
display: flex;
align-items: center;
justify-content: flex-start;
margin-bottom: 10px;
flex-wrap: wrap;
.list-item {
position: relative;
height: 24px;
width: 20px;
font-size: 14px;
line-height: 20px;
margin: 0 16px 0 0;
border-radius: 2px;
text-align: center;
border: 1px solid transparent;
cursor: pointer;
user-select: none;
}
.list-item:hover {
color: $color-primary;
}
.list-item:hover:after {
position: absolute;
content: '';
width: 35%;
height: 1px;
background: $color-primary;
left: calc((100% - 35%) / 2);
bottom: 0;
}
.item-active {
background: $color-primary-active;
border: 1px solid $color-primary;
}
.item-active:hover {
color: #000000;
}
.item-active:hover:after {
display: none;
}
}
.select-list {
margin-bottom: 0;
.list-item {
width: 80px;
margin: 0 10px 0 0;
}
}
.selected {
margin-bottom: -10px;
.list-item {
border: 1px solid $color-primary;
color: $color-primary;
margin-bottom: 10px;
}
.list-item:hover {
background: #f7f8fc;
}
.list-item:hover:after {
display: none;
}
}
.alphabet-content {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
padding: 2px 12px 12px;
background-color: #f7f8fc;
width: 100%;
min-height: 50px;
box-sizing: border-box;
.content-item {
position: relative;
width: 80px;
margin: 10px 8px 0 0;
font-size: 14px;
overflow: hidden;
background: #ffffff;
text-align: center;
height: 28px;
line-height: 26px;
border: 1px solid transparent;
user-select: none;
}
.content-item:hover {
color: #f4b700;
}
.content-item:hover:after {
position: absolute;
content: '';
width: 35%;
height: 1px;
background: #f4b700;
left: calc((100% - 35%) / 2);
bottom: 0;
}
.item-active {
background: $color-primary-active;
border: 1px solid $color-primary;
}
.item-active:hover {
color: #000000;
}
.item-active:hover:after {
display: none;
}
}
.select-region {
.region-label {
margin: 0 12px;
}
.region-label:first-child{
margin-left: 0;
}
}
}
}
.brand-select-item:last-child {
border-bottom: none;
}
}
import React, { useEffect, useState } from 'react';
import './index.scss';
import { pinyin } from 'pinyin-pro';
import { Select } from 'antd';
// 搜索列表的类型
interface searchColumns {
type: 'Alphabet' | 'Brand' | 'Price' | 'Industry' | 'Product';
options: { label: string; value: any; children?: { label: string; value: any }[] }[];
name: string;
label: string;
subLabel?: string;
}
// 传参类型
interface propType {
columns: searchColumns[];
selected: boolean;
region: boolean;
}
const BrandSelectItem: React.FC<{ label: string; children: any }> = (props) => {
const { label, children } = props;
return (
<div className={'brand-select-item'}>
<div className={'item-label'}>{label}</div>
<div className={'item-content'}>{children}</div>
</div>
);
};
const BrandSelectSearch: React.FC<propType> = (props) => {
const { columns, selected, region } = props;
// 字母列表转换
const [alphabetList, setAlphabetList] = useState<{ label?: string; children: any }[]>([]);
// 字母列表索引
const [alphabetIndex, setAlphabetIndex] = useState<number>(0);
// 字母列表详情索引
const [alphabetContentIndex, setAlphabetContentIndex] = useState<number>(0);
// 普通筛选索引
const [optionsIndex, setOptionsIndex] = useState<{ index: number; subIndex?: number }[]>([]);
// 转换过后的普通筛选列表
const [columnsList, setColumnsList] = useState<searchColumns[]>([]);
// 获取字母列表 (将传入的列表转成以拼音开头的数组)
const getAlphabetList = () => {
// 如果没有字母列表则不执行
if (!columns.some((i) => i.type === 'Alphabet')) return;
// 获取字母列表
const options = columns.find((i) => i.type === 'Alphabet')?.options;
// 获取开头字母列表(去重)
const arr = [
...new Set(
options?.map((i) =>
pinyin(i.label, { toneType: 'none', type: 'array' })?.at(0)?.at(0)?.toUpperCase(),
),
),
].sort();
// 转换成展示列表
setAlphabetList(
arr?.map((i) => {
const children =
options?.filter(
(j) =>
pinyin(j.label, { toneType: 'none', type: 'array' })?.at(0)?.at(0)?.toUpperCase() ===
i,
) || [];
return {
label: i,
children: [{ label: '不限', value: 'all' }, ...children],
};
}),
);
};
// 获取普通列表
const getOptionsList = (options: { label: string; value: any }[]) => {
return [{ label: '不限', value: 'all' }, ...options];
};
// componentDidMount
useEffect(() => {
if (!columns) return;
getAlphabetList();
// 初始化索引
setOptionsIndex(columns.map((i) => (i.subLabel ? { index: 0, subIndex: 0 } : { index: 0 })));
// 初始化列表
setColumnsList(columns?.map((i) => ({ ...i, options: getOptionsList(i.options) })));
}, [columns]);
// componentDidUpdate
useEffect(() => {
// 如果没有普通筛选列表则不执行
if (!optionsIndex.length) return;
// 如果普通筛选列表全为0则不执行
if (!optionsIndex.some((i) => i.index !== 0)) return;
console.log('optionsIndex --->', optionsIndex);
console.log(
'componentDidUpdate -->',
optionsIndex.map((i, j) => columnsList[j].options[i.index]),
);
}, [optionsIndex]);
return (
<div className={'brand-select-search-view'}>
{region && (
<BrandSelectItem label={'地区'}>
<div className={'select-region'}>
<span className={'region-label'}></span>
<Select placeholder={'请选择省份'} options={[]} size={'small'} />
<span className={'region-label'}></span>
<Select placeholder={'请选择城市'} options={[]} size={'small'} />
</div>
</BrandSelectItem>
)}
{columnsList.map((i, j) => {
if (i.type === 'Alphabet') {
return (
<BrandSelectItem label={'品牌'} key={j}>
<div className='alphabet-list'>
{alphabetList.map((n, m) => (
<div
className={`list-item ${alphabetIndex === m && 'item-active'}`}
key={m}
onClick={() => {
setAlphabetIndex(m);
setAlphabetContentIndex(0);
}}
>
{n.label}
</div>
))}
</div>
<div className='alphabet-content'>
{alphabetList[alphabetIndex]?.children?.map((n: any, m: number) => (
<div
className={`content-item ${alphabetContentIndex === m && 'item-active'}`}
key={m}
onClick={() => {
setAlphabetContentIndex(alphabetContentIndex === m ? 0 : m);
const index =
columnsList
.find((i) => i.type === 'Alphabet')
?.options?.findIndex((i) => i.label === n.label) || 0;
// setOptionsIndex(optionsIndex?.map((i, k) => (k === j ? index : i)));
setOptionsIndex(optionsIndex?.map((i, k) => (k === j ? { index } : i)));
}}
>
{n.label}
</div>
))}
</div>
</BrandSelectItem>
);
}
if (['Industry', 'Brand', 'Price', 'Product'].includes(i.type)) {
return (
<div key={j}>
<BrandSelectItem label={i.label}>
<div className='select-list'>
{i.options?.map((n, m) => (
<div
className={`list-item ${optionsIndex[j].index === m && 'item-active'}`}
key={m}
onClick={() => {
setOptionsIndex(
optionsIndex.map((l, k) =>
k === j
? optionsIndex[j].index === m
? i.subLabel
? { index: 0, subIndex: 0 }
: { index: 0 }
: i.subLabel
? { index: m, subIndex: 0 }
: { index: m }
: l,
),
);
}}
>
{n.label}
</div>
))}
</div>
</BrandSelectItem>
{!!i.subLabel && (
<BrandSelectItem label={i.subLabel}>
<div className='select-list'>
{getOptionsList(i.options[optionsIndex[j].index]?.children || [])?.map(
(n, m) => (
<div
className={`list-item ${optionsIndex[j].subIndex === m && 'item-active'}`}
key={m}
onClick={() => {
setOptionsIndex(
optionsIndex.map((i, k) =>
k === j ? { ...i, subIndex: m === i.subIndex ? 0 : m } : i,
),
);
}}
>
{n.label}
</div>
),
)}
</div>
</BrandSelectItem>
)}
</div>
);
}
})}
{selected && (
<BrandSelectItem label={'已选'}>
<div className='select-list selected'>
{optionsIndex.map(
(n, m) =>
columnsList[m].options[n.index].label !== '不限' && (
<div
className={`list-item`}
key={m}
onClick={() => {
// setOptionsIndex(
// optionsIndex.map((i, k) => (k === j ? (optionsIndex[j] === m ? 0 : m) : i)),
// );
}}
>
{columnsList[m].options[n.index].label}
</div>
),
)}
</div>
</BrandSelectItem>
)}
</div>
);
};
export default BrandSelectSearch;
import React from 'react';
function Index() {
return <div>123132</div>;
}
export default Index;
.uploader-view{
.ant-upload-wrapper .ant-upload-list .ant-upload-list-item-container{
//width: 200px !important;
}
}
import React, { useState } from 'react';
import { message, Upload, UploadProps } from 'antd';
// import { UploadFile } from "antd/es/upload/interface";
import './index.scss';
interface PropsType {
listType?: 'text' | 'picture' | 'picture-card'; // 上传列表的内建样式
fileSize?: number; // 文件大小
fileType?: string[]; // 上传文件类型
fileLength?: number; // 最大上传文件数量
children: React.ReactNode; // 上传按钮
onChange?: (fileList: any[]) => void; // 上传文件改变时的状态
onRemove?: (fileList: any[]) => void;
}
export const Uploader: React.FC<PropsType> = (props) => {
Uploader.defaultProps = {
listType: 'text',
fileSize: 2,
fileLength: 1,
fileType: ['image/png', 'image/jpeg', 'image/jpg', 'image/gif', 'image/bmp'],
// eslint-disable-next-line @typescript-eslint/no-empty-function
onChange: () => {},
onRemove: () => {},
};
const { fileType, children, listType, fileSize, fileLength, onChange, onRemove } = props;
const [fileList, setFileList] = useState<any[]>([]);
// 上传文件配置
const uploadProps: UploadProps = {
listType,
fileList,
beforeUpload: (res) => {
const isType = fileType?.includes(res.type);
const isSize = res.size / 1024 / 1024 < (fileSize || 2);
if (!isType) {
message.error('请上传正确的格式!').then();
return isType;
}
if (!isSize) {
message.error('文件最大2M,请压缩后上传!').then();
return isSize;
}
},
customRequest: (res) => {
if (fileList.length >= (fileLength || 1)) {
message.error(`最多上传${fileLength || 1}个文件`).then();
return;
}
setFileList([...fileList, res.file]);
onChange?.([...fileList, res.file]);
},
onRemove: (res) => {
const newFileList = fileList.filter((item) => item.uid !== res.uid);
setFileList(newFileList);
onRemove?.(newFileList);
},
// onPreview: { onPreview },
};
return (
<div className='uploader-view'>
<Upload {...uploadProps} style={{ width: '100%' }}>
<>{fileList.length < (fileLength || 1) && children}</>
</Upload>
</div>
);
};
import React from 'react';
import ReactDOM from 'react-dom/client';
import './assets/css/index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {BrowserRouter, Routes, Route} from "react-router-dom";
import {router} from "./router";
const routerList = router.map((i: any, j: number) => {
return <Route path={i.path} element={<i.element/>} key={j}/>;
})
ReactDOM.createRoot(document.getElementById("root")!).render(
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
{routerList}
{/*<Route index element={<Home />} />*/}
{/*<Route path="teams" element={<Teams />}>*/}
{/* <Route path=":teamId" element={<Team />} />*/}
{/* <Route path="new" element={<NewTeamForm />} />*/}
{/* <Route index element={<LeagueStandings />} />*/}
{/*</Route>*/}
</Route>
</Routes>
</BrowserRouter>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
import React from 'react';
import ReactDOM from 'react-dom/client';
import 'antd/dist/reset.css';
import { ConfigProvider } from 'antd';
import App from './App';
import 'dayjs/locale/zh-cn';
import zhCN from 'antd/locale/zh_CN';
import './assets/style/index.scss';
import dayjs from 'dayjs';
dayjs.locale('zh-cn');
const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render(
// <React.StrictMode>
<ConfigProvider locale={zhCN}>
<App />
</ConfigProvider>,
// </React.StrictMode>,
);
import { useRouteError } from 'react-router-dom';
export default function ErrorPage() {
const error: any = useRouteError();
console.error(error);
return (
<div id='error-page'>
<h1>Oops!</h1>
<p>Sorry, an unexpected error has occurred.</p>
<p>
<i>{error.statusText || error.message}</i>
</p>
</div>
);
}
import { Button } from 'antd';
import React from 'react';
import BrandSelectSearch from '~/components/brandSelectSearch';
const SearchView = () => {
return (
<div
style={{
padding: 10,
background: 'aliceblue',
boxSizing: 'border-box',
width: '100%',
height: '100%',
}}
>
<BrandSelectSearch
selected={true}
region={true}
columns={[
{
type: 'Product',
name: 'product',
label: '产品',
options: [
{ label: '无人机', value: 1 },
{ label: '挂载', value: 2 },
{ label: '地面站', value: 3 },
{ label: '电池', value: 4 },
{ label: '解决方案', value: 5 },
],
},
{
type: 'Brand',
name: 'brand',
label: '品牌',
subLabel: '型号',
options: [
{
label: '科比特',
value: 'MMC',
children: [
{ label: '入云龙', value: 1 },
{ label: '小旋风', value: 2 },
],
},
{
label: '大疆',
value: 'DJI',
children: [
{ label: '御2', value: 1 },
{ label: '悟2', value: 2 },
],
},
{
label: '小米',
value: 'MI',
children: [
{ label: '小米12', value: 1 },
{ label: '小米13', value: 2 },
],
},
{
label: '华为',
value: 'HUAWEI',
children: [
{ label: 'P50 Pro', value: 1 },
{ label: 'P60 Pro', value: 2 },
],
},
{
label: '苹果',
value: 'APPLE',
children: [
{ label: 'iPhone 13', value: 1 },
{ label: 'iPhone 14', value: 2 },
],
},
],
},
{
type: 'Industry',
name: 'industry',
label: '行业',
options: [
{ label: '公共安全', value: 1 },
{ label: '交通安全', value: 2 },
{ label: '应急', value: 3 },
{ label: '消防', value: 4 },
{ label: '城管', value: 5 },
{ label: '环保', value: 6 },
],
},
{
type: 'Price',
name: 'price',
label: '价格',
options: [
{ label: '0-3万', value: [0, 3] },
{ label: '3-5万', value: [3, 5] },
{ label: '5-10万', value: [5, 10] },
{ label: '10-15万', value: [10, 15] },
{ label: '15-20万', value: [15, 20] },
{ label: '20-30万', value: [20, 30] },
{ label: '30万以上', value: [30, null] },
],
},
]}
/>
<div
style={{
height: 100,
width: 400,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-around',
}}
>
<Button type={'primary'}>确定</Button>
<Button type={'default'}>确定</Button>
<Button type={'dashed'}>确定</Button>
<Button type={'link'}>确定</Button>
<Button type={'ghost'}>确定</Button>
</div>
</div>
);
};
export default SearchView;
import React from "react";
import {commonAPI} from '../../api'
export const Home = () => {
const [token, setToken] = React.useState('');
const GetLogin = async () => {
const res: any = await commonAPI.platformLogin({
accountNo: 'zlk',
passWord: 'mmc123456',
});
setToken(res.result.token);
console.log('res -->', res);
};
React.useEffect(()=>{
console.log('首页 !!!');
GetLogin();
},[])
const list = [1,2,3,4,5]
return (
<div style={{ padding: "1rem 0" }}>
<div>home !</div>
<div>{token}</div>
{list.map((i,j)=>{
return(
<h2 key={j}>{j} Home {i}</h2>
)
})}
</div>
);
}
/// <reference types="react-scripts" />
import { ReportHandler } from 'web-vitals';
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;
import {Home} from "../pages/testPage";
// import About from "../pages/test/About";
import { createHashRouter } from 'react-router-dom';
import { routerList } from '~/router/router';
export const router = [
{
path: 'home',
element: Home,
},
// {
// path: 'about',
// element: Home,
// }
];
// 导出路由表
export const router = createHashRouter(routerList);
// 路由表类型
// export type { routerItem } from "./router";
import React from 'react';
import { Navigate, RouteObject } from 'react-router-dom';
import ErrorPage from '~/pages/common/error';
import SearchView from '~/pages/test/search';
interface RouteObjectType {
meta?: {
id: number;
hidden?: boolean;
icon?: any;
customIcon?: boolean;
title: string;
};
}
// 路由数组
export const routerList: Array<RouteObject & RouteObjectType> = [
{
path: '*',
element: <div>404</div>,
errorElement: <ErrorPage />,
},
{
path: '/',
element: <Navigate to='/search' />,
errorElement: <ErrorPage />,
},
{
path: '/test',
element: <div>1223123</div>,
errorElement: <ErrorPage />,
},
{
path: '/search',
element: <SearchView />,
errorElement: <ErrorPage />,
meta: {
id: 1,
title: '时间计算器',
},
},
];
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';
import { message } from 'antd';
import * as XLSX from 'xlsx';
// 通过FileReader对象读取文件
export const XLSXFileReader = (file: Blob) => {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = (event) => {
try {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const { result } = event.target;
// 以二进制流方式读取得到整份excel表格对象
const workbook = XLSX.read(result, { type: 'binary' });
// 存储获取到的数据
const data = {};
// 遍历每张工作表进行读取(这里默认只读取第一张表)
for (const sheet in workbook.Sheets) {
const tempData: any[] = [];
// eslint-disable-next-line
// eslint-disable-next-line no-prototype-builtins
if (workbook.Sheets.hasOwnProperty(sheet)) {
// 利用 sheet_to_json 方法将 excel 转成 json 数据
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
data[sheet] = tempData.concat(XLSX.utils.sheet_to_json(workbook.Sheets[sheet]));
}
}
// console.log(data);
// 最终获取到并且格式化后的 json 数据
// message.success('上传成功!').then();
//上传成功啦,data为上传后的数据
resolve(data);
} catch (e) {
// 这里可以抛出文件类型错误不正确的相关提示
message.error('文件类型不正确!').then();
reject(e);
}
};
fileReader.readAsBinaryString(file);
});
};
/// <reference types="vite/client" />
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noEmit": true,
"jsx": "react-jsx"
"jsx": "preserve",
"incremental": true,
"baseUrl": ".",
"paths": {
"~/*": ["src/*"]
}
},
"include": [
"src"
]
"include": ["vite.config.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}
This source diff could not be displayed because it is too large. You can view the blob instead.
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
// https://vitejs.dev/config/
export default defineConfig({
base: './',
plugins: [react(), tsconfigPaths()],
server: {
host: '0.0.0.0',
},
});
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论