1. 技术架构概述
- 技术栈: Vue 3 (Composition API) + Pinia + Element Plus + JavaScript
- 核心目标: 实现配置驱动的动态搜索面板,支持复杂的搜索项自定义配置,以及搜索场景(模板)的全生命周期管理(保存、回填、默认、共享、删除)。
- UX 重点:
- 搜索项配置 : 摒弃
el-transfer,采用自定义双面板设计,实现独立搜索、精确计数与全选逻辑。 - 异步交互: 所有敏感操作(设为默认、删除、分享)均包含 Loading 状态、超时熔断与错误回滚机制。
2. 数据模型定义 (Data Models)
2.1 搜索配置项 (SearchField)
描述"搜索项池"中的每一个可用字段。
javascript
// 数据源:Store.allFields
{
key: "region", // [必填] 字段唯一标识,用于 v-model 绑定
label: "Region", // [必填] UI 显示名称
type: "select", // [必填] 组件类型: 'input' | 'select' | 'date-picker'
options: [ // [可选] 下拉选项数据 (仅 type='select' 有效)
{ label: "All Regions", value: "all" },
{ label: "Beijing", value: "bj" }
],
defaultValue: "all" // [可选] 默认值
}
2.2 搜索模板 (SearchTemplate)
描述用户保存的搜索场景(布局 + 数据)。
javascript
// 数据源:Store.templates
{
id: 101,
name: "我的日常巡检", // 模板名称
type: "private", // 类型: 'public' (系统公用) | 'private' (个人) | 'shared' (他人共享)
isDefault: true, // 是否为默认模板 (同一用户下互斥)
creator: "admin", // 创建人
createTime: "2026-01-28 10:00:00",
// 【核心载荷】
content: {
// 布局信息:决定显示哪些字段,以及顺序
activeFieldKeys: ["region", "status", "ticketId"],
// 值信息:决定字段里填什么内容
fieldValues: {
region: "bj",
status: "running",
ticketId: ""
}
},
// 【权限控制】前端根据此字段控制按钮显隐
permission: {
canDelete: true, // 是否可删除
canShare: true // 是否可分享
}
}
3. 接口 API 定义 (API Interface)
所有接口均为异步操作,前端需处理 Pending 状态。
| 功能模块 | HTTP 方法 | URL 路径 | 请求参数 (Payload) | 响应/说明 |
|---|---|---|---|---|
| 初始化 | GET | /api/search/fields |
?domain=RAN |
返回 SearchField[] |
| 获取模板 | GET | /api/search/templates |
?userId=... |
返回 SearchTemplate[] |
| 保存模板 | POST | /api/search/templates |
{ name: "...", content: { activeFieldKeys: [], fieldValues: {} } } |
返回新模板 ID |
| 设为默认 | PUT | /api/search/templates/{id}/default |
- | 成功则后端自动将其他设为 false。前端需设置超时控制。 |
| 删除模板 | DELETE | /api/search/templates/{id} |
- | 需二次确认 |
| 共享模板 | POST | /api/search/templates/{id}/share |
{ target: "user_id_or_group", description: "..." } |
共享给特定用户或组 |
4. 状态管理设计 (Pinia Store)
Store Name : searchStore
State
allFields: Array - 所有可用字段定义。activeFieldKeys: Array - 当前面板显示的字段 Key (有序)。searchForm: Object - 当前表单输入值{ key: value }。templates: Array - 模板列表。
Actions (核心逻辑)
applyTemplate(template):
- 步骤 : 1. 覆盖
activeFieldKeys(恢复布局); 2. 深拷贝并覆盖searchForm(恢复数据)。 - 效果: 界面即时刷新,无需重新请求字段接口。
updateActiveFields(newKeys):
- 仅更新布局,保留
searchForm中已存在的用户输入值,防止配置过程中数据丢失。
apiSetDefault(id)(Async):
- 调用后端接口,成功后更新本地
templates数组中的isDefault状态(互斥逻辑)。
apiDeleteTemplate(id)(Async):
- 调用后端接口,成功后从本地数组移除该项。
apiShareTemplate(id, shareInfo)(Async):
- 调用后端接口提交分享请求。
5. 组件交互与 UX 设计细节
5.1 搜索配置弹窗 (SearchConfigDialog.vue)
设计目标: 像素级还原 UX 设计稿,实现高密度信息展示。
-
布局架构 : 自定义左右双面板(非
el-transfer)。 -
左面板 (待选池):
-
Header :
[Checkbox] 全部待选项|计数: 勾选数/总数。 -
Body: 顶部固定搜索框(过滤左侧列表),下方为滚动列表。
-
右面板 (已选池):
-
Header :
[Checkbox] 已选搜索项|计数: 勾选数/总数| [内嵌搜索框] (位于Header右侧,size=small)。 -
Body: 仅展示滚动列表。
-
交互逻辑:
-
独立过滤: 左右搜索框互不影响。
-
计数定义 : 右侧计数
4/9表示"当前配置了9个字段,其中4个被勾选准备移除"。 -
状态保持 : 打开弹窗时深拷贝当前配置,点击"确定"后才提交到 Store。
5.2 模板管理弹窗 (TemplateManagerDialog.vue)
设计目标: 稳健的异步操作反馈。
-
设为默认 (Set Default):
-
交互 : 使用
el-switch。 -
Loading: 细粒度控制,仅当前操作行的 Switch 显示 Loading。
-
超时熔断 : 前端强制 3秒超时 (
Promise.race)。若接口无响应,自动抛出错误并回滚 Switch 状态,防止 UI 卡死。 -
删除 (Delete):
-
交互: 红色图标按钮 + Tooltip。
-
流程 : 点击 ->
ElMessageBox二次确认 -> 确认按钮转圈 (Loading) -> API 调用 -> 成功提示。 -
分享 (Share):
-
交互: 蓝色分享图标。
-
流程: 弹出子对话框 -> 输入对象 -> 点击确定 (按钮 Loading) -> API 调用 -> 关闭弹窗。
6. 异常处理策略
- 接口超时:
- 在"设为默认"操作中,如果后端超过 3000ms 未响应,前端视为失败,立即恢复 UI 状态并提示"请求超时"。
- 数据一致性:
- 在应用模板 (
applyTemplate) 时,若模板中包含的key在当前系统的allFields中已不存在(如字段下线),前端自动过滤该无效 Key,防止渲染报错。
- 操作回滚:
- Switch 组件绑定
:model-value(单向) 而非v-model,只有 API 返回成功后才更新 Store 数据,确保 UI 状态与服务器真实状态一致。