')
+@login_required
+def skip_price_asin_delete_import_progress(import_id):
+ role, current_row, denied = _ensure_backend_menu_access('skip-price-asin')
+ if denied:
+ return denied
+ result, error_response, status = _proxy_backend_java(
+ 'GET',
+ f'/api/admin/skip-price-asins/delete-import/{import_id}',
+ )
+ if error_response is not None:
+ return error_response, status
+ return jsonify({
+ 'success': True,
+ 'progress': _format_query_asin_import_progress(result.get('data') or {}),
+ })
+
+
+@admin_api.route('/skip-price-asins/delete-import', methods=['POST'])
+@login_required
+def delete_import_skip_price_asins():
+ role, current_row, denied = _ensure_backend_menu_access('skip-price-asin')
+ if denied:
+ return denied
+ file_storage = request.files.get('file')
+ if not file_storage or file_storage.filename == '':
+ return jsonify({'success': False, 'error': '请选择 Excel 文件'})
+ group_id_raw = (request.form.get('group_id') or '').strip()
+ if not group_id_raw:
+ return jsonify({'success': False, 'error': '请先选择分组'})
+ params = {
+ 'groupId': group_id_raw,
+ 'operatorId': current_row.get('id') if current_row else None,
+ 'superAdmin': 'true' if role == 'super_admin' else 'false',
+ }
+ files = {
+ 'file': (file_storage.filename, file_storage.stream, file_storage.mimetype or 'application/octet-stream')
+ }
+ result, error_response, status = _proxy_backend_java(
+ 'POST',
+ '/api/admin/skip-price-asins/delete-import',
+ params=params,
+ files=files,
+ timeout=60,
+ )
+ if error_response is not None:
+ return error_response, status
+ summary = result.get('data') or {}
+ return jsonify({
+ 'success': True,
+ 'msg': result.get('message') or '开始删除',
+ 'import_id': summary.get('importId') or '',
+ })
+
+
def _format_query_asin_item(item):
return {
'id': item.get('id'),
diff --git a/backend/config.py b/backend/config.py
index 4e042f5..db46cef 100644
--- a/backend/config.py
+++ b/backend/config.py
@@ -23,9 +23,10 @@ bucket_path = "nanri-image/"
file_url_pre = f"https://{bucket}.oss-cn-hangzhou.aliyuncs.com/"
import os
-# backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://127.0.0.1:18080').rstrip('/')
+backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://127.0.0.1:18080').rstrip('/')
# backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://8.136.19.173:18080').rstrip('/')
-backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://47.111.163.154:18080').rstrip('/')
+# backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://47.111.163.154:18080').rstrip('/')
+# backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://121.196.149.225:18080').rstrip('/')
os.environ['OSS_ACCESS_KEY_ID'] = accessKeyId
os.environ['OSS_ACCESS_KEY_SECRET'] = accessKeySecret
os.environ['SECRET_KEY'] = "ddffc7c1d02121d9554d7b080b2511b6"
diff --git a/backend/utils/auth.py b/backend/utils/auth.py
index 772cd13..5b5c0a7 100644
--- a/backend/utils/auth.py
+++ b/backend/utils/auth.py
@@ -3,7 +3,7 @@
"""
from functools import wraps
-from flask import request, redirect, url_for, session, jsonify
+from flask import request, redirect, url_for, session, jsonify, g
from utils.db import get_db
@@ -13,15 +13,22 @@ def is_session_user_valid():
uid = session.get('user_id')
if not uid:
return False
+ cached_user = getattr(g, '_current_user_row', None)
+ if cached_user and cached_user.get('id') == uid:
+ return True
try:
conn = get_db()
with conn.cursor() as cur:
- cur.execute("SELECT id FROM users WHERE id = %s", (uid,))
+ cur.execute(
+ "SELECT id, username, is_admin, role, created_by_id FROM users WHERE id = %s",
+ (uid,)
+ )
row = cur.fetchone()
conn.close()
if not row:
session.clear()
return False
+ g._current_user_row = row
return True
except Exception:
session.clear()
@@ -34,16 +41,19 @@ def get_current_admin_role():
if not uid:
return None, None
try:
- conn = get_db()
- with conn.cursor() as cur:
- cur.execute(
- "SELECT id, username, is_admin, role, created_by_id FROM users WHERE id = %s",
- (uid,)
- )
- row = cur.fetchone()
- conn.close()
+ row = getattr(g, '_current_user_row', None)
+ if not row or row.get('id') != uid:
+ conn = get_db()
+ with conn.cursor() as cur:
+ cur.execute(
+ "SELECT id, username, is_admin, role, created_by_id FROM users WHERE id = %s",
+ (uid,)
+ )
+ row = cur.fetchone()
+ conn.close()
if not row:
return None, None
+ g._current_user_row = row
role = (row.get('role') or '').strip().lower()
if not role:
role = 'super_admin' if row.get('is_admin') and row.get('created_by_id') is None else (
diff --git a/backend/utils/db.py b/backend/utils/db.py
index edf13ef..5ec2849 100644
--- a/backend/utils/db.py
+++ b/backend/utils/db.py
@@ -6,12 +6,20 @@ import pymysql
from werkzeug.security import generate_password_hash
try:
- from config import mysql_host, mysql_user, mysql_password, mysql_database
+ from config import mysql_host as config_mysql_host
+ from config import mysql_user as config_mysql_user
+ from config import mysql_password as config_mysql_password
+ from config import mysql_database as config_mysql_database
except ImportError:
- mysql_host = os.environ.get('MYSQL_HOST', 'localhost')
- mysql_user = os.environ.get('MYSQL_USER', 'root')
- mysql_password = os.environ.get('MYSQL_PASSWORD', '')
- mysql_database = os.environ.get('MYSQL_DATABASE', 'maixiang_ai')
+ config_mysql_host = 'localhost'
+ config_mysql_user = 'root'
+ config_mysql_password = ''
+ config_mysql_database = 'maixiang_ai'
+
+mysql_host = os.environ.get('MYSQL_HOST', config_mysql_host)
+mysql_user = os.environ.get('MYSQL_USER', config_mysql_user)
+mysql_password = os.environ.get('MYSQL_PASSWORD', config_mysql_password)
+mysql_database = os.environ.get('MYSQL_DATABASE', config_mysql_database)
def get_db():
diff --git a/backend/web_source/_tmp_prefix.js b/backend/web_source/_tmp_prefix.js
deleted file mode 100644
index c578064..0000000
--- a/backend/web_source/_tmp_prefix.js
+++ /dev/null
@@ -1,2000 +0,0 @@
-
- (function () {
- // Tab 鍒囨崲
- var adminTabsEl = document.getElementById('adminTabs');
- if (adminTabsEl) adminTabsEl.innerHTML = '';
- var activeAdminTabName = '';
- var ADMIN_PANEL_MAP = {
- 'users': 'panel-users',
- 'columns': 'panel-columns',
- 'dedupe-total-data': 'panel-dedupe-total-data',
- 'shop-keys': 'panel-shop-keys',
- 'shop-manage': 'panel-shop-manage',
- 'skip-price-asin': 'panel-skip-price-asin',
- 'history': 'panel-history',
- 'version': 'panel-version'
- };
- function runTabLoader(tabName) {
- if (tabName === 'users') { loadUsers(1); loadColumnsForPermission(); }
- else if (tabName === 'columns') loadColumns();
- else if (tabName === 'dedupe-total-data') loadDedupeTotalData(1);
- 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 === 'history') loadHistory(1);
- else if (tabName === 'version') loadVersions();
- }
- function hideAllAdminPanels() {
- document.querySelectorAll('.tab-panel').forEach(function (panel) {
- panel.classList.remove('active');
- panel.style.display = 'none';
- });
- }
- function getActiveAdminTabName() {
- return activeAdminTabName;
- }
- function activateAdminTab(tabName) {
- var panelId = ADMIN_PANEL_MAP[tabName];
- var panel = panelId ? document.getElementById(panelId) : null;
- if (!panel) return;
- activeAdminTabName = tabName;
- document.querySelectorAll('#adminTabs .tab').forEach(function (tab) {
- tab.classList.toggle('active', tab.dataset.tab === tabName);
- });
- hideAllAdminPanels();
- panel.style.display = '';
- panel.classList.add('active');
- runTabLoader(tabName);
- }
- function renderAdminTabs(items) {
- var knownItems = (items || []).filter(function (item) {
- return !!ADMIN_PANEL_MAP[item.route_path];
- });
- if (!knownItems.length) {
- activeAdminTabName = '';
- if (adminTabsEl) adminTabsEl.innerHTML = '鏆傛棤鍙敤鑿滃崟
';
- hideAllAdminPanels();
- return;
- }
- if (adminTabsEl) {
- adminTabsEl.innerHTML = knownItems.map(function (item) {
- return '' + (item.name || item.route_path) + '
';
- }).join('');
- }
- document.querySelectorAll('#adminTabs .tab').forEach(function (tab) {
- tab.onclick = function () {
- activateAdminTab(tab.dataset.tab);
- };
- });
- var fallbackTab = activeAdminTabName && knownItems.some(function (item) { return item.route_path === activeAdminTabName; })
- ? activeAdminTabName
- : knownItems[0].route_path;
- activateAdminTab(fallbackTab);
- }
- function loadAdminMenus(preferredTab) {
- if (preferredTab) activeAdminTabName = preferredTab;
- fetch('/api/admin/current-user/menus')
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (!res.success) {
- if (adminTabsEl) adminTabsEl.innerHTML = '鑿滃崟鍔犺浇澶辫触
';
- hideAllAdminPanels();
- return;
- }
- renderAdminTabs(res.items || []);
- })
- .catch(function () {
- if (adminTabsEl) adminTabsEl.innerHTML = '鑿滃崟鍔犺浇澶辫触
';
- hideAllAdminPanels();
- });
- }
- hideAllAdminPanels();
-
- // ========== 鐢ㄦ埛绠$悊 ==========
- var userPage = 1, userPageSize = 15;
- var currentUserId = null;
- var currentUserRole = 'admin';
- var currentUserUsername = '';
- var adminsList = [];
- function roleLabel(role) {
- if (role === 'super_admin') return '瓒呯骇绠$悊鍛?;
- if (role === 'admin') return '绠$悊鍛?;
- return '鏅€氳处鍙?;
- }
- function buildUserListQuery(page) {
- var q = 'page=' + (page || 1) + '&page_size=' + userPageSize;
- var kw = (document.getElementById('searchUsername').value || '').trim();
- if (kw) q += '&username=' + encodeURIComponent(kw);
- var cby = document.getElementById('filterCreatedBy').value;
- if (cby) q += '&created_by_id=' + encodeURIComponent(cby);
- return q;
- }
- function loadUsers(page) {
- userPage = page || 1;
- fetch('/api/admin/users?' + buildUserListQuery(userPage))
- .then(function (r) { return r.json(); })
- .then(function (res) {
- var tbody = document.getElementById('userListBody');
- if (!res.success) {
- tbody.innerHTML = '| 鍔犺浇澶辫触: ' + (res.error || '') + ' |
';
- return;
- }
- currentUserId = res.current_user_id || null;
- currentUserRole = res.current_user_role || 'admin';
- currentUserUsername = (res.current_user_username || '').trim();
- adminsList = res.admins || [];
- var items = res.items || [];
- if (items.length === 0) {
- tbody.innerHTML = '| 鏆傛棤鐢ㄦ埛 |
';
- } else {
- tbody.innerHTML = items.map(function (u) {
- return '| ' + u.id + ' | ' + (u.username || '') + ' | ' +
- roleLabel(u.role || 'normal') + ' | ' + (u.creator_username || '-') + ' | ' + (u.created_at || '') + ' | ' +
- ' ' +
- '' +
- ' |
';
- }).join('');
- }
- renderPagination('userPagination', res.total, res.page, res.page_size, loadUsers);
- bindUserActions();
- updateCreateFormByRole();
- updateUserFilterByRole();
- })
- .catch(function () {
- document.getElementById('userListBody').innerHTML = '| 璇锋眰澶辫触 |
';
- });
- }
- function updateUserFilterByRole() {
- var grp = document.getElementById('filterCreatedByGroup');
- var sel = document.getElementById('filterCreatedBy');
- if (currentUserRole === 'super_admin') {
- grp.style.display = 'block';
- var cur = sel.value;
- sel.innerHTML = '';
- adminsList.forEach(function (a) {
- var opt = document.createElement('option');
- opt.value = a.id;
- opt.textContent = a.username;
- sel.appendChild(opt);
- });
- sel.value = cur || '';
- } else {
- grp.style.display = 'none';
- }
- }
-
- function updateDedupeTotalDataAccess() {
- var tab = document.querySelector('.tab[data-tab="dedupe-total-data"]');
- var panel = document.getElementById('panel-dedupe-total-data');
- var canUse = currentUserRole === 'super_admin' || (currentUserRole === 'admin' && currentUserUsername === '');
- if (tab) tab.style.display = canUse ? '' : 'none';
- if (panel) panel.style.display = canUse ? '' : 'none';
- if (!canUse && tab && tab.classList.contains('active')) {
- tab.classList.remove('active');
- if (panel) panel.classList.remove('active');
- var usersTab = document.querySelector('.tab[data-tab="users"]');
- var usersPanel = document.getElementById('panel-users');
- if (usersTab) usersTab.classList.add('active');
- if (usersPanel) usersPanel.classList.add('active');
- }
- }
- function updateShopManageAccess() {
- var tab = document.querySelector('.tab[data-tab="shop-manage"]');
- var panel = document.getElementById('panel-shop-manage');
- if (!tab || !panel) return;
- var canUse = currentUserRole === 'super_admin' ||
- !!currentUserAdminPermissionKeys['admin_shop_manage'] ||
- !!currentUserAdminPermissionRoutes['shop-manage'];
- tab.style.display = canUse ? '' : 'none';
- panel.style.display = canUse ? '' : 'none';
- if (!canUse && tab.classList.contains('active')) {
- tab.classList.remove('active');
- panel.classList.remove('active');
- var usersTab = document.querySelector('.tab[data-tab="users"]');
- var usersPanel = document.getElementById('panel-users');
- if (usersTab) usersTab.classList.add('active');
- if (usersPanel) usersPanel.classList.add('active');
- }
- }
- function loadCurrentUserAdminPermissions() {
- currentUserAdminPermissionKeys = {};
- currentUserAdminPermissionRoutes = {};
- if (!currentUserId || currentUserRole === 'super_admin') {
- updateShopManageAccess();
- return;
- }
- fetch('/api/admin/user/' + currentUserId + '/column-permissions?menu_type=admin')
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (!res.success) {
- updateShopManageAccess();
- return;
- }
- (res.items || []).forEach(function (item) {
- var columnKey = (item.column_key || '').trim();
- var routePath = (item.route_path || '').trim();
- if (columnKey) currentUserAdminPermissionKeys[columnKey] = true;
- if (routePath) currentUserAdminPermissionRoutes[routePath] = true;
- });
- updateShopManageAccess();
- })
- .catch(function () {
- updateShopManageAccess();
- });
- }
- function applyTabAccess(tabName, canUse) {
- var tab = document.querySelector('.tab[data-tab="' + tabName + '"]');
- var panel = document.getElementById('panel-' + tabName);
- if (tab) tab.style.display = canUse ? '' : 'none';
- if (panel) panel.style.display = canUse ? '' : 'none';
- if (!canUse && tab && tab.classList.contains('active')) {
- tab.classList.remove('active');
- if (panel) panel.classList.remove('active');
- var usersTab = document.querySelector('.tab[data-tab="users"]');
- var usersPanel = document.getElementById('panel-users');
- if (usersTab) usersTab.classList.add('active');
- if (usersPanel) usersPanel.classList.add('active');
- }
- }
- function hasAdminTabAccess(tabName) {
- var config = ADMIN_TAB_ACCESS_CONFIG[tabName];
- if (!config) return true;
- if (currentUserRole === 'super_admin') return true;
- if (config.superAdminOnly) return false;
- return !!currentUserAdminPermissionKeys[config.columnKey] ||
- !!currentUserAdminPermissionRoutes[config.routePath];
- }
- function refreshAdminTabAccess() {
- Object.keys(ADMIN_TAB_ACCESS_CONFIG).forEach(function (tabName) {
- applyTabAccess(tabName, hasAdminTabAccess(tabName));
- });
- }
- function loadCurrentUserAdminPermissions() {
- currentUserAdminPermissionKeys = {};
- currentUserAdminPermissionRoutes = {};
- if (!currentUserId || currentUserRole === 'super_admin') {
- refreshAdminTabAccess();
- return;
- }
- fetch('/api/admin/user/' + currentUserId + '/column-permissions?menu_type=admin')
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (!res.success) {
- refreshAdminTabAccess();
- return;
- }
- (res.items || []).forEach(function (item) {
- var columnKey = (item.column_key || '').trim();
- var routePath = (item.route_path || '').trim();
- if (columnKey) currentUserAdminPermissionKeys[columnKey] = true;
- if (routePath) currentUserAdminPermissionRoutes[routePath] = true;
- });
- refreshAdminTabAccess();
- })
- .catch(function () {
- refreshAdminTabAccess();
- });
- }
- var allColumnsList = [];
- function loadColumnsForPermission() {
- fetch('/api/admin/columns?menu_type=admin')
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (!res.success) return;
- allColumnsList = res.items || [];
- renderColumnPermissionWrap('createColumnPermissionWrap');
- renderColumnPermissionWrap('editColumnPermissionWrap');
- var selCreate = document.getElementById('createColumnPermissionWrap');
- var selEdit = document.getElementById('editColumnPermissionWrap');
- if (selCreate && !selCreate._colCardsBound) {
- selCreate._colCardsBound = true;
- selCreate.onchange = function () { renderColumnCards('createColumnPermissionWrap'); };
- }
- if (selEdit && !selEdit._colCardsBound) {
- selEdit._colCardsBound = true;
- selEdit.onchange = function () { renderColumnCards('editColumnPermissionWrap'); };
- }
- })
- .catch(function () { });
- }
- var columnCardsContainerMap = { createColumnPermissionWrap: 'createColumnCards', editColumnPermissionWrap: 'editColumnCards' };
- function renderColumnCards(selectId) {
- var sel = document.getElementById(selectId);
- var cardsId = columnCardsContainerMap[selectId];
- var cardsEl = cardsId ? document.getElementById(cardsId) : null;
- if (!sel || sel.tagName !== 'SELECT' || !cardsEl) return;
- cardsEl.innerHTML = '';
- for (var i = 0; i < sel.options.length; i++) {
- var opt = sel.options[i];
- if (opt.disabled || !opt.selected) continue;
- var card = document.createElement('span');
- card.className = 'column-permission-card';
- card.textContent = opt.textContent;
- var btn = document.createElement('button');
- btn.type = 'button';
- btn.className = 'col-card-remove';
- btn.setAttribute('aria-label', '绉婚櫎');
- btn.textContent = '脳';
- (function (option, seldId) {
- btn.onclick = function () {
- option.selected = false;
- renderColumnCards(seldId);
- };
- })(opt, selectId);
- card.appendChild(btn);
- cardsEl.appendChild(card);
- }
- }
- function renderColumnPermissionWrap(wrapId) {
- var sel = document.getElementById(wrapId);
- if (!sel || sel.tagName !== 'SELECT') return;
- sel.innerHTML = '';
- allColumnsList.forEach(function (c) {
- var opt = document.createElement('option');
- opt.value = c.id;
- opt.textContent = c.name + ' (' + c.column_key + ')';
- sel.appendChild(opt);
- });
- if (allColumnsList.length === 0) {
- var opt = document.createElement('option');
- opt.disabled = true;
- opt.textContent = '鏆傛棤鑿滃崟锛岃鍏堝湪鈥滄爮鐩潈闄愰厤缃€濅腑鏂板鑿滃崟';
- sel.appendChild(opt);
- }
- renderColumnCards(wrapId);
- }
- function getSelectedColumnIds(wrapId) {
- var sel = document.getElementById(wrapId);
- if (!sel || sel.tagName !== 'SELECT') return [];
- var ids = [];
- for (var i = 0; i < sel.options.length; i++) {
- if (sel.options[i].selected) {
- var v = parseInt(sel.options[i].value, 10);
- if (!isNaN(v)) ids.push(v);
- }
- }
- return ids;
- }
- function setColumnPermissionCheckboxes(wrapId, columnIds) {
- var sel = document.getElementById(wrapId);
- if (!sel || sel.tagName !== 'SELECT') return;
- var set = {};
- (columnIds || []).forEach(function (id) { set[id] = true; });
- for (var i = 0; i < sel.options.length; i++) {
- var opt = sel.options[i];
- if (opt.disabled) continue;
- opt.selected = set[parseInt(opt.value, 10)] || false;
- }
- renderColumnCards(wrapId);
- }
- function updateCreateFormByRole() {
- var roleSel = document.getElementById('createRole');
- var optAdmin = document.getElementById('optAdmin');
- var formCreatedBy = document.getElementById('formGroupCreatedBy');
- var selCreatedBy = document.getElementById('createCreatedBy');
- if (currentUserRole === 'super_admin') {
- if (optAdmin) optAdmin.style.display = '';
- formCreatedBy.style.display = (roleSel.value === 'normal') ? 'block' : 'none';
- selCreatedBy.innerHTML = '';
- (res.items || []).forEach(function (u) {
- var opt = document.createElement('option');
- opt.value = u.id;
- opt.textContent = u.username + ' (' + roleLabel(u.role || 'normal') + ')';
- sel.appendChild(opt);
- });
- sel.value = cur || '';
- });
- }
- var shopManageGroupUsers = [];
- function refreshShopManageGroupUserSelect(selectedUserId) {
- var sel = document.getElementById('shopManageGroupUserSelect');
- if (!sel) return;
- var opts = [''];
- shopManageGroupUsers.forEach(function (u) {
- opts.push('');
- });
- sel.innerHTML = opts.join('');
- if (selectedUserId != null && selectedUserId !== '') {
- sel.value = String(selectedUserId);
- }
- syncShopManageGroupNameWithUser();
- }
- function syncShopManageGroupNameWithUser() {
- var sel = document.getElementById('shopManageGroupUserSelect');
- var input = document.getElementById('shopManageGroupInput');
- if (!sel || !input) return;
- var selectedUser = null;
- shopManageGroupUsers.some(function (u) {
- if (String(u.id) === String(sel.value || '')) {
- selectedUser = u;
- return true;
- }
- return false;
- });
- input.value = selectedUser ? (selectedUser.username || '') : '';
- }
- function loadUserOptions() {
- return fetch('/api/admin/users?page=1&page_size=999')
- .then(function (r) { return r.json(); })
- .then(function (res) {
- var items = res.items || [];
- shopManageGroupUsers = items.map(function (u) {
- return { id: u.id, username: u.username || '', role: u.role || 'normal' };
- });
- refreshShopManageGroupUserSelect(document.getElementById('shopManageGroupUserSelect') ? document.getElementById('shopManageGroupUserSelect').value : '');
- var sel = document.getElementById('filterUser');
- var cur = sel.value;
- sel.innerHTML = '';
- items.forEach(function (u) {
- var opt = document.createElement('option');
- opt.value = u.id;
- opt.textContent = u.username + ' (' + roleLabel(u.role || 'normal') + ')';
- sel.appendChild(opt);
- });
- sel.value = cur || '';
- });
- }
- document.getElementById('btnFilterHistory').onclick = function () { loadHistory(1); };
-
- // ========== 鏁版嵁鍘婚噸鎬绘暟鎹?==========
- var dedupeTotalDataPage = 1, dedupeTotalDataPageSize = 15;
- function buildDedupeTotalDataQuery(page) {
- var q = 'page=' + (page || 1) + '&page_size=' + dedupeTotalDataPageSize;
- var keyword = (document.getElementById('searchDedupeTotalData').value || '').trim();
- if (keyword) q += '&keyword=' + encodeURIComponent(keyword);
- return q;
- }
- function loadDedupeTotalData(page) {
- dedupeTotalDataPage = page || 1;
- fetch('/api/admin/dedupe-total-data?' + buildDedupeTotalDataQuery(dedupeTotalDataPage))
- .then(function (r) { return r.json(); })
- .then(function (res) {
- var tbody = document.getElementById('dedupeTotalDataListBody');
- if (!res.success) {
- tbody.innerHTML = '| 鍔犺浇澶辫触: ' + (res.error || '') + ' |
';
- return;
- }
- var items = res.items || [];
- if (items.length === 0) {
- tbody.innerHTML = '| 鏆傛棤鎬绘暟鎹?/td> |
';
- } else {
- tbody.innerHTML = items.map(function (item) {
- return '| ' + item.id + ' | ' + (item.data_value || '') + ' | ' + (item.created_at || '') + ' | ' +
- ' ' +
- '' +
- ' |
';
- }).join('');
- }
- renderPagination('dedupeTotalDataPagination', res.total, res.page, res.page_size, loadDedupeTotalData);
- bindDedupeTotalDataActions();
- })
- .catch(function () {
- document.getElementById('dedupeTotalDataListBody').innerHTML = '| 璇锋眰澶辫触 |
';
- });
- }
- function bindDedupeTotalDataActions() {
- document.querySelectorAll('[data-dedupe-total-edit]').forEach(function (btn) {
- btn.onclick = function () {
- document.getElementById('editDedupeTotalDataId').value = btn.dataset.dedupeTotalEdit || '';
- document.getElementById('editDedupeTotalDataValue').value = (btn.dataset.value || '').replace(/"/g, '"');
- document.getElementById('msgEditDedupeTotalData').textContent = '';
- document.getElementById('msgEditDedupeTotalData').className = 'msg';
- document.getElementById('editDedupeTotalDataModal').classList.add('show');
- };
- });
- document.querySelectorAll('[data-dedupe-total-delete]').forEach(function (btn) {
- btn.onclick = function () {
- var value = (btn.dataset.value || '').replace(/"/g, '"');
- if (!confirm('纭畾鍒犻櫎鎬绘暟鎹€? + value + '鈥濆悧锛?)) return;
- fetch('/api/admin/dedupe-total-data/' + btn.dataset.dedupeTotalDelete, { method: 'DELETE' })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (res.success) { loadDedupeTotalData(dedupeTotalDataPage); }
- else { alert(res.error || '鍒犻櫎澶辫触'); }
- });
- };
- });
- }
- document.getElementById('btnSearchDedupeTotalData').onclick = function () { loadDedupeTotalData(1); };
- var dedupeImportPollTimer = null;
- var dedupeDeleteImportPollTimer = null;
- function stopDedupeImportProgress() {
- if (dedupeImportPollTimer) {
- clearInterval(dedupeImportPollTimer);
- dedupeImportPollTimer = null;
- }
- }
- function stopDedupeDeleteImportProgress() {
- if (dedupeDeleteImportPollTimer) {
- clearInterval(dedupeDeleteImportPollTimer);
- dedupeDeleteImportPollTimer = null;
- }
- }
- function setDedupeImportProgress(percent, text) {
- var wrap = document.getElementById('dedupeTotalDataProgressWrap');
- var fill = document.getElementById('dedupeTotalDataProgressFill');
- var textEl = document.getElementById('dedupeTotalDataProgressText');
- wrap.style.display = 'block';
- fill.style.width = Math.max(0, Math.min(100, percent || 0)) + '%';
- textEl.textContent = text || '';
- }
- function setDedupeDeleteImportProgress(percent, text) {
- var wrap = document.getElementById('dedupeTotalDataDeleteProgressWrap');
- var fill = document.getElementById('dedupeTotalDataDeleteProgressFill');
- var textEl = document.getElementById('dedupeTotalDataDeleteProgressText');
- wrap.style.display = 'block';
- fill.style.width = Math.max(0, Math.min(100, percent || 0)) + '%';
- textEl.textContent = text || '';
- }
- function pollDedupeImport(importId) {
- stopDedupeImportProgress();
- function tick() {
- fetch('/api/admin/dedupe-total-data/import/' + encodeURIComponent(importId))
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (!res.success) {
- stopDedupeImportProgress();
- document.getElementById('msgDedupeTotalData').textContent = res.error || '鏌ヨ瀵煎叆杩涘害澶辫触';
- document.getElementById('msgDedupeTotalData').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;
- setDedupeImportProgress(percent, '澶勭悊涓細宸插鐞?' + processedRows + ' / ' + totalRows + '锛屾柊澧?' + (progress.inserted_count || 0) + '锛岃烦杩?' + (progress.skipped_count || 0));
- if (progress.status === 'success') {
- stopDedupeImportProgress();
- document.getElementById('msgDedupeTotalData').textContent = '瀵煎叆鎴愬姛锛氭€昏鏁?' + (progress.total_rows || 0) + '锛孉SIN 鏁伴噺 ' + (progress.asin_count || 0) + '锛屾柊澧?' + (progress.inserted_count || 0) + '锛岃烦杩?' + (progress.skipped_count || 0);
- document.getElementById('msgDedupeTotalData').className = 'msg ok';
- loadDedupeTotalData(1);
- } else if (progress.status === 'failed') {
- stopDedupeImportProgress();
- document.getElementById('msgDedupeTotalData').textContent = progress.error_message || '瀵煎叆澶辫触';
- document.getElementById('msgDedupeTotalData').className = 'msg err';
- }
- })
- .catch(function () {
- stopDedupeImportProgress();
- document.getElementById('msgDedupeTotalData').textContent = '鏌ヨ瀵煎叆杩涘害澶辫触';
- document.getElementById('msgDedupeTotalData').className = 'msg err';
- });
- }
- tick();
- dedupeImportPollTimer = setInterval(tick, 1000);
- }
- function pollDedupeDeleteImport(importId) {
- stopDedupeDeleteImportProgress();
- function tick() {
- fetch('/api/admin/dedupe-total-data/delete-import/' + encodeURIComponent(importId))
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (!res.success) {
- stopDedupeDeleteImportProgress();
- document.getElementById('msgDeleteDedupeTotalData').textContent = res.error || '鏌ヨ鍒犻櫎杩涘害澶辫触';
- document.getElementById('msgDeleteDedupeTotalData').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;
- setDedupeDeleteImportProgress(percent, '澶勭悊涓細宸插鐞?' + processedRows + ' / ' + totalRows + '锛屽垹闄?' + (progress.deleted_count || 0) + '锛岃烦杩?' + (progress.skipped_count || 0));
- if (progress.status === 'success') {
- stopDedupeDeleteImportProgress();
- document.getElementById('msgDeleteDedupeTotalData').textContent = '鍒犻櫎鎴愬姛锛氭€昏鏁?' + (progress.total_rows || 0) + '锛孉SIN 鏁伴噺 ' + (progress.asin_count || 0) + '锛屽垹闄?' + (progress.deleted_count || 0) + '锛岃烦杩?' + (progress.skipped_count || 0);
- document.getElementById('msgDeleteDedupeTotalData').className = 'msg ok';
- loadDedupeTotalData(1);
- } else if (progress.status === 'failed') {
- stopDedupeDeleteImportProgress();
- document.getElementById('msgDeleteDedupeTotalData').textContent = progress.error_message || '鍒犻櫎澶辫触';
- document.getElementById('msgDeleteDedupeTotalData').className = 'msg err';
- }
- })
- .catch(function () {
- stopDedupeDeleteImportProgress();
- document.getElementById('msgDeleteDedupeTotalData').textContent = '鏌ヨ鍒犻櫎杩涘害澶辫触';
- document.getElementById('msgDeleteDedupeTotalData').className = 'msg err';
- });
- }
- tick();
- dedupeDeleteImportPollTimer = setInterval(tick, 1000);
- }
-
- document.getElementById('btnAddDedupeTotalData').onclick = function () {
- var fileInput = document.getElementById('dedupeTotalDataFile');
- var msgEl = document.getElementById('msgDedupeTotalData');
- msgEl.textContent = '';
- msgEl.className = 'msg';
- stopDedupeImportProgress();
- document.getElementById('dedupeTotalDataProgressWrap').style.display = 'none';
- if (!fileInput.files || fileInput.files.length === 0) {
- msgEl.textContent = '璇烽€夋嫨 Excel 鏂囦欢';
- msgEl.classList.add('err');
- return;
- }
- var file = fileInput.files[0];
- var lowerName = (file.name || '').toLowerCase();
- if (!(lowerName.endsWith('.xlsx') || lowerName.endsWith('.xls'))) {
- msgEl.textContent = '浠呮敮鎸?.xlsx 鎴?.xls 鏂囦欢';
- msgEl.classList.add('err');
- return;
- }
- var formData = new FormData();
- formData.append('file', file);
- var xhr = new XMLHttpRequest();
- xhr.open('POST', '/api/admin/dedupe-total-data/import', true);
- xhr.upload.onprogress = function (event) {
- if (event.lengthComputable) {
- var percent = Math.round(event.loaded * 100 / event.total);
- setDedupeImportProgress(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 || '瀵煎叆澶辫触';
- msgEl.className = 'msg err';
- return;
- }
- setDedupeImportProgress(100, '涓婁紶瀹屾垚锛屽悗绔鐞嗕腑...');
- pollDedupeImport(res.import_id);
- fileInput.value = '';
- };
- xhr.onerror = function () {
- msgEl.textContent = '璇锋眰澶辫触';
- msgEl.className = 'msg err';
- };
- xhr.send(formData);
- };
- document.getElementById('btnDeleteImportDedupeTotalData').onclick = function () {
- var fileInput = document.getElementById('dedupeTotalDataDeleteFile');
- var msgEl = document.getElementById('msgDeleteDedupeTotalData');
- msgEl.textContent = '';
- msgEl.className = 'msg';
- stopDedupeDeleteImportProgress();
- document.getElementById('dedupeTotalDataDeleteProgressWrap').style.display = 'none';
- if (!fileInput.files || fileInput.files.length === 0) {
- msgEl.textContent = '璇烽€夋嫨 Excel 鏂囦欢';
- msgEl.classList.add('err');
- return;
- }
- var file = fileInput.files[0];
- var lowerName = (file.name || '').toLowerCase();
- if (!(lowerName.endsWith('.xlsx') || lowerName.endsWith('.xls'))) {
- msgEl.textContent = '浠呮敮鎸?.xlsx 鎴?.xls 鏂囦欢';
- msgEl.classList.add('err');
- return;
- }
- if (!confirm('纭畾鎸?Excel 涓殑 ASIN 鎵归噺鍒犻櫎鍖归厤鐨勬€绘暟鎹悧锛?)) {
- return;
- }
- var formData = new FormData();
- formData.append('file', file);
- var xhr = new XMLHttpRequest();
- xhr.open('POST', '/api/admin/dedupe-total-data/delete-import', true);
- xhr.upload.onprogress = function (event) {
- if (event.lengthComputable) {
- var percent = Math.round(event.loaded * 100 / event.total);
- setDedupeDeleteImportProgress(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 || '鍒犻櫎澶辫触';
- msgEl.className = 'msg err';
- return;
- }
- setDedupeDeleteImportProgress(100, '涓婁紶瀹屾垚锛屽悗绔鐞嗕腑...');
- pollDedupeDeleteImport(res.import_id);
- fileInput.value = '';
- };
- xhr.onerror = function () {
- msgEl.textContent = '璇锋眰澶辫触';
- msgEl.className = 'msg err';
- };
- xhr.send(formData);
- };
- document.getElementById('btnSaveDedupeTotalData').onclick = function () {
- var itemId = document.getElementById('editDedupeTotalDataId').value;
- var value = (document.getElementById('editDedupeTotalDataValue').value || '').trim();
- var msgEl = document.getElementById('msgEditDedupeTotalData');
- msgEl.textContent = '';
- msgEl.className = 'msg';
- if (!value) {
- msgEl.textContent = '璇峰~鍐欐€绘暟鎹€?;
- msgEl.classList.add('err');
- return;
- }
- fetch('/api/admin/dedupe-total-data/' + itemId, {
- method: 'PUT',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ data_value: value })
- })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (res.success) {
- document.getElementById('editDedupeTotalDataModal').classList.remove('show');
- loadDedupeTotalData(dedupeTotalDataPage);
- } else {
- msgEl.textContent = res.error || '淇濆瓨澶辫触';
- msgEl.classList.add('err');
- }
- });
- };
- document.getElementById('btnCloseEditDedupeTotalData').onclick = function () {
- document.getElementById('editDedupeTotalDataModal').classList.remove('show');
- };
-
- // ========== 搴楅摵瀵嗛挜绠$悊 ==========
- var shopKeyPage = 1, shopKeyPageSize = 15;
- function buildShopKeyQuery(page) {
- return 'page=' + (page || 1) + '&page_size=' + shopKeyPageSize;
- }
- function loadShopKeys(page) {
- shopKeyPage = page || 1;
- fetch('/api/admin/shop-keys?' + buildShopKeyQuery(shopKeyPage))
- .then(function (r) { return r.json(); })
- .then(function (res) {
- var tbody = document.getElementById('shopKeyListBody');
- if (!res.success) {
- tbody.innerHTML = '| 鍔犺浇澶辫触: ' + (res.error || '') + ' |
';
- return;
- }
- var items = res.items || [];
- if (items.length === 0) {
- tbody.innerHTML = '| 鏆傛棤搴楅摵瀵嗛挜 |
';
- } else {
- tbody.innerHTML = items.map(function (item, index) {
- var rowNo = (shopKeyPage - 1) * shopKeyPageSize + index + 1;
- return '| ' + rowNo + ' | ' + (item.ziniao_account_name || '') + ' | ' + (item.ziniao_token || '') + ' | ' + (item.created_at || '') + ' | ' + (item.updated_at || '') + ' | ' +
- ' ' +
- '' +
- ' |
';
- }).join('');
- }
- renderPagination('shopKeyPagination', res.total, res.page, res.page_size, loadShopKeys);
- bindShopKeyActions();
- })
- .catch(function () {
- document.getElementById('shopKeyListBody').innerHTML = '| 璇锋眰澶辫触 |
';
- });
- }
- function bindShopKeyActions() {
- document.querySelectorAll('[data-shop-key-edit]').forEach(function (btn) {
- btn.onclick = function () {
- var item = {};
- try { item = JSON.parse((btn.dataset.shopKey || '').replace(/"/g, '"')); } catch (e) { item = {}; }
- document.getElementById('editShopKeyId').value = item.id || '';
- document.getElementById('editShopKeyZiniaoAccountName').value = item.ziniao_account_name || '';
- document.getElementById('editShopKeyZiniaoToken').value = item.ziniao_token || '';
- document.getElementById('msgEditShopKey').textContent = '';
- document.getElementById('msgEditShopKey').className = 'msg';
- document.getElementById('editShopKeyModal').classList.add('show');
- };
- });
- document.querySelectorAll('[data-shop-key-delete]').forEach(function (btn) {
- btn.onclick = function () {
- var name = (btn.dataset.ziniaoAccountName || '').replace(/"/g, '"');
- if (!confirm('纭畾鍒犻櫎搴楅摵瀵嗛挜鈥? + name + '鈥濆悧锛?)) return;
- fetch('/api/admin/shop-key/' + btn.dataset.shopKeyDelete, { method: 'DELETE' })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (res.success) { loadShopKeys(shopKeyPage); }
- else { alert(res.error || '鍒犻櫎澶辫触'); }
- });
- };
- });
- }
- document.getElementById('btnCreateShopKey').onclick = function () {
- var ziniaoAccountName = (document.getElementById('shopKeyZiniaoAccountName').value || '').trim();
- var ziniaoToken = (document.getElementById('shopKeyZiniaoToken').value || '').trim();
- var msgEl = document.getElementById('msgShopKey');
- msgEl.textContent = '';
- msgEl.className = 'msg';
- if (!ziniaoAccountName || !ziniaoToken) {
- msgEl.textContent = '璇峰畬鏁村~鍐欑传楦熻处鍙峰悕绉般€佺传楦熶护鐗?;
- msgEl.classList.add('err');
- return;
- }
- fetch('/api/admin/shop-key', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({
- ziniao_account_name: ziniaoAccountName,
- ziniao_token: ziniaoToken
- })
- })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (res.success) {
- document.getElementById('shopKeyZiniaoAccountName').value = '';
- document.getElementById('shopKeyZiniaoToken').value = '';
- msgEl.textContent = res.msg || '鍒涘缓鎴愬姛';
- msgEl.className = 'msg ok';
- loadShopKeys(1);
- } else {
- msgEl.textContent = res.error || '鍒涘缓澶辫触';
- msgEl.className = 'msg err';
- }
- })
- .catch(function () {
- msgEl.textContent = '璇锋眰澶辫触';
- msgEl.className = 'msg err';
- });
- };
- document.getElementById('btnSaveShopKey').onclick = function () {
- var itemId = document.getElementById('editShopKeyId').value;
- var ziniaoAccountName = (document.getElementById('editShopKeyZiniaoAccountName').value || '').trim();
- var ziniaoToken = (document.getElementById('editShopKeyZiniaoToken').value || '').trim();
- var msgEl = document.getElementById('msgEditShopKey');
- msgEl.textContent = '';
- msgEl.className = 'msg';
- if (!ziniaoAccountName || !ziniaoToken) {
- msgEl.textContent = '璇峰畬鏁村~鍐欑传楦熻处鍙峰悕绉般€佺传楦熶护鐗?;
- msgEl.classList.add('err');
- return;
- }
- fetch('/api/admin/shop-key/' + itemId, {
- method: 'PUT',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({
- ziniao_account_name: ziniaoAccountName,
- ziniao_token: ziniaoToken
- })
- })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (res.success) {
- document.getElementById('editShopKeyModal').classList.remove('show');
- loadShopKeys(shopKeyPage);
- } else {
- msgEl.textContent = res.error || '淇濆瓨澶辫触';
- msgEl.classList.add('err');
- }
- })
- .catch(function () {
- msgEl.textContent = '璇锋眰澶辫触';
- msgEl.classList.add('err');
- });
- };
- document.getElementById('btnCloseEditShopKey').onclick = function () {
- document.getElementById('editShopKeyModal').classList.remove('show');
- };
-
- // ========== 搴楅摵绠$悊 ==========
- var shopManagePage = 1, shopManagePageSize = 15;
- var shopManageGroups = [];
-
- function buildShopManageQuery(page) {
- var query = 'page=' + (page || 1) + '&page_size=' + shopManagePageSize;
- var groupId = (document.getElementById('shopManageFilterGroupId').value || '').trim();
- var shopName = (document.getElementById('shopManageFilterShopName').value || '').trim();
- if (groupId) query += '&group_id=' + encodeURIComponent(groupId);
- if (shopName) query += '&shop_name=' + encodeURIComponent(shopName);
- return query;
- }
-
- function refreshShopGroupSelects(selectedCreateId, selectedEditId) {
- var createSel = document.getElementById('shopManageGroupSelect');
- var editSel = document.getElementById('editShopManageGroupSelect');
- var filterSel = document.getElementById('shopManageFilterGroupId');
- var skipCreateSel = document.getElementById('skipPriceAsinGroupSelect');
- var skipFilterSel = document.getElementById('skipPriceAsinFilterGroupId');
- var chooseSkipShopSel = document.getElementById('chooseSkipPriceAsinShopGroupId');
- var selectedFilterId = filterSel ? filterSel.value : '';
- var selectedSkipCreateId = skipCreateSel ? skipCreateSel.value : '';
- var selectedSkipFilterId = skipFilterSel ? skipFilterSel.value : '';
- var selectedChooseSkipShopId = chooseSkipShopSel ? chooseSkipShopSel.value : '';
- var createOpts = [''];
- var filterOpts = [''];
- shopManageGroups.forEach(function (g) {
- var option = '';
- createOpts.push(option);
- filterOpts.push(option);
- });
- createSel.innerHTML = createOpts.join('');
- editSel.innerHTML = createOpts.join('');
- if (skipCreateSel) skipCreateSel.innerHTML = createOpts.join('');
- if (filterSel) filterSel.innerHTML = filterOpts.join('');
- if (skipFilterSel) skipFilterSel.innerHTML = filterOpts.join('');
- if (chooseSkipShopSel) chooseSkipShopSel.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;
- }
-
- function loadShopManageGroups(selectedCreateId, selectedEditId) {
- return fetch('/api/admin/shop-manage-groups')
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (!res.success) throw new Error(res.error || '鍔犺浇鍒嗙粍澶辫触');
- shopManageGroups = res.items || [];
- refreshShopGroupSelects(selectedCreateId, selectedEditId);
- return shopManageGroups;
- })
- .catch(function () {
- shopManageGroups = [];
- refreshShopGroupSelects();
- return [];
- });
- }
-
- function openShopManageGroupModal() {
- document.getElementById('shopManageGroupEditId').value = '';
- document.getElementById('shopManageGroupInput').value = '';
- document.getElementById('msgShopManageGroup').textContent = '';
- document.getElementById('msgShopManageGroup').className = 'msg';
- loadShopManageGroups().then(function () {
- renderShopManageGroupRows();
- document.getElementById('shopManageGroupModal').classList.add('show');
- });
- }
-
- function renderShopManageGroupRows() {
- var tbody = document.getElementById('shopManageGroupListBody');
- if (!shopManageGroups.length) {
- tbody.innerHTML = '| 鏆傛棤鍒嗙粍 |
';
- return;
- }
- tbody.innerHTML = shopManageGroups.map(function (item, index) {
- return '| ' + (index + 1) + ' | ' + (item.group_name || '') + ' | ' + (item.created_at || '') + ' | ' + (item.updated_at || '') + ' | ' +
- ' ' +
- '' +
- ' |
';
- }).join('');
-
- document.querySelectorAll('[data-shop-group-edit]').forEach(function (btn) {
- btn.onclick = function () {
- document.getElementById('shopManageGroupEditId').value = btn.dataset.shopGroupEdit;
- document.getElementById('shopManageGroupInput').value = (btn.dataset.shopGroupName || '').replace(/"/g, '"');
- };
- });
-
- document.querySelectorAll('[data-shop-group-delete]').forEach(function (btn) {
- btn.onclick = function () {
- var gid = btn.dataset.shopGroupDelete;
- var gname = (btn.dataset.shopGroupName || '').replace(/"/g, '"');
- if (!confirm('纭畾鍒犻櫎鍒嗙粍鈥? + gname + '鈥濆悧锛?)) return;
- fetch('/api/admin/shop-manage-group/' + gid, { method: 'DELETE' })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (!res.success) {
- alert(res.error || '鍒犻櫎澶辫触');
- return;
- }
- loadShopManageGroups().then(function () {
- renderShopManageGroupRows();
- loadShopManage(shopManagePage);
- loadSkipPriceAsin(skipPriceAsinPage);
- });
- });
- };
- });
- }
-
- function loadShopManage(page) {
- shopManagePage = page || 1;
- fetch('/api/admin/shop-manages?' + buildShopManageQuery(shopManagePage))
- .then(function (r) { return r.json(); })
- .then(function (res) {
- var tbody = document.getElementById('shopManageListBody');
- if (!res.success) {
- tbody.innerHTML = '| 鍔犺浇澶辫触: ' + (res.error || '') + ' |
';
- return;
- }
- var items = res.items || [];
- if (items.length === 0) {
- tbody.innerHTML = '| 鏆傛棤搴楅摵 |
';
- } else {
- tbody.innerHTML = items.map(function (item, index) {
- var rowNo = (shopManagePage - 1) * shopManagePageSize + index + 1;
- return '| ' + rowNo + ' | ' + (item.group_name || '') + ' | ' + (item.shop_name || '') + ' | ' + (item.mall_name || '') + ' | ' + (item.account || '') + ' | ' + (item.password || '') + ' | ' + (item.created_at || '') + ' | ' + (item.updated_at || '') + ' | ' +
- ' ' +
- '' +
- ' |
';
- }).join('');
- }
- renderPagination('shopManagePagination', res.total, res.page, res.page_size, loadShopManage);
- bindShopManageActions();
- })
- .catch(function () {
- document.getElementById('shopManageListBody').innerHTML = '| 璇锋眰澶辫触 |
';
- });
- }
-
- function bindShopManageActions() {
- document.querySelectorAll('[data-shop-manage-edit]').forEach(function (btn) {
- btn.onclick = function () {
- var item = {};
- try { item = JSON.parse((btn.dataset.shopManage || '').replace(/"/g, '"')); } catch (e) { item = {}; }
- document.getElementById('editShopManageId').value = item.id || '';
- document.getElementById('editShopManageShopName').value = item.shop_name || '';
- document.getElementById('editShopManageMallName').value = item.mall_name || '';
- document.getElementById('editShopManageAccount').value = item.account || '';
- document.getElementById('editShopManagePassword').value = item.password || '';
- document.getElementById('msgEditShopManage').textContent = '';
- document.getElementById('msgEditShopManage').className = 'msg';
- loadShopManageGroups(null, item.group_id).then(function () {
- document.getElementById('editShopManageModal').classList.add('show');
- });
- };
- });
- document.querySelectorAll('[data-shop-manage-delete]').forEach(function (btn) {
- btn.onclick = function () {
- var name = (btn.dataset.shopManageName || '').replace(/"/g, '"');
- if (!confirm('纭畾鍒犻櫎搴楅摵鈥? + name + '鈥濆悧锛?)) return;
- fetch('/api/admin/shop-manage/' + btn.dataset.shopManageDelete, { method: 'DELETE' })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (res.success) { loadShopManage(shopManagePage); }
- else { alert(res.error || '鍒犻櫎澶辫触'); }
- });
- };
- });
- }
-
- document.getElementById('btnManageShopGroups').onclick = openShopManageGroupModal;
- document.getElementById('btnManageShopGroupsFromEdit').onclick = openShopManageGroupModal;
- document.getElementById('btnSearchShopManage').onclick = function () {
- loadShopManage(1);
- };
- document.getElementById('shopManageFilterShopName').addEventListener('keydown', function (e) {
- if (e.key === 'Enter') {
- e.preventDefault();
- loadShopManage(1);
- }
- });
- document.getElementById('btnCloseShopManageGroupModal').onclick = function () {
- document.getElementById('shopManageGroupModal').classList.remove('show');
- };
- document.getElementById('btnCancelShopManageGroupEdit').onclick = function () {
- document.getElementById('shopManageGroupEditId').value = '';
- document.getElementById('shopManageGroupInput').value = '';
- };
- document.getElementById('btnSaveShopManageGroup').onclick = function () {
- var editId = (document.getElementById('shopManageGroupEditId').value || '').trim();
- var groupName = (document.getElementById('shopManageGroupInput').value || '').trim();
- var msgEl = document.getElementById('msgShopManageGroup');
- msgEl.textContent = '';
- msgEl.className = 'msg';
- if (!groupName) {
- msgEl.textContent = '璇疯緭鍏ュ垎缁勫悕绉?;
- msgEl.className = 'msg err';
- return;
- }
- var method = editId ? 'PUT' : 'POST';
- var url = editId ? ('/api/admin/shop-manage-group/' + editId) : '/api/admin/shop-manage-group';
- fetch(url, {
- method: method,
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ group_name: groupName })
- })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (!res.success) {
- msgEl.textContent = res.error || '淇濆瓨澶辫触';
- msgEl.className = 'msg err';
- return;
- }
- document.getElementById('shopManageGroupEditId').value = '';
- document.getElementById('shopManageGroupInput').value = '';
- msgEl.textContent = res.msg || '淇濆瓨鎴愬姛';
- msgEl.className = 'msg ok';
- loadShopManageGroups().then(function () {
- renderShopManageGroupRows();
- loadShopManage(shopManagePage);
- loadSkipPriceAsin(skipPriceAsinPage);
- });
- })
- .catch(function () {
- msgEl.textContent = '璇锋眰澶辫触';
- msgEl.className = 'msg err';
- });
- };
-
- function refreshShopGroupSelects(selectedCreateId, selectedEditId) {
- var createSel = document.getElementById('shopManageGroupSelect');
- var editSel = document.getElementById('editShopManageGroupSelect');
- var filterSel = document.getElementById('shopManageFilterGroupId');
- var skipCreateSel = document.getElementById('skipPriceAsinGroupSelect');
- var skipFilterSel = document.getElementById('skipPriceAsinFilterGroupId');
- var chooseSkipShopSel = document.getElementById('chooseSkipPriceAsinShopGroupId');
- var selectedFilterId = filterSel ? filterSel.value : '';
- var selectedSkipCreateId = skipCreateSel ? skipCreateSel.value : '';
- var selectedSkipFilterId = skipFilterSel ? skipFilterSel.value : '';
- var selectedChooseSkipShopId = chooseSkipShopSel ? chooseSkipShopSel.value : '';
- var createOpts = [''];
- var filterOpts = [''];
- shopManageGroups.forEach(function (g) {
- var option = '';
- createOpts.push(option);
- filterOpts.push(option);
- });
- createSel.innerHTML = createOpts.join('');
- editSel.innerHTML = createOpts.join('');
- if (skipCreateSel) skipCreateSel.innerHTML = createOpts.join('');
- if (filterSel) filterSel.innerHTML = filterOpts.join('');
- if (skipFilterSel) skipFilterSel.innerHTML = filterOpts.join('');
- if (chooseSkipShopSel) chooseSkipShopSel.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;
- }
-
- function loadShopManageGroups(selectedCreateId, selectedEditId) {
- return fetch('/api/admin/shop-manage-groups')
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (!res.success) throw new Error(res.error || '鍔犺浇鍒嗙粍澶辫触');
- shopManageGroups = res.items || [];
- refreshShopGroupSelects(selectedCreateId, selectedEditId);
- return shopManageGroups;
- })
- .catch(function () {
- shopManageGroups = [];
- refreshShopGroupSelects();
- return [];
- });
- }
-
- function resetShopManageGroupForm() {
- document.getElementById('shopManageGroupEditId').value = '';
- document.getElementById('shopManageGroupInput').value = '';
- document.getElementById('msgShopManageGroup').textContent = '';
- document.getElementById('msgShopManageGroup').className = 'msg';
- refreshShopManageGroupUserSelect('');
- }
-
- function openShopManageGroupModal() {
- resetShopManageGroupForm();
- loadUserOptions()
- .then(function () { return loadShopManageGroups(); })
- .then(function () {
- renderShopManageGroupRows();
- document.getElementById('shopManageGroupModal').classList.add('show');
- });
- }
-
- function renderShopManageGroupRows() {
- var tbody = document.getElementById('shopManageGroupListBody');
- if (!shopManageGroups.length) {
- tbody.innerHTML = '| 鏆傛棤鍒嗙粍 |
';
- return;
- }
- tbody.innerHTML = shopManageGroups.map(function (item, index) {
- return '| ' + (index + 1) + ' | ' + (item.group_name || '') + ' | ' + (item.username || '') + ' | ' + (item.created_at || '') + ' | ' + (item.updated_at || '') + ' | ' +
- ' ' +
- '' +
- ' |
';
- }).join('');
-
- document.querySelectorAll('[data-shop-group-edit]').forEach(function (btn) {
- btn.onclick = function () {
- document.getElementById('shopManageGroupEditId').value = btn.dataset.shopGroupEdit;
- refreshShopManageGroupUserSelect(btn.dataset.shopGroupUserId || '');
- };
- });
-
- document.querySelectorAll('[data-shop-group-delete]').forEach(function (btn) {
- btn.onclick = function () {
- var gid = btn.dataset.shopGroupDelete;
- var gname = (btn.dataset.shopGroupName || '').replace(/"/g, '"');
- if (!confirm('纭畾鍒犻櫎鍒嗙粍鈥? + gname + '鈥濆悧锛?)) return;
- fetch('/api/admin/shop-manage-group/' + gid, { method: 'DELETE' })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (!res.success) {
- alert(res.error || '鍒犻櫎澶辫触');
- return;
- }
- loadShopManageGroups().then(function () {
- renderShopManageGroupRows();
- loadShopManage(shopManagePage);
- loadSkipPriceAsin(skipPriceAsinPage);
- });
- });
- };
- });
- }
-
- document.getElementById('shopManageGroupUserSelect').onchange = syncShopManageGroupNameWithUser;
- document.getElementById('btnManageShopGroups').onclick = openShopManageGroupModal;
- document.getElementById('btnManageShopGroupsFromEdit').onclick = openShopManageGroupModal;
- document.getElementById('btnManageSkipPriceAsinGroups').onclick = openShopManageGroupModal;
- document.getElementById('btnCloseShopManageGroupModal').onclick = function () {
- document.getElementById('shopManageGroupModal').classList.remove('show');
- };
- document.getElementById('btnCancelShopManageGroupEdit').onclick = resetShopManageGroupForm;
- document.getElementById('btnSaveShopManageGroup').onclick = function () {
- var editId = (document.getElementById('shopManageGroupEditId').value || '').trim();
- var groupName = (document.getElementById('shopManageGroupInput').value || '').trim();
- var userId = (document.getElementById('shopManageGroupUserSelect').value || '').trim();
- var msgEl = document.getElementById('msgShopManageGroup');
- msgEl.textContent = '';
- msgEl.className = 'msg';
- if (!userId || !groupName) {
- msgEl.textContent = '璇烽€夋嫨鍏宠仈鐢ㄦ埛';
- msgEl.className = 'msg err';
- return;
- }
- var method = editId ? 'PUT' : 'POST';
- var url = editId ? ('/api/admin/shop-manage-group/' + editId) : '/api/admin/shop-manage-group';
- fetch(url, {
- method: method,
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ group_name: groupName, user_id: Number(userId) })
- })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (!res.success) {
- msgEl.textContent = res.error || '淇濆瓨澶辫触';
- msgEl.className = 'msg err';
- return;
- }
- resetShopManageGroupForm();
- msgEl.textContent = res.msg || '淇濆瓨鎴愬姛';
- msgEl.className = 'msg ok';
- loadShopManageGroups().then(function () {
- renderShopManageGroupRows();
- loadShopManage(shopManagePage);
- loadSkipPriceAsin(skipPriceAsinPage);
- });
- })
- .catch(function () {
- msgEl.textContent = '璇锋眰澶辫触';
- msgEl.className = 'msg err';
- });
- };
-
- document.getElementById('btnCreateShopManage').onclick = function () {
- var groupId = (document.getElementById('shopManageGroupSelect').value || '').trim();
- var shopName = (document.getElementById('shopManageShopName').value || '').trim();
- var mallName = (document.getElementById('shopManageMallName').value || '').trim();
- var account = (document.getElementById('shopManageAccount').value || '').trim();
- var password = (document.getElementById('shopManagePassword').value || '').trim();
- var msgEl = document.getElementById('msgShopManage');
- msgEl.textContent = '';
- msgEl.className = 'msg';
- if (!groupId || !shopName || !mallName || !account || !password) {
- msgEl.textContent = '璇峰畬鏁村~鍐欏垎缁勩€佸簵閾哄悕銆佸簵閾哄晢鍩庡悕銆佽处鍙枫€佸瘑鐮?;
- msgEl.classList.add('err');
- return;
- }
- fetch('/api/admin/shop-manage', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ group_id: Number(groupId), shop_name: shopName, mall_name: mallName, account: account, password: password })
- })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (res.success) {
- document.getElementById('shopManageGroupSelect').value = '';
- document.getElementById('shopManageShopName').value = '';
- document.getElementById('shopManageMallName').value = '';
- document.getElementById('shopManageAccount').value = '';
- document.getElementById('shopManagePassword').value = '';
- msgEl.textContent = res.msg || '鍒涘缓鎴愬姛';
- msgEl.className = 'msg ok';
- loadShopManage(1);
- } else {
- msgEl.textContent = res.error || '鍒涘缓澶辫触';
- msgEl.className = 'msg err';
- }
- })
- .catch(function () {
- msgEl.textContent = '璇锋眰澶辫触';
- msgEl.className = 'msg err';
- });
- };
-
- document.getElementById('btnSaveShopManage').onclick = function () {
- var itemId = document.getElementById('editShopManageId').value;
- var groupId = (document.getElementById('editShopManageGroupSelect').value || '').trim();
- var shopName = (document.getElementById('editShopManageShopName').value || '').trim();
- var mallName = (document.getElementById('editShopManageMallName').value || '').trim();
- var account = (document.getElementById('editShopManageAccount').value || '').trim();
- var password = (document.getElementById('editShopManagePassword').value || '').trim();
- var msgEl = document.getElementById('msgEditShopManage');
- msgEl.textContent = '';
- msgEl.className = 'msg';
- if (!groupId || !shopName || !mallName || !account || !password) {
- msgEl.textContent = '璇峰畬鏁村~鍐欏垎缁勩€佸簵閾哄悕銆佸簵閾哄晢鍩庡悕銆佽处鍙枫€佸瘑鐮?;
- msgEl.classList.add('err');
- return;
- }
- fetch('/api/admin/shop-manage/' + itemId, {
- method: 'PUT',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ group_id: Number(groupId), shop_name: shopName, mall_name: mallName, account: account, password: password })
- })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (res.success) {
- document.getElementById('editShopManageModal').classList.remove('show');
- loadShopManage(shopManagePage);
- } else {
- msgEl.textContent = res.error || '淇濆瓨澶辫触';
- msgEl.classList.add('err');
- }
- })
- .catch(function () {
- msgEl.textContent = '璇锋眰澶辫触';
- msgEl.classList.add('err');
- });
- };
- document.getElementById('btnCloseEditShopManage').onclick = function () {
- document.getElementById('editShopManageModal').classList.remove('show');
- };
-
- // ========== 鐗堟湰绠$悊 ==========
- // ========== 璺宠繃璺熶环 ASIN ==========
- var skipPriceAsinPage = 1, skipPriceAsinPageSize = 15;
- var chooseSkipPriceAsinShopPage = 1, chooseSkipPriceAsinShopPageSize = 10;
- var skipPriceCountryColumns = [
- { 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 buildChooseSkipPriceAsinShopQuery(page) {
- var query = 'page=' + (page || 1) + '&page_size=' + chooseSkipPriceAsinShopPageSize;
- var groupId = (document.getElementById('chooseSkipPriceAsinShopGroupId').value || '').trim();
- var shopName = (document.getElementById('chooseSkipPriceAsinShopKeyword').value || '').trim();
- if (groupId) query += '&group_id=' + encodeURIComponent(groupId);
- if (shopName) query += '&shop_name=' + encodeURIComponent(shopName);
- return query;
- }
- function loadChooseSkipPriceAsinShops(page) {
- chooseSkipPriceAsinShopPage = page || 1;
- fetch('/api/admin/shop-manages?' + buildChooseSkipPriceAsinShopQuery(chooseSkipPriceAsinShopPage))
- .then(function (r) { return r.json(); })
- .then(function (res) {
- var tbody = document.getElementById('chooseSkipPriceAsinShopListBody');
- if (!res.success) {
- tbody.innerHTML = '| 鍔犺浇澶辫触: ' + (res.error || '') + ' |
';
- return;
- }
- var items = res.items || [];
- if (!items.length) {
- tbody.innerHTML = '| 鏆傛棤搴楅摵 |
';
- } else {
- tbody.innerHTML = items.map(function (item, index) {
- var rowNo = (chooseSkipPriceAsinShopPage - 1) * chooseSkipPriceAsinShopPageSize + index + 1;
- return '| ' + rowNo + ' | ' + (item.group_name || '') + ' | ' + (item.shop_name || '') + ' | ' + (item.mall_name || '') + ' | ' + (item.account || '') + ' | ' +
- '' +
- ' |
';
- }).join('');
- }
- renderPagination('chooseSkipPriceAsinShopPagination', res.total, res.page, res.page_size, loadChooseSkipPriceAsinShops);
- bindChooseSkipPriceAsinShopActions();
- })
- .catch(function () {
- document.getElementById('chooseSkipPriceAsinShopListBody').innerHTML = '| 璇锋眰澶辫触 |
';
- });
- }
- function bindChooseSkipPriceAsinShopActions() {
- document.querySelectorAll('[data-choose-skip-price-asin-shop]').forEach(function (btn) {
- btn.onclick = function () {
- document.getElementById('skipPriceAsinShopName').value = (btn.dataset.shopName || '').replace(/"/g, '"');
- if (!document.getElementById('skipPriceAsinGroupSelect').value && btn.dataset.groupId) {
- document.getElementById('skipPriceAsinGroupSelect').value = btn.dataset.groupId;
- }
- document.getElementById('chooseSkipPriceAsinShopModal').classList.remove('show');
- };
- });
- }
- function openChooseSkipPriceAsinShopModal() {
- var currentGroupId = (document.getElementById('skipPriceAsinGroupSelect').value || '').trim();
- if (currentGroupId) {
- document.getElementById('chooseSkipPriceAsinShopGroupId').value = currentGroupId;
- }
- document.getElementById('chooseSkipPriceAsinShopKeyword').value = (document.getElementById('skipPriceAsinShopName').value || '').trim();
- document.getElementById('chooseSkipPriceAsinShopModal').classList.add('show');
- loadChooseSkipPriceAsinShops(1);
- }
- function setupSkipPriceAsinShopPicker() {
- var input = document.getElementById('skipPriceAsinShopName');
- var button = document.getElementById('btnChooseSkipPriceAsinShop');
- if (!input || !button) return;
- var inputParent = input.parentNode;
- if (inputParent && inputParent.style && inputParent.style.display === 'flex') return;
- var legacyWrap = button.parentNode;
- var wrapper = document.createElement('div');
- wrapper.style.display = 'flex';
- wrapper.style.gap = '8px';
- wrapper.style.alignItems = 'center';
- input.parentNode.insertBefore(wrapper, input);
- wrapper.appendChild(input);
- wrapper.appendChild(button);
- button.style.whiteSpace = 'nowrap';
- button.style.marginTop = '0';
- if (legacyWrap && legacyWrap !== wrapper) {
- legacyWrap.style.display = 'none';
- }
- }
- function getSelectedSkipPriceCountries() {
- return Array.from(document.getElementById('skipPriceAsinCountries').selectedOptions).map(function (option) {
- return option.value;
- });
- }
- function renderSkipPriceAsinInputs() {
- var container = document.getElementById('skipPriceAsinInputs');
- var selectedCountries = getSelectedSkipPriceCountries();
- var existingValues = {};
- container.querySelectorAll('[data-skip-price-country-input]').forEach(function (input) {
- existingValues[input.getAttribute('data-skip-price-country-input')] = input.value;
- });
- if (!selectedCountries.length) {
- container.innerHTML = '璇烽€夋嫨鍥藉鍚庤緭鍏?ASIN
';
- return;
- }
- container.innerHTML = selectedCountries.map(function (countryCode) {
- var country = skipPriceCountryColumns.find(function (item) { return item.code === countryCode; });
- var label = country ? country.label : countryCode;
- var value = existingValues[countryCode] || '';
- return '' +
- '' + label + '' +
- '' +
- '
';
- }).join('');
- }
- function collectSkipPriceAsinMappings(countries) {
- var mappings = {};
- for (var i = 0; i < countries.length; i++) {
- var countryCode = countries[i];
- var input = document.querySelector('[data-skip-price-country-input="' + countryCode + '"]');
- var asin = input ? (input.value || '').trim().toUpperCase() : '';
- if (!asin) {
- var country = skipPriceCountryColumns.find(function (item) { return item.code === countryCode; });
- var label = country ? country.label : countryCode;
- throw new Error(label + ' ASIN 涓嶈兘涓虹┖');
- }
- mappings[countryCode] = asin;
- }
- return mappings;
- }
- function buildSkipPriceAsinQuery(page) {
- var query = 'page=' + (page || 1) + '&page_size=' + skipPriceAsinPageSize;
- var groupId = (document.getElementById('skipPriceAsinFilterGroupId').value || '').trim();
- var shopName = (document.getElementById('skipPriceAsinFilterShopName').value || '').trim();
- var asin = (document.getElementById('skipPriceAsinFilterAsin').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 renderSkipPriceAsinCell(item, country) {
- var value = item[country.field] || '';
- if (!value) return '-';
- return '' +
- '' + value + '' +
- '' +
- '' +
- '
';
- }
- function bindSkipPriceAsinActions() {
- document.querySelectorAll('[data-skip-price-asin-edit]').forEach(function (btn) {
- btn.onclick = function () {
- var shopName = (btn.dataset.shopName || '').replace(/"/g, '"');
- var countryCode = btn.dataset.country || '';
- var currentAsin = (btn.dataset.asin || '').replace(/"/g, '"');
- var nextAsin = prompt('璇疯緭鍏ュ簵閾衡€? + shopName + '鈥濆湪 ' + countryCode + ' 鐨?ASIN', currentAsin);
- if (nextAsin === null) return;
- nextAsin = (nextAsin || '').trim();
- if (!nextAsin) {
- alert('ASIN 涓嶈兘涓虹┖');
- return;
- }
- fetch('/api/admin/skip-price-asin/' + btn.dataset.skipPriceAsinEdit + '/country/' + countryCode, {
- method: 'PUT',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ asin: nextAsin })
- })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (res.success) loadSkipPriceAsin(skipPriceAsinPage);
- else alert(res.error || '淇濆瓨澶辫触');
- });
- };
- });
- document.querySelectorAll('[data-skip-price-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/skip-price-asin/' + btn.dataset.skipPriceAsinDelete + '/country/' + countryCode, {
- method: 'DELETE'
- })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (res.success) loadSkipPriceAsin(skipPriceAsinPage);
- else alert(res.error || '鍒犻櫎澶辫触');
- });
- };
- });
- }
- function loadSkipPriceAsin(page) {
- skipPriceAsinPage = page || 1;
- fetch('/api/admin/skip-price-asins?' + buildSkipPriceAsinQuery(skipPriceAsinPage))
- .then(function (r) { return r.json(); })
- .then(function (res) {
- var tbody = document.getElementById('skipPriceAsinListBody');
- if (!res.success) {
- tbody.innerHTML = '| 鍔犺浇澶辫触: ' + (res.error || '') + ' |
';
- return;
- }
- var items = res.items || [];
- if (items.length === 0) {
- tbody.innerHTML = '| 鏆傛棤鏁版嵁 |
';
- } else {
- tbody.innerHTML = items.map(function (item, index) {
- var rowNo = (skipPriceAsinPage - 1) * skipPriceAsinPageSize + index + 1;
- return '| ' + rowNo + ' | ' + (item.group_name || '') + ' | ' + (item.shop_name || '') + ' | ' +
- skipPriceCountryColumns.map(function (country) {
- return '' + renderSkipPriceAsinCell(item, country) + ' | ';
- }).join('') +
- '
';
- }).join('');
- }
- renderPagination('skipPriceAsinPagination', res.total, res.page, res.page_size, loadSkipPriceAsin);
- bindSkipPriceAsinActions();
- })
- .catch(function () {
- document.getElementById('skipPriceAsinListBody').innerHTML = '| 璇锋眰澶辫触 |
';
- });
- }
- document.getElementById('btnManageSkipPriceAsinGroups').onclick = openShopManageGroupModal;
- document.getElementById('btnChooseSkipPriceAsinShop').onclick = openChooseSkipPriceAsinShopModal;
- document.getElementById('btnSearchChooseSkipPriceAsinShop').onclick = function () {
- loadChooseSkipPriceAsinShops(1);
- };
- document.getElementById('chooseSkipPriceAsinShopGroupId').onchange = function () {
- loadChooseSkipPriceAsinShops(1);
- };
- document.getElementById('chooseSkipPriceAsinShopKeyword').addEventListener('keydown', function (e) {
- if (e.key === 'Enter') {
- e.preventDefault();
- loadChooseSkipPriceAsinShops(1);
- }
- });
- document.getElementById('btnCloseChooseSkipPriceAsinShopModal').onclick = function () {
- document.getElementById('chooseSkipPriceAsinShopModal').classList.remove('show');
- };
- document.getElementById('skipPriceAsinCountries').addEventListener('change', renderSkipPriceAsinInputs);
- document.getElementById('btnSearchSkipPriceAsin').onclick = function () {
- loadSkipPriceAsin(1);
- };
- document.getElementById('skipPriceAsinFilterShopName').addEventListener('keydown', function (e) {
- if (e.key === 'Enter') {
- e.preventDefault();
- loadSkipPriceAsin(1);
- }
- });
- document.getElementById('skipPriceAsinFilterAsin').addEventListener('keydown', function (e) {
- if (e.key === 'Enter') {
- e.preventDefault();
- loadSkipPriceAsin(1);
- }
- });
- document.getElementById('btnCreateSkipPriceAsin').onclick = function () {
- var groupId = (document.getElementById('skipPriceAsinGroupSelect').value || '').trim();
- var shopName = (document.getElementById('skipPriceAsinShopName').value || '').trim();
- var countries = getSelectedSkipPriceCountries();
- var msgEl = document.getElementById('msgSkipPriceAsin');
- msgEl.textContent = '';
- msgEl.className = 'msg';
- if (!groupId || !shopName || !countries.length) {
- msgEl.textContent = '璇峰畬鏁村~鍐欏垎缁勩€佸簵閾哄悕銆佸浗瀹跺拰 ASIN';
- msgEl.className = 'msg err';
- return;
- }
- var asinMappings = {};
- try {
- asinMappings = collectSkipPriceAsinMappings(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/skip-price-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('skipPriceAsinGroupSelect').value = '';
- document.getElementById('skipPriceAsinShopName').value = '';
- Array.from(document.getElementById('skipPriceAsinCountries').options).forEach(function (option) {
- option.selected = false;
- });
- renderSkipPriceAsinInputs();
- msgEl.textContent = res.msg || '淇濆瓨鎴愬姛';
- msgEl.className = 'msg ok';
- loadSkipPriceAsin(1);
- })
- .catch(function () {
- msgEl.textContent = '璇锋眰澶辫触';
- msgEl.className = 'msg err';
- });
- };
- setupSkipPriceAsinShopPicker();
- renderSkipPriceAsinInputs();
- function loadVersions() {
- fetch('/api/admin/versions')
- .then(function (r) { return r.json(); })
- .then(function (res) {
- var tbody = document.getElementById('versionListBody');
- if (!res.success) {
- tbody.innerHTML = '| 鍔犺浇澶辫触: ' + (res.error || '') + ' |
';
- return;
- }
- var items = res.items || [];
- if (items.length === 0) {
- tbody.innerHTML = '| 鏆傛棤鐗堟湰璁板綍 |
';
- } else {
- tbody.innerHTML = items.map(function (v) {
- var url = (v.file_url || '').replace(/"/g, '"');
- return '| ' + (v.version || '') + ' | ' + url + ' | ' + (v.created_at || '') + ' | 涓嬭浇 |
';
- }).join('');
- }
- })
- .catch(function () {
- document.getElementById('versionListBody').innerHTML = '| 璇锋眰澶辫触 |
';
- });
- }
- document.getElementById('btnUploadVersion').onclick = function () {
- var version = (document.getElementById('versionNumber').value || '').trim();
- var fileInput = document.getElementById('versionZip');
- var msgEl = document.getElementById('msgVersion');
- msgEl.textContent = '';
- msgEl.className = 'msg';
- if (!version) {
- msgEl.textContent = '璇峰~鍐欑増鏈彿';
- msgEl.classList.add('err');
- return;
- }
- if (!fileInput.files || fileInput.files.length === 0) {
- msgEl.textContent = '璇烽€夋嫨 zip 鍘嬬缉鍖?;
- msgEl.classList.add('err');
- return;
- }
- var file = fileInput.files[0];
- if (!(file.name || '').toLowerCase().endsWith('.zip')) {
- msgEl.textContent = '浠呮敮鎸?.zip 鏍煎紡';
- msgEl.classList.add('err');
- return;
- }
- var formData = new FormData();
- formData.append('version', version);
- formData.append('file', file);
- msgEl.textContent = '涓婁紶涓?..';
- msgEl.classList.remove('err', 'ok');
- fetch('/api/admin/version', {
- method: 'POST',
- body: formData
- })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (res.success) {
- msgEl.textContent = '鍙戝竷鎴愬姛銆傜増鏈細' + res.version + '锛岄摼鎺ワ細' + (res.file_url || '');
- msgEl.classList.add('ok');
- document.getElementById('versionNumber').value = '';
- fileInput.value = '';
- loadVersions();
- } else {
- msgEl.textContent = res.error || '涓婁紶澶辫触';
- msgEl.classList.add('err');
- }
- })
- .catch(function () {
- msgEl.textContent = '璇锋眰澶辫触';
- msgEl.classList.add('err');
- });
- };
-
- // ========== 鏍忕洰鏉冮檺閰嶇疆 ==========
- function loadColumns() {
- fetch('/api/admin/columns')
- .then(function (r) { return r.json(); })
- .then(function (res) {
- var tbody = document.getElementById('columnListBody');
- if (!res.success) {
- tbody.innerHTML = '| 鍔犺浇澶辫触: ' + (res.error || '') + ' |
';
- return;
- }
- allColumnsList = res.items || [];
- if (allColumnsList.length === 0) {
- tbody.innerHTML = '| 鏆傛棤鑿滃崟锛岃鍦ㄤ笂鏂规柊澧?/td> |
';
- } else {
- tbody.innerHTML = allColumnsList.map(function (c) {
- return '| ' + c.id + ' | ' + (c.name || '') + ' | ' + (c.column_key || '') + ' | ' + (c.created_at || '') + ' | ' +
- ' ' +
- ' |
';
- }).join('');
- }
- bindColumnActions();
- })
- .catch(function () {
- document.getElementById('columnListBody').innerHTML = '| 璇锋眰澶辫触 |
';
- });
- }
- function bindColumnActions() {
- document.querySelectorAll('[data-column-edit]').forEach(function (btn) {
- btn.onclick = function () {
- document.getElementById('editColumnId').value = btn.dataset.columnEdit || '';
- document.getElementById('editColumnName').value = (btn.dataset.name || '').replace(/"/g, '"');
- document.getElementById('editColumnKey').value = (btn.dataset.key || '').replace(/"/g, '"');
- document.getElementById('msgEditColumn').textContent = '';
- document.getElementById('editColumnModal').classList.add('show');
- };
- });
- document.querySelectorAll('[data-column-delete]').forEach(function (btn) {
- btn.onclick = function () {
- if (!confirm('纭畾鍒犻櫎鑿滃崟鈥? + (btn.dataset.name || '').replace(/"/g, '"') + '鈥濆悧锛?)) return;
- fetch('/api/admin/column/' + btn.dataset.columnDelete, { method: 'DELETE' })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (res.success) { loadColumns(); loadColumnsForPermission(); loadAdminMenus(getActiveAdminTabName()); }
- else { alert(res.error || '鍒犻櫎澶辫触'); }
- });
- };
- });
- }
- document.getElementById('btnAddColumn').onclick = function () {
- var name = (document.getElementById('columnName').value || '').trim();
- var key = (document.getElementById('columnKey').value || '').trim();
- var msgEl = document.getElementById('msgColumn');
- msgEl.textContent = '';
- msgEl.className = 'msg';
- if (!name) { msgEl.textContent = '璇峰~鍐欒彍鍗曞悕绉?; msgEl.classList.add('err'); return; }
- if (!key) {
- msgEl.textContent = '璇峰~鍐欐爮鐩爣璇?; msgEl.classList.add('err'); return;
- }
- fetch('/api/admin/column', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ name: name, column_key: key })
- })
- .then(function (r) { return r.json(); })
- .then(function (res) {
- if (res.success) {
- msgEl.textContent = res.msg || '鏂板鎴愬姛';
- msgEl.classList.add('ok');
- document.getElementById('columnName').value = '';
- document.getElementById('columnKey').value = '';
- loadColumns();
- loadColumnsForPermission();
- loadAdminMenus(getActiveAdminTabName());
- } else {
diff --git a/backend/web_source/admin.html b/backend/web_source/admin.html
index ccfb20b..cc8d4f7 100644
--- a/backend/web_source/admin.html
+++ b/backend/web_source/admin.html
@@ -227,6 +227,65 @@
color: #666;
}
+ .request-loading-bar {
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 0;
+ height: 3px;
+ background: #667eea;
+ opacity: 0;
+ z-index: 3000;
+ transition: width 0.2s ease, opacity 0.2s ease;
+ }
+
+ .request-loading-bar.show {
+ width: 74%;
+ opacity: 1;
+ }
+
+ .request-loading-bar.finishing {
+ width: 100%;
+ opacity: 0;
+ }
+
+ .request-loading {
+ position: fixed;
+ right: 24px;
+ top: 72px;
+ display: none;
+ align-items: center;
+ gap: 10px;
+ padding: 10px 14px;
+ color: #333;
+ background: rgba(255, 255, 255, 0.96);
+ border: 1px solid #e6eaf2;
+ border-radius: 8px;
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
+ font-size: 13px;
+ z-index: 3000;
+ pointer-events: none;
+ }
+
+ .request-loading.show {
+ display: flex;
+ }
+
+ .request-spinner {
+ width: 16px;
+ height: 16px;
+ border: 2px solid #dce2ff;
+ border-top-color: #667eea;
+ border-radius: 50%;
+ animation: request-spin 0.8s linear infinite;
+ }
+
+ @keyframes request-spin {
+ to {
+ transform: rotate(360deg);
+ }
+ }
+
table {
width: 100%;
border-collapse: collapse;
@@ -336,6 +395,178 @@
font-size: 16px;
}
+ #shopManageGroupModal .shop-group-modal {
+ width: min(1180px, calc(100vw - 48px));
+ max-width: none;
+ max-height: calc(100vh - 48px);
+ padding: 0;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .shop-group-modal-header {
+ padding: 20px 24px 14px;
+ border-bottom: 1px solid #edf0f5;
+ flex: 0 0 auto;
+ }
+
+ .shop-group-modal-header h3 {
+ margin: 0;
+ }
+
+ .shop-group-editor {
+ padding: 18px 24px 14px;
+ display: grid;
+ grid-template-columns: minmax(180px, 240px) minmax(240px, 320px) minmax(360px, 1fr);
+ gap: 16px;
+ align-items: start;
+ flex: 0 0 auto;
+ }
+
+ .shop-group-editor .form-group {
+ margin-bottom: 0;
+ }
+
+ .shop-group-member-select {
+ min-height: 128px;
+ max-height: 180px;
+ }
+
+ .shop-group-help {
+ color: #777;
+ font-size: 12px;
+ line-height: 1.5;
+ margin-top: 6px;
+ }
+
+ .shop-group-action-bar {
+ padding: 0 24px 12px;
+ display: flex;
+ gap: 8px;
+ justify-content: flex-end;
+ align-items: center;
+ flex: 0 0 auto;
+ }
+
+ #msgShopManageGroup {
+ margin: 0;
+ padding: 0 24px 10px;
+ min-height: 18px;
+ flex: 0 0 auto;
+ }
+
+ .shop-group-table-wrap {
+ margin: 0 24px;
+ border: 1px solid #edf0f5;
+ border-radius: 8px;
+ overflow: auto;
+ min-height: 220px;
+ flex: 1 1 auto;
+ }
+
+ .shop-group-table {
+ min-width: 1040px;
+ table-layout: fixed;
+ }
+
+ .shop-group-table th {
+ position: sticky;
+ top: 0;
+ z-index: 1;
+ }
+
+ .shop-group-table th,
+ .shop-group-table td {
+ vertical-align: top;
+ }
+
+ .shop-group-table .col-index {
+ width: 58px;
+ }
+
+ .shop-group-table .col-name {
+ width: 130px;
+ }
+
+ .shop-group-table .col-leader {
+ width: 110px;
+ }
+
+ .shop-group-table .col-count {
+ width: 86px;
+ }
+
+ .shop-group-table .col-members {
+ width: auto;
+ }
+
+ .shop-group-table .col-time {
+ width: 120px;
+ }
+
+ .shop-group-table .col-action {
+ width: 128px;
+ }
+
+ .shop-group-time-cell,
+ .shop-group-action-cell {
+ white-space: nowrap;
+ }
+
+ .shop-group-name-cell,
+ .shop-group-leader-cell {
+ word-break: break-word;
+ }
+
+ .shop-group-members {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ max-height: 96px;
+ overflow-y: auto;
+ padding-right: 4px;
+ }
+
+ .shop-group-member-chip {
+ display: inline-flex;
+ align-items: center;
+ max-width: 150px;
+ padding: 3px 8px;
+ border-radius: 999px;
+ background: #eef1ff;
+ color: #4f63d8;
+ font-size: 12px;
+ line-height: 1.4;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .shop-group-modal-footer {
+ padding: 14px 24px 18px;
+ display: flex;
+ gap: 8px;
+ justify-content: flex-end;
+ border-top: 1px solid #edf0f5;
+ flex: 0 0 auto;
+ }
+
+ @media (max-width: 900px) {
+ #shopManageGroupModal .shop-group-modal {
+ width: calc(100vw - 24px);
+ max-height: calc(100vh - 24px);
+ }
+
+ .shop-group-editor {
+ grid-template-columns: 1fr;
+ }
+
+ .shop-group-table-wrap {
+ margin: 0 16px;
+ }
+ }
+
.column-permission-cards {
display: flex;
flex-wrap: wrap;
@@ -347,6 +578,97 @@
overflow: hidden;
}
+ .multi-select-native {
+ position: absolute;
+ opacity: 0;
+ pointer-events: none;
+ width: 1px !important;
+ height: 1px !important;
+ min-height: 0 !important;
+ padding: 0 !important;
+ border: 0 !important;
+ }
+
+ .multi-select-dropdown {
+ position: relative;
+ width: 100%;
+ }
+
+ .multi-select-trigger {
+ width: 100%;
+ min-height: 42px;
+ padding: 10px 34px 10px 12px;
+ border: 1px solid #ddd;
+ border-radius: 6px;
+ background: #fff;
+ color: #333;
+ font-size: 14px;
+ text-align: left;
+ cursor: pointer;
+ position: relative;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .multi-select-trigger::after {
+ content: "";
+ position: absolute;
+ right: 12px;
+ top: 50%;
+ width: 7px;
+ height: 7px;
+ border-right: 1.5px solid #666;
+ border-bottom: 1.5px solid #666;
+ transform: translateY(-65%) rotate(45deg);
+ }
+
+ .multi-select-dropdown.open .multi-select-trigger {
+ border-color: #667eea;
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.12);
+ }
+
+ .multi-select-panel {
+ display: none;
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: calc(100% + 6px);
+ z-index: 30;
+ background: #fff;
+ border: 1px solid #ddd;
+ border-radius: 8px;
+ box-shadow: 0 12px 28px rgba(0, 0, 0, 0.14);
+ padding: 6px;
+ max-height: 220px;
+ overflow-y: auto;
+ }
+
+ .multi-select-dropdown.open .multi-select-panel {
+ display: block;
+ }
+
+ .multi-select-option {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ min-height: 34px;
+ padding: 7px 8px;
+ border-radius: 6px;
+ cursor: pointer;
+ font-size: 14px;
+ color: #333;
+ }
+
+ .multi-select-option:hover {
+ background: #f4f6ff;
+ }
+
+ .multi-select-option input {
+ width: auto;
+ margin: 0;
+ }
+
.column-permission-card {
display: inline-flex;
align-items: center;
@@ -398,6 +720,11 @@
+
+
+
+ 请求处理中...
+
管理后台
@@ -762,7 +1089,7 @@
-