Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 07a1cdb063 | |||
| 2942bcc380 | |||
| 349337e75f | |||
| 9bdd8261fe | |||
| 04c8505531 | |||
| c9edf4a4c8 |
+41
-1
@@ -5597,6 +5597,8 @@ def get_items():
|
||||
favorites = set(session.get('favorites', []))
|
||||
|
||||
available_only = str(request.args.get('available_only', '')).strip().lower() in ('1', 'true', 'yes', 'on')
|
||||
search_term = str(request.args.get('search', '')).strip()
|
||||
search_scope = str(request.args.get('search_scope', 'all')).strip().lower()
|
||||
offset_raw = request.args.get('offset')
|
||||
limit_raw = request.args.get('limit')
|
||||
light_mode_param = str(request.args.get('light_mode', '')).strip().lower()
|
||||
@@ -5632,6 +5634,42 @@ def get_items():
|
||||
'Deleted': {'$ne': True},
|
||||
}
|
||||
|
||||
if search_term:
|
||||
search_pattern = re.escape(search_term[:200])
|
||||
if search_scope in ('description', 'title_description'):
|
||||
search_fields = ['Name', 'Beschreibung']
|
||||
else:
|
||||
search_fields = [
|
||||
'Name', 'Beschreibung', 'Code_4', 'ISBN',
|
||||
'Author', 'Autor',
|
||||
]
|
||||
|
||||
direct_matches = [{field: {'$regex': search_pattern, '$options': 'i'}}
|
||||
for field in search_fields]
|
||||
if search_scope not in ('description', 'title_description') and search_term.isdigit():
|
||||
direct_matches.append({'Code_4': int(search_term)})
|
||||
grouped_parent_ids = [
|
||||
child.get('ParentItemId')
|
||||
for child in items_col.find(
|
||||
{
|
||||
'IsGroupedSubItem': True,
|
||||
'Deleted': {'$ne': True},
|
||||
'$or': direct_matches,
|
||||
},
|
||||
{'ParentItemId': 1},
|
||||
)
|
||||
if child.get('ParentItemId')
|
||||
]
|
||||
if grouped_parent_ids:
|
||||
direct_matches.append({'_id': {'$in': grouped_parent_ids}})
|
||||
|
||||
base_query = {
|
||||
'$and': [
|
||||
base_query,
|
||||
{'$or': direct_matches},
|
||||
]
|
||||
}
|
||||
|
||||
total_count = items_col.count_documents(base_query)
|
||||
|
||||
light_projection = {
|
||||
@@ -10791,7 +10829,9 @@ def search_word(word):
|
||||
if (term_lower in text.lower()) or (term_lower in title_text.lower()):
|
||||
_id = i.get("_id")
|
||||
if _id is not None:
|
||||
id_set.add(str(_id))
|
||||
item_id = str(_id)
|
||||
parent_id = i.get('ParentItemId')
|
||||
id_set.add(str(parent_id or item_id))
|
||||
|
||||
return jsonify({"success": True, "response": list(id_set)})
|
||||
except Exception as e:
|
||||
|
||||
@@ -1301,8 +1301,6 @@
|
||||
<button class="function-search-btn" type="submit">Los</button>
|
||||
</form>
|
||||
</div>
|
||||
{% if current_tenant_db %}
|
||||
<span class="navbar-text tenant-badge" title="Aktive Tenant-Datenbank">{{ current_tenant_db }}</span>
|
||||
{% endif %}
|
||||
<span class="navbar-text text-light me-3">{{ session['username'] }}</span>
|
||||
<div class="dropdown me-2 user-menu-wrap">
|
||||
@@ -1332,7 +1330,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
{% endif %}
|
||||
|
||||
{% if library_module_enabled and CURRENT_MODULE == 'library' %}
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" id="libraryNavbar">
|
||||
|
||||
@@ -3206,9 +3206,12 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
||||
});
|
||||
}
|
||||
|
||||
function loadItems(offset = 0, append = false) {
|
||||
function loadItems(offset = 0, append = false, searchTerm = '', searchScope = 'all') {
|
||||
// Keep list payload lightweight; full details are fetched on-demand in openItemQuick.
|
||||
return fetch(`{{ url_for('get_items') }}?offset=${offset}&limit=${MAIN_ADMIN_ITEMS_PAGE_SIZE}&light_mode=true`)
|
||||
const searchParams = searchTerm
|
||||
? `&search=${encodeURIComponent(searchTerm)}&search_scope=${encodeURIComponent(searchScope)}`
|
||||
: '';
|
||||
return fetch(`{{ url_for('get_items') }}?offset=${offset}&limit=${MAIN_ADMIN_ITEMS_PAGE_SIZE}&light_mode=true${searchParams}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const itemsContainer = document.querySelector('#items-container');
|
||||
@@ -3241,7 +3244,7 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
||||
}
|
||||
pageItems.sort((a, b) => {
|
||||
const nameA = a.Name ? a.Name.toLowerCase() : '';
|
||||
const nameB = a.Name ? a.Name.toLowerCase() : '';
|
||||
const nameB = b.Name ? b.Name.toLowerCase() : '';
|
||||
return nameA.localeCompare(nameB);
|
||||
});
|
||||
|
||||
@@ -3681,7 +3684,11 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
||||
card.classList.remove('highlight-item', 'code-match', 'exact-code-match');
|
||||
});
|
||||
|
||||
applyFilters(true);
|
||||
if (codeSearchTerm) {
|
||||
loadItems(0, false, codeSearchTerm, 'all');
|
||||
} else {
|
||||
loadItems();
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
searchInput.classList.remove('searching');
|
||||
@@ -3883,7 +3890,7 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
||||
card.classList.remove('highlight-item', 'code-match', 'exact-code-match');
|
||||
});
|
||||
|
||||
applyFilters();
|
||||
loadItems();
|
||||
}
|
||||
|
||||
// Description search using backend substring match
|
||||
@@ -3892,21 +3899,12 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
||||
const term = (input?.value || '').trim();
|
||||
if (!term){
|
||||
descSearchIds = null;
|
||||
applyFilters(true);
|
||||
loadItems(0, false, codeSearchTerm, 'all');
|
||||
return;
|
||||
}
|
||||
input?.classList.add('searching');
|
||||
fetch(`/search_word/${encodeURIComponent(term)}`)
|
||||
.then(r=>r.json())
|
||||
.then(data=>{
|
||||
if (data && data.success && Array.isArray(data.response)){
|
||||
descSearchIds = new Set(data.response.map(String));
|
||||
} else {
|
||||
descSearchIds = new Set();
|
||||
}
|
||||
applyFilters(true);
|
||||
})
|
||||
.catch(()=>{ descSearchIds = new Set(); applyFilters(true); })
|
||||
descSearchIds = null;
|
||||
loadItems(0, false, term, 'title_description')
|
||||
.finally(()=>{ setTimeout(()=> input?.classList.remove('searching'), 300); });
|
||||
}
|
||||
|
||||
@@ -3914,7 +3912,7 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
||||
const input = document.getElementById('desc-search');
|
||||
if (input) input.value = '';
|
||||
descSearchIds = null;
|
||||
applyFilters();
|
||||
loadItems(0, false, codeSearchTerm, 'all');
|
||||
}
|
||||
|
||||
// Open item modal with fresh details from backend.
|
||||
|
||||
@@ -21,9 +21,8 @@
|
||||
<div class="card shadow-sm border-0 h-100 rounded-3">
|
||||
<div class="card-header bg-white border-bottom py-3 d-flex justify-content-between align-items-center">
|
||||
<h2 class="card-title h5 mb-0 fw-semibold text-primary">
|
||||
<i class="bi bi-funnel me-2"></i>{{ filter_names.get('1', 'Jahrgangsstufe') }}
|
||||
<i class="bi bi-funnel me-2"></i>{{ filter_names.get('2', 'Jahrgangsstufe') }}
|
||||
</h2>
|
||||
<span class="badge bg-primary-subtle text-primary rounded-pill">Filter 1</span>
|
||||
</div>
|
||||
<div class="card-body p-4">
|
||||
<form method="POST" action="{{ url_for('add_filter_value', filter_num=1) }}" class="mb-4">
|
||||
@@ -87,9 +86,8 @@
|
||||
<div class="card shadow-sm border-0 h-100 rounded-3">
|
||||
<div class="card-header bg-white border-bottom py-3 d-flex justify-content-between align-items-center">
|
||||
<h2 class="card-title h5 mb-0 fw-semibold text-primary">
|
||||
<i class="bi bi-funnel me-2"></i>{{ filter_names.get('2', 'Fachgebiet') }}
|
||||
<i class="bi bi-funnel me-2"></i>{{ filter_names.get('1', 'Fachgebiet') }}
|
||||
</h2>
|
||||
<span class="badge bg-primary-subtle text-primary rounded-pill">Filter 2</span>
|
||||
</div>
|
||||
<div class="card-body p-4">
|
||||
<form method="POST" action="{{ url_for('add_filter_value', filter_num=2) }}" class="mb-4">
|
||||
|
||||
Reference in New Issue
Block a user