# 技术设计: <功能名称>

> 输入: 解析报告 (parse.md) + 确认结果 (confirm-scope)
> 设计日期: <日期>
> 版本: v1.0

---

## 0. 确认结果

| 维度 | 确认值 |
|------|--------|
| 项目根目录 | <绝对路径> |
| 实施范围 | <模块列表> |
| 后端 center | modules-center/{module}-center |
| 后端包路径 | com.twsz.mom.{module}.{sub} |
| 前端 API 目录 | src/api/{domain}/ |
| 前端页面目录 | src/views/{domain}/{entity}/ |
| 编号生成 | @AutoGenCode / 无 |
| 状态流转 | 有(审核/弃审) / 无 |
| 已有代码影响 | <列表或无> |

---

## 1. 数据库设计

### 1.1 索引设计规范

**索引命名规范**（严格遵守）：

| 索引类型 | 命名格式 | 示例 | 说明 |
|----------|----------|------|------|
| 主键索引 | `{tableName}_PK` | `pc_cad_data_PK` | 主键约束自动命名 |
| 普通索引 | `{tableName}_N1` ~ `N5` | `pc_cad_data_N1` | 按顺序编号，最多 5 个 |
| 唯一索引 | `{tableName}_U1` ~ `U5` | `pc_cad_data_U1` | 按顺序编号，最多 5 个 |

**唯一索引规范**：
- 必须以 `org_id` 作为首列，组成联合唯一索引
- 格式: `(org_id, 业务字段1, 业务字段2, ...)`
- 示例: `CREATE UNIQUE INDEX pc_cad_data_U1 ON pc_cad_data(org_id, material_code) TABLESPACE MES_IDX_COM;`

**表空间定义**：

| 表空间名称 | 用途 | 说明 |
|------------|------|------|
| MES_DATA_WORKS | 生产数据表空间 | 存储基础数据表、车间数据表 |
| MES_DATA_WMS | 仓库数据表空间 | 存储仓库表 |
| MES_DATA_COM | 基础数据表空间 | 存储基础数据表 |
| MES_IDX_WORKS | 生产索引表空间 | 存储基础数据、主车间索引 |
| MES_IDX_WMS | 仓库索引表空间 | 存储仓库表索引 |
| MES_IDX_COM | 基础数据表索引空间 | 存储基础数据索引 |

> 使用 confirm-scope 中确认的表空间。数据表使用 `MES_DATA_xxx`，索引使用 `MES_IDX_xxx`。

### 1.2 新建表

#### 表: <table_name>

```sql
CREATE TABLE <table_name> (
    id                NUMBER(19)      NOT NULL,
    org_id            NUMBER(19)      NOT NULL,
    -- 业务字段
    <column_name>     <oracle_type>   <constraint>,
    -- 审计字段
    created_by        VARCHAR2(64),
    created_date      DATE            DEFAULT SYSDATE,
    last_updated_by   VARCHAR2(64),
    last_updated_date DATE            DEFAULT SYSDATE,
    CONSTRAINT <tableName>_PK PRIMARY KEY (id) USING INDEX TABLESPACE <index_tablespace>
) TABLESPACE <data_tablespace>;

COMMENT ON TABLE <table_name> IS '<表中文名>';
COMMENT ON COLUMN <table_name>.id IS '主键';
COMMENT ON COLUMN <table_name>.org_id IS '组织ID';
-- 其他字段注释
```

**索引**:

| 索引名 | 字段 | 类型 | 表空间 | 说明 |
|--------|------|------|--------|------|
| `<tableName>_U1` | org_id, <业务字段> | UNIQUE | `<index_tablespace>` | 联合唯一（org_id 首列） |
| `<tableName>_N1` | <字段> | NORMAL | `<index_tablespace>` | 普通索引 |

**索引创建语句**:

```sql
-- 唯一索引（org_id 联合）
CREATE UNIQUE INDEX <tableName>_U1 ON <table_name>(org_id, <业务字段>) TABLESPACE <index_tablespace>;

-- 普通索引
CREATE INDEX <tableName>_N1 ON <table_name>(<字段>) TABLESPACE <index_tablespace>;
```

**建表方式**:
- [ ] dbx MCP 工具（优先）
- [ ] SQL 脚本执行

> **org_id 处理说明**: org_id 仅在 DDL 中定义（用于唯一索引组合列），**不在 Entity 中声明**。
> MyBatis-Plus `TenantLineInnerInterceptor` 已配置多租户，INSERT/SELECT/UPDATE/DELETE 自动注入 `org_id` 条件。
> 业务代码（Entity、Mapper XML、Service、Controller）无需显式处理 org_id。

### 1.2 修改表（如有）

#### 表: <existing_table_name>

```sql
ALTER TABLE <existing_table_name> ADD (
    <new_column> <oracle_type> <constraint>
);

COMMENT ON COLUMN <existing_table_name>.<new_column> IS '<说明>';
```

---

## 2. API 接口设计

### 2.1 标准 CRUD 接口

> 完整路径前缀: `/api/<api-path>/<entity>`

| # | Method | Path | 描述 | 请求体 | 响应体 |
|:-:|--------|------|------|--------|--------|
| 1 | POST | `/{entity}/search` | 分页查询 | PageForm<Entity> | Page<Entity> |
| 2 | POST | `/{entity}/add` | 新增 | Entity | — |
| 3 | PUT | `/{entity}/update` | 修改 | Entity | — |
| 4 | DELETE | `/{entity}/delete` | 批量删除 | Long[] ids | — |
| 5 | POST | `/{entity}/export` | 导出 Excel | Entity | file |
| 6 | POST | `/{entity}/uploadExcel` | 导入 Excel | MultipartFile | — |

