Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ umi-react-admin 是一个基于 Umi Max 的企业级 React 后台管理系统模

## 技术栈

- **框架**: Umi Max 4.x + React 18 + TypeScript 5.x
- **框架**: Umi Max 4.x + React 19(项目直接依赖,umi 别名到它)+ TypeScript 6
- **UI**: Ant Design 5 + Ant Design Pro Components
- **样式**: Tailwind CSS 4(CSS 优先配置,工具类不分层,见 tailwind.css 头注释)+ Less
- **状态管理**: Umi initialState(全局用户与主题)+ 组件内 state(未启用 valtio)
Expand Down Expand Up @@ -85,7 +85,8 @@ config/
- [config/routes.ts](config/routes.ts) - 路由配置
- [tailwind.css](tailwind.css) - Tailwind CSS 配置(v4 无 JS 配置文件)
- [.prettierrc](.prettierrc) - Prettier 配置
- [.eslintrc.js](.eslintrc.js) - ESLint 配置
- [eslint.config.mjs](eslint.config.mjs) - ESLint 10 flat config(移植自 umi lint 预设)
- [stylelint.config.mjs](stylelint.config.mjs) - stylelint 17 配置

## 特殊说明

Expand Down
14 changes: 0 additions & 14 deletions .eslintignore

This file was deleted.

34 changes: 0 additions & 34 deletions .eslintrc.js

This file was deleted.

6 changes: 3 additions & 3 deletions .lintstagedrc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"*.{md,json}": ["prettier --cache --write"],
"*.{js,jsx,mjs,cjs}": ["eslint --fix --max-warnings=0", "prettier --cache --write"],
"*.{css,less}": ["max lint --fix --stylelint-only", "prettier --cache --write"],
"*.ts?(x)": ["eslint --fix --max-warnings=0", "prettier --cache --parser=typescript --write"]
"*.{js,jsx,mjs,cjs}": ["eslint --fix --max-warnings=0 --no-warn-ignored", "prettier --cache --write"],
"*.{css,less}": ["stylelint --fix --allow-empty-input", "prettier --cache --write"],
"*.ts?(x)": ["eslint --fix --max-warnings=0 --no-warn-ignored", "prettier --cache --parser=typescript --write"]
}
15 changes: 3 additions & 12 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
# 本文件只承载鉴权与 registry(pnpm 11 起其余配置一律写在 pnpm-workspace.yaml,这里写了也不生效)。
# 仓库不指定 registry(CI、Docker 与全球贡献者默认走 npm 官方源)。
# 国内开发者请在自己的 ~/.npmrc 配置镜像,例如:registry=https://registry.npmmirror.com/
# 注意镜像源不支持 audit 通道,安全审计需显式走官方源:
# pnpm audit --registry=https://registry.npmjs.org/

# 将依赖提升至node_modules根目录。
shamefully-hoist=true

# 如果希望自动安装对等依赖项
auto-install-peers=true

# 如果您不希望pnpm在对等依赖问题上失败
strict-peer-dependencies=false

# 锁文件纪律:不在 .npmrc 全局关闭 frozen-lockfile。
# CI/GitHub Actions 已显式 --frozen-lockfile,Vercel 由 vercel.json 的 installCommand 锁定,
#
# 锁文件纪律:CI/GitHub Actions 已显式 --frozen-lockfile,Vercel 由 vercel.json 的 installCommand 锁定,
# pnpm 在 CI 环境也会自动启用 frozen 模式;本地开发保持默认以便更新锁文件。
18 changes: 0 additions & 18 deletions .stylelintrc.js

This file was deleted.

10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@

## [未发布] - 2026-09 治理批次(feat/next-umi)

### 依赖升级阶段 4(2026-09-23)

