495 lines
12 KiB
Markdown
495 lines
12 KiB
Markdown
# 中国烟草AI合同及卷宗审核系统 - 开发规范指南
|
|
|
|
## 📋 概述
|
|
|
|
本文档定义了「中国烟草AI合同及卷宗审核系统」的开发规范,包括技术架构、设计风格、代码规范、UI组件等各个方面,确保团队开发的一致性和代码质量。
|
|
|
|
## 🏗 技术架构规范
|
|
|
|
### 核心技术栈
|
|
- **前端框架**: Remix (React) + TypeScript
|
|
- **构建工具**: Vite
|
|
- **样式系统**: Tailwind CSS + 自定义CSS
|
|
- **图标库**: Remixicon (已本地化)
|
|
- **文档处理**: react-pdf, mammoth, docx-preview
|
|
- **代码规范**: ESLint + TypeScript
|
|
- **状态管理**: React Context + useState/useEffect
|
|
|
|
### 项目结构规范
|
|
```
|
|
app/
|
|
├── api/ # API层接口
|
|
├── components/ # 组件
|
|
│ ├── ui/ # 通用UI组件
|
|
│ ├── layout/ # 布局组件
|
|
│ ├── error/ # 错误处理组件
|
|
│ └── [feature]/ # 功能特定组件
|
|
├── routes/ # Remix路由页面
|
|
├── styles/ # 样式文件
|
|
│ ├── main.css # 主样式
|
|
│ └── components/ # 组件样式
|
|
├── types/ # TypeScript类型定义
|
|
├── contexts/ # React Context
|
|
├── models/ # 数据模型
|
|
└── utils.ts # 工具函数
|
|
```
|
|
|
|
## 🎨 设计系统规范
|
|
|
|
### 颜色主题
|
|
```css
|
|
/* 主色调 - 中国烟草企业绿 */
|
|
--color-primary: #00684a; /* 主色 */
|
|
--color-primary-hover: #005a3f; /* 悬停色 */
|
|
--color-primary-light: rgba(0, 104, 74, 0.1); /* 浅色背景 */
|
|
|
|
/* 状态颜色 */
|
|
--color-success: #52c41a; /* 成功绿 */
|
|
--color-warning: #faad14; /* 警告橙 */
|
|
--color-error: #f5222d; /* 错误红 */
|
|
|
|
/* 中性色系 */
|
|
--color-gray-50: #f8f9fa; /* 最浅灰 */
|
|
--color-gray-100: #f1f3f5;
|
|
--color-gray-200: #e9ecef;
|
|
--color-gray-300: #dee2e6;
|
|
--color-gray-400: #ced4da;
|
|
--color-gray-500: #adb5bd; /* 中性灰 */
|
|
--color-gray-600: #868e96;
|
|
--color-gray-700: #495057;
|
|
--color-gray-800: #343a40;
|
|
--color-gray-900: #212529; /* 最深灰 */
|
|
```
|
|
|
|
### 字体规范
|
|
```css
|
|
font-family: [
|
|
"-apple-system",
|
|
"BlinkMacSystemFont",
|
|
"Segoe UI",
|
|
"Roboto",
|
|
"Helvetica Neue",
|
|
"Arial",
|
|
"Noto Sans SC", /* 中文优先 */
|
|
"PingFang SC",
|
|
"Microsoft YaHei UI",
|
|
"Microsoft YaHei",
|
|
"sans-serif"
|
|
];
|
|
```
|
|
|
|
### 间距系统
|
|
- 使用Tailwind默认间距: 4px基数 (1, 2, 3, 4, 5, 6...)
|
|
- 页面容器内边距: `p-5` (20px)
|
|
- 卡片内边距: `p-4` (16px)
|
|
- 组件间距: `mb-4` `mt-6` (16px, 24px)
|
|
|
|
### 圆角规范
|
|
- 按钮、卡片: `rounded-md` (6px)
|
|
- 输入框: `rounded-md` (6px)
|
|
- 头像: `rounded-full`
|
|
- 标签: `rounded-md`
|
|
|
|
### 阴影系统
|
|
```css
|
|
/* 卡片阴影 */
|
|
.card: shadow-sm; /* 默认 */
|
|
.card:hover: shadow-md; /* 悬停 */
|
|
.sidebar: shadow-[0_0_15px_rgba(0,0,0,0.05)]; /* 侧边栏 */
|
|
```
|
|
|
|
## 🧩 组件设计规范
|
|
|
|
### 按钮组件
|
|
```tsx
|
|
// 类型定义
|
|
type ButtonType = 'primary' | 'default' | 'danger';
|
|
type ButtonSize = 'small' | 'medium' | 'large';
|
|
|
|
// 样式类
|
|
.ant-btn-primary: bg-[#00684a] text-white hover:bg-[#005a3f]
|
|
.ant-btn-default: bg-white border border-gray-300 text-gray-800
|
|
.ant-btn-danger: bg-[#f5222d] text-white hover:bg-[#cf1f29]
|
|
```
|
|
|
|
### 卡片组件
|
|
```tsx
|
|
// 基础结构
|
|
<Card title="标题" icon="ri-icon-name" className="additional-classes">
|
|
<div className="card-body">内容</div>
|
|
</Card>
|
|
|
|
// 样式规范
|
|
.card: bg-white rounded-lg shadow overflow-hidden
|
|
.card-header: px-5 py-4 border-b border-gray-100
|
|
.card-title: text-base font-medium text-gray-900
|
|
```
|
|
|
|
### 布局组件
|
|
```tsx
|
|
// 侧边栏宽度
|
|
.sidebar: w-[280px] /* 展开状态 */
|
|
.sidebar.collapsed: w-20 /* 收缩状态 */
|
|
|
|
// 主内容区适配
|
|
.main-content: ml-[280px] /* 对应侧边栏宽度 */
|
|
.main-content.sidebar-collapsed: ml-20
|
|
```
|
|
|
|
## 📝 代码规范
|
|
|
|
### TypeScript规范
|
|
```typescript
|
|
// 接口命名使用PascalCase
|
|
interface DocumentUI {
|
|
id: string;
|
|
name: string;
|
|
status: ProcessingStatus;
|
|
}
|
|
|
|
// 类型联合使用字符串字面量
|
|
type ProcessingStatus = 'Waiting' | 'Cutting' | 'Extractioning' | 'Evaluationing' | 'Processed';
|
|
|
|
// 组件Props接口
|
|
interface ComponentProps {
|
|
children: React.ReactNode;
|
|
className?: string;
|
|
disabled?: boolean;
|
|
}
|
|
```
|
|
|
|
### React组件规范
|
|
```tsx
|
|
// 函数组件使用function声明
|
|
export function ComponentName({ prop1, prop2 }: ComponentProps) {
|
|
// useState放在顶部
|
|
const [state, setState] = useState<Type>(initialValue);
|
|
|
|
// useEffect按逻辑分组
|
|
useEffect(() => {
|
|
// 副作用逻辑
|
|
}, [dependencies]);
|
|
|
|
// 事件处理函数
|
|
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
|
|
// 处理逻辑
|
|
};
|
|
|
|
return (
|
|
<div className="component-container">
|
|
{/* JSX内容 */}
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
### 文件命名规范
|
|
- 组件文件: `PascalCase.tsx` (如: `Button.tsx`)
|
|
- 路由文件: `kebab-case.tsx` (如: `user-profile.tsx`)
|
|
- 样式文件: `kebab-case.css` (如: `button.css`)
|
|
- 工具文件: `camelCase.ts` (如: `utils.ts`)
|
|
|
|
### 导入顺序规范
|
|
```typescript
|
|
// 1. React相关
|
|
import React, { useState, useEffect } from 'react';
|
|
import { Link, useLoaderData } from '@remix-run/react';
|
|
|
|
// 2. 第三方库
|
|
import dayjs from 'dayjs';
|
|
|
|
// 3. 内部组件 (~/ 别名)
|
|
import { Card } from '~/components/ui/Card';
|
|
import { Button } from '~/components/ui/Button';
|
|
|
|
// 4. 类型定义
|
|
import type { DocumentUI } from '~/types/document';
|
|
|
|
// 5. 样式文件
|
|
import styles from '~/styles/components/component.css?url';
|
|
```
|
|
|
|
### CSS类命名规范
|
|
```css
|
|
/* BEM方法论 + 功能前缀 */
|
|
.sidebar-menu-item /* 组件-子元素-状态 */
|
|
.sidebar-menu-item.active /* 状态修饰符 */
|
|
.ant-btn-primary /* 组件库前缀 */
|
|
.text-primary /* 工具类 */
|
|
```
|
|
|
|
## 🎯 UI/UX设计规范
|
|
|
|
### 交互动效
|
|
```css
|
|
/* 统一过渡动效 */
|
|
.transition-all-ease: transition-all duration-200 ease-in-out;
|
|
|
|
/* 悬停效果 */
|
|
.sidebar-menu-item:hover: bg-[rgba(0,104,74,0.05)];
|
|
.card:hover: shadow-md;
|
|
```
|
|
|
|
### 状态指示
|
|
```typescript
|
|
// 文件处理状态
|
|
const statusConfig = {
|
|
"Waiting": { label: "上传中", icon: "ri-loader-line", color: "blue" },
|
|
"Cutting": { label: "切分中", icon: "ri-loader-line", color: "purple" },
|
|
"Extractioning": { label: "抽取中", icon: "ri-loader-line", color: "cyan" },
|
|
"Evaluationing": { label: "评查中", icon: "ri-loader-line", color: "teal" },
|
|
"Processed": { label: "已完成", icon: "ri-check-line", color: "green" }
|
|
};
|
|
```
|
|
|
|
### 图标使用规范 (RemixIcon 本地化)
|
|
```tsx
|
|
// 基本图标使用
|
|
<i className="ri-home-line"></i>
|
|
<i className="ri-file-list-3-line"></i>
|
|
<i className="ri-user-line"></i>
|
|
|
|
// 图标尺寸控制
|
|
<i className="ri-home-line ri-lg"></i> // 大图标
|
|
<i className="ri-home-line ri-xl"></i> // 特大图标
|
|
<i className="ri-home-line ri-2x"></i> // 2倍大小
|
|
|
|
// 结合样式使用
|
|
<i className="ri-error-warning-line text-red-500"></i>
|
|
<i className="ri-check-line text-green-600"></i>
|
|
<i className="ri-information-line text-blue-500"></i>
|
|
|
|
// 在按钮组件中使用
|
|
<Button icon="ri-add-line">添加</Button>
|
|
<Button icon="ri-edit-line">编辑</Button>
|
|
<Button icon="ri-delete-bin-line">删除</Button>
|
|
```
|
|
|
|
**图标系统特点:**
|
|
- **本地化部署**: 字体文件已复制到 `public/fonts/` 目录,无外网依赖
|
|
- **预加载优化**: 通过 `<link rel="preload">` 确保首次访问图标立即显示
|
|
- **完整支持**: 包含3000+图标,支持所有RemixIcon官方图标
|
|
- **性能优化**: 启用 `font-display: swap` 提供更好的加载体验
|
|
- **浏览器兼容**: 支持IE9+到最新浏览器
|
|
|
|
**⚠️ 重要注意事项 - 避免样式冲突:**
|
|
|
|
在使用CSS样式隔离(如 `all: unset` 或强制 `font-family: inherit`)时,必须为RemixIcon图标添加例外规则:
|
|
|
|
```css
|
|
/* 错误示例 - 会导致图标不显示 */
|
|
.my-isolated-container * {
|
|
font-family: inherit !important; /* 这会覆盖图标字体 */
|
|
}
|
|
|
|
/* 正确示例 - 添加图标例外规则 */
|
|
.my-isolated-container * {
|
|
font-family: inherit !important;
|
|
}
|
|
.my-isolated-container [class^="ri-"],
|
|
.my-isolated-container [class*=" ri-"],
|
|
.my-isolated-container i[class^="ri-"],
|
|
.my-isolated-container i[class*=" ri-"] {
|
|
font-family: 'remixicon' !important;
|
|
font-style: normal !important;
|
|
font-weight: normal !important;
|
|
font-variant: normal !important;
|
|
text-transform: none !important;
|
|
line-height: 1 !important;
|
|
-webkit-font-smoothing: antialiased !important;
|
|
-moz-osx-font-smoothing: grayscale !important;
|
|
speak: none !important;
|
|
}
|
|
```
|
|
|
|
**常见问题排查:**
|
|
1. **图标显示为方块或问号**: 检查是否有CSS规则覆盖了 `font-family: 'remixicon'`
|
|
2. **只在特定页面不显示**: 检查该页面是否使用了样式隔离规则
|
|
3. **首次加载不显示**: 确认字体预加载配置正确
|
|
4. **部分图标不显示**: 检查CSS选择器优先级和 `!important` 使用
|
|
|
|
### 国际化和本地化
|
|
- 界面语言: 简体中文为主
|
|
- 日期格式: `YYYY年MM月DD日`
|
|
- 时间格式: `HH:mm:ss`
|
|
- 数字格式: 使用中文习惯 (如: 万、千)
|
|
|
|
## 🔧 工具配置规范
|
|
|
|
### ESLint配置要点
|
|
```javascript
|
|
// 启用的规则
|
|
- "plugin:react/recommended"
|
|
- "plugin:react-hooks/recommended"
|
|
- "plugin:@typescript-eslint/recommended"
|
|
- "plugin:jsx-a11y/recommended"
|
|
```
|
|
|
|
### Tailwind配置扩展
|
|
```typescript
|
|
// tailwind.config.ts
|
|
theme: {
|
|
extend: {
|
|
colors: {
|
|
primary: {
|
|
DEFAULT: '#1677ff', // 保持Remix默认,实际使用CSS变量覆盖
|
|
// ... 其他色阶
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## 📊 性能优化规范
|
|
|
|
### 组件优化
|
|
```typescript
|
|
// 使用React.memo对纯组件优化
|
|
export const MemoizedComponent = React.memo(Component);
|
|
|
|
// 防抖工具函数使用
|
|
import { debounce } from '~/utils';
|
|
const debouncedHandler = debounce(handler, 300);
|
|
```
|
|
|
|
### 资源加载
|
|
```typescript
|
|
// 样式文件异步加载
|
|
import styles from '~/styles/component.css?url';
|
|
|
|
// 组件懒加载
|
|
const LazyComponent = lazy(() => import('~/components/LazyComponent'));
|
|
```
|
|
|
|
## 🚨 错误处理规范
|
|
|
|
### 错误边界
|
|
```tsx
|
|
// 统一错误处理组件
|
|
<AppErrorBoundary
|
|
status={500}
|
|
statusText="服务器错误"
|
|
message="服务器发生了意外错误,请稍后重试"
|
|
/>
|
|
```
|
|
|
|
### API错误处理
|
|
```typescript
|
|
// 统一的API响应处理
|
|
if (response.error) {
|
|
console.error('API错误:', response.error);
|
|
return Response.json(
|
|
{ error: response.error },
|
|
{ status: response.status || 500 }
|
|
);
|
|
}
|
|
```
|
|
|
|
## 📱 响应式设计规范
|
|
|
|
### 断点使用
|
|
- `sm`: 640px+ (移动端横屏)
|
|
- `md`: 768px+ (平板)
|
|
- `lg`: 1024px+ (桌面)
|
|
- `xl`: 1280px+ (大屏)
|
|
|
|
### 适配策略
|
|
```css
|
|
/* 移动端优先 */
|
|
.content-container: p-5;
|
|
@screen sm: .content-container: p-6;
|
|
|
|
/* 侧边栏响应式 */
|
|
@screen md: .sidebar-toggle: block;
|
|
```
|
|
|
|
## 🔍 可访问性规范
|
|
|
|
### 语义化HTML
|
|
```tsx
|
|
// 使用语义化标签
|
|
<main className="main-content">
|
|
<nav className="breadcrumb" aria-label="页面导航">
|
|
<section className="content-section">
|
|
```
|
|
|
|
### 键盘导航
|
|
```tsx
|
|
// 确保所有交互元素可键盘访问
|
|
<button
|
|
onKeyDown={(e) => e.key === 'Enter' && handleClick()}
|
|
aria-label="操作按钮"
|
|
>
|
|
```
|
|
|
|
## 📋 开发流程规范
|
|
|
|
### 组件开发流程
|
|
1. 创建组件TypeScript接口定义
|
|
2. 实现组件逻辑 (`.tsx`)
|
|
3. 编写组件样式 (`.css`)
|
|
4. 在`main.css`中导入样式
|
|
5. 编写使用示例
|
|
6. 进行测试验证
|
|
|
|
### 页面开发流程
|
|
1. 在`routes/`下创建路由文件
|
|
2. 定义`loader`函数处理数据获取
|
|
3. 实现页面组件
|
|
4. 配置`meta`和`links`
|
|
5. 添加错误处理
|
|
6. 测试页面功能
|
|
|
|
## 🚀 部署和构建规范
|
|
|
|
### 环境变量
|
|
```typescript
|
|
// 生产环境配置
|
|
NODE_ENV=production
|
|
DATABASE_URL=...
|
|
SESSION_SECRET=...
|
|
```
|
|
|
|
### 构建优化
|
|
```typescript
|
|
// vite.config.ts优化配置
|
|
export default defineConfig({
|
|
plugins: [remix(), tsconfigPaths()],
|
|
build: {
|
|
rollupOptions: {
|
|
// 代码分割优化
|
|
}
|
|
}
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 📚 开发检查清单
|
|
|
|
### 新组件开发
|
|
- [ ] TypeScript接口定义完整
|
|
- [ ] 样式使用设计系统颜色
|
|
- [ ] 支持必要的props (className, disabled等)
|
|
- [ ] 添加适当的过渡动效
|
|
- [ ] 编写组件文档注释
|
|
|
|
### 新页面开发
|
|
- [ ] loader函数处理数据和错误
|
|
- [ ] meta信息配置完整
|
|
- [ ] 响应式设计适配
|
|
- [ ] 错误边界处理
|
|
- [ ] 面包屑导航配置
|
|
|
|
### 代码提交前
|
|
- [ ] ESLint检查通过
|
|
- [ ] TypeScript编译无错误
|
|
- [ ] 样式符合设计系统
|
|
- [ ] 组件功能测试完成
|
|
- [ ] 代码注释清晰完整
|
|
|
|
---
|
|
|
|
*此规范将根据项目发展持续更新和完善。*
|
|
|