279 lines
8.3 KiB
Markdown
279 lines
8.3 KiB
Markdown
|
|
# Design Document
|
|||
|
|
|
|||
|
|
## Overview
|
|||
|
|
|
|||
|
|
本设计文档描述了在样品管理系统中为样品型号和硬件版本号字段实现自动完成功能的技术方案。该功能将使用 Element UI 的 el-autocomplete 组件,从已有样品数据中提取不重复的字段值作为候选列表,并支持实时模糊搜索。
|
|||
|
|
|
|||
|
|
## Architecture
|
|||
|
|
|
|||
|
|
该功能主要涉及前端实现,需要在样品管理页面中:
|
|||
|
|
1. 将普通输入框替换为自动完成组件
|
|||
|
|
2. 从已加载的样品列表中提取候选值
|
|||
|
|
3. 实现模糊搜索过滤逻辑
|
|||
|
|
|
|||
|
|
### 数据流
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
用户输入
|
|||
|
|
↓
|
|||
|
|
触发 querySearch 方法
|
|||
|
|
↓
|
|||
|
|
从 sampleList 提取不重复的字段值
|
|||
|
|
↓
|
|||
|
|
根据输入内容进行模糊匹配(不区分大小写)
|
|||
|
|
↓
|
|||
|
|
返回过滤后的候选列表(最多20项)
|
|||
|
|
↓
|
|||
|
|
显示在下拉列表中
|
|||
|
|
↓
|
|||
|
|
用户选择或继续输入
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Components and Interfaces
|
|||
|
|
|
|||
|
|
### 修改的组件
|
|||
|
|
|
|||
|
|
**文件路径**: `ruoyi-fastapi-frontend/src/views/warehouse/sample/index.vue`
|
|||
|
|
|
|||
|
|
#### 1. 替换样品型号输入框
|
|||
|
|
|
|||
|
|
将原有的 `el-input` 替换为 `el-autocomplete`:
|
|||
|
|
|
|||
|
|
```vue
|
|||
|
|
<el-autocomplete
|
|||
|
|
v-model="form.sampleModel"
|
|||
|
|
:fetch-suggestions="querySampleModel"
|
|||
|
|
placeholder="请输入样品型号"
|
|||
|
|
style="width: 100%"
|
|||
|
|
:trigger-on-focus="false"
|
|||
|
|
clearable
|
|||
|
|
/>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 2. 替换硬件版本号输入框
|
|||
|
|
|
|||
|
|
将原有的 `el-input` 替换为 `el-autocomplete`:
|
|||
|
|
|
|||
|
|
```vue
|
|||
|
|
<el-autocomplete
|
|||
|
|
v-model="form.hardwareVersion"
|
|||
|
|
:fetch-suggestions="queryHardwareVersion"
|
|||
|
|
placeholder="请输入硬件版本号"
|
|||
|
|
style="width: 100%"
|
|||
|
|
:trigger-on-focus="false"
|
|||
|
|
clearable
|
|||
|
|
/>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3. 添加查询方法
|
|||
|
|
|
|||
|
|
在 `methods` 中添加两个查询方法:
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
/** 查询样品型号建议 */
|
|||
|
|
querySampleModel(queryString, cb) {
|
|||
|
|
// 从 sampleList 中提取不重复的样品型号
|
|||
|
|
const models = [...new Set(
|
|||
|
|
this.sampleList
|
|||
|
|
.map(item => item.sampleModel)
|
|||
|
|
.filter(model => model && model.trim() !== '')
|
|||
|
|
)];
|
|||
|
|
|
|||
|
|
// 转换为 autocomplete 需要的格式
|
|||
|
|
const suggestions = models.map(model => ({ value: model }));
|
|||
|
|
|
|||
|
|
// 如果有输入内容,进行模糊匹配(不区分大小写)
|
|||
|
|
const results = queryString
|
|||
|
|
? suggestions.filter(item =>
|
|||
|
|
item.value.toLowerCase().includes(queryString.toLowerCase())
|
|||
|
|
)
|
|||
|
|
: suggestions;
|
|||
|
|
|
|||
|
|
// 限制返回最多20项
|
|||
|
|
cb(results.slice(0, 20));
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/** 查询硬件版本号建议 */
|
|||
|
|
queryHardwareVersion(queryString, cb) {
|
|||
|
|
// 从 sampleList 中提取不重复的硬件版本号
|
|||
|
|
const versions = [...new Set(
|
|||
|
|
this.sampleList
|
|||
|
|
.map(item => item.hardwareVersion)
|
|||
|
|
.filter(version => version && version.trim() !== '')
|
|||
|
|
)];
|
|||
|
|
|
|||
|
|
// 转换为 autocomplete 需要的格式
|
|||
|
|
const suggestions = versions.map(version => ({ value: version }));
|
|||
|
|
|
|||
|
|
// 如果有输入内容,进行模糊匹配(不区分大小写)
|
|||
|
|
const results = queryString
|
|||
|
|
? suggestions.filter(item =>
|
|||
|
|
item.value.toLowerCase().includes(queryString.toLowerCase())
|
|||
|
|
)
|
|||
|
|
: suggestions;
|
|||
|
|
|
|||
|
|
// 限制返回最多20项
|
|||
|
|
cb(results.slice(0, 20));
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Element UI Autocomplete 组件属性说明
|
|||
|
|
|
|||
|
|
- **v-model**: 双向绑定输入值
|
|||
|
|
- **fetch-suggestions**: 获取建议列表的方法,接收 queryString 和 callback 两个参数
|
|||
|
|
- **placeholder**: 输入框占位文本
|
|||
|
|
- **trigger-on-focus**: 设置为 false,只在用户输入时触发搜索,而不是聚焦时
|
|||
|
|
- **clearable**: 显示清除按钮
|
|||
|
|
|
|||
|
|
## Data Models
|
|||
|
|
|
|||
|
|
### 候选项数据格式
|
|||
|
|
|
|||
|
|
Element UI Autocomplete 要求候选项为对象数组,每个对象必须包含 `value` 属性:
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
[
|
|||
|
|
{ value: "型号A" },
|
|||
|
|
{ value: "型号B" },
|
|||
|
|
{ value: "型号C" }
|
|||
|
|
]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 样品数据模型
|
|||
|
|
|
|||
|
|
使用现有的样品列表数据 `sampleList`,无需修改数据结构:
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
{
|
|||
|
|
sampleId: Number,
|
|||
|
|
receiptNo: String,
|
|||
|
|
sampleModel: String, // 用于提取样品型号候选值
|
|||
|
|
sampleSn: String,
|
|||
|
|
hardwareVersion: String, // 用于提取硬件版本号候选值
|
|||
|
|
externalStatus: String,
|
|||
|
|
testItems: String,
|
|||
|
|
testDeadline: String,
|
|||
|
|
status: String,
|
|||
|
|
remark: String
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Correctness Properties
|
|||
|
|
|
|||
|
|
*A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
|
|||
|
|
|
|||
|
|
### Property 1: 候选列表唯一性
|
|||
|
|
|
|||
|
|
*For any* 样品列表数据,提取的样品型号或硬件版本号候选列表中不应包含重复值
|
|||
|
|
|
|||
|
|
**Validates: Requirements 1.1, 2.1**
|
|||
|
|
|
|||
|
|
### Property 2: 模糊搜索包含性
|
|||
|
|
|
|||
|
|
*For any* 用户输入的查询字符串和候选列表,返回的结果中每个候选项都应包含查询字符串(不区分大小写)
|
|||
|
|
|
|||
|
|
**Validates: Requirements 1.2, 2.2, 3.1, 3.2, 3.3**
|
|||
|
|
|
|||
|
|
### Property 3: 空值过滤
|
|||
|
|
|
|||
|
|
*For any* 样品列表数据,提取的候选列表不应包含 null、undefined 或空字符串值
|
|||
|
|
|
|||
|
|
**Validates: Requirements 1.5, 2.5**
|
|||
|
|
|
|||
|
|
### Property 4: 结果数量限制
|
|||
|
|
|
|||
|
|
*For any* 查询结果,返回的候选项数量不应超过 20 个
|
|||
|
|
|
|||
|
|
**Validates: Requirements 4.2**
|
|||
|
|
|
|||
|
|
### Property 5: 用户输入自由性
|
|||
|
|
|
|||
|
|
*For any* 用户输入的文本,无论是否在候选列表中,系统都应允许用户提交该值
|
|||
|
|
|
|||
|
|
**Validates: Requirements 1.4, 2.4**
|
|||
|
|
|
|||
|
|
## Error Handling
|
|||
|
|
|
|||
|
|
### 数据缺失处理
|
|||
|
|
|
|||
|
|
- 当 `sampleList` 为空时,候选列表为空数组,用户可以正常输入
|
|||
|
|
- 当某个样品的 `sampleModel` 或 `hardwareVersion` 为 null/undefined 时,过滤逻辑会自动排除这些值
|
|||
|
|
|
|||
|
|
### 性能考虑
|
|||
|
|
|
|||
|
|
- 使用 `Set` 数据结构去重,时间复杂度 O(n)
|
|||
|
|
- 模糊搜索使用 `includes` 方法,对于小数据集(通常少于1000条)性能足够
|
|||
|
|
- 限制返回最多 20 项,避免渲染过多 DOM 元素
|
|||
|
|
|
|||
|
|
### 浏览器兼容性
|
|||
|
|
|
|||
|
|
- Element UI Autocomplete 组件支持主流浏览器
|
|||
|
|
- `Set`、`Array.includes`、`String.toLowerCase` 等 API 在现代浏览器中均支持
|
|||
|
|
|
|||
|
|
## Testing Strategy
|
|||
|
|
|
|||
|
|
### 单元测试
|
|||
|
|
|
|||
|
|
1. **候选列表提取测试**
|
|||
|
|
- 测试从样品列表中正确提取不重复的样品型号
|
|||
|
|
- 测试从样品列表中正确提取不重复的硬件版本号
|
|||
|
|
- 测试空值和 null 值被正确过滤
|
|||
|
|
|
|||
|
|
2. **模糊搜索测试**
|
|||
|
|
- 测试不区分大小写的模糊匹配
|
|||
|
|
- 测试空查询字符串返回所有候选项
|
|||
|
|
- 测试查询字符串匹配部分候选项
|
|||
|
|
|
|||
|
|
3. **结果限制测试**
|
|||
|
|
- 测试返回结果不超过 20 项
|
|||
|
|
- 测试候选项少于 20 项时返回全部
|
|||
|
|
|
|||
|
|
### 手动测试场景
|
|||
|
|
|
|||
|
|
1. **基本功能测试**
|
|||
|
|
- 点击样品型号输入框,验证不显示下拉列表(trigger-on-focus=false)
|
|||
|
|
- 输入部分文本,验证显示匹配的候选项
|
|||
|
|
- 从下拉列表选择一项,验证值正确填入
|
|||
|
|
- 输入不存在的值,验证可以正常提交
|
|||
|
|
|
|||
|
|
2. **模糊搜索测试**
|
|||
|
|
- 输入小写字母,验证匹配大小写混合的候选项
|
|||
|
|
- 输入大写字母,验证匹配小写的候选项
|
|||
|
|
- 输入中文,验证正确匹配
|
|||
|
|
|
|||
|
|
3. **边界情况测试**
|
|||
|
|
- 样品列表为空时,验证输入框正常工作
|
|||
|
|
- 候选项超过 20 个时,验证只显示前 20 个
|
|||
|
|
- 快速输入和删除,验证搜索响应流畅
|
|||
|
|
|
|||
|
|
4. **键盘交互测试**
|
|||
|
|
- 使用上下箭头键导航候选列表
|
|||
|
|
- 按 Enter 键选择高亮项
|
|||
|
|
- 按 Esc 键关闭候选列表
|
|||
|
|
|
|||
|
|
## Implementation Notes
|
|||
|
|
|
|||
|
|
### 实现步骤
|
|||
|
|
|
|||
|
|
1. 在 `ruoyi-fastapi-frontend/src/views/warehouse/sample/index.vue` 文件中定位到表单部分
|
|||
|
|
2. 将样品型号的 `el-input` 替换为 `el-autocomplete`
|
|||
|
|
3. 将硬件版本号的 `el-input` 替换为 `el-autocomplete`
|
|||
|
|
4. 在 `methods` 中添加 `querySampleModel` 和 `queryHardwareVersion` 方法
|
|||
|
|
5. 测试功能
|
|||
|
|
|
|||
|
|
### 注意事项
|
|||
|
|
|
|||
|
|
- `trigger-on-focus` 设置为 `false` 可以避免用户聚焦时立即显示所有候选项,只在用户输入时才显示
|
|||
|
|
- 使用 `Set` 去重时,相同的字符串会被自动合并
|
|||
|
|
- `fetch-suggestions` 方法必须调用回调函数 `cb(results)` 来返回结果
|
|||
|
|
- 候选项对象必须包含 `value` 属性,这是 Element UI 的要求
|
|||
|
|
|
|||
|
|
### 可选优化
|
|||
|
|
|
|||
|
|
如果未来需要更高级的功能,可以考虑:
|
|||
|
|
|
|||
|
|
1. **远程搜索**: 如果样品数据量很大,可以改为调用后端 API 进行搜索
|
|||
|
|
2. **自定义模板**: 使用 scoped slot 自定义候选项的显示格式,例如显示使用频率
|
|||
|
|
3. **最近使用**: 优先显示用户最近使用过的型号或版本号
|
|||
|
|
4. **防抖优化**: 添加防抖逻辑,减少搜索频率
|