- pnpm 10 → 11.27.1:11 起不读 `package.json#pnpm` 与 `.npmrc` 非鉴权配置,overrides(49 条)与提升等配置迁入 `pnpm-workspace.yaml`,`allowBuilds` 显式记录不执行的安装脚本;Dockerfile 同步拷贝该文件。未选 12.x:12 是 Rust 重写的原生二进制,pnpm 10 自动切换到它在本机即失败(ENOEXEC)
- 关闭 `shamefullyHoist`:node_modules 顶层只剩声明的依赖;Cesium 默认 token 白名单与 mock 可加载性门禁改为沿依赖链解析传递依赖
- TypeScript 5.9 → 6.0(最后一个带 JS 编译器 API 的版本)。TS 7 暂缓:typescript-eslint 最新版 peer `<6.1.0`;实测 TS 7.0.2 对本项目类型检查 0 错误、1.35s
- ESLint 8(@umijs/lint 预设)→ ESLint 10 flat config(`eslint.config.mjs`,逐条移植 umi 规则集);stylelint 14 → 17(`stylelint.config.mjs`)。ESLint 9 已于 2026-08 EOL 故直接上 10
- React 18 → 19(项目直接依赖,umi 别名到它)、@types/react 19、react-pdf 11(PDF.js 6.3,`suspense={false}` 保留原告警);antd 5 经官方 `@ant-design/v5-patch-for-react-19` 兼容 React 19
- 高德页去掉 `@pansy/react-amap`(其 Marker 调用 React 19 已删除的 `unmountComponentAtNode`,库 2024-06 后无更新),改为直接调用 JS API 2.0,加载器仍用 `@pansy/amap-api-loader`,未配 key 时行为不变
- antd 6 + pro-components 3(beta)放在独立实验分支 `chore/deps-phase4-antd6-experimental`,未并入本阶段

### 依赖升级阶段 3(2026-09-23)

- FullCalendar 6 → 7:五个插件包合并为 `@fullcalendar/react/*` 入口,新增 peer `temporal-polyfill`;v7 不再内置 CSS,改为引入 skeleton + Classic 主题(保持 v6 外观);类型改名(`DateSelectArg` → `DateSelectInfo` 等);日历随应用暗色主题切换(调色板读取祖先 `data-color-scheme`)。可见差异:v6 下日期数字被 antd 的链接色染成蓝色,v7 恢复正文色;列头默认不加粗
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## 环境准备

- Node.js 24 LTS(见 `.nvmrc`,推荐 nvm / fnm);最低 22.22.2
- pnpm 10+(`packageManager` 字段钉住版本,corepack 可自动启用)
- pnpm 11(`packageManager` 字段钉住版本,pnpm 10 与 corepack 会自动切换);配置在 `pnpm-workspace.yaml`,`.npmrc` 只放鉴权与 registry。从 pnpm 10 首次切换时 node_modules 需重建(非交互终端加 `--config.confirm-modules-purge=false`)

