Files
senmesh-zc/frontend/AGENTS.md
KodouWZF 47273ae3fd init: 信创文件安全传输系统内外网本地 Docker 部署
包含 s-file 后端、React 前端、MeshSafe 安全检测对接,以及内外网两套
compose/nginx/配置(仅前端 28180/28280 对外发布,其余端口不暴露)。

说明:deploy/config/application-iw.yml 与 application-ow.yml 按维护者
明确要求原样入库,其中含本机 Docker 用的库口令、RabbitMQ 口令与 JWT
密钥;上生产前需替换。
2026-11-02 10:59:03 +08:00

89 lines
6.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md
森睿智传(senmesh-zc-legacy)——内网/外网文件传输与网盘管理 Web 端(React SPA)。后端为 s-file(alita-bjy-uygur 仓库),本项目为其前端。
## 常用命令
```bash
bun install # 安装依赖(使用 bun.lock;Node >= 20,本机经 nvm 提供)
bun run dev # 启动开发服务器(Vite)
bun run build # tsc -b && vite build(类型检查 + 构建,构建目标 chrome86)
bun run build:inside # 内网包(VITE_IS_INSIDE=true)→ dist/inside
bun run build:outside # 外网包(VITE_IS_INSIDE=false)→ dist/outside
bun run lint # ESLint(存在大量存量告警,见「代码约定」)
bun run preview # 预览构建产物
```
内外网发布包构建后打 tar(解压后 index.html 在顶层,可直接作为 nginx 站点根):
```bash
tar -czf release/senmesh-zc-inside.tar.gz --exclude='.DS_Store' -C dist/inside .
tar -czf release/senmesh-zc-outside.tar.gz --exclude='.DS_Store' -C dist/outside .
```
没有测试框架,验证手段为 `build`(含 tsc 严格检查)+ 浏览器冒烟。
## 关键注意事项
- **路由树是生成的**:`src/routeTree.gen.ts` 由 `@tanstack/router-plugin` 在 dev/build 时生成。新增路由文件后直接跑 `tsc -b` 会报路由不存在 —— 先跑 `bunx vite build`(或启动 dev)再跑 `bunx tsc -b`。
- **Hash 路由**:`createHashHistory`,页面地址形如 `/#/admin/user`,直接访问不带 `#` 的路径会落到首页。
- **ESLint 基线**:存量代码大量 `no-explicit-any`、`useColumns` 在回调中调用等告警属既有风格;新代码与周围风格保持一致即可,`tsc` 严格检查(`strict`、`noUnusedLocals`、`noUnusedParameters`)才是硬门禁。
## 技术栈
React 19 · TypeScript(strict) · Vite(rolldown-vite) · TanStack Router(文件路由 + autoCodeSplitting)· TanStack Query v5(全局 `retry: false`、`refetchOnWindowFocus: false`,见 `src/main.tsx`)· TanStack Table · zustand(persist + derive-zustand)· axios · Tailwind 3 + shadcn/ui(Radix)· lucide-react · sonner · react-dropzone · react-hook-form + zod
## 目录结构
```
src/
apis/ # 接口函数,按域分文件(user/org/file/upload-config)
lib/http/ # axios 实例与拦截器(index.ts 导出 http 与常量)
routes/
(user)/ # 用户端网盘页面(my/outside/inside/share/recycle)
admin/ # 管理后台;route.tsx 定义侧边菜单
extract/ # 抽取
components/ # 共享业务组件;ui/ 为 shadcn 基础组件
hooks/ # 共享 hooks(kebab-case 文件名,如 use-upload-config.ts)
stores/user.ts # 登录态 store(persist,key 为 `${VITE_STORE_PREFIX}_user`)
```
### 路由/页面组织约定
- 功能目录 = `index.tsx`(路由 + `useColumns` + 页面组件)+ `-hooks/` + `-components/`;`-` 前缀目录不参与路由。
- 列表页统一走 `useFetchList` 模式:`useState` 分页 `{pageIndex, pageSize}` + `useQuery`(queryKey 含 `[名称, pagination, params]`)+ `useReactTable`(`getCoreRowModel`、手动分页)+ 共享 `<DataTable>`/`<Pagination>`。
- 筛选条件采用「点击查询后生效」:草稿 state 与提交 params 分离,提交时过滤空值并重置到第一页(参考 `admin/org-account`、`admin/file-record`)。
- 管理后台菜单在 `admin/route.tsx` 的 `menus` 中维护;仅平台机构(超管)可见的菜单加入 `platformOnlyUrls`(由 `useIsPlatformOrg` 即 `org.id === 1` 判断),机构级菜单(用户管理、上传配置)不加入。
## HTTP 层与后端约定(重要)
- 响应拦截器(`src/lib/http/interceptors.ts`)resolve 的值是 **AlitaResult 本体**:`{ requestId, code, success, msg, data }`。因此 queryFn 里 `.then(res => res.data)` 拿到的才是业务数据(如分页 `Page`:`{ entityList, totalCount, pageCount }`)。
- 分页参数走 query:`pageNo`(从 1 开始)/`pageSize`。
- code `"200"` 成功;`555/666/999/401/402/700` 拦截器统一 `toast.error(msg)` 后 reject;`401/402` 清 token 并跳转 `/login?redirect=...`;`603` 换 token;非 JSON 响应按文件下载处理。
- **错误提示只依赖拦截器**:mutation 用 `toast.promise(mutateAsync(...), { loading, success })`,**不要加 error 回调**(会与拦截器重复弹错)。
- 请求自动携带 `Authorization: Bearer <token>`(取自 user store)与 X-XSRF-TOKEN。
## 代码约定
- API 函数放 `src/apis/`,形如 `export const xxx = (data: any) => http.post("/path", data)`,参数类型沿用 `any`(存量风格)。
- mutation hooks 放页面 `-hooks/` 下,仿照 `useCancelUser`/`useUserStatusActions`:`useMutation` + `toast.promise` 包装,暴露 `xxx` 与 `xxxIsPending`。
- 表单弹窗优先 react-hook-form + zod(参考 `EditUserDialog`);简单确认弹窗仿 `CancelUserConfirmDialog`(Dialog + Spinner + onSuccess 里 `refetch` + `setOpen(false)`)。
- 页面骨架:外层 `p-4 box-border min-h-full space-y-4` → 标题区(`text-lg` + `text-xs text-black/50` 副标题)→ 白卡片 `p-4 rounded-lg border bg-white space-y-2` → 工具行 → `<DataTable>` + sticky `<Pagination>`。
- 图标用 lucide-react;文案为中文;时间格式 `yyyy-MM-dd HH:mm:ss`;文件大小用 `formatFileSize`(`src/lib/utils.ts`)。
## 环境变量(.env.development / .env.production)
`VITE_API_URL`(dev 为 `/api`,由 vite `server.proxy` 转发到后端)、`VITE_STORE_PREFIX`、`VITE_BASEPATH`、`VITE_APP_TITLE`、`VITE_IS_INSIDE`(内网部署标识,影响菜单文案与路由行为)、`VITE_DOMAIN`、`VITE_INIT_PASSWORD`。
## 后端联调
- 接口文档在后端仓库 `alita-bjy-uygur/docs/` 下的 `接口文档-*.md`,动手前先读对应文档(含字段表、错误文案、权限说明)。
- 管理端接口普遍要求「平台管理员/机构管理员」身份,前端仅做菜单/入口级控制,权限由后端兜底;错误文案以文档「校验失败提示」为准,前端校验提示需与后端 msg 保持一致。
- 后端不可达时的冒烟技巧:登录态持久化在 localStorage `senmeshzc_user`,注入 `{"state":{"token":"...","user":{...},"org":{...}},"version":0}` 后刷新即可进入受限页面验证 UI(`org.id = 1` 即平台机构)。
## 验证清单
1. `bunx vite build && bunx tsc -b` 通过(新增路由时先 build 再 tsc)。
2. `bun run dev` + 浏览器过一遍改动页面:菜单显隐、空态/加载/错误重试态、弹窗交互、toast 文案。
3. 涉及上传/记录等平台差异逻辑时,分别验证内网(`VITE_IS_INSIDE=true`)口径。