feat(M08-B): 补联调检查项搜索
This commit is contained in:
@@ -31,6 +31,13 @@
|
|||||||
:value="owner"
|
:value="owner"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
|
<el-input
|
||||||
|
v-model="keywordFilter"
|
||||||
|
class="handoff-search"
|
||||||
|
clearable
|
||||||
|
:prefix-icon="Search"
|
||||||
|
:placeholder="'\u641c\u7d22\u68c0\u67e5\u9879/\u8d1f\u8d23\u4eba/\u8bc1\u636e'"
|
||||||
|
/>
|
||||||
<el-popover trigger="click" width="360">
|
<el-popover trigger="click" width="360">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-button :icon="ListChecks" :disabled="filteredChecklist.length === 0">
|
<el-button :icon="ListChecks" :disabled="filteredChecklist.length === 0">
|
||||||
@@ -347,7 +354,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, reactive, ref } from 'vue';
|
import { computed, reactive, ref } from 'vue';
|
||||||
import { Check, Copy, Download, FileDown, FileUp, ListChecks, RotateCcw } from '@lucide/vue';
|
import { Check, Copy, Download, FileDown, FileUp, ListChecks, RotateCcw, Search } from '@lucide/vue';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
type FieldStatus = 'PENDING' | 'PASS' | 'BLOCKED' | 'SKIP';
|
type FieldStatus = 'PENDING' | 'PASS' | 'BLOCKED' | 'SKIP';
|
||||||
@@ -384,6 +391,7 @@ const sessionStorageKey = 'qipai.cleaning.field-handoff.session';
|
|||||||
const category = ref<'全部' | HandoffItem['category']>('全部');
|
const category = ref<'全部' | HandoffItem['category']>('全部');
|
||||||
const statusFilter = ref<'ALL' | FieldStatus>('ALL');
|
const statusFilter = ref<'ALL' | FieldStatus>('ALL');
|
||||||
const ownerFilter = ref('ALL');
|
const ownerFilter = ref('ALL');
|
||||||
|
const keywordFilter = ref('');
|
||||||
const snapshotInput = ref<HTMLInputElement | null>(null);
|
const snapshotInput = ref<HTMLInputElement | null>(null);
|
||||||
const bulkForm = reactive<{ status: FieldStatus; owner: string; deadline: string; note: string }>({
|
const bulkForm = reactive<{ status: FieldStatus; owner: string; deadline: string; note: string }>({
|
||||||
status: 'PASS',
|
status: 'PASS',
|
||||||
@@ -460,8 +468,26 @@ const filteredChecklist = computed(() => checklist.filter((item) => {
|
|||||||
const ownerMatched = ownerFilter.value === 'ALL'
|
const ownerMatched = ownerFilter.value === 'ALL'
|
||||||
|| (ownerFilter.value === '__UNASSIGNED__' && !owner)
|
|| (ownerFilter.value === '__UNASSIGNED__' && !owner)
|
||||||
|| owner === ownerFilter.value;
|
|| owner === ownerFilter.value;
|
||||||
return categoryMatched && statusMatched && ownerMatched;
|
return categoryMatched && statusMatched && ownerMatched && matchesKeyword(item);
|
||||||
}));
|
}));
|
||||||
|
function matchesKeyword(item: HandoffItem) {
|
||||||
|
const keyword = keywordFilter.value.trim().toLowerCase();
|
||||||
|
if (!keyword) return true;
|
||||||
|
const itemDraft = draft[item.id];
|
||||||
|
return [
|
||||||
|
item.id,
|
||||||
|
item.category,
|
||||||
|
item.title,
|
||||||
|
item.expected,
|
||||||
|
item.evidence,
|
||||||
|
itemDraft.status,
|
||||||
|
itemDraft.owner,
|
||||||
|
itemDraft.deadline,
|
||||||
|
itemDraft.note,
|
||||||
|
itemDraft.evidenceRef
|
||||||
|
].some((value) => String(value).toLowerCase().includes(keyword));
|
||||||
|
}
|
||||||
|
|
||||||
const ownerOptions = computed(() => Array.from(new Set(checklist
|
const ownerOptions = computed(() => Array.from(new Set(checklist
|
||||||
.map((item) => draft[item.id].owner.trim())
|
.map((item) => draft[item.id].owner.trim())
|
||||||
.filter(Boolean))).sort((a, b) => a.localeCompare(b, 'zh-Hans-CN')));
|
.filter(Boolean))).sort((a, b) => a.localeCompare(b, 'zh-Hans-CN')));
|
||||||
|
|||||||
@@ -726,6 +726,10 @@ textarea {
|
|||||||
width: 130px;
|
width: 130px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.handoff-search {
|
||||||
|
width: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
.handoff-bulk-form {
|
.handoff-bulk-form {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
@@ -965,6 +969,10 @@ textarea {
|
|||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.handoff-search {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.preflight-meta {
|
.preflight-meta {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -338,12 +338,16 @@ for (const pattern of [
|
|||||||
'handoff-status-select',
|
'handoff-status-select',
|
||||||
'全部状态',
|
'全部状态',
|
||||||
'ownerFilter',
|
'ownerFilter',
|
||||||
|
'keywordFilter',
|
||||||
|
'matchesKeyword',
|
||||||
'ownerOptions',
|
'ownerOptions',
|
||||||
'ownerProgress',
|
'ownerProgress',
|
||||||
'copyOwnerSummary',
|
'copyOwnerSummary',
|
||||||
'负责人看板',
|
'负责人看板',
|
||||||
'负责人摘要已复制',
|
'负责人摘要已复制',
|
||||||
'handoff-owner-select',
|
'handoff-owner-select',
|
||||||
|
'handoff-search',
|
||||||
|
'\\u641c\\u7d22\\u68c0\\u67e5\\u9879/\\u8d1f\\u8d23\\u4eba/\\u8bc1\\u636e',
|
||||||
'全部负责人',
|
'全部负责人',
|
||||||
'未分派',
|
'未分派',
|
||||||
'批量标记',
|
'批量标记',
|
||||||
@@ -387,6 +391,7 @@ assert.match(styles, /\.handoff-stage-card/);
|
|||||||
assert.match(styles, /\.handoff-owner-board/);
|
assert.match(styles, /\.handoff-owner-board/);
|
||||||
assert.match(styles, /\.handoff-owner-grid/);
|
assert.match(styles, /\.handoff-owner-grid/);
|
||||||
assert.match(styles, /\.handoff-owner-card/);
|
assert.match(styles, /\.handoff-owner-card/);
|
||||||
|
assert.match(styles, /\.handoff-search/);
|
||||||
assert.match(styles, /\.handoff-verdict/);
|
assert.match(styles, /\.handoff-verdict/);
|
||||||
assert.match(styles, /\.handoff-status-select/);
|
assert.match(styles, /\.handoff-status-select/);
|
||||||
assert.match(styles, /\.handoff-bulk-form/);
|
assert.match(styles, /\.handoff-bulk-form/);
|
||||||
|
|||||||
Reference in New Issue
Block a user