```bash
pnpm install
Expand Down
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ FROM node:24-alpine@sha256:ebfe2f90462722a7a4de65e91990e97fe0d401c70e0e762c5b533
WORKDIR /app

# 先装依赖以利用层缓存
COPY package.json pnpm-lock.yaml .npmrc ./
# pnpm-workspace.yaml 承载 overrides 与提升配置,缺了它 --frozen-lockfile 会因配置不符而失败
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
RUN corepack enable && pnpm install --frozen-lockfile

# 源码与构建(Cesium token 经 build-arg 注入,最终 define 进产物)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE) [![Deploy](https://github.com/Jerry-CodeHub/umi-react-admin/actions/workflows/deploy.yml/badge.svg?branch=master)](https://github.com/Jerry-CodeHub/umi-react-admin/actions/workflows/deploy.yml) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](./CONTRIBUTING.md)

`umi-react-admin` 是一个基于 `react` 和 `umi max` 的模板系统, 一款开源免费且开箱即用的系统模板, 使用了最新的 `Umi4.x`, `React18.x` , `antd5.x` , `Tailwindcss` , `CSS in JS` , `TypeScript` , `ProComponents` 等主流技术开发。
`umi-react-admin` 是一个基于 `react` 和 `umi max` 的模板系统, 一款开源免费且开箱即用的系统模板, 使用了最新的 `Umi4.x`, `React19.x` , `antd5.x` , `Tailwindcss` , `CSS in JS` , `TypeScript` , `ProComponents` 等主流技术开发。

**[在线演示](https://jerry-codehub.github.io/umi-react-admin/)**(演示环境:任意用户名/密码登录;纯静态部署下鉴权与表格数据在前端本地模拟)

Expand All @@ -17,7 +17,7 @@
## 环境要求

- Node.js 24 LTS(见 [.nvmrc](./.nvmrc),推荐使用 nvm / fnm 管理);最低 22.22.2(jsdom、Cesium 等依赖的引擎要求)
- pnpm 10+(`packageManager` 字段已钉住版本)
- pnpm 11(`packageManager` 字段已钉住版本,pnpm 10 会自动切换);新发布不足 24 小时的依赖版本会被 pnpm 11 默认的 `minimumReleaseAge` 拒绝
- 国内开发者可在 `~/.npmrc` 自行配置镜像源(本仓库的 `.npmrc` 不携带镜像配置)

## 安装使用
Expand Down
190 changes: 190 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// ESLint 10 flat config。规则集移植自 @umijs/lint 的 recommended 预设(原 .eslintrc.js 经
// @umijs/max/eslint 继承,锁在 ESLint 8 / typescript-eslint 5),再叠加本项目的覆盖项。
import vitest from '@vitest/eslint-plugin';
import jsxA11y from 'eslint-plugin-jsx-a11y';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import { defineConfig } from 'eslint/config';
import globals from 'globals';
import tseslint from 'typescript-eslint';

/** umi recommended:内置规则 */
const umiCoreRules = {
// 不需要返回就用 forEach
'array-callback-return': 'error',
// eqeq 可能导致潜在的类型转换问题(项目覆盖为 warn,见下)
eqeqeq: 'error',
'for-direction': 'error',
// 不加 hasOwnProperty 判断会多出原型链的内容
'guard-for-in': 'error',
'no-async-promise-executor': 'error',
'no-case-declarations': 'error',
'no-debugger': 'error',
'no-delete-var': 'error',
'no-dupe-else-if': 'error',
'no-duplicate-case': 'error',
// eval() 可能导致潜在的安全问题
'no-eval': 'error',
'no-ex-assign': 'error',
// 没必要改 native 变量(umi 预设里的 no-native-reassign 是它的旧名)
'no-global-assign': 'error',
'no-invalid-regexp': 'error',
// 修改对象时,会影响原对象;但是有些场景就是有目的
'no-param-reassign': 'error',
// return 值无意义,可能会理解为 resolve
'no-promise-executor-return': 'error',
'no-self-assign': 'error',
'no-self-compare': 'error',
'no-shadow-restricted-names': 'error',
'no-sparse-arrays': 'error',
'no-unsafe-finally': 'error',
'no-unused-labels': 'error',
'no-useless-catch': 'error',
'no-useless-escape': 'error',
'no-var': 'error',
'no-with': 'error',
'require-yield': 'error',
'use-isnan': 'error',
};

/** umi recommended:React 与 hooks(只开 rules-of-hooks,与原预设一致) */
const umiReactRules = {
// button 自带 submit 属性
'react/button-has-type': 'error',
'react/jsx-key': 'error',
'react/jsx-no-comment-textnodes': 'error',
'react/jsx-no-duplicate-props': 'error',
'react/jsx-no-target-blank': 'error',
'react/jsx-no-undef': 'error',
'react/jsx-uses-react': 'error',
'react/jsx-uses-vars': 'error',
'react/no-children-prop': 'error',
'react/no-danger-with-children': 'error',
'react/no-deprecated': 'error',
'react/no-direct-mutation-state': 'error',
'react/no-find-dom-node': 'error',
'react/no-is-mounted': 'error',
'react/no-string-refs': 'error',
'react/no-render-return-value': 'error',
'react/no-unescaped-entities': 'error',
'react/no-unknown-property': 'error',
'react/require-render-return': 'error',
'react-hooks/rules-of-hooks': 'error',
};

/**
* umi recommended:TypeScript。typescript-eslint 8 删除了 ban-types、no-empty-interface,
* 由 no-empty-object-type / no-unsafe-function-type / no-wrapper-object-types 接替。
*/
const umiTypescriptRules = {
'no-dupe-class-members': 'off',
'no-invalid-this': 'off',
'no-loop-func': 'off',
'no-redeclare': 'off',
'no-unused-expressions': 'off',
'no-unused-vars': 'off',
'no-use-before-define': 'off',
'no-useless-constructor': 'off',
'@typescript-eslint/no-confusing-non-null-assertion': 'error',
'@typescript-eslint/no-dupe-class-members': 'error',
'@typescript-eslint/no-empty-object-type': 'error',
'@typescript-eslint/no-invalid-this': 'error',
'@typescript-eslint/no-loop-func': 'error',
'@typescript-eslint/no-misused-new': 'error',
'@typescript-eslint/no-namespace': 'error',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
'@typescript-eslint/no-redeclare': 'error',
'@typescript-eslint/no-this-alias': 'error',
'@typescript-eslint/no-unsafe-function-type': 'error',
'@typescript-eslint/no-unused-expressions': 'error',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-use-before-define': 'error',
'@typescript-eslint/no-useless-constructor': 'error',
'@typescript-eslint/no-wrapper-object-types': 'error',
'@typescript-eslint/triple-slash-reference': 'error',
};

/** umi recommended 对测试文件启用的 jest 规则,按 vitest 插件的同名规则移植 */
const umiTestRules = {
'vitest/no-conditional-expect': 'error',
'vitest/no-focused-tests': 'error',
'vitest/no-identical-title': 'error',
'vitest/no-interpolation-in-snapshots': 'error',
'vitest/no-mocks-import': 'error',
'vitest/no-standalone-expect': 'error',
'vitest/valid-describe-callback': 'error',
'vitest/valid-expect': 'error',
'vitest/valid-expect-in-promise': 'error',
'vitest/valid-title': 'error',
};

export default defineConfig(
{
ignores: [
'public/Cesium/',
'public/js/',
'dist/',
'src/.umi/',
'src/.umi-production/',
'coverage/',
'.claude/',
'.kilo/',
],
},
{
files: ['**/*.{js,jsx,mjs,cjs,ts,tsx}'],
plugins: { react, 'react-hooks': reactHooks, 'jsx-a11y': jsxA11y },
languageOptions: {
ecmaVersion: 2022,
sourceType: 'module',
parserOptions: { ecmaFeatures: { jsx: true } },
globals: { ...globals.browser, ...globals.node },
},
// 显式版本:eslint-plugin-react 7.37 的 'detect' 走 context.getFilename(),ESLint 10 已删除该 API(会直接崩溃)
settings: { react: { version: '19.3' } },
linterOptions: { reportUnusedDisableDirectives: 'off' },
rules: {
...umiCoreRules,
...umiReactRules,
// ---- 项目覆盖(原 .eslintrc.js)----
// 禁止使用 console.log,但允许 warn 和 error
'no-console': ['warn', { allow: ['warn', 'error'] }],
// 要求使用 === 和 !==
eqeqeq: ['warn', 'always'],
// 禁止在 return、throw、continue 和 break 语句后出现不可达代码
'no-unreachable': 'warn',
// a11y 最小集(阶段5):图片必有 alt、aria 属性合法,不启用大规模规则避免存量误报
'jsx-a11y/alt-text': 'error',
'jsx-a11y/aria-props': 'error',
'jsx-a11y/role-supports-aria-props': 'error',
'jsx-a11y/anchor-is-valid': 'warn',
},
},
{
files: ['**/*.{ts,tsx}'],
languageOptions: { parser: tseslint.parser },
plugins: { '@typescript-eslint': tseslint.plugin },
rules: {
...umiTypescriptRules,
// 禁止未使用的变量(仅警告)
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
// 禁止使用 any 类型(仅警告,避免影响现有代码)
'@typescript-eslint/no-explicit-any': 'warn',
},
},
{
files: ['**/*.{test,spec}.{ts,tsx,js,jsx}'],
plugins: { vitest },
rules: umiTestRules,
},
{
// CommonJS 配置文件(.stylelintrc.js 等)
files: ['**/*.cjs', '.stylelintrc.js'],
languageOptions: { sourceType: 'commonjs' },
},
{
// 构建与门禁脚本是命令行工具,向终端输出是本职
files: ['scripts/**/*.{js,mjs,cjs,ts}'],
rules: { 'no-console': 'off' },
},
);
2 changes: 1 addition & 1 deletion nginx/security-headers.conf
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment
# 白屏后再去掉 -Report-Only 后缀转正式。来源清单按产物逐域核实(与 vercel.json / config.github.ts 保持一致):
# - 'unsafe-eval':Cesium Knockout 模板编译用 new Function(实测在用),pdfjs 已关 isEvalSupported
# - style 'unsafe-inline':AntD cssinjs 运行时注入 + tailwind 任意值
# - 高德/autonavi:react-amap JSONP;openstreetmap:InfoMap OSM 瓦片;ion.cesium.com:默认影像
# - 高德/autonavi:AMap JS API 2.0(经 @pansy/amap-api-loader 加载,JSONP);openstreetmap:InfoMap OSM 瓦片;ion.cesium.com:默认影像
# - virtualearth.net:未配置 ion token 时 Cesium 的 Bing 影像兜底(元数据 + 瓦片)。
# 注意瓦片协议跟随页面协议(uriScheme):本站以 http 提供时 Cesium 会请求 http://ecn.t*.tiles…,
# 与 https:// 白名单不匹配(生产 https 部署不受影响);配置了 ion token 的部署走 ion 影像,与此无关
Expand Down
Loading
Loading