修改完善这个专利部分
This commit is contained in:
@@ -2563,14 +2563,47 @@
|
||||
}
|
||||
function buildQueryAsinQuery(page) {
|
||||
var query = 'page=' + (page || 1) + '&page_size=' + queryAsinPageSize;
|
||||
var filterQuery = buildQueryAsinFilterQuery();
|
||||
if (filterQuery) query += '&' + filterQuery;
|
||||
return query;
|
||||
}
|
||||
function buildQueryAsinFilterQuery() {
|
||||
var query = '';
|
||||
var groupId = (document.getElementById('queryAsinFilterGroupId').value || '').trim();
|
||||
var shopName = (document.getElementById('queryAsinFilterShopName').value || '').trim();
|
||||
var asin = (document.getElementById('queryAsinFilterAsin').value || '').trim();
|
||||
if (groupId) query += '&group_id=' + encodeURIComponent(groupId);
|
||||
if (shopName) query += '&shop_name=' + encodeURIComponent(shopName);
|
||||
if (asin) query += '&asin=' + encodeURIComponent(asin);
|
||||
if (groupId) query += (query ? '&' : '') + 'group_id=' + encodeURIComponent(groupId);
|
||||
if (shopName) query += (query ? '&' : '') + 'shop_name=' + encodeURIComponent(shopName);
|
||||
if (asin) query += (query ? '&' : '') + 'asin=' + encodeURIComponent(asin);
|
||||
return query;
|
||||
}
|
||||
function exportQueryAsin() {
|
||||
var query = buildQueryAsinFilterQuery();
|
||||
var url = '/api/admin/query-asins/export' + (query ? ('?' + query) : '');
|
||||
fetch(url)
|
||||
.then(function (response) {
|
||||
var contentType = response.headers.get('content-type') || '';
|
||||
if (!response.ok || contentType.indexOf('application/json') >= 0) {
|
||||
return response.json().then(function (res) {
|
||||
throw new Error((res && (res.error || res.msg)) || '导出失败');
|
||||
}).catch(function (err) {
|
||||
throw err instanceof Error ? err : new Error('导出失败');
|
||||
});
|
||||
}
|
||||
return response.blob().then(function (blob) {
|
||||
return {
|
||||
blob: blob,
|
||||
filename: extractDownloadFilename(response.headers.get('content-disposition'), 'query-asin.xlsx')
|
||||
};
|
||||
});
|
||||
})
|
||||
.then(function (payload) {
|
||||
triggerBrowserDownload(payload.blob, payload.filename);
|
||||
})
|
||||
.catch(function (err) {
|
||||
alert((err && err.message) || '导出失败');
|
||||
});
|
||||
}
|
||||
function renderQueryAsinCell(item, country) {
|
||||
var asinValue = item[country.field] || '';
|
||||
var infoHtml = asinValue ? '<span>' + asinValue + '</span>' : '<span style="color:#999;">-</span>';
|
||||
@@ -2883,6 +2916,9 @@
|
||||
document.getElementById('btnSearchQueryAsin').onclick = function () {
|
||||
loadQueryAsin(1);
|
||||
};
|
||||
document.getElementById('btnExportQueryAsin').onclick = function () {
|
||||
exportQueryAsin();
|
||||
};
|
||||
document.getElementById('queryAsinFilterShopName').addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
@@ -2964,6 +3000,11 @@
|
||||
renderQueryAsinInputs();
|
||||
|
||||
var productCategoryItems = [];
|
||||
var productCategoryNodeMap = {};
|
||||
var productCategoryPageSize = 20;
|
||||
var productCategoryRootState = { children: [], page: 0, total: 0, hasMore: true, loaded: false, loading: false };
|
||||
var productCategorySearchState = { items: [], page: 0, total: 0, hasMore: false, loading: false };
|
||||
var productCategoryKeyword = '';
|
||||
var editingProductCategoryId = null;
|
||||
|
||||
function resetProductCategoryForm() {
|
||||
@@ -2983,27 +3024,102 @@
|
||||
var selected = selectedValue == null ? select.value : String(selectedValue || '');
|
||||
var excluded = excludedId == null ? editingProductCategoryId : excludedId;
|
||||
var options = ['<option value="">顶级类目</option>'];
|
||||
productCategoryItems.forEach(function (item) {
|
||||
productCategoryItems.slice().sort(function (a, b) {
|
||||
return String(a.path || a.name || '').localeCompare(String(b.path || b.name || ''), 'zh-CN');
|
||||
}).forEach(function (item) {
|
||||
if (excluded && String(item.id) === String(excluded)) return;
|
||||
var prefix = new Array((item.level || 0) + 1).join(' ');
|
||||
options.push('<option value="' + escapeHtml(item.id) + '">' + prefix + escapeHtml(item.name || '') + '</option>');
|
||||
});
|
||||
if (selected && !productCategoryItems.some(function (item) { return String(item.id) === selected; })) {
|
||||
options.push('<option value="' + escapeHtml(selected) + '">当前父级 #' + escapeHtml(selected) + '</option>');
|
||||
}
|
||||
select.innerHTML = options.join('');
|
||||
select.value = selected;
|
||||
}
|
||||
|
||||
function renderProductCategoryRows(items) {
|
||||
function normalizeProductCategoryItem(item, parent) {
|
||||
var id = String(item.id || '');
|
||||
var existing = productCategoryNodeMap[id] || {};
|
||||
var level = item.level != null ? item.level : (parent ? (parent.level || 0) + 1 : 0);
|
||||
var path = item.path || (parent && parent.path ? parent.path + ' / ' + (item.name || '') : (item.name || ''));
|
||||
var normalized = Object.assign(existing, item, {
|
||||
id: item.id,
|
||||
parent_id: item.parent_id == null ? null : item.parent_id,
|
||||
child_count: item.child_count || 0,
|
||||
level: level,
|
||||
path: path,
|
||||
children: existing.children || [],
|
||||
page: existing.page || 0,
|
||||
total: existing.total || 0,
|
||||
hasMore: existing.hasMore !== false,
|
||||
loaded: existing.loaded || false,
|
||||
loading: false,
|
||||
expanded: existing.expanded || false
|
||||
});
|
||||
productCategoryNodeMap[id] = normalized;
|
||||
productCategoryItems = Object.keys(productCategoryNodeMap).map(function (key) { return productCategoryNodeMap[key]; });
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function flattenVisibleProductCategories(items, output) {
|
||||
(items || []).forEach(function (item) {
|
||||
output.push({ type: 'item', item: item });
|
||||
if ((item.child_count || 0) > 0 && item.expanded) {
|
||||
flattenVisibleProductCategories(item.children || [], output);
|
||||
if (item.hasMore) {
|
||||
output.push({ type: 'more', parent: item });
|
||||
}
|
||||
}
|
||||
});
|
||||
return output;
|
||||
}
|
||||
|
||||
function renderProductCategoryRows() {
|
||||
var tbody = document.getElementById('productCategoryListBody');
|
||||
if (!tbody) return;
|
||||
if (!items.length) {
|
||||
var rows = productCategoryKeyword
|
||||
? productCategorySearchState.items.map(function (item) { return { type: 'item', item: item, search: true }; })
|
||||
: flattenVisibleProductCategories(productCategoryRootState.children, []);
|
||||
if (!productCategoryKeyword && productCategoryRootState.hasMore) {
|
||||
rows.push({ type: 'more', parent: null });
|
||||
}
|
||||
if (productCategoryKeyword && productCategorySearchState.hasMore) {
|
||||
rows.push({ type: 'searchMore' });
|
||||
}
|
||||
if (!rows.length) {
|
||||
tbody.innerHTML = '<tr><td colspan="6" class="empty-tip">暂无商品类目</td></tr>';
|
||||
return;
|
||||
}
|
||||
tbody.innerHTML = items.map(function (item) {
|
||||
tbody.innerHTML = rows.map(function (row) {
|
||||
if (row.type === 'more') {
|
||||
var parent = row.parent;
|
||||
var level = parent ? (parent.level || 0) + 1 : 0;
|
||||
var indentMore = Math.max(0, level) * 24;
|
||||
var loading = parent ? parent.loading : productCategoryRootState.loading;
|
||||
var loadedCount = parent ? (parent.children || []).length : (productCategoryRootState.children || []).length;
|
||||
var totalCount = parent ? (parent.total || 0) : (productCategoryRootState.total || 0);
|
||||
return '<tr><td colspan="6"><div class="tree-name-cell"><span class="tree-indent" style="--indent:' + indentMore + 'px;"></span>' +
|
||||
'<button class="btn btn-sm btn-secondary" type="button" data-product-category-load-more="' + escapeHtml(parent ? parent.id : '') + '"' + (loading ? ' disabled' : '') + '>' +
|
||||
(loading ? '加载中...' : '加载更多') + '</button>' +
|
||||
'<span class="empty-tip" style="padding:0;">已加载 ' + escapeHtml(loadedCount) + ' / ' + escapeHtml(totalCount) + '</span></div></td></tr>';
|
||||
}
|
||||
if (row.type === 'searchMore') {
|
||||
var searchLoadedCount = (productCategorySearchState.items || []).length;
|
||||
var searchTotalCount = productCategorySearchState.total || 0;
|
||||
return '<tr><td colspan="6"><button class="btn btn-sm btn-secondary" type="button" data-product-category-search-more' + (productCategorySearchState.loading ? ' disabled' : '') + '>' +
|
||||
(productCategorySearchState.loading ? '加载中...' : '加载更多搜索结果') + '</button> ' +
|
||||
'<span class="empty-tip" style="padding:0;">已加载 ' + escapeHtml(searchLoadedCount) + ' / ' + escapeHtml(searchTotalCount) + '</span></td></tr>';
|
||||
}
|
||||
var item = row.item;
|
||||
var indent = Math.max(0, item.level || 0) * 24;
|
||||
var mark = item.child_count > 0 ? '+' : '-';
|
||||
var hasChildren = (item.child_count || 0) > 0;
|
||||
var expanded = !!item.expanded;
|
||||
var mark = hasChildren ? (expanded ? '-' : '+') : '';
|
||||
return '<tr>' +
|
||||
'<td><div class="tree-name-cell"><span class="tree-indent" style="--indent:' + indent + 'px;"></span><span class="tree-node-mark">' + mark + '</span><strong>' + escapeHtml(item.name || '') + '</strong></div></td>' +
|
||||
'<td><div class="tree-name-cell"><span class="tree-indent" style="--indent:' + indent + 'px;"></span>' +
|
||||
'<button type="button" class="tree-node-mark' + (hasChildren ? '' : ' is-leaf') + '" data-product-category-toggle="' + escapeHtml(item.id) + '"' + (hasChildren ? '' : ' disabled') + '>' + mark + '</button>' +
|
||||
'<strong>' + escapeHtml(item.name || '') + '</strong></div></td>' +
|
||||
'<td><div>' + escapeHtml(item.path || item.name || '') + '</div><div class="category-path">' + escapeHtml(item.category_key || '') + '</div></td>' +
|
||||
'<td>' + escapeHtml(item.sort_order || 0) + '</td>' +
|
||||
'<td><span class="category-tag">' + (item.is_builtin ? '内置' : '自定义') + '</span></td>' +
|
||||
@@ -3012,6 +3128,24 @@
|
||||
'<button class="btn btn-sm btn-danger" data-product-category-delete="' + escapeHtml(item.id) + '" data-product-category-name="' + escapeHtml(item.name || '') + '"' + (item.child_count > 0 ? ' disabled' : '') + '>删除</button></td>' +
|
||||
'</tr>';
|
||||
}).join('');
|
||||
document.querySelectorAll('[data-product-category-toggle]').forEach(function (btn) {
|
||||
btn.onclick = function () {
|
||||
var id = String(btn.dataset.productCategoryToggle || '');
|
||||
if (!id || btn.disabled) return;
|
||||
toggleProductCategoryNode(id);
|
||||
};
|
||||
});
|
||||
document.querySelectorAll('[data-product-category-load-more]').forEach(function (btn) {
|
||||
btn.onclick = function () {
|
||||
var parentId = (btn.dataset.productCategoryLoadMore || '').trim();
|
||||
loadProductCategoryChildren(parentId || null, true);
|
||||
};
|
||||
});
|
||||
document.querySelectorAll('[data-product-category-search-more]').forEach(function (btn) {
|
||||
btn.onclick = function () {
|
||||
loadProductCategorySearch(true);
|
||||
};
|
||||
});
|
||||
document.querySelectorAll('[data-product-category-edit]').forEach(function (btn) {
|
||||
btn.onclick = function () {
|
||||
var item = productCategoryItems.find(function (row) { return String(row.id) === String(btn.dataset.productCategoryEdit); });
|
||||
@@ -3047,28 +3181,136 @@
|
||||
}
|
||||
|
||||
function loadProductCategories() {
|
||||
fetch('/api/admin/product-categories')
|
||||
if (productCategoryKeyword) {
|
||||
productCategorySearchState = { items: [], page: 0, total: 0, hasMore: false, loading: false };
|
||||
loadProductCategorySearch(false);
|
||||
return;
|
||||
}
|
||||
productCategoryRootState = { children: [], page: 0, total: 0, hasMore: true, loaded: false, loading: false };
|
||||
productCategoryNodeMap = {};
|
||||
productCategoryItems = [];
|
||||
renderProductCategoryParentOptions();
|
||||
loadProductCategoryChildren(null, false);
|
||||
}
|
||||
|
||||
function loadProductCategoryChildren(parentId, append) {
|
||||
var parent = parentId ? productCategoryNodeMap[String(parentId)] : null;
|
||||
var state = parent || productCategoryRootState;
|
||||
if (state.loading) return;
|
||||
state.loading = true;
|
||||
var failed = false;
|
||||
renderProductCategoryRows();
|
||||
var nextPage = append ? (state.page || 0) + 1 : 1;
|
||||
var query = '?page=' + nextPage + '&page_size=' + productCategoryPageSize;
|
||||
if (parentId) query += '&parent_id=' + encodeURIComponent(parentId);
|
||||
fetch('/api/admin/product-categories/children' + query)
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
var tbody = document.getElementById('productCategoryListBody');
|
||||
if (!res.success) {
|
||||
failed = true;
|
||||
if (tbody) tbody.innerHTML = '<tr><td colspan="6" class="empty-tip">加载失败: ' + escapeHtml(res.error || '') + '</td></tr>';
|
||||
return;
|
||||
}
|
||||
productCategoryItems = res.items || [];
|
||||
var children = (res.items || []).map(function (item) {
|
||||
return normalizeProductCategoryItem(item, parent);
|
||||
});
|
||||
if (!append) {
|
||||
state.children = [];
|
||||
}
|
||||
state.children = state.children.concat(children);
|
||||
state.page = res.page || nextPage;
|
||||
state.total = res.total || 0;
|
||||
state.hasMore = !!res.has_more;
|
||||
state.loaded = true;
|
||||
renderProductCategoryParentOptions();
|
||||
renderProductCategoryRows(productCategoryItems);
|
||||
renderProductCategoryRows();
|
||||
})
|
||||
.catch(function () {
|
||||
failed = true;
|
||||
var tbody = document.getElementById('productCategoryListBody');
|
||||
if (tbody) tbody.innerHTML = '<tr><td colspan="6" class="empty-tip">请求失败</td></tr>';
|
||||
})
|
||||
.finally(function () {
|
||||
state.loading = false;
|
||||
if (!failed) renderProductCategoryRows();
|
||||
});
|
||||
}
|
||||
|
||||
function loadProductCategorySearch(append) {
|
||||
if (productCategorySearchState.loading) return;
|
||||
productCategorySearchState.loading = true;
|
||||
var failed = false;
|
||||
renderProductCategoryRows();
|
||||
var nextPage = append ? (productCategorySearchState.page || 0) + 1 : 1;
|
||||
fetch('/api/admin/product-categories/search?keyword=' + encodeURIComponent(productCategoryKeyword) +
|
||||
'&page=' + nextPage + '&page_size=' + productCategoryPageSize)
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
var tbody = document.getElementById('productCategoryListBody');
|
||||
if (!res.success) {
|
||||
failed = true;
|
||||
if (tbody) tbody.innerHTML = '<tr><td colspan="6" class="empty-tip">加载失败: ' + escapeHtml(res.error || '') + '</td></tr>';
|
||||
return;
|
||||
}
|
||||
var items = (res.items || []).map(function (item) {
|
||||
var normalized = normalizeProductCategoryItem(item, null);
|
||||
normalized.expanded = false;
|
||||
return normalized;
|
||||
});
|
||||
productCategorySearchState.items = append
|
||||
? productCategorySearchState.items.concat(items)
|
||||
: items;
|
||||
productCategorySearchState.page = res.page || nextPage;
|
||||
productCategorySearchState.total = res.total || 0;
|
||||
productCategorySearchState.hasMore = !!res.has_more;
|
||||
renderProductCategoryParentOptions();
|
||||
renderProductCategoryRows();
|
||||
})
|
||||
.catch(function () {
|
||||
failed = true;
|
||||
var tbody = document.getElementById('productCategoryListBody');
|
||||
if (tbody) tbody.innerHTML = '<tr><td colspan="6" class="empty-tip">请求失败</td></tr>';
|
||||
})
|
||||
.finally(function () {
|
||||
productCategorySearchState.loading = false;
|
||||
if (!failed) renderProductCategoryRows();
|
||||
});
|
||||
}
|
||||
|
||||
function toggleProductCategoryNode(id) {
|
||||
var item = productCategoryNodeMap[String(id)];
|
||||
if (!item) return;
|
||||
item.expanded = !item.expanded;
|
||||
if (item.expanded && !item.loaded) {
|
||||
loadProductCategoryChildren(id, false);
|
||||
return;
|
||||
}
|
||||
renderProductCategoryRows();
|
||||
}
|
||||
|
||||
document.getElementById('btnCancelProductCategoryEdit').onclick = function () {
|
||||
resetProductCategoryForm();
|
||||
};
|
||||
|
||||
document.getElementById('btnSearchProductCategory').onclick = function () {
|
||||
productCategoryKeyword = (document.getElementById('productCategoryKeyword').value || '').trim();
|
||||
loadProductCategories();
|
||||
};
|
||||
|
||||
document.getElementById('btnClearProductCategorySearch').onclick = function () {
|
||||
productCategoryKeyword = '';
|
||||
document.getElementById('productCategoryKeyword').value = '';
|
||||
loadProductCategories();
|
||||
};
|
||||
|
||||
document.getElementById('productCategoryKeyword').onkeydown = function (event) {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
document.getElementById('btnSearchProductCategory').click();
|
||||
}
|
||||
};
|
||||
|
||||
document.getElementById('btnCreateProductCategory').onclick = function () {
|
||||
var msgEl = document.getElementById('msgProductCategory');
|
||||
var name = (document.getElementById('productCategoryName').value || '').trim();
|
||||
|
||||
Reference in New Issue
Block a user