# 中国烟草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: 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(initialValue);
// useEffect按逻辑分组
useEffect(() => {
// 副作用逻辑
}, [dependencies]);
// 事件处理函数
const handleClick = (e: React.MouseEvent) => {
// 处理逻辑
};
return (
{/* JSX内容 */}
);
}
```
### 文件命名规范
- 组件文件: `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
// 基本图标使用
// 图标尺寸控制
// 大图标
// 特大图标
// 2倍大小
// 结合样式使用
// 在按钮组件中使用
```
**图标系统特点:**
- **本地化部署**: 字体文件已复制到 `public/fonts/` 目录,无外网依赖
- **预加载优化**: 通过 `` 确保首次访问图标立即显示
- **完整支持**: 包含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
// 统一错误处理组件
```
### 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
// 使用语义化标签