### 2.2 外部接口（如有）

| # | Method | Path | 调用方 | 描述 |
|:-:|--------|------|--------|------|
| E-1 | | | | |

### 2.3 接口详情

#### API-1: 分页查询

- **路径**: `POST /api/<api-path>/<entity>/search`
- **请求体**:
```json
{
    "size": 20,
    "current": 1,
    "condition": {}
}
```
- **响应体**:
```json
{
    "code": 200,
    "message": "success",
    "data": {
        "records": [],
        "total": 0,
        "size": 20,
        "current": 1
    }
}
```

<!-- 按需补充其他接口详情 -->

---

## 3. 后端代码结构

### 3.1 Entity

**路径**: `modules-center/{module}-center/{module}-service/src/main/java/com/twsz/mom/{module}/{sub}/model/{Entity}.java`

```java
@Data
@EqualsAndHashCode(callSuper = false)
@JsonInclude(JsonInclude.Include.NON_NULL)
@TableName("<table_name>")
public class {Entity} extends BaseModel implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(type = IdType.ASSIGN_ID)
    @JsonSerialize(using = ToStringSerializer.class)
    private Long id;

    // === 业务字段 ===
    // <从功能文档字段表映射，每个字段含 @ExcelProperty>
}
```

### 3.2 Mapper

**接口**: `.../{module}/mapper/{Entity}Mapper.java`
**XML**: `resources/mapper/{module}/{Entity}Mapper.xml`

```java
@Mapper
public interface {Entity}Mapper extends BaseMapper<{Entity}> {
    IPage<{Entity}> pageSearch(Page<{Entity}> p, @Param("entity") {Entity} entity);
    List<{Entity}> list(@Param("entity") {Entity} entity);
}
```

**XML 关键片段**:
```xml
<sql id="Columns">
    id, <业务字段>, created_by, created_date, last_updated_by, last_updated_date
</sql>

<sql id="Where">
    <where>
        <if test="entity.xxx != null and entity.xxx != ''">
            AND xxx = #{entity.xxx}
        </if>
    </where>
</sql>
```

### 3.3 Service

**接口**: `.../{module}/service/{Entity}Service.java`

```java
public interface {Entity}Service extends IService<{Entity}> {
    // <方法签名>
}
```

**关键业务逻辑**:

```
insert({Entity} entity):
    1. <校验规则描述>
    2. <校验通过> → baseMapper.insert(entity)

export({Entity} entity, HttpServletResponse response):
    new BaseExcelExportTemplate<{Entity}>({Entity}.class) {
        getTotal() → <总数查询描述>
        getData(start, size) → <分页查询描述，start 从 1 开始>
    }.exportBatch(response)

handle(List<{Entity}> list):
    // BaseAnalysisEventListener 回调，由 EasyExcel.read(...).doRead() 驱动
    @Transactional(rollbackFor = Exception.class)
    1. <批量导入校验描述>
    2. 批量 insert（按 batchSize 分批）
```

### 3.4 Controller

**路径**: `.../{module}/controller/{Entity}Controller.java`

```java
@RestController
@RequestMapping("/api/<api-path>/<entity>")
public class {Entity}Controller {

    @PostMapping("/search")
    public ResponseWrapper<Page<{Entity}>> search(@RequestBody PageForm<{Entity}> pageForm) { ... }

    // <其他方法>
}
```

---

## 4. 前端代码结构

### 4.1 API 文件

**路径**: `src/api/{domain}/{entity}.js`

```javascript
import axios from '@/libs/request'
import { exportExcel } from '../file'
const root = '/<gateway-prefix>/api'

// <API 方法列表>
```

### 4.2 列表页

**路径**: `src/views/{domain}/{entity}/index.vue`

- **Mixin**: `indexPage`
- **搜索条件**:

| 字段 | 控件 | 说明 |
|------|------|------|
| | Input / Select / DatePicker | |

- **表格列**:

| 列名 | key | slot | 说明 |
|------|-----|------|------|
| ☐ | selection | — | 复选框 |
| | | | |
| 操作 | — | operate | 编辑/查看/删除 |

- **工具栏**: 新增 ✅ | 编辑 ✅ | 查看 ✅ | 删除 ✅ | 导出 ✅ | 导入 ✅

### 4.3 表单页

**路径**: `src/views/{domain}/{entity}/{entity}-form.vue`

- **组件**: `master-sub`
- **表单字段**:

| 字段 | 控件 | 必填 | 校验规则 | 说明 |
|------|------|:----:|----------|------|
| | Input / Select / iSwitch / DatePicker | | | |

- **提交逻辑**: 判断新增/编辑 → 调用 add/update API

---

## 5. 业务逻辑流程

### 5.1 核心操作流程

```
<ASCII 流程图>
```

### 5.2 校验规则汇总

| 编号 | 校验项 | 规则 | 错误提示 | 校验位置 |
|:----:|--------|------|----------|----------|
| V-01 | | | | 前端 + 后端 |

### 5.3 状态流转（如有）

```
<状态机图>
```

---

## 6. 集成点

### 6.1 被调用方

| 调用方 | 接口方式 | 说明 |
|--------|----------|------|
| | | |

### 6.2 菜单权限

| 菜单名 | 权限标识 | 类型 |
|--------|----------|------|
| | | 路由 / 按钮 / API |

---

## 7. 设计决策记录

| 决策 | 选项 | 结论 | 原因 |
|------|------|------|------|
| | | | |
