1. 系统概述
本模块实现了一个**配置驱动(Metadata-Driven)**的动态搜索系统。
- 核心能力:用户可从字段池中自由配置搜索项(布局顺序),并将"布局 + 数据"保存为模板。
- 生命周期 :支持模板的创建、更新(覆盖)、应用、设为默认、共享及删除。
- UX 特性:定制的双面板穿梭框配置页、异步操作的加载/熔断反馈。
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)
描述保存的搜索场景。注意 permission 字段的完整性。
javascript
// 数据源:Store.templates
{
id: 101,
name: "我的日常巡检",
type: "private", // 'public' | 'private' | 'shared'
isDefault: true, // 是否默认模板
creator: "admin",
createTime: "2026-01-29 10:00:00",
// 【核心载荷 Content】
// 建议后端将此字段作为 JSON 类型存储,以适应未来 UI 变化
content: {
// 1. 布局信息: 决定显示哪些字段及顺序
activeFieldKeys: ["region", "status", "ticketId"],
// 2. 值信息: 决定字段内的回填值
fieldValues: {
region: "bj",
status: "running",
ticketId: ""
}
},
// 【权限控制 Permission】
// 前端根据此对象控制 UI 按钮的显隐
permission: {
canDelete: true, // 控制列表中的"删除"按钮
canShare: true, // 控制列表中的"分享"按钮
canUpdate: true // 【关键】控制搜索面板上的"更新模板"按钮
}
}
3. 接口 API 定义 (API Interface)
基础路径: /api/search
3.1 基础数据与列表
| 功能 | Method | Endpoint | 参数/说明 |
|---|---|---|---|
| 获取字段池 | GET |
/fields |
?domain=RAN |
返回 SearchField[] |
| 获取模板列表 | GET | /templates | ?userId=...
返回 SearchTemplate[] (需包含 permission 字段) |
3.2 模板生命周期管理
A. 创建新模板 (Create)
- URL :
POST /templates - 功能: 另存为新模板。
- Request Body:
json
{
"name": "新模板名称",
"type": "private",
"description": "备注",
"content": {
"activeFieldKeys": ["region", "status"],
"fieldValues": { "region": "bj", "status": "open" }
}
}
- Response :
{ code: 200, data: { id: 102 } }(返回新ID以便前端高亮)
B. 更新/覆盖模板 (Update) ------ [新增]
- URL :
PUT /templates/{id} - 功能 : 将当前面板的配置覆盖到已有的模板 ID 上(仅当
permission.canUpdate=true时前端才允许调用)。 - Request Body:
json
{
"name": "我的日常巡检", // 可选,若支持改名则传
"description": "更新了筛选条件",
"content": {
"activeFieldKeys": ["region", "vendor", "status"], // 新的布局
"fieldValues": { "region": "sh", "vendor": "hw", "status": "closed" } // 新的值
}
}
- Response :
{ code: 200, message: "更新成功" }
C. 设为默认 (Set Default)
- URL :
PUT /templates/{id}/default - 逻辑: 后端需保证同一用户下只有一个 Default 模板(互斥)。
- 前端处理 : 需配合
Promise.race实现 3秒超时熔断。
D. 删除模板 (Delete)
- URL :
DELETE /templates/{id}
E. 共享模板 (Share)
- URL :
POST /templates/{id}/share - Body :
{ "targets": ["user_1", "group_A"], "comment": "..." }
4. 前端状态管理 (Pinia Store Design)
Store Name : searchStore
核心 State
currentTemplateId: (新增) 记录当前面板是基于哪个模板加载的。
- 值为
ID(Number/String): 显示"更新模板"按钮。 - 值为
null: 隐藏"更新模板"按钮(代表当前是新建或未保存状态)。
activeFieldKeys:string[](有序布局)。searchForm:Object(表单值)。
核心 Action 流程
- 应用模板 (
applyTemplate):
- 设置
activeFieldKeys和searchForm。 - 设置
currentTemplateId = template.id。 - 效果 : 界面刷新,"更新模板"按钮根据
template.permission.canUpdate显隐。
- 更新当前模板 (
updateCurrentTemplate):
- 校验
currentTemplateId是否存在。 - 构造 Payload (
content包含当前布局和值)。 - 调用
PUT接口。 - 成功后更新本地列表数据,无需刷新页面。
- 搜索项配置变更:
- 当用户在"配置弹窗"修改了布局,或者在"搜索面板"修改了值:
- 策略 : 保持
currentTemplateId不变,允许用户点击"更新"将变更保存回原模板。
5. 关键 UX/UI 实现规范
5.1 搜索面板操作区
按钮组的排列顺序与显示逻辑:
- 查询 (Search) :
Primary按钮。 - 更新模板 (Update) :
Warning/Plain按钮。
- v-if 条件 :
currentTemplateId !== nullANDtemplates.find(id).permission.canUpdate === true。
- 存为模板 (Save As): 普通按钮。始终显示。
- 搜索项配置 (Config): 文字链接/图标按钮。
5.2 搜索项配置弹窗 (Config Dialog)
放弃 el-transfer,采用自定义双面板:
| 区域 | 包含元素 | 交互逻辑 |
|---|---|---|
| 左面板 (待选) | Header: 全选Checkbox + 勾选数/总数 |
Body Top: 独立搜索框
List: 待选字段列表 | 搜索框仅过滤左侧列表。
列表显示所有 !activeFieldKeys.includes(key) 的字段。 |
| 中轴 | 向右按钮 (>)
向左按钮 (<) | 仅操作内存中的临时数组。 |
| 右面板 (已选) | Header: 全选Checkbox + 勾选数/总数 + 内嵌小搜索框
List: 已选字段列表 | 右侧计数器 4/9 含义:当前已选列表中,有4个被勾选(准备移除),共9个。
列表顺序即为最终布局顺序。 |
5.3 异步操作反馈
- Switch 开关: 点击设为默认时,仅当前行显示 Loading,若 API 超时 (3s) 则自动回滚状态。
- 删除确认 : 必须使用
ElMessageBox.confirm,且在 API 请求期间 Confirm 按钮需显示 Loading。