完成查询asin开发
This commit is contained in:
@@ -413,6 +413,7 @@
|
||||
<div class="tab" data-tab="shop-keys">店铺密钥管理</div>
|
||||
<div class="tab" data-tab="shop-manage">店铺管理</div>
|
||||
<div class="tab" data-tab="skip-price-asin">跳过跟价 ASIN</div>
|
||||
<div class="tab" data-tab="query-asin">查询 ASIN</div>
|
||||
<div class="tab" data-tab="history">查看生成记录</div>
|
||||
<div class="tab" data-tab="version">版本管理</div>
|
||||
</div>
|
||||
@@ -817,6 +818,120 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="panel-query-asin" class="tab-panel">
|
||||
<div class="form-box">
|
||||
<h3 style="margin-bottom:16px;font-size:15px;">新增查询 ASIN</h3>
|
||||
<div class="form-row">
|
||||
<div class="form-group" style="min-width:220px;">
|
||||
<label>分组</label>
|
||||
<div style="display:flex;gap:8px;align-items:center;">
|
||||
<select id="queryAsinGroupSelect" style="min-width:150px;">
|
||||
<option value="">请选择分组</option>
|
||||
</select>
|
||||
<button class="btn btn-secondary" id="btnManageQueryAsinGroups" type="button">管理分组</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" style="min-width:340px;">
|
||||
<label>店铺名</label>
|
||||
<div style="display:flex;gap:8px;align-items:center;">
|
||||
<input type="text" id="queryAsinShopName" placeholder="请输入店铺名称" style="flex:1;min-width:180px;">
|
||||
<button class="btn btn-secondary" id="btnChooseQueryAsinShop" type="button">选择店铺</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" style="min-width:220px;">
|
||||
<label>国家</label>
|
||||
<select id="queryAsinCountries" multiple size="5" style="min-height:98px;">
|
||||
<option value="DE">德国</option>
|
||||
<option value="UK">英国</option>
|
||||
<option value="FR">法国</option>
|
||||
<option value="IT">意大利</option>
|
||||
<option value="ES">西班牙</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="min-width:320px;flex:1;">
|
||||
<label>ASIN</label>
|
||||
<div id="queryAsinInputs" style="display:flex;flex-direction:column;gap:8px;">
|
||||
<div style="color:#999;font-size:13px;">请选择国家后输入对应 ASIN</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn" id="btnCreateQueryAsin" style="align-self:flex-end;margin-bottom:40px;">新增 ASIN</button>
|
||||
</div>
|
||||
<p class="msg" id="msgQueryAsin"></p>
|
||||
<div class="form-row" style="align-items:flex-start;gap:16px;margin-top:18px;border-top:1px solid #f0f0f0;padding-top:16px;">
|
||||
<div style="flex:1;min-width:320px;">
|
||||
<h3 style="margin-bottom:12px;font-size:14px;">导入添加</h3>
|
||||
<div class="form-row">
|
||||
<div class="form-group" style="min-width:320px;">
|
||||
<label>上传 Excel(列:分组、店铺名、德国/英国/法国/意大利/西班牙)</label>
|
||||
<input type="file" id="queryAsinImportFile" accept=".xlsx,.xls">
|
||||
</div>
|
||||
<button class="btn" id="btnImportQueryAsin" type="button">上传并添加</button>
|
||||
</div>
|
||||
<p class="msg" id="msgQueryAsinImport"></p>
|
||||
<div class="progress-wrap" id="queryAsinImportProgressWrap" style="display:none;">
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" id="queryAsinImportProgressFill"></div>
|
||||
</div>
|
||||
<div class="progress-text" id="queryAsinImportProgressText"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="flex:1;min-width:320px;">
|
||||
<h3 style="margin-bottom:12px;font-size:14px;">导入删除</h3>
|
||||
<div class="form-row">
|
||||
<div class="form-group" style="min-width:320px;">
|
||||
<label>上传 Excel(匹配分组 + 店铺名 + 国家 ASIN 后删除)</label>
|
||||
<input type="file" id="queryAsinDeleteImportFile" accept=".xlsx,.xls">
|
||||
</div>
|
||||
<button class="btn btn-danger" id="btnDeleteImportQueryAsin" type="button">上传并删除</button>
|
||||
</div>
|
||||
<p class="msg" id="msgQueryAsinDeleteImport"></p>
|
||||
<div class="progress-wrap" id="queryAsinDeleteImportProgressWrap" style="display:none;">
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" id="queryAsinDeleteImportProgressFill"></div>
|
||||
</div>
|
||||
<div class="progress-text" id="queryAsinDeleteImportProgressText"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-box">
|
||||
<h3 style="margin-bottom:16px;font-size:15px;">店铺列表</h3>
|
||||
<div class="form-row" style="margin-bottom:12px;">
|
||||
<div class="form-group" style="min-width:180px;">
|
||||
<label>分组</label>
|
||||
<select id="queryAsinFilterGroupId">
|
||||
<option value="">全部分组</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="min-width:220px;">
|
||||
<label>店铺名</label>
|
||||
<input type="text" id="queryAsinFilterShopName" placeholder="请输入店铺名">
|
||||
</div>
|
||||
<div class="form-group" style="min-width:220px;">
|
||||
<label>ASIN</label>
|
||||
<input type="text" id="queryAsinFilterAsin" placeholder="请输入 ASIN">
|
||||
</div>
|
||||
<button class="btn" id="btnSearchQueryAsin">查询</button>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>序号</th>
|
||||
<th>分组</th>
|
||||
<th>店铺名</th>
|
||||
<th>德国</th>
|
||||
<th>英国</th>
|
||||
<th>法国</th>
|
||||
<th>意大利</th>
|
||||
<th>西班牙</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="queryAsinListBody"></tbody>
|
||||
</table>
|
||||
<div class="pagination" id="queryAsinPagination"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="panel-history" class="tab-panel">
|
||||
<div class="form-box">
|
||||
<h3 style="margin-bottom:16px;font-size:15px;">筛选条件</h3>
|
||||
@@ -1063,6 +1178,69 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-mask" id="chooseQueryAsinShopModal">
|
||||
<div class="modal" style="max-width:900px;width:90%;max-height:80vh;display:flex;flex-direction:column;">
|
||||
<h3>选择店铺</h3>
|
||||
<div class="form-row">
|
||||
<div class="form-group" style="min-width:180px;">
|
||||
<label>分组</label>
|
||||
<select id="chooseQueryAsinShopGroupId">
|
||||
<option value="">全部分组</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="min-width:220px;">
|
||||
<label>店铺名</label>
|
||||
<input type="text" id="chooseQueryAsinShopKeyword" placeholder="请输入店铺名">
|
||||
</div>
|
||||
<button class="btn" id="btnSearchChooseQueryAsinShop" type="button">查询</button>
|
||||
</div>
|
||||
<div style="flex:1;min-height:0;overflow:auto;">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>序号</th>
|
||||
<th>分组</th>
|
||||
<th>店铺名</th>
|
||||
<th>店铺商城名</th>
|
||||
<th>账号</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="chooseQueryAsinShopListBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination" id="chooseQueryAsinShopPagination"></div>
|
||||
<div style="margin-top:16px;display:flex;gap:8px;justify-content:flex-end;">
|
||||
<button class="btn btn-secondary" id="btnCloseChooseQueryAsinShopModal" type="button">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-mask" id="editQueryAsinModal">
|
||||
<div class="modal">
|
||||
<h3>编辑查询 ASIN</h3>
|
||||
<input type="hidden" id="editQueryAsinId">
|
||||
<input type="hidden" id="editQueryAsinCountry">
|
||||
<div class="form-group">
|
||||
<label>店铺名</label>
|
||||
<input type="text" id="editQueryAsinShopName" readonly style="background:#f5f5f5;">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>国家</label>
|
||||
<input type="text" id="editQueryAsinCountryLabel" readonly style="background:#f5f5f5;">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>ASIN</label>
|
||||
<input type="text" id="editQueryAsinValue" placeholder="请输入 ASIN">
|
||||
</div>
|
||||
<p class="msg" id="msgEditQueryAsin"></p>
|
||||
<div style="margin-top:16px;display:flex;gap:8px;">
|
||||
<button class="btn" id="btnSaveQueryAsin">保存</button>
|
||||
<button class="btn btn-secondary" id="btnCloseEditQueryAsin">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-mask" id="editShopManageModal">
|
||||
<div class="modal">
|
||||
<h3>编辑店铺</h3>
|
||||
@@ -1134,6 +1312,7 @@
|
||||
'shop-keys': 'panel-shop-keys',
|
||||
'shop-manage': 'panel-shop-manage',
|
||||
'skip-price-asin': 'panel-skip-price-asin',
|
||||
'query-asin': 'panel-query-asin',
|
||||
'history': 'panel-history',
|
||||
'version': 'panel-version'
|
||||
};
|
||||
@@ -1144,6 +1323,7 @@
|
||||
else if (tabName === 'shop-keys') loadShopKeys(1);
|
||||
else if (tabName === 'shop-manage') loadShopManage(1);
|
||||
else if (tabName === 'skip-price-asin') loadSkipPriceAsin(1);
|
||||
else if (tabName === 'query-asin') loadQueryAsin(1);
|
||||
else if (tabName === 'history') loadHistory(1);
|
||||
else if (tabName === 'version') loadVersions();
|
||||
}
|
||||
@@ -2304,10 +2484,16 @@
|
||||
var skipCreateSel = document.getElementById('skipPriceAsinGroupSelect');
|
||||
var skipFilterSel = document.getElementById('skipPriceAsinFilterGroupId');
|
||||
var chooseSkipShopSel = document.getElementById('chooseSkipPriceAsinShopGroupId');
|
||||
var queryCreateSel = document.getElementById('queryAsinGroupSelect');
|
||||
var queryFilterSel = document.getElementById('queryAsinFilterGroupId');
|
||||
var chooseQueryShopSel = document.getElementById('chooseQueryAsinShopGroupId');
|
||||
var selectedFilterId = filterSel ? filterSel.value : '';
|
||||
var selectedSkipCreateId = skipCreateSel ? skipCreateSel.value : '';
|
||||
var selectedSkipFilterId = skipFilterSel ? skipFilterSel.value : '';
|
||||
var selectedChooseSkipShopId = chooseSkipShopSel ? chooseSkipShopSel.value : '';
|
||||
var selectedQueryCreateId = queryCreateSel ? queryCreateSel.value : '';
|
||||
var selectedQueryFilterId = queryFilterSel ? queryFilterSel.value : '';
|
||||
var selectedChooseQueryShopId = chooseQueryShopSel ? chooseQueryShopSel.value : '';
|
||||
var createOpts = ['<option value="">请选择分组</option>'];
|
||||
var filterOpts = ['<option value="">全部分组</option>'];
|
||||
shopManageGroups.forEach(function (g) {
|
||||
@@ -2318,15 +2504,21 @@
|
||||
createSel.innerHTML = createOpts.join('');
|
||||
editSel.innerHTML = createOpts.join('');
|
||||
if (skipCreateSel) skipCreateSel.innerHTML = createOpts.join('');
|
||||
if (queryCreateSel) queryCreateSel.innerHTML = createOpts.join('');
|
||||
if (filterSel) filterSel.innerHTML = filterOpts.join('');
|
||||
if (skipFilterSel) skipFilterSel.innerHTML = filterOpts.join('');
|
||||
if (chooseSkipShopSel) chooseSkipShopSel.innerHTML = filterOpts.join('');
|
||||
if (queryFilterSel) queryFilterSel.innerHTML = filterOpts.join('');
|
||||
if (chooseQueryShopSel) chooseQueryShopSel.innerHTML = filterOpts.join('');
|
||||
if (selectedCreateId != null) createSel.value = String(selectedCreateId);
|
||||
if (selectedEditId != null) editSel.value = String(selectedEditId);
|
||||
if (filterSel && selectedFilterId) filterSel.value = selectedFilterId;
|
||||
if (skipCreateSel && selectedSkipCreateId) skipCreateSel.value = selectedSkipCreateId;
|
||||
if (skipFilterSel && selectedSkipFilterId) skipFilterSel.value = selectedSkipFilterId;
|
||||
if (chooseSkipShopSel && selectedChooseSkipShopId) chooseSkipShopSel.value = selectedChooseSkipShopId;
|
||||
if (queryCreateSel && selectedQueryCreateId) queryCreateSel.value = selectedQueryCreateId;
|
||||
if (queryFilterSel && selectedQueryFilterId) queryFilterSel.value = selectedQueryFilterId;
|
||||
if (chooseQueryShopSel && selectedChooseQueryShopId) chooseQueryShopSel.value = selectedChooseQueryShopId;
|
||||
}
|
||||
|
||||
function loadShopManageGroups(selectedCreateId, selectedEditId) {
|
||||
@@ -2361,7 +2553,7 @@
|
||||
|
||||
function updateShopManageGroupButtonsAccess() {
|
||||
var canManageGroups = !!currentUserId;
|
||||
['btnManageShopGroups', 'btnManageShopGroupsFromEdit', 'btnManageSkipPriceAsinGroups'].forEach(function (id) {
|
||||
['btnManageShopGroups', 'btnManageShopGroupsFromEdit', 'btnManageSkipPriceAsinGroups', 'btnManageQueryAsinGroups'].forEach(function (id) {
|
||||
var btn = document.getElementById(id);
|
||||
if (btn) btn.style.display = canManageGroups ? '' : 'none';
|
||||
});
|
||||
@@ -2447,6 +2639,10 @@
|
||||
setShopManageGroupGrantRoutes(['skip-price-asin']);
|
||||
openShopManageGroupModal();
|
||||
};
|
||||
document.getElementById('btnManageQueryAsinGroups').onclick = function () {
|
||||
setShopManageGroupGrantRoutes(['query-asin']);
|
||||
openShopManageGroupModal();
|
||||
};
|
||||
document.getElementById('btnSearchShopManage').onclick = function () {
|
||||
loadShopManage(1);
|
||||
};
|
||||
@@ -2990,6 +3186,515 @@
|
||||
};
|
||||
setupSkipPriceAsinShopPicker();
|
||||
renderSkipPriceAsinInputs();
|
||||
|
||||
// ========== 查询 ASIN ==========
|
||||
var queryAsinPage = 1, queryAsinPageSize = 15;
|
||||
var chooseQueryAsinShopPage = 1, chooseQueryAsinShopPageSize = 10;
|
||||
var queryAsinCountryColumns = [
|
||||
{ code: 'DE', field: 'asin_de', label: '德国' },
|
||||
{ code: 'UK', field: 'asin_uk', label: '英国' },
|
||||
{ code: 'FR', field: 'asin_fr', label: '法国' },
|
||||
{ code: 'IT', field: 'asin_it', label: '意大利' },
|
||||
{ code: 'ES', field: 'asin_es', label: '西班牙' }
|
||||
];
|
||||
function getQueryAsinCountryLabel(countryCode) {
|
||||
var country = queryAsinCountryColumns.find(function (item) { return item.code === countryCode; });
|
||||
return country ? country.label : countryCode;
|
||||
}
|
||||
function getSelectedQueryAsinCountries() {
|
||||
return Array.from(document.getElementById('queryAsinCountries').selectedOptions).map(function (option) {
|
||||
return option.value;
|
||||
});
|
||||
}
|
||||
function renderQueryAsinInputs() {
|
||||
var container = document.getElementById('queryAsinInputs');
|
||||
var selectedCountries = getSelectedQueryAsinCountries();
|
||||
var existingValues = {};
|
||||
container.querySelectorAll('[data-query-asin-country-input]').forEach(function (input) {
|
||||
existingValues[input.getAttribute('data-query-asin-country-input')] = input.value;
|
||||
});
|
||||
if (!selectedCountries.length) {
|
||||
container.innerHTML = '<div style="color:#999;font-size:13px;">请选择国家后输入 ASIN</div>';
|
||||
return;
|
||||
}
|
||||
container.innerHTML = selectedCountries.map(function (countryCode) {
|
||||
var label = getQueryAsinCountryLabel(countryCode);
|
||||
var value = existingValues[countryCode] || '';
|
||||
return '<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">' +
|
||||
'<span style="min-width:56px;color:#555;">' + label + '</span>' +
|
||||
'<input type="text" data-query-asin-country-input="' + countryCode + '" value="' + value.replace(/"/g, '"') + '" placeholder="请输入' + label + ' ASIN" style="flex:1;min-width:180px;">' +
|
||||
'</div>';
|
||||
}).join('');
|
||||
}
|
||||
function collectQueryAsinMappings(countries) {
|
||||
var asinMappings = {};
|
||||
for (var i = 0; i < countries.length; i++) {
|
||||
var countryCode = countries[i];
|
||||
var input = document.querySelector('[data-query-asin-country-input="' + countryCode + '"]');
|
||||
var asin = input ? (input.value || '').trim().toUpperCase() : '';
|
||||
if (!asin) {
|
||||
throw new Error(getQueryAsinCountryLabel(countryCode) + ' ASIN 不能为空');
|
||||
}
|
||||
asinMappings[countryCode] = asin;
|
||||
}
|
||||
return asinMappings;
|
||||
}
|
||||
function buildChooseQueryAsinShopQuery(page) {
|
||||
var query = 'page=' + (page || 1) + '&page_size=' + chooseQueryAsinShopPageSize;
|
||||
var groupId = (document.getElementById('chooseQueryAsinShopGroupId').value || '').trim();
|
||||
var shopName = (document.getElementById('chooseQueryAsinShopKeyword').value || '').trim();
|
||||
if (groupId) query += '&group_id=' + encodeURIComponent(groupId);
|
||||
if (shopName) query += '&shop_name=' + encodeURIComponent(shopName);
|
||||
return query;
|
||||
}
|
||||
function loadChooseQueryAsinShops(page) {
|
||||
chooseQueryAsinShopPage = page || 1;
|
||||
fetch('/api/admin/shop-manages?' + buildChooseQueryAsinShopQuery(chooseQueryAsinShopPage))
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
var tbody = document.getElementById('chooseQueryAsinShopListBody');
|
||||
if (!res.success) {
|
||||
tbody.innerHTML = '<tr><td colspan="6" class="empty-tip">加载失败: ' + (res.error || '') + '</td></tr>';
|
||||
return;
|
||||
}
|
||||
var items = res.items || [];
|
||||
if (items.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="6" class="empty-tip">暂无店铺</td></tr>';
|
||||
} else {
|
||||
tbody.innerHTML = items.map(function (item, index) {
|
||||
var rowNo = (chooseQueryAsinShopPage - 1) * chooseQueryAsinShopPageSize + index + 1;
|
||||
return '<tr><td>' + rowNo + '</td><td>' + (item.group_name || '') + '</td><td>' + (item.shop_name || '') + '</td><td>' + (item.mall_name || '') + '</td><td>' + (item.username || '') + '</td><td>' +
|
||||
'<button class="btn btn-sm" type="button" data-choose-query-asin-shop="' + item.id + '" data-shop-name="' + (item.shop_name || '').replace(/"/g, '"') + '" data-group-id="' + (item.group_id || '') + '">选择</button>' +
|
||||
'</td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
renderPagination('chooseQueryAsinShopPagination', res.total, res.page, res.page_size, loadChooseQueryAsinShops);
|
||||
bindChooseQueryAsinShopActions();
|
||||
})
|
||||
.catch(function () {
|
||||
document.getElementById('chooseQueryAsinShopListBody').innerHTML = '<tr><td colspan="6" class="empty-tip">请求失败</td></tr>';
|
||||
});
|
||||
}
|
||||
function bindChooseQueryAsinShopActions() {
|
||||
document.querySelectorAll('[data-choose-query-asin-shop]').forEach(function (btn) {
|
||||
btn.onclick = function () {
|
||||
document.getElementById('queryAsinShopName').value = (btn.dataset.shopName || '').replace(/"/g, '"');
|
||||
if (btn.dataset.groupId) {
|
||||
document.getElementById('queryAsinGroupSelect').value = btn.dataset.groupId;
|
||||
}
|
||||
document.getElementById('chooseQueryAsinShopModal').classList.remove('show');
|
||||
};
|
||||
});
|
||||
}
|
||||
function openChooseQueryAsinShopModal() {
|
||||
var currentGroupId = (document.getElementById('queryAsinGroupSelect').value || '').trim();
|
||||
if (currentGroupId) {
|
||||
document.getElementById('chooseQueryAsinShopGroupId').value = currentGroupId;
|
||||
}
|
||||
document.getElementById('chooseQueryAsinShopKeyword').value = (document.getElementById('queryAsinShopName').value || '').trim();
|
||||
document.getElementById('chooseQueryAsinShopModal').classList.add('show');
|
||||
loadChooseQueryAsinShops(1);
|
||||
}
|
||||
function buildQueryAsinQuery(page) {
|
||||
var query = 'page=' + (page || 1) + '&page_size=' + queryAsinPageSize;
|
||||
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);
|
||||
return query;
|
||||
}
|
||||
function renderQueryAsinCell(item, country) {
|
||||
var asinValue = item[country.field] || '';
|
||||
var infoHtml = asinValue ? '<span>' + asinValue + '</span>' : '<span style="color:#999;">-</span>';
|
||||
var deleteHtml = asinValue
|
||||
? ('<button class="btn btn-sm btn-danger" data-query-asin-delete="' + item.id + '" data-country="' + country.code + '" data-shop-name="' + (item.shop_name || '').replace(/"/g, '"') + '">删除</button>')
|
||||
: '';
|
||||
return '<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">' +
|
||||
infoHtml +
|
||||
'<button class="btn btn-sm" data-query-asin-edit="' + item.id + '" data-country="' + country.code + '" data-asin="' + asinValue.replace(/"/g, '"') + '" data-shop-name="' + (item.shop_name || '').replace(/"/g, '"') + '">编辑</button>' +
|
||||
deleteHtml +
|
||||
'</div>';
|
||||
}
|
||||
function openEditQueryAsinModal(itemId, countryCode, shopName, asinValue) {
|
||||
document.getElementById('editQueryAsinId').value = itemId || '';
|
||||
document.getElementById('editQueryAsinCountry').value = countryCode || '';
|
||||
document.getElementById('editQueryAsinShopName').value = shopName || '';
|
||||
document.getElementById('editQueryAsinCountryLabel').value = getQueryAsinCountryLabel(countryCode || '');
|
||||
document.getElementById('editQueryAsinValue').value = asinValue || '';
|
||||
document.getElementById('msgEditQueryAsin').textContent = '';
|
||||
document.getElementById('msgEditQueryAsin').className = 'msg';
|
||||
document.getElementById('editQueryAsinModal').classList.add('show');
|
||||
}
|
||||
function bindQueryAsinActions() {
|
||||
document.querySelectorAll('[data-query-asin-edit]').forEach(function (btn) {
|
||||
btn.onclick = function () {
|
||||
openEditQueryAsinModal(
|
||||
btn.dataset.queryAsinEdit,
|
||||
btn.dataset.country || '',
|
||||
(btn.dataset.shopName || '').replace(/"/g, '"'),
|
||||
(btn.dataset.asin || '').replace(/"/g, '"')
|
||||
);
|
||||
};
|
||||
});
|
||||
document.querySelectorAll('[data-query-asin-delete]').forEach(function (btn) {
|
||||
btn.onclick = function () {
|
||||
var shopName = (btn.dataset.shopName || '').replace(/"/g, '"');
|
||||
var countryCode = btn.dataset.country || '';
|
||||
if (!confirm('确定删除店铺“' + shopName + '”在 ' + countryCode + ' 的 ASIN 吗?')) return;
|
||||
fetch('/api/admin/query-asin/' + btn.dataset.queryAsinDelete + '/country/' + countryCode, {
|
||||
method: 'DELETE'
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
if (res.success) loadQueryAsin(queryAsinPage);
|
||||
else alert(res.error || '删除失败');
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
function loadQueryAsin(page) {
|
||||
queryAsinPage = page || 1;
|
||||
fetch('/api/admin/query-asins?' + buildQueryAsinQuery(queryAsinPage))
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
var tbody = document.getElementById('queryAsinListBody');
|
||||
if (!res.success) {
|
||||
tbody.innerHTML = '<tr><td colspan="8" class="empty-tip">加载失败: ' + (res.error || '') + '</td></tr>';
|
||||
return;
|
||||
}
|
||||
var items = res.items || [];
|
||||
if (items.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="8" class="empty-tip">暂无数据</td></tr>';
|
||||
} else {
|
||||
tbody.innerHTML = items.map(function (item, index) {
|
||||
var rowNo = (queryAsinPage - 1) * queryAsinPageSize + index + 1;
|
||||
return '<tr><td>' + rowNo + '</td><td>' + (item.group_name || '') + '</td><td>' + (item.shop_name || '') + '</td>' +
|
||||
queryAsinCountryColumns.map(function (country) {
|
||||
return '<td>' + renderQueryAsinCell(item, country) + '</td>';
|
||||
}).join('') +
|
||||
'</tr>';
|
||||
}).join('');
|
||||
}
|
||||
renderPagination('queryAsinPagination', res.total, res.page, res.page_size, loadQueryAsin);
|
||||
bindQueryAsinActions();
|
||||
})
|
||||
.catch(function () {
|
||||
document.getElementById('queryAsinListBody').innerHTML = '<tr><td colspan="8" class="empty-tip">请求失败</td></tr>';
|
||||
});
|
||||
}
|
||||
var queryAsinImportPollTimer = null;
|
||||
var queryAsinDeleteImportPollTimer = null;
|
||||
function stopQueryAsinImportProgress() {
|
||||
if (queryAsinImportPollTimer) {
|
||||
clearInterval(queryAsinImportPollTimer);
|
||||
queryAsinImportPollTimer = null;
|
||||
}
|
||||
}
|
||||
function stopQueryAsinDeleteImportProgress() {
|
||||
if (queryAsinDeleteImportPollTimer) {
|
||||
clearInterval(queryAsinDeleteImportPollTimer);
|
||||
queryAsinDeleteImportPollTimer = null;
|
||||
}
|
||||
}
|
||||
function setQueryAsinImportProgress(percent, text) {
|
||||
var wrap = document.getElementById('queryAsinImportProgressWrap');
|
||||
var fill = document.getElementById('queryAsinImportProgressFill');
|
||||
var textEl = document.getElementById('queryAsinImportProgressText');
|
||||
wrap.style.display = 'block';
|
||||
fill.style.width = Math.max(0, Math.min(100, percent || 0)) + '%';
|
||||
textEl.textContent = text || '';
|
||||
}
|
||||
function setQueryAsinDeleteImportProgress(percent, text) {
|
||||
var wrap = document.getElementById('queryAsinDeleteImportProgressWrap');
|
||||
var fill = document.getElementById('queryAsinDeleteImportProgressFill');
|
||||
var textEl = document.getElementById('queryAsinDeleteImportProgressText');
|
||||
wrap.style.display = 'block';
|
||||
fill.style.width = Math.max(0, Math.min(100, percent || 0)) + '%';
|
||||
textEl.textContent = text || '';
|
||||
}
|
||||
function pollQueryAsinImport(importId) {
|
||||
stopQueryAsinImportProgress();
|
||||
function tick() {
|
||||
fetch('/api/admin/query-asins/import/' + encodeURIComponent(importId))
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
if (!res.success) {
|
||||
stopQueryAsinImportProgress();
|
||||
document.getElementById('msgQueryAsinImport').textContent = res.error || '查询导入进度失败';
|
||||
document.getElementById('msgQueryAsinImport').className = 'msg err';
|
||||
return;
|
||||
}
|
||||
var progress = res.progress || {};
|
||||
var totalRows = progress.total_rows || 0;
|
||||
var processedRows = progress.processed_rows || 0;
|
||||
var percent = totalRows > 0 ? Math.round(processedRows * 100 / totalRows) : 0;
|
||||
setQueryAsinImportProgress(percent, '处理中:已处理 ' + processedRows + ' / ' + totalRows + ',添加 ' + (progress.inserted_count || 0) + ',跳过 ' + (progress.skipped_count || 0));
|
||||
if (progress.status === 'success') {
|
||||
stopQueryAsinImportProgress();
|
||||
document.getElementById('msgQueryAsinImport').textContent = '导入成功:总行数 ' + totalRows + ',ASIN 数量 ' + (progress.asin_count || 0) + ',添加 ' + (progress.inserted_count || 0) + ',跳过 ' + (progress.skipped_count || 0);
|
||||
document.getElementById('msgQueryAsinImport').className = 'msg ok';
|
||||
loadQueryAsin(1);
|
||||
} else if (progress.status === 'failed') {
|
||||
stopQueryAsinImportProgress();
|
||||
document.getElementById('msgQueryAsinImport').textContent = progress.error_message || '导入失败';
|
||||
document.getElementById('msgQueryAsinImport').className = 'msg err';
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
stopQueryAsinImportProgress();
|
||||
document.getElementById('msgQueryAsinImport').textContent = '查询导入进度失败';
|
||||
document.getElementById('msgQueryAsinImport').className = 'msg err';
|
||||
});
|
||||
}
|
||||
tick();
|
||||
queryAsinImportPollTimer = setInterval(tick, 1000);
|
||||
}
|
||||
function pollQueryAsinDeleteImport(importId) {
|
||||
stopQueryAsinDeleteImportProgress();
|
||||
function tick() {
|
||||
fetch('/api/admin/query-asins/delete-import/' + encodeURIComponent(importId))
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
if (!res.success) {
|
||||
stopQueryAsinDeleteImportProgress();
|
||||
document.getElementById('msgQueryAsinDeleteImport').textContent = res.error || '查询删除进度失败';
|
||||
document.getElementById('msgQueryAsinDeleteImport').className = 'msg err';
|
||||
return;
|
||||
}
|
||||
var progress = res.progress || {};
|
||||
var totalRows = progress.total_rows || 0;
|
||||
var processedRows = progress.processed_rows || 0;
|
||||
var percent = totalRows > 0 ? Math.round(processedRows * 100 / totalRows) : 0;
|
||||
setQueryAsinDeleteImportProgress(percent, '处理中:已处理 ' + processedRows + ' / ' + totalRows + ',删除 ' + (progress.deleted_count || 0) + ',跳过 ' + (progress.skipped_count || 0));
|
||||
if (progress.status === 'success') {
|
||||
stopQueryAsinDeleteImportProgress();
|
||||
document.getElementById('msgQueryAsinDeleteImport').textContent = '删除成功:总行数 ' + totalRows + ',ASIN 数量 ' + (progress.asin_count || 0) + ',删除 ' + (progress.deleted_count || 0) + ',跳过 ' + (progress.skipped_count || 0);
|
||||
document.getElementById('msgQueryAsinDeleteImport').className = 'msg ok';
|
||||
loadQueryAsin(1);
|
||||
} else if (progress.status === 'failed') {
|
||||
stopQueryAsinDeleteImportProgress();
|
||||
document.getElementById('msgQueryAsinDeleteImport').textContent = progress.error_message || '删除失败';
|
||||
document.getElementById('msgQueryAsinDeleteImport').className = 'msg err';
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
stopQueryAsinDeleteImportProgress();
|
||||
document.getElementById('msgQueryAsinDeleteImport').textContent = '查询删除进度失败';
|
||||
document.getElementById('msgQueryAsinDeleteImport').className = 'msg err';
|
||||
});
|
||||
}
|
||||
tick();
|
||||
queryAsinDeleteImportPollTimer = setInterval(tick, 1000);
|
||||
}
|
||||
function uploadQueryAsinImport(deleteMode) {
|
||||
var fileInput = document.getElementById(deleteMode ? 'queryAsinDeleteImportFile' : 'queryAsinImportFile');
|
||||
var msgEl = document.getElementById(deleteMode ? 'msgQueryAsinDeleteImport' : 'msgQueryAsinImport');
|
||||
msgEl.textContent = '';
|
||||
msgEl.className = 'msg';
|
||||
if (deleteMode) {
|
||||
stopQueryAsinDeleteImportProgress();
|
||||
document.getElementById('queryAsinDeleteImportProgressWrap').style.display = 'none';
|
||||
} else {
|
||||
stopQueryAsinImportProgress();
|
||||
document.getElementById('queryAsinImportProgressWrap').style.display = 'none';
|
||||
}
|
||||
if (!fileInput.files || fileInput.files.length === 0) {
|
||||
msgEl.textContent = '请选择 Excel 文件';
|
||||
msgEl.className = 'msg err';
|
||||
return;
|
||||
}
|
||||
var file = fileInput.files[0];
|
||||
var lowerName = (file.name || '').toLowerCase();
|
||||
if (!(lowerName.endsWith('.xlsx') || lowerName.endsWith('.xls'))) {
|
||||
msgEl.textContent = '仅支持 .xlsx 或 .xls 文件';
|
||||
msgEl.className = 'msg err';
|
||||
return;
|
||||
}
|
||||
if (deleteMode && !confirm('确定按 Excel 中的分组、店铺名和国家 ASIN 批量删除吗?')) {
|
||||
return;
|
||||
}
|
||||
var formData = new FormData();
|
||||
formData.append('file', file);
|
||||
var groupId = (document.getElementById('queryAsinGroupSelect').value || '').trim();
|
||||
if (groupId) formData.append('group_id', groupId);
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', deleteMode ? '/api/admin/query-asins/delete-import' : '/api/admin/query-asins/import', true);
|
||||
xhr.upload.onprogress = function (event) {
|
||||
if (event.lengthComputable) {
|
||||
var percent = Math.round(event.loaded * 100 / event.total);
|
||||
if (deleteMode) setQueryAsinDeleteImportProgress(percent, '上传中:' + percent + '%');
|
||||
else setQueryAsinImportProgress(percent, '上传中:' + percent + '%');
|
||||
}
|
||||
};
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState !== 4) return;
|
||||
if (xhr.status < 200 || xhr.status >= 300) {
|
||||
msgEl.textContent = '请求失败';
|
||||
msgEl.className = 'msg err';
|
||||
return;
|
||||
}
|
||||
var res;
|
||||
try { res = JSON.parse(xhr.responseText || '{}'); } catch (e) { res = { success: false, error: '返回格式错误' }; }
|
||||
if (!res.success) {
|
||||
msgEl.textContent = res.error || (deleteMode ? '删除失败' : '导入失败');
|
||||
msgEl.className = 'msg err';
|
||||
return;
|
||||
}
|
||||
if (deleteMode) {
|
||||
setQueryAsinDeleteImportProgress(100, '上传完成,后端处理中...');
|
||||
pollQueryAsinDeleteImport(res.import_id);
|
||||
} else {
|
||||
setQueryAsinImportProgress(100, '上传完成,后端处理中...');
|
||||
pollQueryAsinImport(res.import_id);
|
||||
}
|
||||
fileInput.value = '';
|
||||
};
|
||||
xhr.onerror = function () {
|
||||
msgEl.textContent = '请求失败';
|
||||
msgEl.className = 'msg err';
|
||||
};
|
||||
xhr.send(formData);
|
||||
}
|
||||
document.getElementById('btnChooseQueryAsinShop').onclick = openChooseQueryAsinShopModal;
|
||||
document.getElementById('btnSearchChooseQueryAsinShop').onclick = function () {
|
||||
loadChooseQueryAsinShops(1);
|
||||
};
|
||||
document.getElementById('chooseQueryAsinShopGroupId').onchange = function () {
|
||||
loadChooseQueryAsinShops(1);
|
||||
};
|
||||
document.getElementById('chooseQueryAsinShopKeyword').addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
loadChooseQueryAsinShops(1);
|
||||
}
|
||||
});
|
||||
document.getElementById('btnCloseChooseQueryAsinShopModal').onclick = function () {
|
||||
document.getElementById('chooseQueryAsinShopModal').classList.remove('show');
|
||||
};
|
||||
document.getElementById('btnCloseEditQueryAsin').onclick = function () {
|
||||
document.getElementById('editQueryAsinModal').classList.remove('show');
|
||||
};
|
||||
document.getElementById('btnSaveQueryAsin').onclick = function () {
|
||||
var itemId = (document.getElementById('editQueryAsinId').value || '').trim();
|
||||
var countryCode = (document.getElementById('editQueryAsinCountry').value || '').trim();
|
||||
var asin = (document.getElementById('editQueryAsinValue').value || '').trim().toUpperCase();
|
||||
var msgEl = document.getElementById('msgEditQueryAsin');
|
||||
msgEl.textContent = '';
|
||||
msgEl.className = 'msg';
|
||||
if (!itemId || !countryCode) {
|
||||
msgEl.textContent = '缺少编辑记录';
|
||||
msgEl.className = 'msg err';
|
||||
return;
|
||||
}
|
||||
if (!asin) {
|
||||
msgEl.textContent = 'ASIN 不能为空';
|
||||
msgEl.className = 'msg err';
|
||||
return;
|
||||
}
|
||||
fetch('/api/admin/query-asin/' + itemId + '/country/' + countryCode, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ asin: asin })
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
if (!res.success) {
|
||||
msgEl.textContent = res.error || '保存失败';
|
||||
msgEl.className = 'msg err';
|
||||
return;
|
||||
}
|
||||
document.getElementById('editQueryAsinModal').classList.remove('show');
|
||||
loadQueryAsin(queryAsinPage);
|
||||
})
|
||||
.catch(function () {
|
||||
msgEl.textContent = '请求失败';
|
||||
msgEl.className = 'msg err';
|
||||
});
|
||||
};
|
||||
document.getElementById('queryAsinCountries').addEventListener('change', renderQueryAsinInputs);
|
||||
document.getElementById('btnSearchQueryAsin').onclick = function () {
|
||||
loadQueryAsin(1);
|
||||
};
|
||||
document.getElementById('queryAsinFilterShopName').addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
loadQueryAsin(1);
|
||||
}
|
||||
});
|
||||
document.getElementById('queryAsinFilterAsin').addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
loadQueryAsin(1);
|
||||
}
|
||||
});
|
||||
document.getElementById('btnCreateQueryAsin').onclick = function () {
|
||||
var groupId = (document.getElementById('queryAsinGroupSelect').value || '').trim();
|
||||
var shopName = (document.getElementById('queryAsinShopName').value || '').trim();
|
||||
var countries = getSelectedQueryAsinCountries();
|
||||
var msgEl = document.getElementById('msgQueryAsin');
|
||||
msgEl.textContent = '';
|
||||
msgEl.className = 'msg';
|
||||
if (!groupId || !shopName || !countries.length) {
|
||||
msgEl.textContent = '请完整填写分组、店铺名、国家和 ASIN';
|
||||
msgEl.className = 'msg err';
|
||||
return;
|
||||
}
|
||||
var asinMappings = {};
|
||||
try {
|
||||
asinMappings = collectQueryAsinMappings(countries);
|
||||
} catch (err) {
|
||||
msgEl.textContent = err.message || '请输入 ASIN';
|
||||
msgEl.className = 'msg err';
|
||||
return;
|
||||
}
|
||||
var fallbackAsin = '';
|
||||
Object.keys(asinMappings).some(function (countryCode) {
|
||||
fallbackAsin = asinMappings[countryCode] || '';
|
||||
return !!fallbackAsin;
|
||||
});
|
||||
fetch('/api/admin/query-asin', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
group_id: Number(groupId),
|
||||
shop_name: shopName,
|
||||
countries: countries,
|
||||
asin: fallbackAsin,
|
||||
asin_mappings: asinMappings
|
||||
})
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
if (!res.success) {
|
||||
msgEl.textContent = res.error || '保存失败';
|
||||
msgEl.className = 'msg err';
|
||||
return;
|
||||
}
|
||||
document.getElementById('queryAsinGroupSelect').value = '';
|
||||
document.getElementById('queryAsinShopName').value = '';
|
||||
Array.from(document.getElementById('queryAsinCountries').options).forEach(function (option) {
|
||||
option.selected = false;
|
||||
});
|
||||
renderQueryAsinInputs();
|
||||
msgEl.textContent = res.msg || '保存成功';
|
||||
msgEl.className = 'msg ok';
|
||||
loadQueryAsin(1);
|
||||
})
|
||||
.catch(function () {
|
||||
msgEl.textContent = '请求失败';
|
||||
msgEl.className = 'msg err';
|
||||
});
|
||||
};
|
||||
document.getElementById('btnImportQueryAsin').onclick = function () {
|
||||
uploadQueryAsinImport(false);
|
||||
};
|
||||
document.getElementById('btnDeleteImportQueryAsin').onclick = function () {
|
||||
uploadQueryAsinImport(true);
|
||||
};
|
||||
renderQueryAsinInputs();
|
||||
|
||||
function loadVersions() {
|
||||
fetch('/api/admin/versions')
|
||||
.then(function (r) { return r.json(); })
|
||||
|
||||
Reference in New Issue
Block a user