From 4f5540b81491a29b9b7e87101abc8e554438805e Mon Sep 17 00:00:00 2001 From: risingLee <871066422@qq.com> Date: Tue, 30 Dec 2025 15:29:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A0=B7=E5=93=81=E5=9E=8B=E5=8F=B7=E5=92=8C?= =?UTF-8?q?=E7=A1=AC=E4=BB=B6=E7=89=88=E6=9C=AC=E5=8F=B7=E7=9A=84=E7=AD=9B?= =?UTF-8?q?=E9=80=89=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .kiro/specs/sample-autocomplete/design.md | 278 ++++++++++++++++++ .../specs/sample-autocomplete/requirements.md | 63 ++++ .kiro/specs/sample-autocomplete/tasks.md | 31 ++ .kiro/specs/sample-remark-tooltip/tasks.md | 4 +- .../src/views/warehouse/sample/index.vue | 62 +++- 5 files changed, 435 insertions(+), 3 deletions(-) create mode 100644 .kiro/specs/sample-autocomplete/design.md create mode 100644 .kiro/specs/sample-autocomplete/requirements.md create mode 100644 .kiro/specs/sample-autocomplete/tasks.md diff --git a/.kiro/specs/sample-autocomplete/design.md b/.kiro/specs/sample-autocomplete/design.md new file mode 100644 index 0000000..f977f4e --- /dev/null +++ b/.kiro/specs/sample-autocomplete/design.md @@ -0,0 +1,278 @@ +# 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 + +``` + +#### 2. 替换硬件版本号输入框 + +将原有的 `el-input` 替换为 `el-autocomplete`: + +```vue + +``` + +#### 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. **防抖优化**: 添加防抖逻辑,减少搜索频率 diff --git a/.kiro/specs/sample-autocomplete/requirements.md b/.kiro/specs/sample-autocomplete/requirements.md new file mode 100644 index 0000000..d4b1c06 --- /dev/null +++ b/.kiro/specs/sample-autocomplete/requirements.md @@ -0,0 +1,63 @@ +# Requirements Document + +## Introduction + +本文档定义了样品管理系统中样品型号和硬件版本号字段的自动完成功能需求。该功能旨在通过从已有样品数据中提取可能的取值,并支持模糊搜索,提升用户输入效率和数据一致性。 + +## Glossary + +- **样品管理系统(Sample Management System)**: 用于管理入库样品信息的系统模块 +- **自动完成(Autocomplete)**: 根据用户输入自动提示可能的选项,用户可以从列表中选择或继续输入 +- **模糊搜索(Fuzzy Search)**: 根据用户输入的部分内容,在候选列表中查找包含该内容的所有选项 +- **样品型号(Sample Model)**: 样品的型号标识 +- **硬件版本号(Hardware Version)**: 样品的硬件版本标识 +- **候选列表(Candidate List)**: 从已有样品数据中提取的不重复的字段值列表 +- **Element UI Autocomplete**: Element UI 提供的自动完成输入组件 + +## Requirements + +### Requirement 1 + +**User Story:** 作为样品管理员,我希望在输入样品型号时能看到已有的型号列表,以便快速选择而不需要手动输入完整内容。 + +#### Acceptance Criteria + +1. WHEN 用户点击样品型号输入框 THEN 样品管理系统 SHALL 显示所有已存在的不重复样品型号列表 +2. WHEN 用户在样品型号输入框中输入文本 THEN 样品管理系统 SHALL 实时过滤并显示包含该文本的样品型号 +3. WHEN 用户从下拉列表中选择一个样品型号 THEN 样品管理系统 SHALL 将该值填入输入框 +4. WHEN 用户输入的内容不在候选列表中 THEN 样品管理系统 SHALL 允许用户输入新的样品型号 +5. WHEN 样品型号候选列表为空 THEN 样品管理系统 SHALL 允许用户正常输入文本 + +### Requirement 2 + +**User Story:** 作为样品管理员,我希望在输入硬件版本号时能看到已有的版本号列表,以便快速选择而不需要手动输入完整内容。 + +#### Acceptance Criteria + +1. WHEN 用户点击硬件版本号输入框 THEN 样品管理系统 SHALL 显示所有已存在的不重复硬件版本号列表 +2. WHEN 用户在硬件版本号输入框中输入文本 THEN 样品管理系统 SHALL 实时过滤并显示包含该文本的硬件版本号 +3. WHEN 用户从下拉列表中选择一个硬件版本号 THEN 样品管理系统 SHALL 将该值填入输入框 +4. WHEN 用户输入的内容不在候选列表中 THEN 样品管理系统 SHALL 允许用户输入新的硬件版本号 +5. WHEN 硬件版本号候选列表为空 THEN 样品管理系统 SHALL 允许用户正常输入文本 + +### Requirement 3 + +**User Story:** 作为样品管理员,我希望模糊搜索功能不区分大小写,以便更灵活地查找选项。 + +#### Acceptance Criteria + +1. WHEN 用户输入小写字母 THEN 样品管理系统 SHALL 匹配包含对应大写或小写字母的候选项 +2. WHEN 用户输入大写字母 THEN 样品管理系统 SHALL 匹配包含对应大写或小写字母的候选项 +3. WHEN 用户输入混合大小写文本 THEN 样品管理系统 SHALL 以不区分大小写的方式进行模糊匹配 + +### Requirement 4 + +**User Story:** 作为样品管理员,我希望自动完成功能的交互体验流畅,以便提高工作效率。 + +#### Acceptance Criteria + +1. WHEN 用户输入文本时 THEN 样品管理系统 SHALL 在 300 毫秒内显示过滤后的候选列表 +2. WHEN 候选列表显示时 THEN 样品管理系统 SHALL 限制显示最多 20 个候选项以保持界面简洁 +3. WHEN 用户使用键盘上下箭头键 THEN 样品管理系统 SHALL 允许用户在候选列表中导航 +4. WHEN 用户按下 Enter 键 THEN 样品管理系统 SHALL 选择当前高亮的候选项 +5. WHEN 用户点击输入框外部 THEN 样品管理系统 SHALL 关闭候选列表 diff --git a/.kiro/specs/sample-autocomplete/tasks.md b/.kiro/specs/sample-autocomplete/tasks.md new file mode 100644 index 0000000..c85e547 --- /dev/null +++ b/.kiro/specs/sample-autocomplete/tasks.md @@ -0,0 +1,31 @@ +# Implementation Plan + +- [x] 1. 实现样品型号自动完成功能 + + + - 在样品管理页面的表单中,将样品型号的 `el-input` 替换为 `el-autocomplete` 组件 + - 配置组件属性:v-model, fetch-suggestions, placeholder, trigger-on-focus, clearable + - 在 methods 中添加 `querySampleModel` 方法,从 sampleList 提取不重复的样品型号 + - 实现模糊搜索逻辑(不区分大小写) + - 限制返回结果最多 20 项 + - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 3.1, 3.2, 3.3, 4.1, 4.2_ + + + + +- [ ] 2. 实现硬件版本号自动完成功能 + - 在样品管理页面的表单中,将硬件版本号的 `el-input` 替换为 `el-autocomplete` 组件 + - 配置组件属性:v-model, fetch-suggestions, placeholder, trigger-on-focus, clearable + - 在 methods 中添加 `queryHardwareVersion` 方法,从 sampleList 提取不重复的硬件版本号 + - 实现模糊搜索逻辑(不区分大小写) + - 限制返回结果最多 20 项 + - _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 3.1, 3.2, 3.3, 4.1, 4.2_ + +- [ ]* 3. 手动测试自动完成功能 + - 测试样品型号输入框的自动完成功能 + - 测试硬件版本号输入框的自动完成功能 + - 测试模糊搜索(不区分大小写) + - 测试键盘导航(上下箭头、Enter、Esc) + - 测试输入新值(不在候选列表中) + - 测试边界情况(空列表、超过20项) + - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 2.1, 2.2, 2.3, 2.4, 2.5, 3.1, 3.2, 3.3, 4.1, 4.2, 4.3, 4.4, 4.5_ diff --git a/.kiro/specs/sample-remark-tooltip/tasks.md b/.kiro/specs/sample-remark-tooltip/tasks.md index ce0d1d8..e9dae32 100644 --- a/.kiro/specs/sample-remark-tooltip/tasks.md +++ b/.kiro/specs/sample-remark-tooltip/tasks.md @@ -1,6 +1,7 @@ # Implementation Plan -- [-] 1. 在样品管理页面添加备注列 +- [x] 1. 在样品管理页面添加备注列 + - 在 `ruoyi-fastapi-frontend/src/views/warehouse/sample/index.vue` 文件的 `` 组件中添加备注列 - 将备注列放置在状态列和操作列之间 @@ -9,6 +10,7 @@ + - [ ] 1.1 手动测试备注列显示功能 - 测试备注列是否正确显示在表格中 - 测试短备注内容是否完整显示 diff --git a/ruoyi-fastapi-frontend/src/views/warehouse/sample/index.vue b/ruoyi-fastapi-frontend/src/views/warehouse/sample/index.vue index 319a8dc..fa876fc 100644 --- a/ruoyi-fastapi-frontend/src/views/warehouse/sample/index.vue +++ b/ruoyi-fastapi-frontend/src/views/warehouse/sample/index.vue @@ -139,7 +139,14 @@ - + @@ -151,7 +158,14 @@ - + @@ -372,6 +386,50 @@ export default { /** 返回入库单列表 */ handleBack() { this.$router.push('/warehouse/receipt'); + }, + /** 查询样品型号建议 */ + 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)); } } };