diff --git a/nkebao/.env.development b/nkebao/.env.development new file mode 100644 index 00000000..fe189d22 --- /dev/null +++ b/nkebao/.env.development @@ -0,0 +1,4 @@ +# 基础环境变量示例 +VITE_API_BASE_URL=https://ckbapi.quwanzhi.com +VITE_APP_TITLE=Nkebao Base + diff --git a/nkebao/.env.production b/nkebao/.env.production new file mode 100644 index 00000000..fe189d22 --- /dev/null +++ b/nkebao/.env.production @@ -0,0 +1,4 @@ +# 基础环境变量示例 +VITE_API_BASE_URL=https://ckbapi.quwanzhi.com +VITE_APP_TITLE=Nkebao Base + diff --git a/nkebao/.eslintrc.js b/nkebao/.eslintrc.js new file mode 100644 index 00000000..887b3d7a --- /dev/null +++ b/nkebao/.eslintrc.js @@ -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', + }, +}; \ No newline at end of file diff --git a/nkebao/.gitignore b/nkebao/.gitignore new file mode 100644 index 00000000..57747f4f --- /dev/null +++ b/nkebao/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +dist/ +build/ +yarn.lock +.env +.DS_Store \ No newline at end of file diff --git a/nkebao/README.md b/nkebao/README.md new file mode 100644 index 00000000..d67e78b2 --- /dev/null +++ b/nkebao/README.md @@ -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 模板 +``` \ No newline at end of file diff --git a/nkebao/index.html b/nkebao/index.html new file mode 100644 index 00000000..2aaa892e --- /dev/null +++ b/nkebao/index.html @@ -0,0 +1,13 @@ + + + + + + Nkebao Base + + + +
+ + + \ No newline at end of file diff --git a/nkebao/package.json b/nkebao/package.json new file mode 100644 index 00000000..cfa0f01b --- /dev/null +++ b/nkebao/package.json @@ -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" + } +} diff --git a/nkebao/postcss.config.js b/nkebao/postcss.config.js new file mode 100644 index 00000000..34ea9ede --- /dev/null +++ b/nkebao/postcss.config.js @@ -0,0 +1,8 @@ +module.exports = { + plugins: { + 'postcss-pxtorem': { + rootValue: 16, + propList: ['*'], + }, + }, +}; \ No newline at end of file diff --git a/nkebao/src/App.tsx b/nkebao/src/App.tsx new file mode 100644 index 00000000..bb423eff --- /dev/null +++ b/nkebao/src/App.tsx @@ -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 ( + + + } /> + } /> + +
+ + Antd-Mobile 按钮 +
+
+ ); +} + +export default App; diff --git a/nkebao/src/api/module/auth.ts b/nkebao/src/api/module/auth.ts new file mode 100644 index 00000000..dba5ef64 --- /dev/null +++ b/nkebao/src/api/module/auth.ts @@ -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'); \ No newline at end of file diff --git a/nkebao/src/api/request.ts b/nkebao/src/api/request.ts new file mode 100644 index 00000000..aaa2dca1 --- /dev/null +++ b/nkebao/src/api/request.ts @@ -0,0 +1,64 @@ +import axios, { AxiosInstance, AxiosRequestConfig, Method, AxiosResponse } from 'axios'; + +const DEBOUNCE_GAP = 1000; +const debounceMap = new Map(); + +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 { + 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; \ No newline at end of file diff --git a/nkebao/src/main.tsx b/nkebao/src/main.tsx new file mode 100644 index 00000000..f62c6b7b --- /dev/null +++ b/nkebao/src/main.tsx @@ -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(); diff --git a/nkebao/src/pages/About.tsx b/nkebao/src/pages/About.tsx new file mode 100644 index 00000000..370fdfe2 --- /dev/null +++ b/nkebao/src/pages/About.tsx @@ -0,0 +1,7 @@ +import React from "react"; + +const About: React.FC = () => { + return

关于 About

; +}; + +export default About; diff --git a/nkebao/src/pages/Home.tsx b/nkebao/src/pages/Home.tsx new file mode 100644 index 00000000..2f0a324a --- /dev/null +++ b/nkebao/src/pages/Home.tsx @@ -0,0 +1,7 @@ +import React from "react"; + +const Home: React.FC = () => { + return

首页 Home

; +}; + +export default Home; diff --git a/nkebao/src/react-app-env.d.ts b/nkebao/src/react-app-env.d.ts new file mode 100644 index 00000000..751f967f --- /dev/null +++ b/nkebao/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// \ No newline at end of file diff --git a/nkebao/src/styles/global.scss b/nkebao/src/styles/global.scss new file mode 100644 index 00000000..62f63469 --- /dev/null +++ b/nkebao/src/styles/global.scss @@ -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; +} \ No newline at end of file diff --git a/nkebao/tsconfig.json b/nkebao/tsconfig.json new file mode 100644 index 00000000..53184fe3 --- /dev/null +++ b/nkebao/tsconfig.json @@ -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"] +} \ No newline at end of file diff --git a/nkebao/vite.config.ts b/nkebao/vite.config.ts new file mode 100644 index 00000000..52f1437a --- /dev/null +++ b/nkebao/vite.config.ts @@ -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, + }, +}); \ No newline at end of file diff --git a/nkebao/技术栈.md b/nkebao/技术栈.md new file mode 100644 index 00000000..be554562 --- /dev/null +++ b/nkebao/技术栈.md @@ -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 代码规范配置 \ No newline at end of file