feat: WIP 篩選器互相影響 autocomplete 建議
當使用者在 WIP Overview 或 WIP Detail 頁面套用篩選時, 其他篩選欄位的 autocomplete 會根據已選擇的條件過濾, 避免選擇會導致空結果的組合。 - 更新 search_workorders/lot_ids/packages/types 函數支援交叉過濾參數 - API /meta/search 新增 workorder/lotid/package/type 參數 - 前端 autocomplete 請求時自動帶入當前已填入的篩選值 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -263,6 +263,12 @@ def api_meta_search():
|
|||||||
limit: Maximum results (default: 20, max: 50)
|
limit: Maximum results (default: 20, max: 50)
|
||||||
include_dummy: Include DUMMY lots (default: false)
|
include_dummy: Include DUMMY lots (default: false)
|
||||||
|
|
||||||
|
Cross-filter parameters (for interdependent filter suggestions):
|
||||||
|
workorder: Optional WORKORDER cross-filter (fuzzy match)
|
||||||
|
lotid: Optional LOTID cross-filter (fuzzy match)
|
||||||
|
package: Optional PACKAGE_LEF cross-filter (exact match)
|
||||||
|
type: Optional PJ_TYPE cross-filter (exact match)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
JSON with items list containing matching values
|
JSON with items list containing matching values
|
||||||
"""
|
"""
|
||||||
@@ -271,6 +277,12 @@ def api_meta_search():
|
|||||||
limit = min(request.args.get('limit', 20, type=int), 50)
|
limit = min(request.args.get('limit', 20, type=int), 50)
|
||||||
include_dummy = _parse_bool(request.args.get('include_dummy', ''))
|
include_dummy = _parse_bool(request.args.get('include_dummy', ''))
|
||||||
|
|
||||||
|
# Cross-filter parameters
|
||||||
|
workorder = request.args.get('workorder', '').strip() or None
|
||||||
|
lotid = request.args.get('lotid', '').strip() or None
|
||||||
|
package = request.args.get('package', '').strip() or None
|
||||||
|
pj_type = request.args.get('type', '').strip() or None
|
||||||
|
|
||||||
# Validate search field
|
# Validate search field
|
||||||
if search_field not in ('workorder', 'lotid', 'package', 'pj_type'):
|
if search_field not in ('workorder', 'lotid', 'package', 'pj_type'):
|
||||||
return jsonify({
|
return jsonify({
|
||||||
@@ -282,15 +294,27 @@ def api_meta_search():
|
|||||||
if len(q) < 2:
|
if len(q) < 2:
|
||||||
return jsonify({'success': True, 'data': {'items': []}})
|
return jsonify({'success': True, 'data': {'items': []}})
|
||||||
|
|
||||||
# Perform search
|
# Perform search with cross-filters (exclude the field being searched)
|
||||||
if search_field == 'workorder':
|
if search_field == 'workorder':
|
||||||
result = search_workorders(q=q, limit=limit, include_dummy=include_dummy)
|
result = search_workorders(
|
||||||
|
q=q, limit=limit, include_dummy=include_dummy,
|
||||||
|
lotid=lotid, package=package, pj_type=pj_type
|
||||||
|
)
|
||||||
elif search_field == 'lotid':
|
elif search_field == 'lotid':
|
||||||
result = search_lot_ids(q=q, limit=limit, include_dummy=include_dummy)
|
result = search_lot_ids(
|
||||||
|
q=q, limit=limit, include_dummy=include_dummy,
|
||||||
|
workorder=workorder, package=package, pj_type=pj_type
|
||||||
|
)
|
||||||
elif search_field == 'package':
|
elif search_field == 'package':
|
||||||
result = search_packages(q=q, limit=limit, include_dummy=include_dummy)
|
result = search_packages(
|
||||||
|
q=q, limit=limit, include_dummy=include_dummy,
|
||||||
|
workorder=workorder, lotid=lotid, pj_type=pj_type
|
||||||
|
)
|
||||||
else: # pj_type
|
else: # pj_type
|
||||||
result = search_types(q=q, limit=limit, include_dummy=include_dummy)
|
result = search_types(
|
||||||
|
q=q, limit=limit, include_dummy=include_dummy,
|
||||||
|
workorder=workorder, lotid=lotid, package=package
|
||||||
|
)
|
||||||
|
|
||||||
if result is not None:
|
if result is not None:
|
||||||
return jsonify({'success': True, 'data': {'items': result}})
|
return jsonify({'success': True, 'data': {'items': result}})
|
||||||
|
|||||||
@@ -1177,7 +1177,10 @@ def _get_packages_from_oracle(include_dummy: bool = False) -> Optional[List[Dict
|
|||||||
def search_workorders(
|
def search_workorders(
|
||||||
q: str,
|
q: str,
|
||||||
limit: int = 20,
|
limit: int = 20,
|
||||||
include_dummy: bool = False
|
include_dummy: bool = False,
|
||||||
|
lotid: Optional[str] = None,
|
||||||
|
package: Optional[str] = None,
|
||||||
|
pj_type: Optional[str] = None
|
||||||
) -> Optional[List[str]]:
|
) -> Optional[List[str]]:
|
||||||
"""Search for WORKORDER values matching the query.
|
"""Search for WORKORDER values matching the query.
|
||||||
|
|
||||||
@@ -1187,6 +1190,9 @@ def search_workorders(
|
|||||||
q: Search query (minimum 2 characters)
|
q: Search query (minimum 2 characters)
|
||||||
limit: Maximum number of results (default: 20, max: 50)
|
limit: Maximum number of results (default: 20, max: 50)
|
||||||
include_dummy: If True, include DUMMY lots (default: False)
|
include_dummy: If True, include DUMMY lots (default: False)
|
||||||
|
lotid: Optional LOTID cross-filter (fuzzy match)
|
||||||
|
package: Optional PACKAGE_LEF cross-filter (exact match)
|
||||||
|
pj_type: Optional PJ_TYPE cross-filter (exact match)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List of matching WORKORDER values (distinct)
|
List of matching WORKORDER values (distinct)
|
||||||
@@ -1201,9 +1207,15 @@ def search_workorders(
|
|||||||
cached_df = _get_wip_dataframe()
|
cached_df = _get_wip_dataframe()
|
||||||
if cached_df is not None:
|
if cached_df is not None:
|
||||||
try:
|
try:
|
||||||
df = _filter_base_conditions(cached_df, include_dummy)
|
df = _filter_base_conditions(cached_df, include_dummy, lotid=lotid)
|
||||||
df = df[df['WORKORDER'].notna()]
|
df = df[df['WORKORDER'].notna()]
|
||||||
|
|
||||||
|
# Apply cross-filters
|
||||||
|
if package and 'PACKAGE_LEF' in df.columns:
|
||||||
|
df = df[df['PACKAGE_LEF'] == package]
|
||||||
|
if pj_type and 'PJ_TYPE' in df.columns:
|
||||||
|
df = df[df['PJ_TYPE'] == pj_type]
|
||||||
|
|
||||||
# Filter by search query (case-insensitive)
|
# Filter by search query (case-insensitive)
|
||||||
df = df[df['WORKORDER'].str.contains(q, case=False, na=False)]
|
df = df[df['WORKORDER'].str.contains(q, case=False, na=False)]
|
||||||
|
|
||||||
@@ -1217,19 +1229,29 @@ def search_workorders(
|
|||||||
logger.warning(f"Cache-based workorder search failed, falling back to Oracle: {exc}")
|
logger.warning(f"Cache-based workorder search failed, falling back to Oracle: {exc}")
|
||||||
|
|
||||||
# Fallback to Oracle direct query
|
# Fallback to Oracle direct query
|
||||||
return _search_workorders_from_oracle(q, limit, include_dummy)
|
return _search_workorders_from_oracle(q, limit, include_dummy, lotid, package, pj_type)
|
||||||
|
|
||||||
|
|
||||||
def _search_workorders_from_oracle(
|
def _search_workorders_from_oracle(
|
||||||
q: str,
|
q: str,
|
||||||
limit: int = 20,
|
limit: int = 20,
|
||||||
include_dummy: bool = False
|
include_dummy: bool = False,
|
||||||
|
lotid: Optional[str] = None,
|
||||||
|
package: Optional[str] = None,
|
||||||
|
pj_type: Optional[str] = None
|
||||||
) -> Optional[List[str]]:
|
) -> Optional[List[str]]:
|
||||||
"""Search workorders directly from Oracle (fallback)."""
|
"""Search workorders directly from Oracle (fallback)."""
|
||||||
try:
|
try:
|
||||||
conditions = _build_base_conditions(include_dummy)
|
conditions = _build_base_conditions(include_dummy, lotid=lotid)
|
||||||
conditions.append(f"WORKORDER LIKE '%{_escape_sql(q)}%'")
|
conditions.append(f"WORKORDER LIKE '%{_escape_sql(q)}%'")
|
||||||
conditions.append("WORKORDER IS NOT NULL")
|
conditions.append("WORKORDER IS NOT NULL")
|
||||||
|
|
||||||
|
# Apply cross-filters
|
||||||
|
if package:
|
||||||
|
conditions.append(f"PACKAGE_LEF = '{_escape_sql(package)}'")
|
||||||
|
if pj_type:
|
||||||
|
conditions.append(f"PJ_TYPE = '{_escape_sql(pj_type)}'")
|
||||||
|
|
||||||
where_clause = f"WHERE {' AND '.join(conditions)}"
|
where_clause = f"WHERE {' AND '.join(conditions)}"
|
||||||
|
|
||||||
sql = f"""
|
sql = f"""
|
||||||
@@ -1253,7 +1275,10 @@ def _search_workorders_from_oracle(
|
|||||||
def search_lot_ids(
|
def search_lot_ids(
|
||||||
q: str,
|
q: str,
|
||||||
limit: int = 20,
|
limit: int = 20,
|
||||||
include_dummy: bool = False
|
include_dummy: bool = False,
|
||||||
|
workorder: Optional[str] = None,
|
||||||
|
package: Optional[str] = None,
|
||||||
|
pj_type: Optional[str] = None
|
||||||
) -> Optional[List[str]]:
|
) -> Optional[List[str]]:
|
||||||
"""Search for LOTID values matching the query.
|
"""Search for LOTID values matching the query.
|
||||||
|
|
||||||
@@ -1263,6 +1288,9 @@ def search_lot_ids(
|
|||||||
q: Search query (minimum 2 characters)
|
q: Search query (minimum 2 characters)
|
||||||
limit: Maximum number of results (default: 20, max: 50)
|
limit: Maximum number of results (default: 20, max: 50)
|
||||||
include_dummy: If True, include DUMMY lots (default: False)
|
include_dummy: If True, include DUMMY lots (default: False)
|
||||||
|
workorder: Optional WORKORDER cross-filter (fuzzy match)
|
||||||
|
package: Optional PACKAGE_LEF cross-filter (exact match)
|
||||||
|
pj_type: Optional PJ_TYPE cross-filter (exact match)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List of matching LOTID values
|
List of matching LOTID values
|
||||||
@@ -1277,7 +1305,13 @@ def search_lot_ids(
|
|||||||
cached_df = _get_wip_dataframe()
|
cached_df = _get_wip_dataframe()
|
||||||
if cached_df is not None:
|
if cached_df is not None:
|
||||||
try:
|
try:
|
||||||
df = _filter_base_conditions(cached_df, include_dummy)
|
df = _filter_base_conditions(cached_df, include_dummy, workorder=workorder)
|
||||||
|
|
||||||
|
# Apply cross-filters
|
||||||
|
if package and 'PACKAGE_LEF' in df.columns:
|
||||||
|
df = df[df['PACKAGE_LEF'] == package]
|
||||||
|
if pj_type and 'PJ_TYPE' in df.columns:
|
||||||
|
df = df[df['PJ_TYPE'] == pj_type]
|
||||||
|
|
||||||
# Filter by search query (case-insensitive)
|
# Filter by search query (case-insensitive)
|
||||||
df = df[df['LOTID'].str.contains(q, case=False, na=False)]
|
df = df[df['LOTID'].str.contains(q, case=False, na=False)]
|
||||||
@@ -1292,18 +1326,28 @@ def search_lot_ids(
|
|||||||
logger.warning(f"Cache-based lot ID search failed, falling back to Oracle: {exc}")
|
logger.warning(f"Cache-based lot ID search failed, falling back to Oracle: {exc}")
|
||||||
|
|
||||||
# Fallback to Oracle direct query
|
# Fallback to Oracle direct query
|
||||||
return _search_lot_ids_from_oracle(q, limit, include_dummy)
|
return _search_lot_ids_from_oracle(q, limit, include_dummy, workorder, package, pj_type)
|
||||||
|
|
||||||
|
|
||||||
def _search_lot_ids_from_oracle(
|
def _search_lot_ids_from_oracle(
|
||||||
q: str,
|
q: str,
|
||||||
limit: int = 20,
|
limit: int = 20,
|
||||||
include_dummy: bool = False
|
include_dummy: bool = False,
|
||||||
|
workorder: Optional[str] = None,
|
||||||
|
package: Optional[str] = None,
|
||||||
|
pj_type: Optional[str] = None
|
||||||
) -> Optional[List[str]]:
|
) -> Optional[List[str]]:
|
||||||
"""Search lot IDs directly from Oracle (fallback)."""
|
"""Search lot IDs directly from Oracle (fallback)."""
|
||||||
try:
|
try:
|
||||||
conditions = _build_base_conditions(include_dummy)
|
conditions = _build_base_conditions(include_dummy, workorder=workorder)
|
||||||
conditions.append(f"LOTID LIKE '%{_escape_sql(q)}%'")
|
conditions.append(f"LOTID LIKE '%{_escape_sql(q)}%'")
|
||||||
|
|
||||||
|
# Apply cross-filters
|
||||||
|
if package:
|
||||||
|
conditions.append(f"PACKAGE_LEF = '{_escape_sql(package)}'")
|
||||||
|
if pj_type:
|
||||||
|
conditions.append(f"PJ_TYPE = '{_escape_sql(pj_type)}'")
|
||||||
|
|
||||||
where_clause = f"WHERE {' AND '.join(conditions)}"
|
where_clause = f"WHERE {' AND '.join(conditions)}"
|
||||||
|
|
||||||
sql = f"""
|
sql = f"""
|
||||||
@@ -1327,7 +1371,10 @@ def _search_lot_ids_from_oracle(
|
|||||||
def search_packages(
|
def search_packages(
|
||||||
q: str,
|
q: str,
|
||||||
limit: int = 20,
|
limit: int = 20,
|
||||||
include_dummy: bool = False
|
include_dummy: bool = False,
|
||||||
|
workorder: Optional[str] = None,
|
||||||
|
lotid: Optional[str] = None,
|
||||||
|
pj_type: Optional[str] = None
|
||||||
) -> Optional[List[str]]:
|
) -> Optional[List[str]]:
|
||||||
"""Search for PACKAGE_LEF values matching the query.
|
"""Search for PACKAGE_LEF values matching the query.
|
||||||
|
|
||||||
@@ -1337,6 +1384,9 @@ def search_packages(
|
|||||||
q: Search query (minimum 2 characters)
|
q: Search query (minimum 2 characters)
|
||||||
limit: Maximum number of results (default: 20, max: 50)
|
limit: Maximum number of results (default: 20, max: 50)
|
||||||
include_dummy: If True, include DUMMY lots (default: False)
|
include_dummy: If True, include DUMMY lots (default: False)
|
||||||
|
workorder: Optional WORKORDER cross-filter (fuzzy match)
|
||||||
|
lotid: Optional LOTID cross-filter (fuzzy match)
|
||||||
|
pj_type: Optional PJ_TYPE cross-filter (exact match)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List of matching PACKAGE_LEF values (distinct)
|
List of matching PACKAGE_LEF values (distinct)
|
||||||
@@ -1351,15 +1401,19 @@ def search_packages(
|
|||||||
cached_df = _get_wip_dataframe()
|
cached_df = _get_wip_dataframe()
|
||||||
if cached_df is not None:
|
if cached_df is not None:
|
||||||
try:
|
try:
|
||||||
df = _filter_base_conditions(cached_df, include_dummy)
|
df = _filter_base_conditions(cached_df, include_dummy, workorder=workorder, lotid=lotid)
|
||||||
|
|
||||||
# Check if PACKAGE_LEF column exists
|
# Check if PACKAGE_LEF column exists
|
||||||
if 'PACKAGE_LEF' not in df.columns:
|
if 'PACKAGE_LEF' not in df.columns:
|
||||||
logger.warning("PACKAGE_LEF column not found in cache")
|
logger.warning("PACKAGE_LEF column not found in cache")
|
||||||
return _search_packages_from_oracle(q, limit, include_dummy)
|
return _search_packages_from_oracle(q, limit, include_dummy, workorder, lotid, pj_type)
|
||||||
|
|
||||||
df = df[df['PACKAGE_LEF'].notna()]
|
df = df[df['PACKAGE_LEF'].notna()]
|
||||||
|
|
||||||
|
# Apply cross-filter
|
||||||
|
if pj_type and 'PJ_TYPE' in df.columns:
|
||||||
|
df = df[df['PJ_TYPE'] == pj_type]
|
||||||
|
|
||||||
# Filter by search query (case-insensitive)
|
# Filter by search query (case-insensitive)
|
||||||
df = df[df['PACKAGE_LEF'].str.contains(q, case=False, na=False)]
|
df = df[df['PACKAGE_LEF'].str.contains(q, case=False, na=False)]
|
||||||
|
|
||||||
@@ -1373,19 +1427,27 @@ def search_packages(
|
|||||||
logger.warning(f"Cache-based package search failed, falling back to Oracle: {exc}")
|
logger.warning(f"Cache-based package search failed, falling back to Oracle: {exc}")
|
||||||
|
|
||||||
# Fallback to Oracle direct query
|
# Fallback to Oracle direct query
|
||||||
return _search_packages_from_oracle(q, limit, include_dummy)
|
return _search_packages_from_oracle(q, limit, include_dummy, workorder, lotid, pj_type)
|
||||||
|
|
||||||
|
|
||||||
def _search_packages_from_oracle(
|
def _search_packages_from_oracle(
|
||||||
q: str,
|
q: str,
|
||||||
limit: int = 20,
|
limit: int = 20,
|
||||||
include_dummy: bool = False
|
include_dummy: bool = False,
|
||||||
|
workorder: Optional[str] = None,
|
||||||
|
lotid: Optional[str] = None,
|
||||||
|
pj_type: Optional[str] = None
|
||||||
) -> Optional[List[str]]:
|
) -> Optional[List[str]]:
|
||||||
"""Search packages directly from Oracle (fallback)."""
|
"""Search packages directly from Oracle (fallback)."""
|
||||||
try:
|
try:
|
||||||
conditions = _build_base_conditions(include_dummy)
|
conditions = _build_base_conditions(include_dummy, workorder=workorder, lotid=lotid)
|
||||||
conditions.append(f"PACKAGE_LEF LIKE '%{_escape_sql(q)}%'")
|
conditions.append(f"PACKAGE_LEF LIKE '%{_escape_sql(q)}%'")
|
||||||
conditions.append("PACKAGE_LEF IS NOT NULL")
|
conditions.append("PACKAGE_LEF IS NOT NULL")
|
||||||
|
|
||||||
|
# Apply cross-filter
|
||||||
|
if pj_type:
|
||||||
|
conditions.append(f"PJ_TYPE = '{_escape_sql(pj_type)}'")
|
||||||
|
|
||||||
where_clause = f"WHERE {' AND '.join(conditions)}"
|
where_clause = f"WHERE {' AND '.join(conditions)}"
|
||||||
|
|
||||||
sql = f"""
|
sql = f"""
|
||||||
@@ -1409,7 +1471,10 @@ def _search_packages_from_oracle(
|
|||||||
def search_types(
|
def search_types(
|
||||||
q: str,
|
q: str,
|
||||||
limit: int = 20,
|
limit: int = 20,
|
||||||
include_dummy: bool = False
|
include_dummy: bool = False,
|
||||||
|
workorder: Optional[str] = None,
|
||||||
|
lotid: Optional[str] = None,
|
||||||
|
package: Optional[str] = None
|
||||||
) -> Optional[List[str]]:
|
) -> Optional[List[str]]:
|
||||||
"""Search for PJ_TYPE values matching the query.
|
"""Search for PJ_TYPE values matching the query.
|
||||||
|
|
||||||
@@ -1419,6 +1484,9 @@ def search_types(
|
|||||||
q: Search query (minimum 2 characters)
|
q: Search query (minimum 2 characters)
|
||||||
limit: Maximum number of results (default: 20, max: 50)
|
limit: Maximum number of results (default: 20, max: 50)
|
||||||
include_dummy: If True, include DUMMY lots (default: False)
|
include_dummy: If True, include DUMMY lots (default: False)
|
||||||
|
workorder: Optional WORKORDER cross-filter (fuzzy match)
|
||||||
|
lotid: Optional LOTID cross-filter (fuzzy match)
|
||||||
|
package: Optional PACKAGE_LEF cross-filter (exact match)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List of matching PJ_TYPE values (distinct)
|
List of matching PJ_TYPE values (distinct)
|
||||||
@@ -1433,15 +1501,19 @@ def search_types(
|
|||||||
cached_df = _get_wip_dataframe()
|
cached_df = _get_wip_dataframe()
|
||||||
if cached_df is not None:
|
if cached_df is not None:
|
||||||
try:
|
try:
|
||||||
df = _filter_base_conditions(cached_df, include_dummy)
|
df = _filter_base_conditions(cached_df, include_dummy, workorder=workorder, lotid=lotid)
|
||||||
|
|
||||||
# Check if PJ_TYPE column exists
|
# Check if PJ_TYPE column exists
|
||||||
if 'PJ_TYPE' not in df.columns:
|
if 'PJ_TYPE' not in df.columns:
|
||||||
logger.warning("PJ_TYPE column not found in cache")
|
logger.warning("PJ_TYPE column not found in cache")
|
||||||
return _search_types_from_oracle(q, limit, include_dummy)
|
return _search_types_from_oracle(q, limit, include_dummy, workorder, lotid, package)
|
||||||
|
|
||||||
df = df[df['PJ_TYPE'].notna()]
|
df = df[df['PJ_TYPE'].notna()]
|
||||||
|
|
||||||
|
# Apply cross-filter
|
||||||
|
if package and 'PACKAGE_LEF' in df.columns:
|
||||||
|
df = df[df['PACKAGE_LEF'] == package]
|
||||||
|
|
||||||
# Filter by search query (case-insensitive)
|
# Filter by search query (case-insensitive)
|
||||||
df = df[df['PJ_TYPE'].str.contains(q, case=False, na=False)]
|
df = df[df['PJ_TYPE'].str.contains(q, case=False, na=False)]
|
||||||
|
|
||||||
@@ -1455,19 +1527,27 @@ def search_types(
|
|||||||
logger.warning(f"Cache-based type search failed, falling back to Oracle: {exc}")
|
logger.warning(f"Cache-based type search failed, falling back to Oracle: {exc}")
|
||||||
|
|
||||||
# Fallback to Oracle direct query
|
# Fallback to Oracle direct query
|
||||||
return _search_types_from_oracle(q, limit, include_dummy)
|
return _search_types_from_oracle(q, limit, include_dummy, workorder, lotid, package)
|
||||||
|
|
||||||
|
|
||||||
def _search_types_from_oracle(
|
def _search_types_from_oracle(
|
||||||
q: str,
|
q: str,
|
||||||
limit: int = 20,
|
limit: int = 20,
|
||||||
include_dummy: bool = False
|
include_dummy: bool = False,
|
||||||
|
workorder: Optional[str] = None,
|
||||||
|
lotid: Optional[str] = None,
|
||||||
|
package: Optional[str] = None
|
||||||
) -> Optional[List[str]]:
|
) -> Optional[List[str]]:
|
||||||
"""Search types directly from Oracle (fallback)."""
|
"""Search types directly from Oracle (fallback)."""
|
||||||
try:
|
try:
|
||||||
conditions = _build_base_conditions(include_dummy)
|
conditions = _build_base_conditions(include_dummy, workorder=workorder, lotid=lotid)
|
||||||
conditions.append(f"PJ_TYPE LIKE '%{_escape_sql(q)}%'")
|
conditions.append(f"PJ_TYPE LIKE '%{_escape_sql(q)}%'")
|
||||||
conditions.append("PJ_TYPE IS NOT NULL")
|
conditions.append("PJ_TYPE IS NOT NULL")
|
||||||
|
|
||||||
|
# Apply cross-filter
|
||||||
|
if package:
|
||||||
|
conditions.append(f"PACKAGE_LEF = '{_escape_sql(package)}'")
|
||||||
|
|
||||||
where_clause = f"WHERE {' AND '.join(conditions)}"
|
where_clause = f"WHERE {' AND '.join(conditions)}"
|
||||||
|
|
||||||
sql = f"""
|
sql = f"""
|
||||||
|
|||||||
@@ -876,9 +876,32 @@
|
|||||||
};
|
};
|
||||||
const field = fieldMap[type] || type;
|
const field = fieldMap[type] || type;
|
||||||
|
|
||||||
|
// Build cross-filter parameters (exclude current field being searched)
|
||||||
|
// Get current input values for cross-filtering
|
||||||
|
const currentWorkorder = document.getElementById('filterWorkorder').value.trim();
|
||||||
|
const currentLotid = document.getElementById('filterLotid').value.trim();
|
||||||
|
const currentPackage = document.getElementById('filterPackage').value.trim();
|
||||||
|
const currentType = document.getElementById('filterType').value.trim();
|
||||||
|
|
||||||
|
const params = { field, q: query, limit: 20 };
|
||||||
|
|
||||||
|
// Add cross-filters (exclude the field being searched)
|
||||||
|
if (type !== 'workorder' && currentWorkorder) {
|
||||||
|
params.workorder = currentWorkorder;
|
||||||
|
}
|
||||||
|
if (type !== 'lotid' && currentLotid) {
|
||||||
|
params.lotid = currentLotid;
|
||||||
|
}
|
||||||
|
if (type !== 'package' && currentPackage) {
|
||||||
|
params.package = currentPackage;
|
||||||
|
}
|
||||||
|
if (type !== 'type' && currentType) {
|
||||||
|
params.type = currentType;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await MesApi.get('/api/wip/meta/search', {
|
const result = await MesApi.get('/api/wip/meta/search', {
|
||||||
params: { field, q: query, limit: 20 },
|
params,
|
||||||
silent: true,
|
silent: true,
|
||||||
retries: 0 // No retry for autocomplete
|
retries: 0 // No retry for autocomplete
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -967,9 +967,32 @@
|
|||||||
};
|
};
|
||||||
const field = fieldMap[type] || type;
|
const field = fieldMap[type] || type;
|
||||||
|
|
||||||
|
// Build cross-filter parameters (exclude current field being searched)
|
||||||
|
// Get current input values for cross-filtering
|
||||||
|
const currentWorkorder = document.getElementById('filterWorkorder').value.trim();
|
||||||
|
const currentLotid = document.getElementById('filterLotid').value.trim();
|
||||||
|
const currentPackage = document.getElementById('filterPackage').value.trim();
|
||||||
|
const currentType = document.getElementById('filterType').value.trim();
|
||||||
|
|
||||||
|
const params = { field, q: query, limit: 20 };
|
||||||
|
|
||||||
|
// Add cross-filters (exclude the field being searched)
|
||||||
|
if (type !== 'workorder' && currentWorkorder) {
|
||||||
|
params.workorder = currentWorkorder;
|
||||||
|
}
|
||||||
|
if (type !== 'lotid' && currentLotid) {
|
||||||
|
params.lotid = currentLotid;
|
||||||
|
}
|
||||||
|
if (type !== 'package' && currentPackage) {
|
||||||
|
params.package = currentPackage;
|
||||||
|
}
|
||||||
|
if (type !== 'type' && currentType) {
|
||||||
|
params.type = currentType;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await MesApi.get('/api/wip/meta/search', {
|
const result = await MesApi.get('/api/wip/meta/search', {
|
||||||
params: { field, q: query, limit: 20 },
|
params,
|
||||||
silent: true,
|
silent: true,
|
||||||
retries: 0 // No retry for autocomplete
|
retries: 0 // No retry for autocomplete
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user