feat: 本次提交更新内容如下
新项目模板初始化
This commit is contained in:
4
nkebao/.env.development
Normal file
4
nkebao/.env.development
Normal file
@@ -0,0 +1,4 @@
|
||||
# 基础环境变量示例
|
||||
VITE_API_BASE_URL=https://ckbapi.quwanzhi.com
|
||||
VITE_APP_TITLE=Nkebao Base
|
||||
|
||||
4
nkebao/.env.production
Normal file
4
nkebao/.env.production
Normal file
@@ -0,0 +1,4 @@
|
||||
# 基础环境变量示例
|
||||
VITE_API_BASE_URL=https://ckbapi.quwanzhi.com
|
||||
VITE_APP_TITLE=Nkebao Base
|
||||
|
||||
21
nkebao/.eslintrc.js
Normal file
21
nkebao/.eslintrc.js
Normal file
@@ -0,0 +1,21 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
'react-app',
|
||||
'plugin:react/recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['react', '@typescript-eslint', 'prettier'],
|
||||
rules: {
|
||||
'prettier/prettier': 'warn',
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'warn',
|
||||
},
|
||||
};
|
||||
6
nkebao/.gitignore
vendored
Normal file
6
nkebao/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
node_modules/
|
||||
dist/
|
||||
build/
|
||||
yarn.lock
|
||||
.env
|
||||
.DS_Store
|
||||
33
nkebao/README.md
Normal file
33
nkebao/README.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Nkebao Base
|
||||
|
||||
基于 React + TypeScript + axios + sass + React Router v6 + antd + antd-mobile 的基础项目模板。
|
||||
|
||||
## 启动方式
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
yarn start
|
||||
```
|
||||
|
||||
## 技术栈
|
||||
- React
|
||||
- TypeScript
|
||||
- axios
|
||||
- sass
|
||||
- React Router v6
|
||||
- antd
|
||||
- antd-mobile
|
||||
- postcss-pxtorem (rem 适配)
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
src/
|
||||
api/ # axios 封装
|
||||
pages/ # 页面组件
|
||||
styles/ # 全局样式
|
||||
App.tsx # 入口组件
|
||||
main.tsx # 入口文件
|
||||
public/
|
||||
index.html # HTML 模板
|
||||
```
|
||||
13
nkebao/index.html
Normal file
13
nkebao/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Nkebao Base</title>
|
||||
<style>html{font-size:16px;}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
37
nkebao/package.json
Normal file
37
nkebao/package.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "nkebao-base",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"antd": "^5.13.1",
|
||||
"antd-mobile": "^5.39.1",
|
||||
"axios": "^1.6.7",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.20.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.0.14",
|
||||
"@types/react": "^19.1.8",
|
||||
"@types/react-dom": "^19.1.6",
|
||||
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
||||
"@typescript-eslint/parser": "^7.7.0",
|
||||
"@vitejs/plugin-react": "^4.6.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-react": "^7.34.1",
|
||||
"postcss": "^8.4.38",
|
||||
"postcss-pxtorem": "^6.0.0",
|
||||
"prettier": "^3.2.5",
|
||||
"sass": "^1.75.0",
|
||||
"typescript": "^5.4.5",
|
||||
"vite": "^7.0.5"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint 'src/**/*.{js,jsx,ts,tsx}' --fix"
|
||||
}
|
||||
}
|
||||
8
nkebao/postcss.config.js
Normal file
8
nkebao/postcss.config.js
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'postcss-pxtorem': {
|
||||
rootValue: 16,
|
||||
propList: ['*'],
|
||||
},
|
||||
},
|
||||
};
|
||||
23
nkebao/src/App.tsx
Normal file
23
nkebao/src/App.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import React from "react";
|
||||
import { BrowserRouter, Routes, Route } from "react-router-dom";
|
||||
import { Button } from "antd";
|
||||
import { Button as MobileButton } from "antd-mobile";
|
||||
import Home from "./pages/Home";
|
||||
import About from "./pages/About";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/about" element={<About />} />
|
||||
</Routes>
|
||||
<div style={{ margin: 16 }}>
|
||||
<Button type="primary">Antd 按钮</Button>
|
||||
<MobileButton color="primary">Antd-Mobile 按钮</MobileButton>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
22
nkebao/src/api/module/auth.ts
Normal file
22
nkebao/src/api/module/auth.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { request } from '@/api/request';
|
||||
|
||||
export const list = (data?: any) =>
|
||||
request('/cw/companyUser/list', data, 'GET');
|
||||
|
||||
export const joinAudit = (data: any) =>
|
||||
request('/cw/companyUser/joinAudit', data, 'PUT');
|
||||
|
||||
export const listJoinAudit = (data?: any) =>
|
||||
request('/cw/companyUser/listJoinAudit', data, 'GET');
|
||||
|
||||
export const CwCompanyUserApplyAdd = (data: any) =>
|
||||
request('/cw/CwCompanyUserApply/add', data, 'PUT');
|
||||
|
||||
export const CwCompanyUserApplyAdminList = (data?: any) =>
|
||||
request('/cw/CwCompanyUserApply/adminList', data, 'GET');
|
||||
|
||||
export const CwCompanyUserApplyAudit = (data: any) =>
|
||||
request('/cw/CwCompanyUserApply/audit', data, 'POST');
|
||||
|
||||
export const CwCompanyUserApplyUserList = (data?: any) =>
|
||||
request('/cw/CwCompanyUserApply/userList', data, 'GET');
|
||||
64
nkebao/src/api/request.ts
Normal file
64
nkebao/src/api/request.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import axios, { AxiosInstance, AxiosRequestConfig, Method, AxiosResponse } from 'axios';
|
||||
|
||||
const DEBOUNCE_GAP = 1000;
|
||||
const debounceMap = new Map<string, number>();
|
||||
|
||||
const instance: AxiosInstance = axios.create({
|
||||
baseURL: (import.meta as any).env?.VITE_API_BASE_URL || '/api',
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
instance.interceptors.request.use(config => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
config.headers = config.headers || {};
|
||||
config.headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
||||
instance.interceptors.response.use(
|
||||
(res: AxiosResponse) => {
|
||||
if (res.data && (res.data.code === 200 || res.data.success)) {
|
||||
return res.data.data ?? res.data;
|
||||
}
|
||||
window?.alert?.(res.data?.msg || '接口错误');
|
||||
return Promise.reject(res.data?.msg || '接口错误');
|
||||
},
|
||||
err => {
|
||||
window?.alert?.(err.message || '网络异常');
|
||||
return Promise.reject(err);
|
||||
}
|
||||
);
|
||||
|
||||
export function request(
|
||||
url: string,
|
||||
data?: any,
|
||||
method: Method = 'GET',
|
||||
config?: AxiosRequestConfig
|
||||
): Promise<any> {
|
||||
const key = `${method}_${url}_${JSON.stringify(data)}`;
|
||||
const now = Date.now();
|
||||
const last = debounceMap.get(key) || 0;
|
||||
if (now - last < DEBOUNCE_GAP) {
|
||||
return Promise.reject('请求过于频繁,请稍后再试');
|
||||
}
|
||||
debounceMap.set(key, now);
|
||||
|
||||
const axiosConfig: AxiosRequestConfig = {
|
||||
url,
|
||||
method,
|
||||
...config,
|
||||
};
|
||||
if (method.toUpperCase() === 'GET') {
|
||||
axiosConfig.params = data;
|
||||
} else {
|
||||
axiosConfig.data = data;
|
||||
}
|
||||
return instance(axiosConfig);
|
||||
}
|
||||
|
||||
export default request;
|
||||
7
nkebao/src/main.tsx
Normal file
7
nkebao/src/main.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import React from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import App from "./App";
|
||||
import "./styles/global.scss";
|
||||
|
||||
const root = createRoot(document.getElementById("root")!);
|
||||
root.render(<App />);
|
||||
7
nkebao/src/pages/About.tsx
Normal file
7
nkebao/src/pages/About.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import React from "react";
|
||||
|
||||
const About: React.FC = () => {
|
||||
return <h1>关于 About</h1>;
|
||||
};
|
||||
|
||||
export default About;
|
||||
7
nkebao/src/pages/Home.tsx
Normal file
7
nkebao/src/pages/Home.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import React from "react";
|
||||
|
||||
const Home: React.FC = () => {
|
||||
return <h1>首页 Home</h1>;
|
||||
};
|
||||
|
||||
export default Home;
|
||||
1
nkebao/src/react-app-env.d.ts
vendored
Normal file
1
nkebao/src/react-app-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="react-scripts" />
|
||||
18
nkebao/src/styles/global.scss
Normal file
18
nkebao/src/styles/global.scss
Normal file
@@ -0,0 +1,18 @@
|
||||
html, body {
|
||||
height: 100%;
|
||||
overflow: hidden; // 禁止 body 滚动和回弹
|
||||
}
|
||||
|
||||
#root, .app-content {
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch; // iOS 惯性滚动
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
23
nkebao/tsconfig.json
Normal file
23
nkebao/tsconfig.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
15
nkebao/vite.config.ts
Normal file
15
nkebao/vite.config.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import path from 'path';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve('src'),
|
||||
},
|
||||
},
|
||||
server: {
|
||||
open: true,
|
||||
},
|
||||
});
|
||||
26
nkebao/技术栈.md
Normal file
26
nkebao/技术栈.md
Normal file
@@ -0,0 +1,26 @@
|
||||
## 使用技术栈
|
||||
- React 18
|
||||
- TypeScript
|
||||
- Vite(新一代前端构建工具)
|
||||
- axios
|
||||
- sass (scss)
|
||||
- React Router v6
|
||||
- antd-mobile
|
||||
- antd(已设置基础单位为 rem,配合 postcss-pxtorem)
|
||||
- postcss-pxtorem(px 转 rem,移动端适配)
|
||||
- ESLint + Prettier(代码规范与自动格式化)
|
||||
- 路径别名 @ 指向 src 目录
|
||||
|
||||
## 关于兼容与工程化
|
||||
- 自动化脚本(yarn lint、yarn dev 等)
|
||||
- 移动端 rem 适配(html 根字体 + pxtorem)
|
||||
- iOS 浏览器滚动回弹兼容问题已通过全局样式处理
|
||||
- 支持 VS Code 编辑器自动格式化(推荐配合 ESLint/Prettier 插件)
|
||||
|
||||
## 目录结构简要
|
||||
- src/ 业务源码(pages、api、styles、App.tsx、main.tsx 等)
|
||||
- public/ 静态资源目录
|
||||
- index.html 项目入口(根目录)
|
||||
- vite.config.ts 构建与路径别名配置
|
||||
- tsconfig.json TypeScript 配置
|
||||
- .eslintrc.js 代码规范配置
|
||||
Reference in New Issue
Block a user