5441 lines
211 KiB
HTML
5441 lines
211 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<link rel="icon" href="data:,">
|
|
<title>管理后台 - 数富AI</title>
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
:root {
|
|
--c-primary: #6366f1;
|
|
--c-primary-strong: #5457e8;
|
|
--c-primary-soft: #eef0fe;
|
|
--c-bg: #f2f4f8;
|
|
--c-card: #ffffff;
|
|
--c-border: #e5e8f0;
|
|
--c-text: #1c2333;
|
|
--c-text-2: #5d6675;
|
|
--c-text-3: #98a1b3;
|
|
--c-danger: #e5484d;
|
|
--c-danger-soft: #fdecec;
|
|
--c-success: #18a058;
|
|
--c-warning: #d97706;
|
|
--c-sidebar: #181d2b;
|
|
--c-sidebar-2: #212839;
|
|
--c-sidebar-text: #a8b1c7;
|
|
--radius: 12px;
|
|
--radius-sm: 8px;
|
|
--shadow-card: 0 1px 2px rgba(16, 24, 40, 0.04), 0 6px 16px -8px rgba(16, 24, 40, 0.08);
|
|
--shadow-pop: 0 12px 32px rgba(16, 24, 40, 0.14);
|
|
}
|
|
|
|
body {
|
|
font-family: "Microsoft YaHei", "PingFang SC", "Helvetica Neue", sans-serif;
|
|
background: var(--c-bg);
|
|
color: var(--c-text);
|
|
}
|
|
|
|
.admin-layout {
|
|
display: grid;
|
|
grid-template-columns: 236px minmax(0, 1fr);
|
|
min-height: 100vh;
|
|
}
|
|
|
|
/* ===== 侧边栏 ===== */
|
|
.admin-sidebar {
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: linear-gradient(180deg, var(--c-sidebar-2) 0%, var(--c-sidebar) 100%);
|
|
color: var(--c-sidebar-text);
|
|
border-right: 1px solid rgba(255, 255, 255, 0.05);
|
|
position: sticky;
|
|
top: 0;
|
|
height: 100vh;
|
|
overflow: hidden;
|
|
z-index: 30;
|
|
}
|
|
|
|
.admin-brand {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
padding: 18px 16px 16px;
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
|
}
|
|
|
|
.admin-brand-mark {
|
|
flex: 0 0 auto;
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: 9px;
|
|
background: linear-gradient(135deg, #6366f1, #7a8bf0);
|
|
color: #fff;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 15px;
|
|
font-weight: 700;
|
|
box-shadow: 0 4px 10px rgba(99, 102, 241, 0.35);
|
|
}
|
|
|
|
.admin-brand-text {
|
|
min-width: 0;
|
|
line-height: 1.2;
|
|
}
|
|
|
|
.admin-brand-name {
|
|
display: block;
|
|
color: #fff;
|
|
font-size: 15px;
|
|
font-weight: 600;
|
|
letter-spacing: 0.5px;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.admin-brand-sub {
|
|
display: block;
|
|
font-size: 11px;
|
|
color: #7b8398;
|
|
margin-top: 2px;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.admin-menu {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
padding: 6px 10px 16px;
|
|
}
|
|
|
|
.admin-menu::-webkit-scrollbar {
|
|
width: 6px;
|
|
}
|
|
|
|
.admin-menu::-webkit-scrollbar-thumb {
|
|
background: rgba(255, 255, 255, 0.12);
|
|
border-radius: 99px;
|
|
}
|
|
|
|
.menu-group {
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.menu-group:first-child {
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.menu-group-title {
|
|
display: flex;
|
|
align-items: center;
|
|
width: 100%;
|
|
padding: 9px 11px;
|
|
border: 0;
|
|
border-radius: 8px;
|
|
background: transparent;
|
|
color: #8a93ab;
|
|
font-family: inherit;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
letter-spacing: 1.2px;
|
|
cursor: pointer;
|
|
text-align: left;
|
|
user-select: none;
|
|
transition: color 0.15s ease, background 0.15s ease;
|
|
}
|
|
|
|
.menu-group-title:hover {
|
|
color: #c3cadd;
|
|
background: rgba(255, 255, 255, 0.04);
|
|
}
|
|
|
|
.menu-group-title:focus-visible {
|
|
outline: 2px solid #8b8ff5;
|
|
outline-offset: -2px;
|
|
}
|
|
|
|
.menu-group-chevron {
|
|
flex: 0 0 auto;
|
|
display: inline-flex;
|
|
width: 13px;
|
|
height: 13px;
|
|
margin-left: auto;
|
|
color: currentColor;
|
|
transition: transform 0.18s ease;
|
|
}
|
|
|
|
.menu-group-chevron svg {
|
|
width: 13px;
|
|
height: 13px;
|
|
}
|
|
|
|
.menu-group.is-collapsed .menu-group-chevron {
|
|
transform: rotate(-90deg);
|
|
}
|
|
|
|
.menu-group.is-collapsed .menu-group-body {
|
|
display: none;
|
|
}
|
|
|
|
.menu-group-body {
|
|
padding: 3px 0 6px;
|
|
}
|
|
|
|
.menu-empty {
|
|
padding: 24px 12px;
|
|
text-align: center;
|
|
color: #69718a;
|
|
font-size: 13px;
|
|
}
|
|
|
|
/* 菜单项(保留 .tab 类名兼容权限显隐逻辑) */
|
|
.tab {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
padding: 9px 12px;
|
|
margin-bottom: 2px;
|
|
border-radius: 8px;
|
|
color: var(--c-sidebar-text);
|
|
font-size: 13.5px;
|
|
cursor: pointer;
|
|
position: relative;
|
|
user-select: none;
|
|
transition: background 0.15s ease, color 0.15s ease;
|
|
}
|
|
|
|
.tab:hover {
|
|
background: rgba(255, 255, 255, 0.06);
|
|
color: #fff;
|
|
}
|
|
|
|
.tab.active {
|
|
background: rgba(102, 126, 234, 0.20);
|
|
color: #fff;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.tab.active::before {
|
|
content: "";
|
|
position: absolute;
|
|
left: 0;
|
|
top: 22%;
|
|
bottom: 22%;
|
|
width: 3px;
|
|
border-radius: 99px;
|
|
background: #8b8ff5;
|
|
}
|
|
|
|
.adm-icon {
|
|
flex: 0 0 auto;
|
|
display: inline-flex;
|
|
width: 18px;
|
|
height: 18px;
|
|
color: #8991a6;
|
|
}
|
|
|
|
.tab:hover .adm-icon,
|
|
.tab.active .adm-icon {
|
|
color: #8fa0f3;
|
|
}
|
|
|
|
.adm-icon svg {
|
|
width: 18px;
|
|
height: 18px;
|
|
}
|
|
|
|
.adm-label {
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.admin-sidebar-foot {
|
|
padding: 12px 16px;
|
|
font-size: 11px;
|
|
color: #59627a;
|
|
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* ===== 主内容区 ===== */
|
|
.admin-main {
|
|
min-width: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.admin-topbar {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 20;
|
|
height: 56px;
|
|
background: rgba(255, 255, 255, 0.92);
|
|
backdrop-filter: blur(8px);
|
|
border-bottom: 1px solid var(--c-border);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
padding: 0 24px;
|
|
}
|
|
|
|
.admin-page-title {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
color: var(--c-text);
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.admin-user-box {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
flex: 0 0 auto;
|
|
}
|
|
|
|
.admin-user-avatar {
|
|
width: 30px;
|
|
height: 30px;
|
|
border-radius: 50%;
|
|
background: linear-gradient(135deg, #6366f1, #7a8bf0);
|
|
color: #fff;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
flex: 0 0 auto;
|
|
box-shadow: 0 2px 6px rgba(99, 102, 241, 0.3);
|
|
}
|
|
|
|
.admin-user-name {
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
color: var(--c-text);
|
|
max-width: 220px;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.admin-user-role {
|
|
font-size: 12px;
|
|
color: var(--c-primary-strong);
|
|
background: var(--c-primary-soft);
|
|
padding: 3px 9px;
|
|
border-radius: 999px;
|
|
white-space: nowrap;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.admin-user-logout {
|
|
padding: 6px 14px;
|
|
font-size: 12.5px;
|
|
font-weight: 500;
|
|
background: #fff;
|
|
color: var(--c-text-2);
|
|
border: 1px solid var(--c-border);
|
|
border-radius: var(--radius-sm);
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
|
|
}
|
|
|
|
.admin-user-logout:hover {
|
|
color: var(--c-primary);
|
|
border-color: #b9bcf3;
|
|
background: var(--c-primary-soft);
|
|
opacity: 1;
|
|
}
|
|
|
|
.admin-content {
|
|
flex: 1;
|
|
padding: 20px 24px 40px;
|
|
}
|
|
|
|
.tab-panel {
|
|
display: none;
|
|
}
|
|
|
|
.tab-panel.active {
|
|
display: block;
|
|
}
|
|
|
|
/* Form & Table */
|
|
.form-box,
|
|
.panel-box {
|
|
background: var(--c-card);
|
|
border: 1px solid var(--c-border);
|
|
border-radius: var(--radius);
|
|
padding: 24px;
|
|
margin-bottom: 20px;
|
|
box-shadow: var(--shadow-card);
|
|
}
|
|
|
|
.form-box > h3:first-child,
|
|
.panel-box > h3:first-child {
|
|
margin-bottom: 16px;
|
|
font-size: 15px;
|
|
font-weight: 600;
|
|
color: var(--c-text);
|
|
}
|
|
|
|
.form-box > p:first-child {
|
|
margin: -6px 0 16px;
|
|
}
|
|
|
|
.form-group {
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.form-group label {
|
|
display: block;
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
color: var(--c-text-2);
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.form-group input,
|
|
.form-group select,
|
|
.form-group textarea,
|
|
.form-group input[type="search"] {
|
|
width: 100%;
|
|
padding: 9px 12px;
|
|
border: 1px solid var(--c-border);
|
|
border-radius: var(--radius-sm);
|
|
background: #fbfcfe;
|
|
color: var(--c-text);
|
|
font: inherit;
|
|
font-size: 13.5px;
|
|
transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
|
|
}
|
|
|
|
.form-group input:focus,
|
|
.form-group select:focus,
|
|
.form-group textarea:focus {
|
|
outline: none;
|
|
border-color: var(--c-primary);
|
|
background: #fff;
|
|
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.12);
|
|
}
|
|
|
|
.form-group input::placeholder,
|
|
.form-group textarea::placeholder {
|
|
color: var(--c-text-3);
|
|
}
|
|
|
|
.form-group input[type="file"] {
|
|
padding: 7px 10px;
|
|
background: #fff;
|
|
}
|
|
|
|
.form-group input[type="checkbox"],
|
|
.form-group input[type="radio"] {
|
|
width: 16px;
|
|
height: 16px;
|
|
margin-right: 8px;
|
|
accent-color: var(--c-primary);
|
|
vertical-align: -3px;
|
|
}
|
|
|
|
.form-group input[readonly] {
|
|
background: #f4f6fa;
|
|
color: var(--c-text-2);
|
|
}
|
|
|
|
.form-row {
|
|
display: flex;
|
|
gap: 16px;
|
|
flex-wrap: wrap;
|
|
align-items: flex-end;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.form-row .form-group {
|
|
margin-bottom: 0;
|
|
flex: 1;
|
|
min-width: 120px;
|
|
}
|
|
|
|
.dedupe-filter-row {
|
|
display: grid;
|
|
grid-template-columns: repeat(4, minmax(160px, 1fr)) auto;
|
|
gap: 12px;
|
|
align-items: end;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.dedupe-filter-row .form-group {
|
|
min-width: 0;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.dedupe-filter-actions {
|
|
display: flex;
|
|
gap: 8px;
|
|
align-items: center;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.dedupe-filter-date-row {
|
|
display: flex;
|
|
gap: 12px;
|
|
align-items: flex-end;
|
|
flex-wrap: wrap;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.dedupe-filter-date-row .form-group {
|
|
flex: 0 0 200px;
|
|
min-width: 0;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.dedupe-filter-date-row .dedupe-filter-actions {
|
|
margin-left: auto;
|
|
}
|
|
|
|
.btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 6px;
|
|
padding: 9px 18px;
|
|
background: linear-gradient(135deg, #6366f1, #5457e8);
|
|
color: #fff;
|
|
border: none;
|
|
border-radius: var(--radius-sm);
|
|
cursor: pointer;
|
|
font: inherit;
|
|
font-size: 13.5px;
|
|
font-weight: 500;
|
|
line-height: 1;
|
|
white-space: nowrap;
|
|
box-shadow: 0 1px 2px rgba(84, 87, 232, 0.25);
|
|
transition: box-shadow 0.15s ease, transform 0.15s ease, background 0.15s ease, opacity 0.15s ease;
|
|
}
|
|
|
|
.btn:hover {
|
|
box-shadow: 0 4px 10px rgba(84, 87, 232, 0.32);
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.btn:active {
|
|
transform: translateY(0);
|
|
}
|
|
|
|
.btn:focus-visible {
|
|
outline: 2px solid var(--c-primary);
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
.btn-sm {
|
|
padding: 6px 12px;
|
|
font-size: 12.5px;
|
|
box-shadow: none;
|
|
}
|
|
|
|
.btn-sm:hover {
|
|
transform: none;
|
|
box-shadow: 0 2px 6px rgba(84, 87, 232, 0.25);
|
|
}
|
|
|
|
.btn-danger {
|
|
background: var(--c-danger);
|
|
box-shadow: 0 1px 2px rgba(229, 72, 77, 0.25);
|
|
}
|
|
|
|
.btn-danger:hover {
|
|
box-shadow: 0 4px 10px rgba(229, 72, 77, 0.32);
|
|
}
|
|
|
|
.btn-secondary {
|
|
background: #fff;
|
|
color: var(--c-text-2);
|
|
border: 1px solid var(--c-border);
|
|
box-shadow: none;
|
|
}
|
|
|
|
.btn-secondary:hover {
|
|
color: var(--c-primary);
|
|
border-color: #b9bcf3;
|
|
background: var(--c-primary-soft);
|
|
box-shadow: none;
|
|
}
|
|
|
|
.msg {
|
|
margin-top: 12px;
|
|
font-size: 13px;
|
|
line-height: 1.6;
|
|
padding: 8px 12px;
|
|
border-radius: var(--radius-sm);
|
|
border: 1px solid transparent;
|
|
white-space: pre-wrap;
|
|
word-break: break-word;
|
|
}
|
|
|
|
.msg.ok {
|
|
color: var(--c-success);
|
|
background: #f0faf4;
|
|
border-color: #c7e9d4;
|
|
}
|
|
|
|
.msg.err {
|
|
color: var(--c-danger);
|
|
background: #fff5f5;
|
|
border-color: #f5d2d2;
|
|
}
|
|
|
|
.progress-wrap {
|
|
margin-top: 12px;
|
|
}
|
|
|
|
.progress-bar {
|
|
width: 100%;
|
|
height: 8px;
|
|
background: #eef1f6;
|
|
border-radius: 999px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.progress-fill {
|
|
width: 0;
|
|
height: 100%;
|
|
background: linear-gradient(90deg, #6366f1, #8fa0f3);
|
|
border-radius: 999px;
|
|
transition: width 0.3s ease;
|
|
}
|
|
|
|
.progress-text {
|
|
margin-top: 8px;
|
|
font-size: 12.5px;
|
|
color: var(--c-text-2);
|
|
}
|
|
|
|
.request-loading-bar {
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
width: 0;
|
|
height: 3px;
|
|
background: #6366f1;
|
|
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: var(--c-text);
|
|
background: rgba(255, 255, 255, 0.96);
|
|
border: 1px solid #e6eaf2;
|
|
border-radius: 10px;
|
|
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;
|
|
}
|
|
|
|
.dedupe-export-wait-mask {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 3100;
|
|
display: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 20px;
|
|
background: rgba(17, 24, 39, 0.38);
|
|
}
|
|
|
|
.dedupe-export-wait-mask.show {
|
|
display: flex;
|
|
}
|
|
|
|
.dedupe-export-wait {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 14px;
|
|
width: min(440px, calc(100vw - 40px));
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
background: #fff;
|
|
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.2);
|
|
}
|
|
|
|
.dedupe-export-wait .request-spinner {
|
|
flex: 0 0 auto;
|
|
width: 24px;
|
|
height: 24px;
|
|
border-width: 3px;
|
|
}
|
|
|
|
.dedupe-export-wait-title {
|
|
margin-bottom: 4px;
|
|
color: #1f2937;
|
|
font-size: 15px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.dedupe-export-wait-detail {
|
|
color: #687386;
|
|
font-size: 13px;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.request-spinner {
|
|
width: 16px;
|
|
height: 16px;
|
|
border: 2px solid #dfe3ff;
|
|
border-top-color: #6366f1;
|
|
border-radius: 50%;
|
|
animation: request-spin 0.8s linear infinite;
|
|
}
|
|
|
|
@keyframes request-spin {
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 13.5px;
|
|
}
|
|
|
|
.panel-box > table,
|
|
.modal table {
|
|
width: 100%;
|
|
}
|
|
|
|
th,
|
|
td {
|
|
padding: 11px 12px;
|
|
text-align: left;
|
|
border-bottom: 1px solid #eef1f6;
|
|
font-size: 13.5px;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
th {
|
|
background: #f7f8fb;
|
|
color: var(--c-text-2);
|
|
font-weight: 600;
|
|
font-size: 12.5px;
|
|
letter-spacing: 0.4px;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
tbody tr {
|
|
transition: background 0.12s ease;
|
|
}
|
|
|
|
tbody tr:hover,
|
|
tbody tr:hover td {
|
|
background: #f6f8fd;
|
|
}
|
|
|
|
tbody tr:last-child td {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.panel-box > table,
|
|
.modal > table {
|
|
display: block;
|
|
max-width: 100%;
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.pagination {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin-top: 16px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.pagination span {
|
|
font-size: 13px;
|
|
color: var(--c-text-2);
|
|
}
|
|
|
|
.pagination button {
|
|
padding: 6px 13px;
|
|
border: 1px solid var(--c-border);
|
|
background: #fff;
|
|
cursor: pointer;
|
|
border-radius: var(--radius-sm);
|
|
color: var(--c-text);
|
|
font: inherit;
|
|
font-size: 12.5px;
|
|
transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
|
|
}
|
|
|
|
.pagination button:hover:not(:disabled) {
|
|
color: var(--c-primary);
|
|
border-color: #b9bcf3;
|
|
background: var(--c-primary-soft);
|
|
}
|
|
|
|
.pagination button:disabled {
|
|
opacity: 0.45;
|
|
cursor: not-allowed;
|
|
background: #f7f8fb;
|
|
}
|
|
|
|
.pagination-jump {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: 14px;
|
|
color: var(--c-text-2);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.pagination-jump input {
|
|
width: 64px;
|
|
height: 32px;
|
|
padding: 4px 8px;
|
|
border: 1px solid var(--c-border);
|
|
border-radius: var(--radius-sm);
|
|
font-size: 13px;
|
|
text-align: center;
|
|
background: #fbfcfe;
|
|
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
|
}
|
|
|
|
.pagination-jump input:focus {
|
|
outline: none;
|
|
border-color: var(--c-primary);
|
|
background: #fff;
|
|
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.12);
|
|
}
|
|
|
|
.thumb {
|
|
width: 56px;
|
|
height: 56px;
|
|
object-fit: cover;
|
|
border-radius: 6px;
|
|
margin-right: 8px;
|
|
vertical-align: middle;
|
|
border: 1px solid var(--c-border);
|
|
}
|
|
|
|
.thumb-wrap {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 4px;
|
|
}
|
|
|
|
.empty-tip {
|
|
color: var(--c-text-3);
|
|
font-size: 13.5px;
|
|
padding: 44px 24px;
|
|
text-align: center;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.tree-name-cell {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
min-height: 24px;
|
|
}
|
|
|
|
.tree-indent {
|
|
flex: 0 0 auto;
|
|
width: var(--indent, 0px);
|
|
}
|
|
|
|
.tree-node-mark {
|
|
width: 20px;
|
|
height: 20px;
|
|
border: 0;
|
|
border-radius: 5px;
|
|
background: #eef0fe;
|
|
color: #6366f1;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 13px;
|
|
font-weight: 700;
|
|
cursor: pointer;
|
|
padding: 0;
|
|
line-height: 1;
|
|
transition: background 0.12s ease, color 0.12s ease;
|
|
}
|
|
|
|
.tree-node-mark:not(.is-leaf):hover {
|
|
background: #6366f1;
|
|
color: #fff;
|
|
}
|
|
|
|
.tree-node-mark.is-leaf {
|
|
background: transparent;
|
|
cursor: default;
|
|
}
|
|
|
|
.category-path {
|
|
color: var(--c-text-3);
|
|
font-size: 12px;
|
|
margin-top: 4px;
|
|
}
|
|
|
|
.category-tag {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
padding: 3px 9px;
|
|
border-radius: 999px;
|
|
background: var(--c-primary-soft);
|
|
color: var(--c-primary-strong);
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.modal-mask {
|
|
display: none;
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: rgba(15, 20, 34, 0.46);
|
|
backdrop-filter: blur(2px);
|
|
z-index: 1000;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.modal-mask.show {
|
|
display: flex;
|
|
animation: modal-fade-in 0.16s ease;
|
|
}
|
|
|
|
@keyframes modal-fade-in {
|
|
from {
|
|
opacity: 0;
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
#shopManageGroupModal {
|
|
z-index: 1010;
|
|
}
|
|
|
|
.shop-key-whitelist-status {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
min-height: 24px;
|
|
padding: 3px 9px;
|
|
border: 1px solid transparent;
|
|
border-radius: 999px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.shop-key-whitelist-status.is-allowed {
|
|
color: var(--c-success);
|
|
background: #eaf8f0;
|
|
border-color: #b9e3ca;
|
|
}
|
|
|
|
.shop-key-whitelist-status.is-blocked {
|
|
color: var(--c-danger);
|
|
background: #fff0ee;
|
|
border-color: #f2c0ba;
|
|
}
|
|
|
|
.shop-key-whitelist-status.is-unknown {
|
|
color: #667085;
|
|
background: #f2f4f7;
|
|
border-color: #d0d5dd;
|
|
}
|
|
|
|
.shop-key-table-scroll {
|
|
width: 100%;
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.shop-key-table-scroll table {
|
|
min-width: 900px;
|
|
}
|
|
|
|
.shop-password-cell {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
min-width: 86px;
|
|
}
|
|
|
|
.shop-password-value {
|
|
min-width: 48px;
|
|
max-width: 220px;
|
|
overflow-wrap: anywhere;
|
|
font-family: Consolas, "Courier New", monospace;
|
|
}
|
|
|
|
.shop-password-toggle {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex: 0 0 28px;
|
|
width: 28px;
|
|
height: 28px;
|
|
padding: 0;
|
|
border: 0;
|
|
border-radius: 4px;
|
|
color: #667085;
|
|
background: transparent;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.shop-password-toggle:hover:not(:disabled) {
|
|
color: #5158d9;
|
|
background: #eef0fe;
|
|
}
|
|
|
|
.shop-password-toggle:focus-visible {
|
|
outline: 2px solid #6366f1;
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
.shop-password-toggle:disabled {
|
|
cursor: wait;
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.shop-password-toggle svg {
|
|
width: 17px;
|
|
height: 17px;
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-width: 2;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.dedupe-group-access {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
margin-bottom: 18px;
|
|
padding: 0 0 14px;
|
|
border-bottom: 1px solid #edf0f5;
|
|
}
|
|
|
|
.dedupe-group-access-main {
|
|
min-width: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.dedupe-group-access-title {
|
|
flex: 0 0 auto;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
color: var(--c-text);
|
|
}
|
|
|
|
.dedupe-group-summary {
|
|
min-width: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
flex-wrap: wrap;
|
|
color: var(--c-text-2);
|
|
font-size: 13px;
|
|
}
|
|
|
|
.dedupe-group-summary-chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
max-width: 220px;
|
|
padding: 4px 10px;
|
|
border: 1px solid var(--c-border);
|
|
border-radius: 6px;
|
|
background: #f8f9fc;
|
|
color: var(--c-text-2);
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.modal {
|
|
background: #fff;
|
|
border-radius: 14px;
|
|
padding: 24px;
|
|
min-width: 320px;
|
|
width: min(920px, calc(100vw - 48px));
|
|
max-width: 90%;
|
|
max-height: calc(100vh - 48px);
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
box-sizing: border-box;
|
|
box-shadow: 0 24px 60px rgba(16, 24, 40, 0.22);
|
|
}
|
|
|
|
.modal h3 {
|
|
margin-bottom: 16px;
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
color: var(--c-text);
|
|
}
|
|
|
|
#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: var(--c-text-2);
|
|
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: #eef0fe;
|
|
color: #4f5ad8;
|
|
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) {
|
|
.dedupe-filter-row {
|
|
grid-template-columns: repeat(2, minmax(180px, 1fr));
|
|
}
|
|
|
|
.dedupe-filter-actions {
|
|
grid-column: 1 / -1;
|
|
}
|
|
|
|
.dedupe-group-access {
|
|
align-items: stretch;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.dedupe-group-access .btn {
|
|
align-self: flex-start;
|
|
}
|
|
|
|
#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;
|
|
gap: 8px;
|
|
min-height: 32px;
|
|
margin-bottom: 8px;
|
|
width: 100%;
|
|
max-width: 100%;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.column-permission-tree {
|
|
max-height: 280px;
|
|
overflow: auto;
|
|
border: 1px solid var(--c-border);
|
|
border-radius: var(--radius-sm);
|
|
padding: 8px 10px;
|
|
background: #fff;
|
|
}
|
|
|
|
.column-tree-node {
|
|
display: block;
|
|
padding: 4px 0;
|
|
}
|
|
|
|
.column-tree-group + .column-tree-group {
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.column-tree-group-toggle {
|
|
display: flex;
|
|
align-items: center;
|
|
width: 100%;
|
|
min-height: 36px;
|
|
padding: 6px 10px;
|
|
border: 0;
|
|
border-radius: 4px;
|
|
background: #f3f5f8;
|
|
color: var(--c-text);
|
|
cursor: pointer;
|
|
text-align: left;
|
|
}
|
|
|
|
.column-tree-group-toggle::before {
|
|
content: '\203A';
|
|
flex: 0 0 20px;
|
|
font-size: 20px;
|
|
line-height: 1;
|
|
color: #667085;
|
|
transition: transform 0.15s ease;
|
|
}
|
|
|
|
.column-tree-group-toggle[aria-expanded="true"]::before {
|
|
transform: rotate(90deg);
|
|
}
|
|
|
|
.column-tree-group-toggle:hover {
|
|
background: #e9edf3;
|
|
}
|
|
|
|
.column-tree-group-toggle:focus-visible {
|
|
outline: 2px solid #4f46e5;
|
|
outline-offset: -2px;
|
|
}
|
|
|
|
.column-tree-group-name {
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.column-tree-group-count {
|
|
margin-left: auto;
|
|
font-size: 12px;
|
|
color: #667085;
|
|
}
|
|
|
|
.column-tree-group-body {
|
|
padding-top: 4px;
|
|
}
|
|
|
|
.column-tree-row {
|
|
display: flex;
|
|
align-items: center;
|
|
min-height: 28px;
|
|
}
|
|
|
|
.column-tree-node label {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 7px;
|
|
margin: 0;
|
|
min-height: 28px;
|
|
font-size: 13px;
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.column-tree-toggle,
|
|
.column-tree-toggle-spacer {
|
|
flex: 0 0 24px;
|
|
width: 24px;
|
|
height: 28px;
|
|
}
|
|
|
|
.column-tree-toggle {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 0;
|
|
border: 0;
|
|
background: transparent;
|
|
color: var(--c-text-2);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.column-tree-toggle::before {
|
|
content: '\203A';
|
|
display: block;
|
|
font-size: 20px;
|
|
line-height: 1;
|
|
transition: transform 0.15s ease;
|
|
}
|
|
|
|
.column-tree-toggle[aria-expanded="true"]::before {
|
|
transform: rotate(90deg);
|
|
}
|
|
|
|
.column-tree-toggle:hover {
|
|
color: #4f46e5;
|
|
}
|
|
|
|
.column-tree-toggle:focus-visible {
|
|
outline: 2px solid #4f46e5;
|
|
outline-offset: -2px;
|
|
}
|
|
|
|
.column-tree-node[data-depth="1"] > .column-tree-row { padding-left: 22px; }
|
|
.column-tree-node[data-depth="2"] > .column-tree-row { padding-left: 44px; }
|
|
.column-tree-node input[type="checkbox"] { width: auto; }
|
|
.column-tree-node .inherited-label { color: var(--c-text-3); }
|
|
|
|
.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 var(--c-border);
|
|
border-radius: var(--radius-sm);
|
|
background: #fbfcfe;
|
|
color: var(--c-text);
|
|
font-size: 13.5px;
|
|
text-align: left;
|
|
cursor: pointer;
|
|
position: relative;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
|
|
}
|
|
|
|
.multi-select-trigger:hover {
|
|
border-color: #c4c8ec;
|
|
background: #fff;
|
|
}
|
|
|
|
.multi-select-trigger::after {
|
|
content: "";
|
|
position: absolute;
|
|
right: 12px;
|
|
top: 50%;
|
|
width: 7px;
|
|
height: 7px;
|
|
border-right: 1.5px solid var(--c-text-3);
|
|
border-bottom: 1.5px solid var(--c-text-3);
|
|
transform: translateY(-65%) rotate(45deg);
|
|
}
|
|
|
|
.multi-select-dropdown.open .multi-select-trigger {
|
|
border-color: var(--c-primary);
|
|
background: #fff;
|
|
box-shadow: 0 0 0 3px rgba(99, 102, 241, 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 var(--c-border);
|
|
border-radius: 10px;
|
|
box-shadow: var(--shadow-pop);
|
|
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: var(--c-text);
|
|
}
|
|
|
|
.multi-select-option:hover {
|
|
background: var(--c-primary-soft);
|
|
}
|
|
|
|
.multi-select-option input {
|
|
width: auto;
|
|
margin: 0;
|
|
}
|
|
|
|
.column-permission-card {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 4px 10px;
|
|
background: #e9ecfb;
|
|
color: #6366f1;
|
|
border-radius: 6px;
|
|
font-size: 13px;
|
|
max-width: 100%;
|
|
min-width: 0;
|
|
flex: 0 1 auto;
|
|
white-space: normal;
|
|
overflow-wrap: anywhere;
|
|
word-break: break-word;
|
|
}
|
|
|
|
.column-permission-card .col-card-remove {
|
|
flex: 0 0 auto;
|
|
margin-left: 2px;
|
|
padding: 0 4px;
|
|
line-height: 1;
|
|
cursor: pointer;
|
|
color: var(--c-text-3);
|
|
border: none;
|
|
background: none;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.column-permission-card .col-card-remove:hover {
|
|
color: var(--c-danger);
|
|
}
|
|
|
|
.column-permission-select {
|
|
width: 100%;
|
|
max-width: 100%;
|
|
min-height: 120px;
|
|
height: 220px;
|
|
max-height: 260px;
|
|
overflow-y: auto;
|
|
padding: 8px;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.column-permission-select option {
|
|
padding: 4px 0;
|
|
}
|
|
|
|
.image-video-panel-box {
|
|
padding: 0;
|
|
}
|
|
|
|
.image-video-results {
|
|
padding: 20px 20px 0;
|
|
}
|
|
|
|
.image-video-panel-box>.pagination {
|
|
padding: 0 20px 20px;
|
|
}
|
|
|
|
.image-video-toolbar {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.image-video-toolbar-main {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 18px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.image-video-batch-btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 7px;
|
|
min-height: 36px;
|
|
padding: 8px 14px;
|
|
background: #6366f1;
|
|
}
|
|
|
|
.image-video-batch-btn:disabled {
|
|
cursor: not-allowed;
|
|
opacity: .45;
|
|
}
|
|
|
|
.image-video-batch-btn svg,
|
|
.image-video-card-action svg {
|
|
width: 15px;
|
|
height: 15px;
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-width: 2;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
}
|
|
|
|
.image-video-select-all {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
color: var(--c-text);
|
|
font-size: 14px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.image-video-select-all input {
|
|
width: 16px;
|
|
height: 16px;
|
|
accent-color: #6366f1;
|
|
}
|
|
|
|
.image-video-download-progress {
|
|
min-height: 18px;
|
|
color: var(--c-text-2);
|
|
font-size: 13px;
|
|
}
|
|
|
|
.image-video-summary {
|
|
color: var(--c-text-2);
|
|
font-size: 13px;
|
|
text-align: right;
|
|
}
|
|
|
|
.image-video-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
gap: 20px;
|
|
}
|
|
|
|
.image-video-card {
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
background: #fff;
|
|
border: 1px solid var(--c-border);
|
|
border-radius: 10px;
|
|
box-shadow: var(--shadow-card);
|
|
transition: border-color .2s ease, box-shadow .2s ease, transform .2s ease;
|
|
}
|
|
|
|
.image-video-card:hover {
|
|
border-color: #b9bcf3;
|
|
box-shadow: 0 10px 22px -8px rgba(99, 102, 241, .18);
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.image-video-card.selected {
|
|
border-color: var(--c-primary);
|
|
box-shadow: 0 0 0 2px rgba(99, 102, 241, .14), 0 10px 22px -8px rgba(99, 102, 241, .2);
|
|
}
|
|
|
|
.image-video-media {
|
|
position: relative;
|
|
width: 100%;
|
|
aspect-ratio: 16/9;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: #10131a;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.image-video-media video {
|
|
display: block;
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: contain;
|
|
background: #000;
|
|
}
|
|
|
|
.image-video-card-check {
|
|
position: absolute;
|
|
top: 11px;
|
|
left: 11px;
|
|
z-index: 2;
|
|
width: 17px;
|
|
height: 17px;
|
|
accent-color: #6366f1;
|
|
cursor: pointer;
|
|
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .55));
|
|
}
|
|
|
|
.image-video-unavailable {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 8px;
|
|
padding: 20px;
|
|
color: #bcc2cc;
|
|
text-align: center;
|
|
}
|
|
|
|
.image-video-unavailable svg {
|
|
width: 34px;
|
|
height: 34px;
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-width: 1.5;
|
|
}
|
|
|
|
.image-video-unavailable strong {
|
|
color: #e2e5ec;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.image-video-card-body {
|
|
padding: 15px 16px 16px;
|
|
}
|
|
|
|
.image-video-card-head {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 10px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.image-video-card-title {
|
|
min-width: 0;
|
|
font-size: 15px;
|
|
font-weight: 600;
|
|
color: var(--c-text);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.image-video-status {
|
|
flex: 0 0 auto;
|
|
display: inline-block;
|
|
padding: 3px 9px;
|
|
border-radius: 999px;
|
|
background: #f2f4f8;
|
|
color: #5d6675;
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.image-video-status.SUCCESS {
|
|
color: var(--c-success);
|
|
background: #f0faf4;
|
|
}
|
|
|
|
.image-video-status.FAILED {
|
|
color: var(--c-danger);
|
|
background: #fff5f5;
|
|
}
|
|
|
|
.image-video-status.RUNNING,
|
|
.image-video-status.POLLING {
|
|
color: var(--c-warning);
|
|
background: #fdf6e9;
|
|
}
|
|
|
|
.image-video-card-info {
|
|
display: grid;
|
|
gap: 7px;
|
|
}
|
|
|
|
.image-video-info-row {
|
|
display: grid;
|
|
grid-template-columns: 68px minmax(0, 1fr);
|
|
gap: 8px;
|
|
color: var(--c-text-2);
|
|
font-size: 13px;
|
|
line-height: 1.45;
|
|
}
|
|
|
|
.image-video-info-row span,
|
|
.image-video-info-row a {
|
|
min-width: 0;
|
|
color: var(--c-text);
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.image-video-info-row a {
|
|
color: #5457e8;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.image-video-info-row a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.image-video-copy-link {
|
|
min-width: 0;
|
|
padding: 0;
|
|
border: 0;
|
|
background: none;
|
|
color: #5457e8;
|
|
cursor: pointer;
|
|
font: inherit;
|
|
text-align: left;
|
|
}
|
|
|
|
.image-video-copy-link:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.image-video-copy-link.copied {
|
|
color: var(--c-success);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.image-video-card-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 9px;
|
|
margin-top: 15px;
|
|
}
|
|
|
|
.image-video-card-action {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 6px;
|
|
min-height: 32px;
|
|
padding: 6px 11px;
|
|
border: 1px solid #6366f1;
|
|
border-radius: 4px;
|
|
background: #fff;
|
|
color: #5457e8;
|
|
cursor: pointer;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.image-video-card-action:hover {
|
|
background: #6366f1;
|
|
color: #fff;
|
|
}
|
|
|
|
.image-video-card-action:disabled {
|
|
cursor: not-allowed;
|
|
opacity: .45;
|
|
}
|
|
|
|
.image-video-empty {
|
|
grid-column: 1/-1;
|
|
padding: 64px 20px;
|
|
border: 1px dashed #c7cbf0;
|
|
border-radius: 10px;
|
|
color: var(--c-text-2);
|
|
text-align: center;
|
|
background: var(--c-primary-soft);
|
|
}
|
|
|
|
.shop-data-task-card .image-video-card-body {
|
|
min-height: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.shop-data-task-card .image-video-card-info {
|
|
flex: none;
|
|
}
|
|
|
|
.shop-data-group-head {
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.shop-data-group-meta {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
color: var(--c-text-2);
|
|
font-size: 12px;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.shop-data-result-list {
|
|
margin-top: 8px;
|
|
border-top: 1px solid #eef1f6;
|
|
}
|
|
|
|
.shop-data-result {
|
|
padding: 13px 0 12px;
|
|
border-bottom: 1px solid #eef1f6;
|
|
}
|
|
|
|
.shop-data-result:last-child {
|
|
border-bottom: 0;
|
|
padding-bottom: 0;
|
|
}
|
|
|
|
.shop-data-result.selected {
|
|
margin-left: -8px;
|
|
margin-right: -8px;
|
|
padding-left: 8px;
|
|
padding-right: 8px;
|
|
border-radius: 4px;
|
|
background: #f4f6fe;
|
|
}
|
|
|
|
.shop-data-result-head {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 10px;
|
|
}
|
|
|
|
.shop-data-result .shop-data-task-title {
|
|
font-size: 13px;
|
|
}
|
|
|
|
.shop-data-result .image-video-card-info {
|
|
margin-top: 9px;
|
|
}
|
|
|
|
.shop-data-result .image-video-card-actions {
|
|
margin-top: 11px;
|
|
}
|
|
|
|
.shop-data-task-title {
|
|
min-width: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 9px;
|
|
color: var(--c-text);
|
|
font-size: 15px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.shop-data-task-title input {
|
|
flex: 0 0 auto;
|
|
width: 17px;
|
|
height: 17px;
|
|
accent-color: #6366f1;
|
|
}
|
|
|
|
.shop-data-task-title span {
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.shop-data-result .image-video-status[title] {
|
|
cursor: help;
|
|
}
|
|
|
|
.shop-data-delete-action {
|
|
margin-left: auto;
|
|
border-color: #f0b2b4;
|
|
color: var(--c-danger);
|
|
}
|
|
|
|
.shop-data-delete-action:hover:not(:disabled) {
|
|
border-color: var(--c-danger);
|
|
background: var(--c-danger);
|
|
color: #fff;
|
|
}
|
|
|
|
.image-video-permission-btn {
|
|
display: none;
|
|
min-height: 36px;
|
|
padding: 8px 14px;
|
|
}
|
|
|
|
.image-video-permission-modal {
|
|
width: min(620px, calc(100vw - 32px));
|
|
}
|
|
|
|
.image-video-permission-head {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.image-video-permission-tools {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.image-video-permission-tabs {
|
|
display: flex;
|
|
gap: 4px;
|
|
margin-bottom: 12px;
|
|
padding: 3px;
|
|
border-radius: 6px;
|
|
background: #f1f3f8;
|
|
}
|
|
|
|
.image-video-permission-tab {
|
|
flex: 1;
|
|
min-height: 34px;
|
|
padding: 7px 10px;
|
|
border: 0;
|
|
border-radius: 4px;
|
|
background: transparent;
|
|
color: var(--c-text-2);
|
|
cursor: pointer;
|
|
font: inherit;
|
|
font-size: 13px;
|
|
transition: background 0.15s ease, color 0.15s ease;
|
|
}
|
|
|
|
.image-video-permission-tab.active {
|
|
background: #fff;
|
|
color: #4f46e5;
|
|
box-shadow: 0 1px 4px rgba(99, 102, 241, 0.14);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.image-video-permission-search {
|
|
flex: 1;
|
|
min-width: 0;
|
|
padding: 9px 10px;
|
|
border: 1px solid var(--c-border);
|
|
border-radius: var(--radius-sm);
|
|
font: inherit;
|
|
}
|
|
|
|
.image-video-permission-list {
|
|
max-height: 52vh;
|
|
overflow: auto;
|
|
border: 1px solid #e5e7f2;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.image-video-permission-row {
|
|
display: grid;
|
|
grid-template-columns: 24px minmax(0, 1fr) auto;
|
|
align-items: center;
|
|
gap: 10px;
|
|
min-height: 48px;
|
|
padding: 9px 12px;
|
|
border-bottom: 1px solid #eef1f6;
|
|
}
|
|
|
|
.image-video-permission-row:last-child {
|
|
border-bottom: 0;
|
|
}
|
|
|
|
.image-video-permission-row input {
|
|
width: 16px;
|
|
height: 16px;
|
|
accent-color: #6366f1;
|
|
}
|
|
|
|
.image-video-permission-user {
|
|
min-width: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
}
|
|
|
|
.image-video-permission-name {
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
color: var(--c-text);
|
|
}
|
|
|
|
.image-video-permission-role {
|
|
color: var(--c-text-3);
|
|
font-size: 12px;
|
|
}
|
|
|
|
.image-video-permission-state {
|
|
min-width: 68px;
|
|
padding: 4px 10px;
|
|
border: 1px solid var(--c-border);
|
|
border-radius: 999px;
|
|
background: #fff;
|
|
color: #6d7688;
|
|
cursor: pointer;
|
|
font-size: 12px;
|
|
white-space: nowrap;
|
|
transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
|
|
}
|
|
|
|
.image-video-permission-state.granted {
|
|
border-color: #b9bcf3;
|
|
background: #f0f1fe;
|
|
color: #4f46e5;
|
|
}
|
|
|
|
.image-video-permission-state.pending {
|
|
border-color: #f0d48c;
|
|
background: #fdf6e9;
|
|
color: var(--c-warning);
|
|
}
|
|
|
|
.image-video-permission-summary {
|
|
margin: 0 0 10px;
|
|
color: var(--c-text-2);
|
|
font-size: 13px;
|
|
}
|
|
|
|
.image-video-permission-empty {
|
|
padding: 36px 16px;
|
|
color: var(--c-text-2);
|
|
text-align: center;
|
|
}
|
|
|
|
.image-video-permission-actions {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 8px;
|
|
margin-top: 16px;
|
|
}
|
|
|
|
@media (max-width: 960px) {
|
|
.admin-layout {
|
|
grid-template-columns: minmax(0, 1fr);
|
|
}
|
|
|
|
.admin-sidebar {
|
|
position: static;
|
|
height: auto;
|
|
border-right: none;
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
|
}
|
|
|
|
.admin-brand {
|
|
padding: 12px 16px 8px;
|
|
}
|
|
|
|
.admin-menu {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
overflow-x: auto;
|
|
overscroll-behavior-x: contain;
|
|
padding: 0 12px 10px;
|
|
}
|
|
|
|
.menu-group {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
margin: 0;
|
|
}
|
|
|
|
.menu-group.is-collapsed .menu-group-body {
|
|
display: flex;
|
|
}
|
|
|
|
.menu-group-body {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
padding: 0;
|
|
}
|
|
|
|
.menu-group + .menu-group::before {
|
|
content: "";
|
|
width: 1px;
|
|
height: 14px;
|
|
background: rgba(255, 255, 255, 0.14);
|
|
margin: 0 6px;
|
|
flex: 0 0 auto;
|
|
}
|
|
|
|
.menu-group-title {
|
|
display: none;
|
|
}
|
|
|
|
.menu-group-chevron {
|
|
display: none;
|
|
}
|
|
|
|
.menu-group.is-collapsed .menu-group-body {
|
|
display: flex;
|
|
}
|
|
|
|
.tab {
|
|
flex: 0 0 auto;
|
|
padding: 7px 10px;
|
|
margin-bottom: 0;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.tab.active::before {
|
|
top: auto;
|
|
bottom: -10px;
|
|
left: 20%;
|
|
right: 20%;
|
|
width: auto;
|
|
height: 3px;
|
|
}
|
|
|
|
.admin-topbar {
|
|
padding: 0 14px;
|
|
height: 52px;
|
|
}
|
|
|
|
.admin-user-name {
|
|
max-width: 120px;
|
|
}
|
|
|
|
.admin-content {
|
|
padding: 16px 14px 32px;
|
|
}
|
|
|
|
.admin-sidebar-foot {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 760px) {
|
|
.form-row {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
}
|
|
|
|
.form-row .form-group {
|
|
flex: none;
|
|
min-width: 0;
|
|
}
|
|
|
|
.dedupe-filter-date-row .form-group {
|
|
flex: 1 1 100%;
|
|
min-width: 0;
|
|
}
|
|
|
|
.dedupe-filter-date-row .dedupe-filter-actions {
|
|
margin-left: 0;
|
|
}
|
|
|
|
.admin-content {
|
|
padding: 16px 14px 28px;
|
|
}
|
|
|
|
.form-box,
|
|
.panel-box {
|
|
padding: 18px;
|
|
}
|
|
|
|
.dedupe-filter-row {
|
|
grid-template-columns: minmax(0, 1fr);
|
|
}
|
|
|
|
.dedupe-filter-actions {
|
|
grid-column: auto;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.admin-user-role {
|
|
display: none;
|
|
}
|
|
|
|
.image-video-results {
|
|
padding: 16px;
|
|
}
|
|
|
|
.image-video-toolbar {
|
|
align-items: flex-start;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.image-video-summary {
|
|
text-align: left;
|
|
}
|
|
|
|
.image-video-grid {
|
|
grid-template-columns: minmax(0, 1fr);
|
|
gap: 16px;
|
|
}
|
|
}
|
|
/* ===== 全局滚动条 ===== */
|
|
::-webkit-scrollbar {
|
|
width: 8px;
|
|
height: 8px;
|
|
}
|
|
|
|
::-webkit-scrollbar-track {
|
|
background: transparent;
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb {
|
|
background: #ccd3e2;
|
|
border-radius: 99px;
|
|
border: 2px solid transparent;
|
|
background-clip: content-box;
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: #aab3c8;
|
|
background-clip: content-box;
|
|
}
|
|
|
|
:focus-visible {
|
|
outline: 2px solid var(--c-primary);
|
|
outline-offset: 1px;
|
|
}
|
|
|
|
|
|
/* ===== 数富AI Admin Console Refresh =====
|
|
设计基线:深色专业控制台 / 高密度数据工作台 / 语义化状态色
|
|
与原有 class、id、inline loader 兼容,只重塑视觉层级与交互反馈。 */
|
|
:root {
|
|
color-scheme: dark;
|
|
--c-primary: #818cf8;
|
|
--c-primary-strong: #a5b4fc;
|
|
--c-primary-soft: rgba(129, 140, 248, 0.15);
|
|
--c-bg: #0b1220;
|
|
--c-card: #141e31;
|
|
--c-card-raised: #1a2740;
|
|
--c-border: rgba(148, 163, 184, 0.18);
|
|
--c-border-strong: rgba(148, 163, 184, 0.32);
|
|
--c-text: #f1f5f9;
|
|
--c-text-2: #b8c4d8;
|
|
--c-text-3: #8795ad;
|
|
--c-danger: #fb7185;
|
|
--c-danger-soft: rgba(251, 113, 133, 0.13);
|
|
--c-success: #4ade80;
|
|
--c-warning: #fbbf24;
|
|
--c-sidebar: #080f1d;
|
|
--c-sidebar-2: #101a2e;
|
|
--c-sidebar-text: #aab7cd;
|
|
--radius: 16px;
|
|
--radius-sm: 10px;
|
|
--shadow-card: 0 1px 2px rgba(2, 6, 23, 0.36), 0 16px 34px -24px rgba(2, 6, 23, 0.9);
|
|
--shadow-pop: 0 24px 80px rgba(2, 6, 23, 0.56);
|
|
--motion-fast: 160ms;
|
|
--motion-base: 220ms;
|
|
}
|
|
|
|
html {
|
|
min-width: 320px;
|
|
background: var(--c-bg);
|
|
}
|
|
|
|
body {
|
|
min-width: 320px;
|
|
font-family: Inter, "SF Pro Display", "Microsoft YaHei", "PingFang SC", "Helvetica Neue", sans-serif;
|
|
font-size: 14px;
|
|
line-height: 1.5;
|
|
background:
|
|
radial-gradient(circle at 16% -12%, rgba(99, 102, 241, 0.15), transparent 32rem),
|
|
radial-gradient(circle at 96% 8%, rgba(34, 197, 94, 0.05), transparent 24rem),
|
|
var(--c-bg);
|
|
color: var(--c-text);
|
|
}
|
|
|
|
.skip-link {
|
|
position: fixed;
|
|
top: 12px;
|
|
left: 12px;
|
|
z-index: 4000;
|
|
padding: 10px 14px;
|
|
border-radius: 9px;
|
|
background: var(--c-primary);
|
|
color: #0b1220;
|
|
font-weight: 700;
|
|
transform: translateY(-160%);
|
|
transition: transform var(--motion-fast) ease;
|
|
}
|
|
|
|
.skip-link:focus {
|
|
transform: translateY(0);
|
|
}
|
|
|
|
.admin-layout {
|
|
grid-template-columns: 252px minmax(0, 1fr);
|
|
background: transparent;
|
|
}
|
|
|
|
.admin-sidebar {
|
|
background:
|
|
linear-gradient(180deg, rgba(16, 26, 46, 0.98), rgba(8, 15, 29, 0.99)),
|
|
radial-gradient(circle at 10% 0%, rgba(129, 140, 248, 0.12), transparent 20rem);
|
|
border-right: 1px solid rgba(148, 163, 184, 0.14);
|
|
box-shadow: 20px 0 48px rgba(2, 6, 23, 0.18);
|
|
}
|
|
|
|
.admin-brand {
|
|
min-height: 76px;
|
|
padding: 20px 18px 18px;
|
|
border-bottom-color: rgba(148, 163, 184, 0.14);
|
|
}
|
|
|
|
.admin-brand-mark {
|
|
width: 36px;
|
|
height: 36px;
|
|
border-radius: 11px;
|
|
background: linear-gradient(135deg, #818cf8, #4f46e5);
|
|
color: #eef2ff;
|
|
box-shadow: 0 8px 22px rgba(79, 70, 229, 0.36);
|
|
}
|
|
|
|
.admin-brand-name {
|
|
color: #f8fafc;
|
|
font-size: 15px;
|
|
letter-spacing: 0.35px;
|
|
}
|
|
|
|
.admin-brand-sub {
|
|
color: #8492aa;
|
|
letter-spacing: 0.1px;
|
|
}
|
|
|
|
.admin-menu {
|
|
padding: 12px 12px 18px;
|
|
scrollbar-color: rgba(148, 163, 184, 0.22) transparent;
|
|
}
|
|
|
|
.menu-group {
|
|
margin-top: 18px;
|
|
}
|
|
|
|
.menu-group:first-child {
|
|
margin-top: 4px;
|
|
}
|
|
|
|
.menu-group-title {
|
|
min-height: 40px;
|
|
padding: 9px 11px;
|
|
color: #8190a8;
|
|
letter-spacing: 1.1px;
|
|
}
|
|
|
|
.menu-group-title:hover {
|
|
color: #d8e0ee;
|
|
background: rgba(148, 163, 184, 0.08);
|
|
}
|
|
|
|
.tab {
|
|
min-height: 42px;
|
|
margin-bottom: 4px;
|
|
padding: 10px 12px;
|
|
border: 1px solid transparent;
|
|
background: transparent;
|
|
color: var(--c-sidebar-text);
|
|
font: inherit;
|
|
font-size: 13.5px;
|
|
text-align: left;
|
|
width: 100%;
|
|
transition: background var(--motion-fast) ease, border-color var(--motion-fast) ease, color var(--motion-fast) ease, transform var(--motion-fast) ease;
|
|
}
|
|
|
|
.tab:hover {
|
|
background: rgba(148, 163, 184, 0.08);
|
|
border-color: rgba(148, 163, 184, 0.12);
|
|
color: #f8fafc;
|
|
transform: translateX(2px);
|
|
}
|
|
|
|
.tab.active {
|
|
background: linear-gradient(90deg, rgba(129, 140, 248, 0.22), rgba(129, 140, 248, 0.08));
|
|
border-color: rgba(129, 140, 248, 0.24);
|
|
color: #f8fafc;
|
|
box-shadow: inset 3px 0 0 #818cf8, 0 8px 18px -16px rgba(129, 140, 248, 0.9);
|
|
}
|
|
|
|
.tab.active::before {
|
|
display: none;
|
|
}
|
|
|
|
.adm-icon {
|
|
width: 19px;
|
|
height: 19px;
|
|
color: #8290a8;
|
|
}
|
|
|
|
.tab:hover .adm-icon,
|
|
.tab.active .adm-icon {
|
|
color: #a5b4fc;
|
|
}
|
|
|
|
.admin-sidebar-foot {
|
|
padding: 14px 18px 18px;
|
|
color: #72819a;
|
|
border-top: 1px solid rgba(148, 163, 184, 0.12);
|
|
letter-spacing: 0.2px;
|
|
}
|
|
|
|
.admin-main {
|
|
min-width: 0;
|
|
background: transparent;
|
|
}
|
|
|
|
.admin-topbar {
|
|
height: 76px;
|
|
padding: 0 32px;
|
|
background: rgba(11, 18, 32, 0.76);
|
|
border-bottom-color: rgba(148, 163, 184, 0.14);
|
|
box-shadow: 0 10px 30px -28px rgba(2, 6, 23, 0.9);
|
|
backdrop-filter: blur(18px);
|
|
}
|
|
|
|
.admin-topbar-left {
|
|
min-width: 0;
|
|
}
|
|
|
|
.admin-topbar-kicker {
|
|
display: block;
|
|
margin-bottom: 2px;
|
|
color: #7888a3;
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
letter-spacing: 1.6px;
|
|
line-height: 1.2;
|
|
}
|
|
|
|
.admin-page-heading {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 9px;
|
|
min-width: 0;
|
|
}
|
|
|
|
.admin-page-section,
|
|
.admin-page-separator {
|
|
color: #8d9bb2;
|
|
font-size: 12px;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.admin-page-separator {
|
|
color: #52617b;
|
|
}
|
|
|
|
.admin-page-title {
|
|
color: var(--c-text);
|
|
font-size: 18px;
|
|
font-weight: 650;
|
|
letter-spacing: -0.2px;
|
|
}
|
|
|
|
.admin-user-box {
|
|
gap: 12px;
|
|
}
|
|
|
|
.admin-user-avatar {
|
|
width: 34px;
|
|
height: 34px;
|
|
background: linear-gradient(135deg, #818cf8, #4f46e5);
|
|
color: #eef2ff;
|
|
box-shadow: 0 6px 16px rgba(79, 70, 229, 0.28);
|
|
}
|
|
|
|
.admin-user-name {
|
|
color: #dbe4f1;
|
|
font-weight: 550;
|
|
}
|
|
|
|
.admin-user-role {
|
|
color: #c7d2fe;
|
|
background: rgba(129, 140, 248, 0.15);
|
|
border: 1px solid rgba(129, 140, 248, 0.22);
|
|
}
|
|
|
|
.admin-user-logout {
|
|
min-height: 40px;
|
|
padding: 8px 14px;
|
|
background: rgba(20, 30, 49, 0.86);
|
|
color: #b8c4d8;
|
|
border-color: rgba(148, 163, 184, 0.22);
|
|
}
|
|
|
|
.admin-user-logout:hover {
|
|
color: #f1f5f9;
|
|
border-color: rgba(129, 140, 248, 0.5);
|
|
background: rgba(129, 140, 248, 0.14);
|
|
}
|
|
|
|
.admin-content {
|
|
width: min(100%, 1680px);
|
|
padding: 30px 32px 56px;
|
|
}
|
|
|
|
.tab-panel.active {
|
|
animation: admin-panel-enter 240ms ease both;
|
|
}
|
|
|
|
@keyframes admin-panel-enter {
|
|
from { opacity: 0; transform: translateY(6px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
.form-box,
|
|
.panel-box {
|
|
background: linear-gradient(145deg, rgba(20, 30, 49, 0.98), rgba(16, 26, 46, 0.96));
|
|
border-color: var(--c-border);
|
|
border-radius: 18px;
|
|
padding: 24px;
|
|
box-shadow: var(--shadow-card);
|
|
}
|
|
|
|
.form-box:hover,
|
|
.panel-box:hover {
|
|
border-color: rgba(148, 163, 184, 0.25);
|
|
}
|
|
|
|
.form-box > h3:first-child,
|
|
.panel-box > h3:first-child,
|
|
.modal h3 {
|
|
color: var(--c-text);
|
|
letter-spacing: -0.15px;
|
|
}
|
|
|
|
.form-group label {
|
|
color: var(--c-text-2);
|
|
letter-spacing: 0.05px;
|
|
}
|
|
|
|
.form-group input,
|
|
.form-group select,
|
|
.form-group textarea,
|
|
.form-group input[type="search"] {
|
|
min-height: 42px;
|
|
background: rgba(11, 18, 32, 0.7);
|
|
border-color: rgba(148, 163, 184, 0.22);
|
|
color: var(--c-text);
|
|
color-scheme: dark;
|
|
}
|
|
|
|
.form-group textarea {
|
|
min-height: 96px;
|
|
}
|
|
|
|
.form-group input:focus,
|
|
.form-group select:focus,
|
|
.form-group textarea:focus {
|
|
background: rgba(11, 18, 32, 0.9);
|
|
border-color: var(--c-primary);
|
|
box-shadow: 0 0 0 3px rgba(129, 140, 248, 0.16);
|
|
}
|
|
|
|
.form-group input::placeholder,
|
|
.form-group textarea::placeholder {
|
|
color: #708099;
|
|
}
|
|
|
|
.form-group input[type="file"] {
|
|
min-height: 42px;
|
|
padding: 7px 10px;
|
|
background: rgba(11, 18, 32, 0.7);
|
|
}
|
|
|
|
.form-group input[type="file"]::file-selector-button {
|
|
margin-right: 10px;
|
|
padding: 6px 10px;
|
|
border: 1px solid rgba(129, 140, 248, 0.32);
|
|
border-radius: 7px;
|
|
background: rgba(129, 140, 248, 0.13);
|
|
color: #dbe4ff;
|
|
font: inherit;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.form-group input[readonly] {
|
|
background: rgba(148, 163, 184, 0.08) !important;
|
|
color: var(--c-text-2);
|
|
}
|
|
|
|
.btn {
|
|
min-height: 42px;
|
|
padding: 10px 17px;
|
|
background: linear-gradient(135deg, #818cf8, #6366f1);
|
|
color: #0b1220;
|
|
font-weight: 700;
|
|
box-shadow: 0 7px 18px -12px rgba(129, 140, 248, 0.9);
|
|
transition: box-shadow var(--motion-fast) ease, transform var(--motion-fast) ease, background var(--motion-fast) ease, opacity var(--motion-fast) ease;
|
|
}
|
|
|
|
.btn:hover {
|
|
background: linear-gradient(135deg, #a5b4fc, #818cf8);
|
|
color: #0b1220;
|
|
box-shadow: 0 11px 24px -12px rgba(129, 140, 248, 0.95);
|
|
}
|
|
|
|
.btn:active {
|
|
transform: translateY(1px) scale(0.99);
|
|
}
|
|
|
|
.btn-secondary {
|
|
background: rgba(20, 30, 49, 0.72);
|
|
color: var(--c-text-2);
|
|
border: 1px solid rgba(148, 163, 184, 0.24);
|
|
}
|
|
|
|
.btn-secondary:hover {
|
|
color: var(--c-text);
|
|
border-color: rgba(129, 140, 248, 0.48);
|
|
background: rgba(129, 140, 248, 0.13);
|
|
}
|
|
|
|
.btn-danger {
|
|
background: linear-gradient(135deg, #fb7185, #e11d48);
|
|
color: #fff1f2;
|
|
}
|
|
|
|
.btn-danger:hover {
|
|
background: linear-gradient(135deg, #fda4af, #fb7185);
|
|
color: #4c0519;
|
|
}
|
|
|
|
.btn-sm {
|
|
min-height: 36px;
|
|
padding: 7px 12px;
|
|
}
|
|
|
|
.msg {
|
|
color: var(--c-text-2);
|
|
background: rgba(148, 163, 184, 0.06);
|
|
border-color: rgba(148, 163, 184, 0.15);
|
|
}
|
|
|
|
.msg.ok {
|
|
color: #86efac;
|
|
background: rgba(74, 222, 128, 0.11);
|
|
border-color: rgba(74, 222, 128, 0.25);
|
|
}
|
|
|
|
.msg.err {
|
|
color: #fda4af;
|
|
background: rgba(251, 113, 133, 0.11);
|
|
border-color: rgba(251, 113, 133, 0.25);
|
|
}
|
|
|
|
.progress-bar {
|
|
background: rgba(148, 163, 184, 0.12);
|
|
}
|
|
|
|
.progress-fill {
|
|
background: linear-gradient(90deg, #818cf8, #4ade80);
|
|
}
|
|
|
|
.request-loading {
|
|
color: var(--c-text);
|
|
background: rgba(20, 30, 49, 0.96);
|
|
border-color: rgba(148, 163, 184, 0.24);
|
|
box-shadow: var(--shadow-pop);
|
|
}
|
|
|
|
.request-spinner {
|
|
border-color: rgba(129, 140, 248, 0.22);
|
|
border-top-color: var(--c-primary);
|
|
}
|
|
|
|
.dedupe-export-wait-mask {
|
|
background: rgba(2, 6, 23, 0.68);
|
|
backdrop-filter: blur(7px);
|
|
}
|
|
|
|
.dedupe-export-wait {
|
|
background: #18243a;
|
|
border: 1px solid var(--c-border-strong);
|
|
box-shadow: var(--shadow-pop);
|
|
}
|
|
|
|
.dedupe-export-wait-title {
|
|
color: var(--c-text);
|
|
}
|
|
|
|
.dedupe-export-wait-detail {
|
|
color: var(--c-text-2);
|
|
}
|
|
|
|
th,
|
|
td {
|
|
border-bottom-color: rgba(148, 163, 184, 0.14);
|
|
}
|
|
|
|
th {
|
|
background: rgba(11, 18, 32, 0.62);
|
|
color: var(--c-text-2);
|
|
}
|
|
|
|
tbody tr:hover {
|
|
background: rgba(129, 140, 248, 0.07);
|
|
}
|
|
|
|
.empty-tip {
|
|
color: var(--c-text-3);
|
|
}
|
|
|
|
.tree-node-mark {
|
|
background: rgba(129, 140, 248, 0.14);
|
|
color: var(--c-primary-strong);
|
|
}
|
|
|
|
.tree-node-mark:not(.is-leaf):hover {
|
|
background: var(--c-primary);
|
|
color: #0b1220;
|
|
}
|
|
|
|
.tree-node-mark.is-leaf {
|
|
background: transparent;
|
|
}
|
|
|
|
.category-path,
|
|
.progress-text {
|
|
color: var(--c-text-3);
|
|
}
|
|
|
|
.category-tag {
|
|
background: rgba(129, 140, 248, 0.14);
|
|
color: var(--c-primary-strong);
|
|
border: 1px solid rgba(129, 140, 248, 0.22);
|
|
}
|
|
|
|
.modal-mask {
|
|
background: rgba(2, 6, 23, 0.7);
|
|
backdrop-filter: blur(8px);
|
|
}
|
|
|
|
.modal {
|
|
background: #18243a;
|
|
border: 1px solid var(--c-border-strong);
|
|
box-shadow: var(--shadow-pop);
|
|
}
|
|
|
|
.shop-group-modal-header,
|
|
.shop-group-table-wrap,
|
|
.dedupe-group-access {
|
|
border-color: rgba(148, 163, 184, 0.16);
|
|
}
|
|
|
|
.shop-group-table-wrap {
|
|
background: rgba(11, 18, 32, 0.38);
|
|
}
|
|
|
|
.dedupe-group-summary-chip {
|
|
background: rgba(148, 163, 184, 0.08);
|
|
color: var(--c-text-2);
|
|
border-color: rgba(148, 163, 184, 0.18);
|
|
}
|
|
|
|
.shop-key-whitelist-status.is-allowed {
|
|
color: #86efac;
|
|
background: rgba(74, 222, 128, 0.11);
|
|
border-color: rgba(74, 222, 128, 0.25);
|
|
}
|
|
|
|
.shop-key-whitelist-status.is-blocked {
|
|
color: #fda4af;
|
|
background: rgba(251, 113, 133, 0.11);
|
|
border-color: rgba(251, 113, 133, 0.25);
|
|
}
|
|
|
|
.shop-key-whitelist-status.is-unknown {
|
|
color: var(--c-text-2);
|
|
background: rgba(148, 163, 184, 0.08);
|
|
border-color: rgba(148, 163, 184, 0.2);
|
|
}
|
|
|
|
.shop-password-toggle {
|
|
width: 40px;
|
|
height: 40px;
|
|
flex-basis: 40px;
|
|
color: var(--c-text-2);
|
|
}
|
|
|
|
.shop-password-toggle:hover:not(:disabled) {
|
|
color: var(--c-primary-strong);
|
|
background: rgba(129, 140, 248, 0.13);
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb {
|
|
background: rgba(148, 163, 184, 0.28);
|
|
background-clip: content-box;
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: rgba(148, 163, 184, 0.46);
|
|
background-clip: content-box;
|
|
}
|
|
|
|
:focus-visible {
|
|
outline: 2px solid #a5b4fc;
|
|
outline-offset: 3px;
|
|
}
|
|
|
|
@media (max-width: 960px) {
|
|
.admin-topbar {
|
|
padding: 0 20px;
|
|
}
|
|
|
|
.admin-content {
|
|
padding: 24px 20px 44px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 760px) {
|
|
.admin-brand {
|
|
min-height: 68px;
|
|
padding: 14px 16px 12px;
|
|
}
|
|
|
|
.admin-topbar {
|
|
height: 68px;
|
|
padding: 0 14px;
|
|
}
|
|
|
|
.admin-topbar-kicker,
|
|
.admin-page-section,
|
|
.admin-page-separator {
|
|
display: none;
|
|
}
|
|
|
|
.admin-page-title {
|
|
font-size: 16px;
|
|
}
|
|
|
|
.admin-content {
|
|
padding: 18px 14px 32px;
|
|
}
|
|
|
|
.form-box,
|
|
.panel-box {
|
|
padding: 18px;
|
|
border-radius: 14px;
|
|
}
|
|
|
|
.admin-user-box {
|
|
gap: 8px;
|
|
}
|
|
|
|
.admin-user-name {
|
|
max-width: 104px;
|
|
}
|
|
|
|
.admin-user-logout {
|
|
min-height: 38px;
|
|
padding: 7px 10px;
|
|
}
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
scroll-behavior: auto !important;
|
|
animation-duration: 0.01ms !important;
|
|
animation-iteration-count: 1 !important;
|
|
transition-duration: 0.01ms !important;
|
|
}
|
|
}
|
|
|
|
/* ===== 组件层深色适配与触控尺寸 ===== */
|
|
html { scroll-padding-top: 92px; }
|
|
|
|
.menu-group-title,
|
|
.tab,
|
|
.btn,
|
|
.btn-sm,
|
|
.admin-user-logout,
|
|
.shop-password-toggle,
|
|
.image-video-card-action,
|
|
.image-video-permission-tab,
|
|
.image-video-permission-state {
|
|
min-height: 44px;
|
|
}
|
|
|
|
.form-group input,
|
|
.form-group select,
|
|
.form-group textarea,
|
|
.form-group input[type="search"],
|
|
.multi-select-trigger,
|
|
.image-video-permission-search {
|
|
min-height: 44px;
|
|
}
|
|
|
|
.column-permission-tree,
|
|
.multi-select-panel,
|
|
.column-permission-select {
|
|
background: rgba(11, 18, 32, 0.72);
|
|
border-color: rgba(148, 163, 184, 0.22);
|
|
color: var(--c-text);
|
|
color-scheme: dark;
|
|
}
|
|
|
|
.column-tree-group-toggle {
|
|
min-height: 44px;
|
|
background: rgba(148, 163, 184, 0.08);
|
|
color: var(--c-text);
|
|
}
|
|
|
|
.column-tree-group-toggle:hover,
|
|
.column-tree-toggle:hover {
|
|
background: rgba(129, 140, 248, 0.13);
|
|
color: var(--c-primary-strong);
|
|
}
|
|
|
|
.column-tree-group-toggle::before,
|
|
.column-tree-group-count {
|
|
color: var(--c-text-3);
|
|
}
|
|
|
|
.column-tree-node label {
|
|
min-height: 36px;
|
|
color: var(--c-text-2);
|
|
}
|
|
|
|
.multi-select-trigger {
|
|
background: rgba(11, 18, 32, 0.7);
|
|
border-color: rgba(148, 163, 184, 0.22);
|
|
color: var(--c-text);
|
|
}
|
|
|
|
.multi-select-trigger:hover,
|
|
.multi-select-dropdown.open .multi-select-trigger {
|
|
background: rgba(11, 18, 32, 0.92);
|
|
border-color: var(--c-primary);
|
|
}
|
|
|
|
.multi-select-option {
|
|
min-height: 44px;
|
|
color: var(--c-text-2);
|
|
}
|
|
|
|
.multi-select-option:hover {
|
|
background: rgba(129, 140, 248, 0.13);
|
|
color: var(--c-text);
|
|
}
|
|
|
|
.column-permission-card {
|
|
background: rgba(129, 140, 248, 0.14);
|
|
color: var(--c-primary-strong);
|
|
border: 1px solid rgba(129, 140, 248, 0.22);
|
|
}
|
|
|
|
.image-video-card {
|
|
background: linear-gradient(145deg, rgba(20, 30, 49, 0.98), rgba(16, 26, 46, 0.96));
|
|
border-color: rgba(148, 163, 184, 0.18);
|
|
}
|
|
|
|
.image-video-card:hover {
|
|
border-color: rgba(129, 140, 248, 0.48);
|
|
box-shadow: 0 14px 28px -18px rgba(2, 6, 23, 0.95);
|
|
}
|
|
|
|
.image-video-status {
|
|
background: rgba(148, 163, 184, 0.1);
|
|
color: var(--c-text-2);
|
|
}
|
|
|
|
.image-video-status.SUCCESS {
|
|
color: #86efac;
|
|
background: rgba(74, 222, 128, 0.11);
|
|
}
|
|
|
|
.image-video-status.FAILED {
|
|
color: #fda4af;
|
|
background: rgba(251, 113, 133, 0.11);
|
|
}
|
|
|
|
.image-video-status.RUNNING,
|
|
.image-video-status.POLLING {
|
|
color: #fde68a;
|
|
background: rgba(251, 191, 36, 0.12);
|
|
}
|
|
|
|
.image-video-info-row a,
|
|
.image-video-copy-link {
|
|
color: var(--c-primary-strong);
|
|
}
|
|
|
|
.image-video-card-action {
|
|
border-color: rgba(129, 140, 248, 0.42);
|
|
background: rgba(20, 30, 49, 0.72);
|
|
color: var(--c-primary-strong);
|
|
}
|
|
|
|
.image-video-card-action:hover {
|
|
background: var(--c-primary);
|
|
color: #0b1220;
|
|
}
|
|
|
|
.image-video-empty {
|
|
border-color: rgba(129, 140, 248, 0.32);
|
|
background: rgba(129, 140, 248, 0.08);
|
|
color: var(--c-text-2);
|
|
}
|
|
|
|
.shop-data-result-list,
|
|
.shop-data-result {
|
|
border-color: rgba(148, 163, 184, 0.14);
|
|
}
|
|
|
|
.shop-data-result.selected {
|
|
background: rgba(129, 140, 248, 0.09);
|
|
}
|
|
|
|
.image-video-permission-tabs {
|
|
background: rgba(11, 18, 32, 0.72);
|
|
border: 1px solid rgba(148, 163, 184, 0.16);
|
|
}
|
|
|
|
.image-video-permission-tab {
|
|
color: var(--c-text-2);
|
|
}
|
|
|
|
.image-video-permission-tab:hover,
|
|
.image-video-permission-tab:focus-visible {
|
|
color: var(--c-text);
|
|
background: rgba(129, 140, 248, 0.1);
|
|
}
|
|
|
|
.image-video-permission-tab.active {
|
|
background: rgba(129, 140, 248, 0.2);
|
|
color: var(--c-primary-strong);
|
|
box-shadow: none;
|
|
}
|
|
|
|
.image-video-permission-search {
|
|
padding: 9px 12px;
|
|
background: rgba(11, 18, 32, 0.7);
|
|
border: 1px solid rgba(148, 163, 184, 0.22);
|
|
border-radius: var(--radius-sm);
|
|
color: var(--c-text);
|
|
font: inherit;
|
|
color-scheme: dark;
|
|
}
|
|
|
|
.image-video-permission-search:focus {
|
|
outline: none;
|
|
border-color: var(--c-primary);
|
|
box-shadow: 0 0 0 3px rgba(129, 140, 248, 0.16);
|
|
}
|
|
|
|
.image-video-permission-list {
|
|
border-color: rgba(148, 163, 184, 0.2);
|
|
background: rgba(11, 18, 32, 0.42);
|
|
}
|
|
|
|
.image-video-permission-row {
|
|
border-bottom-color: rgba(148, 163, 184, 0.14);
|
|
}
|
|
|
|
.image-video-permission-state {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: rgba(148, 163, 184, 0.08);
|
|
color: var(--c-text-2);
|
|
}
|
|
|
|
.image-video-permission-state.granted {
|
|
border-color: rgba(129, 140, 248, 0.32);
|
|
background: rgba(129, 140, 248, 0.14);
|
|
color: var(--c-primary-strong);
|
|
}
|
|
|
|
.image-video-permission-state.pending {
|
|
border-color: rgba(251, 191, 36, 0.32);
|
|
background: rgba(251, 191, 36, 0.12);
|
|
color: #fde68a;
|
|
}
|
|
|
|
.image-video-permission-empty {
|
|
color: var(--c-text-2);
|
|
}
|
|
|
|
select option {
|
|
background: #141e31;
|
|
color: var(--c-text);
|
|
}
|
|
|
|
@media (max-width: 760px) {
|
|
.btn-sm,
|
|
.image-video-permission-tab {
|
|
min-height: 44px;
|
|
}
|
|
}
|
|
|
|
|
|
/* 重新声明断点规则:覆盖全局桌面网格,避免平板端侧栏被拉成整页高 */
|
|
@media (max-width: 960px) {
|
|
.admin-layout {
|
|
grid-template-columns: minmax(0, 1fr);
|
|
}
|
|
|
|
.admin-sidebar {
|
|
position: static;
|
|
height: auto;
|
|
border-right: none;
|
|
border-bottom: 1px solid rgba(148, 163, 184, 0.14);
|
|
}
|
|
|
|
.admin-brand {
|
|
padding: 14px 16px 10px;
|
|
}
|
|
|
|
.admin-menu {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
overflow-x: auto;
|
|
overflow-y: hidden;
|
|
overscroll-behavior-x: contain;
|
|
padding: 0 12px 12px;
|
|
}
|
|
|
|
.menu-group {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
flex: 0 0 auto;
|
|
margin: 0;
|
|
}
|
|
|
|
.menu-group-body {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
padding: 0;
|
|
}
|
|
|
|
.menu-group-title,
|
|
.menu-group-chevron {
|
|
display: none;
|
|
}
|
|
|
|
.menu-group + .menu-group::before {
|
|
content: "";
|
|
width: 1px;
|
|
height: 18px;
|
|
margin: 0 6px;
|
|
background: rgba(148, 163, 184, 0.2);
|
|
}
|
|
|
|
.tab {
|
|
flex: 0 0 auto;
|
|
width: auto;
|
|
margin-bottom: 0;
|
|
white-space: nowrap;
|
|
transform: none;
|
|
}
|
|
|
|
.tab:hover {
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.tab.active {
|
|
box-shadow: inset 0 -3px 0 #818cf8, 0 8px 18px -16px rgba(129, 140, 248, 0.9);
|
|
}
|
|
|
|
.admin-sidebar-foot {
|
|
display: none;
|
|
}
|
|
|
|
.admin-topbar {
|
|
padding: 0 20px;
|
|
}
|
|
|
|
.admin-content {
|
|
padding: 24px 20px 44px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 760px) {
|
|
.admin-topbar {
|
|
height: 68px;
|
|
padding: 0 14px;
|
|
}
|
|
|
|
.admin-topbar-kicker,
|
|
.admin-page-section,
|
|
.admin-page-separator {
|
|
display: none;
|
|
}
|
|
|
|
.admin-page-title {
|
|
font-size: 16px;
|
|
}
|
|
|
|
.admin-content {
|
|
padding: 18px 14px 32px;
|
|
}
|
|
|
|
.form-box,
|
|
.panel-box {
|
|
padding: 18px;
|
|
border-radius: 14px;
|
|
}
|
|
|
|
.admin-user-box {
|
|
gap: 8px;
|
|
}
|
|
|
|
.admin-user-name {
|
|
max-width: 104px;
|
|
}
|
|
|
|
.admin-user-logout {
|
|
padding: 7px 10px;
|
|
}
|
|
}
|
|
|
|
|
|
/* ===== 莫兰迪亮色主题与数据表布局优化 ===== */
|
|
:root {
|
|
color-scheme: light;
|
|
--c-primary: #607a6d;
|
|
--c-primary-strong: #456052;
|
|
--c-primary-soft: #e7eeea;
|
|
--c-bg: #f2f4f1;
|
|
--c-card: #ffffff;
|
|
--c-card-raised: #f8faf8;
|
|
--c-border: #dbe3dd;
|
|
--c-border-strong: #bdcbc1;
|
|
--c-text: #29362f;
|
|
--c-text-2: #5d6c63;
|
|
--c-text-3: #7f8d84;
|
|
--c-danger: #a9545d;
|
|
--c-danger-soft: #f6e8e8;
|
|
--c-success: #4e8068;
|
|
--c-warning: #a87538;
|
|
--c-sidebar: #e7ece8;
|
|
--c-sidebar-2: #f1f4f1;
|
|
--c-sidebar-text: #596a60;
|
|
--radius: 14px;
|
|
--radius-sm: 9px;
|
|
--shadow-card: 0 1px 2px rgba(60, 77, 67, 0.05), 0 14px 30px -24px rgba(60, 77, 67, 0.28);
|
|
--shadow-pop: 0 22px 60px rgba(49, 64, 55, 0.2);
|
|
}
|
|
|
|
html { background: var(--c-bg); }
|
|
|
|
body {
|
|
color: var(--c-text);
|
|
background:
|
|
radial-gradient(circle at 14% -14%, rgba(177, 198, 185, 0.32), transparent 34rem),
|
|
radial-gradient(circle at 100% 0%, rgba(213, 190, 178, 0.17), transparent 26rem),
|
|
var(--c-bg);
|
|
}
|
|
|
|
.admin-sidebar {
|
|
background: linear-gradient(180deg, var(--c-sidebar-2), var(--c-sidebar));
|
|
color: var(--c-sidebar-text);
|
|
border-right: 1px solid #d5ded7;
|
|
box-shadow: 14px 0 34px -28px rgba(52, 70, 59, 0.34);
|
|
}
|
|
|
|
.admin-brand { border-bottom-color: #d5ded7; }
|
|
.admin-brand-mark,
|
|
.admin-user-avatar {
|
|
background: linear-gradient(135deg, #7f998a, #607a6d);
|
|
color: #ffffff;
|
|
box-shadow: 0 8px 20px rgba(96, 122, 109, 0.25);
|
|
}
|
|
.admin-brand-name { color: var(--c-text); }
|
|
.admin-brand-sub { color: #7b8981; }
|
|
.admin-menu { scrollbar-color: #c1cec4 transparent; }
|
|
.menu-group-title { color: #748279; }
|
|
.menu-group-title:hover { color: var(--c-primary-strong); background: rgba(96, 122, 109, 0.09); }
|
|
.tab { color: var(--c-sidebar-text); }
|
|
.tab:hover { color: var(--c-primary-strong); background: rgba(96, 122, 109, 0.09); border-color: rgba(96, 122, 109, 0.16); }
|
|
.tab.active { color: var(--c-primary-strong); background: linear-gradient(90deg, #dce8df, #edf3ee); border-color: #b8cbbd; box-shadow: inset 3px 0 0 #6f8b7b, 0 8px 18px -16px rgba(96, 122, 109, 0.5); }
|
|
.tab.active .adm-icon, .tab:hover .adm-icon { color: #607f6d; }
|
|
.admin-sidebar-foot { color: #7b8981; border-top-color: #d5ded7; }
|
|
|
|
.admin-topbar {
|
|
background: rgba(255, 255, 255, 0.9);
|
|
border-bottom-color: #dbe3dd;
|
|
box-shadow: 0 10px 28px -28px rgba(52, 70, 59, 0.42);
|
|
}
|
|
.admin-topbar-kicker { color: #74877b; }
|
|
.admin-page-section { color: #77877e; }
|
|
.admin-page-separator { color: #b1bdb5; }
|
|
.admin-page-title { color: var(--c-text); }
|
|
.admin-user-name { color: var(--c-text); }
|
|
.admin-user-role { color: var(--c-primary-strong); background: #e5eee7; border-color: #c4d5c8; }
|
|
.admin-user-logout { color: var(--c-text-2); background: #ffffff; border-color: #cfdad2; }
|
|
.admin-user-logout:hover { color: var(--c-primary-strong); border-color: #9eb5a5; background: #edf4ee; }
|
|
|
|
.admin-content { width: 100%; max-width: none; }
|
|
.tab-panel { width: 100%; min-width: 0; }
|
|
.form-box, .panel-box { width: 100%; min-width: 0; background: linear-gradient(145deg, #ffffff, #f9fbf9); border-color: var(--c-border); box-shadow: var(--shadow-card); }
|
|
.form-box:hover, .panel-box:hover { border-color: #c3d2c7; }
|
|
.form-box > h3:first-child, .panel-box > h3:first-child, .modal h3 { color: var(--c-text); }
|
|
.form-group label { color: var(--c-text-2); }
|
|
.form-group input, .form-group select, .form-group textarea, .form-group input[type="search"], .multi-select-trigger, .image-video-permission-search { background: #f8faf8; border-color: #cfdad2; color: var(--c-text); color-scheme: light; }
|
|
.form-group input:hover, .form-group select:hover, .form-group textarea:hover, .multi-select-trigger:hover { border-color: #aebfb3; }
|
|
.form-group input:focus, .form-group select:focus, .form-group textarea:focus, .image-video-permission-search:focus { background: #ffffff; border-color: #6f8b7b; box-shadow: 0 0 0 3px rgba(111, 139, 123, 0.16); }
|
|
.form-group input::placeholder, .form-group textarea::placeholder, .image-video-permission-search::placeholder { color: #87958c; }
|
|
.form-group input[type="file"] { background: #ffffff; }
|
|
.form-group input[type="file"]::file-selector-button { border-color: #b5c9ba; background: #edf3ee; color: var(--c-primary-strong); }
|
|
.form-group input[readonly] { background: #eef2ef !important; color: var(--c-text-2); }
|
|
|
|
.btn { background: linear-gradient(135deg, #718b7c, #607a6d); color: #ffffff; box-shadow: 0 8px 18px -14px rgba(96, 122, 109, 0.72); }
|
|
.btn:hover { background: linear-gradient(135deg, #7f998a, #6b8577); color: #ffffff; box-shadow: 0 11px 22px -14px rgba(96, 122, 109, 0.78); }
|
|
.btn-secondary { background: #ffffff; color: var(--c-text-2); border-color: #cbd8cf; }
|
|
.btn-secondary:hover { color: var(--c-primary-strong); border-color: #99b09f; background: #edf4ee; }
|
|
.btn-danger { background: linear-gradient(135deg, #bb6c72, #a9545d); color: #ffffff; }
|
|
.btn-danger:hover { background: linear-gradient(135deg, #c77b80, #b45e67); color: #ffffff; }
|
|
.msg { color: var(--c-text-2); background: #f2f6f3; border-color: #d8e2da; }
|
|
.msg.ok { color: #3d7158; background: #e8f2eb; border-color: #bcd5c3; }
|
|
.msg.err { color: #91474f; background: #f8ebeb; border-color: #e4c2c5; }
|
|
.progress-bar { background: #e4ebe5; }
|
|
.progress-fill { background: linear-gradient(90deg, #7f998a, #b49a84); }
|
|
.request-loading { color: var(--c-text); background: rgba(255, 255, 255, 0.97); border-color: #cbd8cf; box-shadow: var(--shadow-pop); }
|
|
.request-spinner { border-color: #d9e5dc; border-top-color: #6f8b7b; }
|
|
.dedupe-export-wait-mask, .modal-mask { background: rgba(52, 67, 58, 0.38); backdrop-filter: blur(6px); }
|
|
.dedupe-export-wait, .modal { background: #ffffff; border-color: #cbd8cf; box-shadow: var(--shadow-pop); }
|
|
.dedupe-export-wait-title { color: var(--c-text); }
|
|
.dedupe-export-wait-detail { color: var(--c-text-2); }
|
|
|
|
.table-scroll { width: 100%; min-width: 0; overflow-x: auto; overflow-y: hidden; border: 1px solid #e0e7e1; border-radius: 10px; background: #ffffff; }
|
|
.panel-box > .table-scroll { width: 100%; }
|
|
.table-scroll > table { width: 100% !important; min-width: 0; table-layout: fixed; }
|
|
.panel-box > table { width: 100% !important; table-layout: fixed; }
|
|
th { background: #edf2ee; color: #4e6055; border-bottom-color: #d5e0d7; }
|
|
td { color: var(--c-text); border-bottom-color: #e2e9e3; }
|
|
tbody tr:hover { background: #f0f6f1; }
|
|
.empty-tip { color: var(--c-text-3); }
|
|
.pagination { color: var(--c-text-2); }
|
|
.pagination button { background: #ffffff; border-color: #cbd8cf; color: var(--c-text-2); }
|
|
.pagination button:hover:not(:disabled) { background: #edf4ee; border-color: #99b09f; color: var(--c-primary-strong); }
|
|
.pagination button:disabled { background: #eef2ef; color: #9aa79e; }
|
|
|
|
#panel-users .user-table-scroll th:nth-child(1) { width: 8%; }
|
|
#panel-users .user-table-scroll th:nth-child(2) { width: 20%; }
|
|
#panel-users .user-table-scroll th:nth-child(3) { width: 17%; }
|
|
#panel-users .user-table-scroll th:nth-child(4) { width: 20%; }
|
|
#panel-users .user-table-scroll th:nth-child(5) { width: 22%; }
|
|
#panel-users .user-table-scroll th:nth-child(6) { width: 13%; }
|
|
#panel-dedupe-total-data .dedupe-table-scroll th:nth-child(1) { width: 13%; }
|
|
#panel-dedupe-total-data .dedupe-table-scroll th:nth-child(2) { width: 18%; }
|
|
#panel-dedupe-total-data .dedupe-table-scroll th:nth-child(3) { width: 12%; }
|
|
#panel-dedupe-total-data .dedupe-table-scroll th:nth-child(4) { width: 16%; }
|
|
#panel-dedupe-total-data .dedupe-table-scroll th:nth-child(5) { width: 16%; }
|
|
#panel-dedupe-total-data .dedupe-table-scroll th:nth-child(6) { width: 16%; }
|
|
#panel-dedupe-total-data .dedupe-table-scroll th:nth-child(7) { width: 9%; }
|
|
|
|
.shop-manage-table-scroll > table { min-width: 1220px; table-layout: fixed; }
|
|
#panel-shop-manage .shop-manage-table-scroll th:nth-child(1) { width: 58px; }
|
|
#panel-shop-manage .shop-manage-table-scroll th:nth-child(2) { width: 116px; }
|
|
#panel-shop-manage .shop-manage-table-scroll th:nth-child(3) { width: 126px; }
|
|
#panel-shop-manage .shop-manage-table-scroll th:nth-child(4) { width: 230px; }
|
|
#panel-shop-manage .shop-manage-table-scroll th:nth-child(5) { width: 150px; }
|
|
#panel-shop-manage .shop-manage-table-scroll th:nth-child(6) { width: 190px; }
|
|
#panel-shop-manage .shop-manage-table-scroll th:nth-child(7) { width: 108px; }
|
|
#panel-shop-manage .shop-manage-table-scroll th:nth-child(8), #panel-shop-manage .shop-manage-table-scroll th:nth-child(9) { width: 132px; }
|
|
#panel-shop-manage .shop-manage-table-scroll th:nth-child(10) { width: 150px; }
|
|
#panel-shop-manage .shop-manage-table-scroll td { overflow: hidden; }
|
|
.table-ellipsis { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.shop-password-cell { max-width: 100%; }
|
|
.shop-password-value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
|
|
.category-table-scroll > table { min-width: 860px; }
|
|
.category-table-scroll td { vertical-align: middle; }
|
|
.category-table-scroll .category-path-value { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.category-table-scroll .category-path { display: none; }
|
|
.category-tag { background: #e7eee9; border-color: #c5d6c9; color: var(--c-primary-strong); }
|
|
.tree-node-mark { background: #e5eee7; color: var(--c-primary-strong); }
|
|
.tree-node-mark:not(.is-leaf):hover { background: #6f8b7b; color: #ffffff; }
|
|
.column-permission-tree, .multi-select-panel, .column-permission-select { background: #ffffff; border-color: #cfdad2; color: var(--c-text); color-scheme: light; }
|
|
.column-tree-group-toggle { background: #edf3ee; color: var(--c-text); }
|
|
.column-tree-group-toggle:hover, .column-tree-toggle:hover { background: #e2ede4; color: var(--c-primary-strong); }
|
|
.column-tree-node label { color: var(--c-text-2); }
|
|
.multi-select-option { color: var(--c-text-2); }
|
|
.multi-select-option:hover { background: #edf4ee; color: var(--c-text); }
|
|
.column-permission-card { background: #e5eee7; color: var(--c-primary-strong); border-color: #c4d6c9; }
|
|
.image-video-card { background: #ffffff; border-color: var(--c-border); }
|
|
.image-video-card:hover { border-color: #a9bfaf; box-shadow: 0 14px 28px -18px rgba(60, 77, 67, 0.32); }
|
|
.image-video-status { background: #edf2ee; color: var(--c-text-2); }
|
|
.image-video-status.SUCCESS { color: #3e7258; background: #e8f2eb; }
|
|
.image-video-status.FAILED { color: #934a52; background: #f8ebeb; }
|
|
.image-video-status.RUNNING, .image-video-status.POLLING { color: #8c642b; background: #f7efdf; }
|
|
.image-video-info-row a, .image-video-copy-link { color: var(--c-primary-strong); }
|
|
.image-video-card-action { border-color: #a9bfaf; background: #ffffff; color: var(--c-primary-strong); }
|
|
.image-video-card-action:hover { background: #6f8b7b; color: #ffffff; }
|
|
.image-video-empty { border-color: #b8cdbd; background: #edf4ee; color: var(--c-text-2); }
|
|
.shop-data-result-list, .shop-data-result { border-color: #e0e8e1; }
|
|
.shop-data-result.selected { background: #eef5ef; }
|
|
.image-video-permission-tabs { background: #edf2ee; border-color: #d5e0d7; }
|
|
.image-video-permission-tab { color: var(--c-text-2); }
|
|
.image-video-permission-tab:hover, .image-video-permission-tab:focus-visible { color: var(--c-text); background: #e3eee5; }
|
|
.image-video-permission-tab.active { background: #ffffff; color: var(--c-primary-strong); }
|
|
.image-video-permission-list { border-color: #d5e0d7; background: #ffffff; }
|
|
.image-video-permission-row { border-bottom-color: #e2e9e3; }
|
|
.image-video-permission-state { background: #f0f4f1; color: var(--c-text-2); }
|
|
.image-video-permission-state.granted { border-color: #b8cdbd; background: #e7f0e9; color: var(--c-primary-strong); }
|
|
.image-video-permission-state.pending { border-color: #e1c98d; background: #f8f0df; color: #8b652f; }
|
|
select option { background: #ffffff; color: var(--c-text); }
|
|
::-webkit-scrollbar-thumb { background: #bdcbc0; background-clip: content-box; }
|
|
::-webkit-scrollbar-thumb:hover { background: #9daf9f; background-clip: content-box; }
|
|
:focus-visible { outline-color: #607a6d; }
|
|
|
|
@media (max-width: 960px) {
|
|
.admin-content { padding: 24px 20px 44px; }
|
|
}
|
|
|
|
@media (max-width: 760px) {
|
|
.admin-content { padding: 18px 14px 32px; }
|
|
.table-scroll { border-radius: 9px; }
|
|
.shop-manage-table-scroll > table, .category-table-scroll > table { min-width: 820px; }
|
|
}
|
|
|
|
|
|
/* ===== 蓝白色调 Admin UI / 全页面表格布局升级 ===== */
|
|
:root {
|
|
color-scheme: light;
|
|
--c-primary: #4f78a5;
|
|
--c-primary-strong: #2f5d8b;
|
|
--c-primary-soft: #e7f0f8;
|
|
--c-bg: #f4f7fb;
|
|
--c-card: #ffffff;
|
|
--c-card-raised: #f9fbfd;
|
|
--c-border: #d8e3ee;
|
|
--c-border-strong: #b7c9db;
|
|
--c-text: #24384d;
|
|
--c-text-2: #5b6f83;
|
|
--c-text-3: #8293a5;
|
|
--c-danger: #b35f6a;
|
|
--c-danger-soft: #faecee;
|
|
--c-success: #4e806d;
|
|
--c-warning: #a8793e;
|
|
--c-sidebar: #edf3f9;
|
|
--c-sidebar-2: #f8fbfe;
|
|
--c-sidebar-text: #536a81;
|
|
--radius: 14px;
|
|
--radius-sm: 9px;
|
|
--shadow-card: 0 1px 2px rgba(39, 67, 94, 0.04), 0 14px 30px -24px rgba(39, 67, 94, 0.28);
|
|
--shadow-pop: 0 22px 60px rgba(39, 67, 94, 0.2);
|
|
}
|
|
|
|
html { background: var(--c-bg); }
|
|
body {
|
|
color: var(--c-text);
|
|
background:
|
|
radial-gradient(circle at 12% -16%, rgba(178, 205, 229, 0.3), transparent 34rem),
|
|
radial-gradient(circle at 100% 0%, rgba(214, 226, 239, 0.28), transparent 28rem),
|
|
var(--c-bg);
|
|
}
|
|
|
|
.admin-sidebar {
|
|
background: linear-gradient(180deg, var(--c-sidebar-2), var(--c-sidebar));
|
|
color: var(--c-sidebar-text);
|
|
border-right-color: #d4e0eb;
|
|
box-shadow: 14px 0 34px -28px rgba(39, 67, 94, 0.34);
|
|
}
|
|
.admin-brand { border-bottom-color: #d4e0eb; }
|
|
.admin-brand-mark,
|
|
.admin-user-avatar {
|
|
background: linear-gradient(135deg, #7094ba, #4f78a5);
|
|
color: #ffffff;
|
|
box-shadow: 0 8px 20px rgba(79, 120, 165, 0.24);
|
|
}
|
|
.admin-brand-name { color: var(--c-text); }
|
|
.admin-brand-sub { color: #77899b; }
|
|
.admin-menu { scrollbar-color: #b9cbe0 transparent; }
|
|
.menu-group-title { color: #72859a; }
|
|
.menu-group-title:hover { color: var(--c-primary-strong); background: rgba(79, 120, 165, 0.09); }
|
|
.tab { color: var(--c-sidebar-text); }
|
|
.tab:hover { color: var(--c-primary-strong); background: rgba(79, 120, 165, 0.09); border-color: rgba(79, 120, 165, 0.16); }
|
|
.tab.active { color: var(--c-primary-strong); background: linear-gradient(90deg, #dce9f5, #edf4fa); border-color: #b6cbe0; box-shadow: inset 3px 0 0 #5f85ad, 0 8px 18px -16px rgba(79, 120, 165, 0.55); }
|
|
.tab.active .adm-icon, .tab:hover .adm-icon { color: #5f85ad; }
|
|
.admin-sidebar-foot { color: #7b8d9e; border-top-color: #d4e0eb; }
|
|
|
|
.admin-topbar { background: rgba(255, 255, 255, 0.92); border-bottom-color: #d8e3ee; box-shadow: 0 10px 28px -28px rgba(39, 67, 94, 0.42); }
|
|
.admin-topbar-kicker { color: #70859a; }
|
|
.admin-page-section { color: #718397; }
|
|
.admin-page-separator { color: #b2c1cf; }
|
|
.admin-page-title, .admin-user-name { color: var(--c-text); }
|
|
.admin-user-role { color: var(--c-primary-strong); background: #e6f0f8; border-color: #bfd1e2; }
|
|
.admin-user-logout { color: var(--c-text-2); background: #ffffff; border-color: #cbd9e6; }
|
|
.admin-user-logout:hover { color: var(--c-primary-strong); border-color: #94b0cb; background: #edf5fb; }
|
|
|
|
.admin-content { width: 100%; max-width: none; }
|
|
.tab-panel { width: 100%; min-width: 0; }
|
|
.form-box, .panel-box { width: 100%; min-width: 0; background: linear-gradient(145deg, #ffffff, #f9fbfd); border-color: var(--c-border); box-shadow: var(--shadow-card); }
|
|
.form-box:hover, .panel-box:hover { border-color: #bdd0e1; }
|
|
.form-box > h3:first-child, .panel-box > h3:first-child, .modal h3 { color: var(--c-text); }
|
|
.form-group label { color: var(--c-text-2); }
|
|
.form-group input, .form-group select, .form-group textarea, .form-group input[type="search"], .multi-select-trigger, .image-video-permission-search { background: #f8fbfd; border-color: #cbd9e6; color: var(--c-text); color-scheme: light; }
|
|
.form-group input:hover, .form-group select:hover, .form-group textarea:hover, .multi-select-trigger:hover { border-color: #9fb7cd; }
|
|
.form-group input:focus, .form-group select:focus, .form-group textarea:focus, .image-video-permission-search:focus { background: #ffffff; border-color: #5f85ad; box-shadow: 0 0 0 3px rgba(95, 133, 173, 0.16); }
|
|
.form-group input::placeholder, .form-group textarea::placeholder, .image-video-permission-search::placeholder { color: #8293a5; }
|
|
.form-group input[type="file"] { background: #ffffff; }
|
|
.form-group input[type="file"]::file-selector-button { border-color: #b4c9dd; background: #edf5fb; color: var(--c-primary-strong); }
|
|
.form-group input[readonly] { background: #eef3f7 !important; color: var(--c-text-2); }
|
|
|
|
.btn { background: linear-gradient(135deg, #5f85ad, #4f78a5); color: #ffffff; box-shadow: 0 8px 18px -14px rgba(79, 120, 165, 0.72); }
|
|
.btn:hover { background: linear-gradient(135deg, #7094ba, #5d83ac); color: #ffffff; box-shadow: 0 11px 22px -14px rgba(79, 120, 165, 0.8); }
|
|
.btn-secondary { background: #ffffff; color: var(--c-text-2); border-color: #c7d7e5; }
|
|
.btn-secondary:hover { color: var(--c-primary-strong); border-color: #95b1cb; background: #edf5fb; }
|
|
.btn-danger { background: linear-gradient(135deg, #c06d77, #b35f6a); color: #ffffff; }
|
|
.btn-danger:hover { background: linear-gradient(135deg, #cb7c84, #b96570); color: #ffffff; }
|
|
.msg { color: var(--c-text-2); background: #f1f6fa; border-color: #d6e2ec; }
|
|
.msg.ok { color: #3d7158; background: #e8f2eb; border-color: #bdd7c5; }
|
|
.msg.err { color: #91474f; background: #f8ebeb; border-color: #e4c2c5; }
|
|
.progress-bar { background: #e4ebf2; }
|
|
.progress-fill { background: linear-gradient(90deg, #6f95bb, #a3b7ca); }
|
|
.request-loading { color: var(--c-text); background: rgba(255, 255, 255, 0.97); border-color: #c7d7e5; box-shadow: var(--shadow-pop); }
|
|
.request-spinner { border-color: #d5e3ef; border-top-color: #5f85ad; }
|
|
.dedupe-export-wait-mask, .modal-mask { background: rgba(45, 66, 86, 0.36); backdrop-filter: blur(6px); }
|
|
.dedupe-export-wait, .modal { background: #ffffff; border-color: #c7d7e5; box-shadow: var(--shadow-pop); }
|
|
.dedupe-export-wait-title { color: var(--c-text); }
|
|
.dedupe-export-wait-detail { color: var(--c-text-2); }
|
|
|
|
.table-scroll, .shop-key-table-scroll { width: 100%; min-width: 0; overflow-x: auto; overflow-y: hidden; border: 1px solid #dbe5ee; border-radius: 10px; background: #ffffff; }
|
|
.panel-box > table, .panel-box > .table-scroll > table, .shop-key-table-scroll > table { width: 100% !important; table-layout: fixed; }
|
|
.table-scroll > table { min-width: 0; }
|
|
th { background: #edf4fa; color: #4e6479; border-bottom-color: #d5e1eb; }
|
|
td { color: var(--c-text); border-bottom-color: #e0e8ef; }
|
|
tbody tr:hover { background: #f1f7fb; }
|
|
.empty-tip { color: var(--c-text-3); }
|
|
.pagination { color: var(--c-text-2); }
|
|
.pagination button { background: #ffffff; border-color: #c7d7e5; color: var(--c-text-2); }
|
|
.pagination button:hover:not(:disabled) { background: #edf5fb; border-color: #95b1cb; color: var(--c-primary-strong); }
|
|
.pagination button:disabled { background: #eef3f7; color: #9baaba; }
|
|
.shop-key-table-scroll table { min-width: 980px; }
|
|
|
|
#panel-invalid-asin-data .invalid-asin-table-scroll > table { min-width: 760px; }
|
|
#panel-columns .columns-table-scroll > table { min-width: 980px; }
|
|
#panel-version .version-table-scroll > table { min-width: 760px; }
|
|
#panel-digital-human-version .digital-human-version-table-scroll > table { min-width: 1120px; }
|
|
#panel-history .history-table-scroll > table { min-width: 820px; }
|
|
|
|
.query-asin-table-scroll > table, .skip-price-asin-table-scroll > table { min-width: 1180px; table-layout: fixed; }
|
|
#panel-query-asin .query-asin-table-scroll th:nth-child(1), #panel-skip-price-asin .skip-price-asin-table-scroll th:nth-child(1) { width: 6%; }
|
|
#panel-query-asin .query-asin-table-scroll th:nth-child(2), #panel-skip-price-asin .skip-price-asin-table-scroll th:nth-child(2) { width: 11%; }
|
|
#panel-query-asin .query-asin-table-scroll th:nth-child(3), #panel-skip-price-asin .skip-price-asin-table-scroll th:nth-child(3) { width: 12%; }
|
|
#panel-query-asin .query-asin-table-scroll th:nth-child(n+4), #panel-skip-price-asin .skip-price-asin-table-scroll th:nth-child(n+4) { width: 14.2%; }
|
|
#panel-query-asin .query-asin-table-scroll td, #panel-skip-price-asin .skip-price-asin-table-scroll td { vertical-align: top; }
|
|
|
|
.table-ellipsis { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.asin-cell-layout { display: flex; flex-direction: column; align-items: stretch; gap: 8px; min-width: 0; }
|
|
.asin-cell-content { min-width: 0; overflow: hidden; }
|
|
.asin-cell-value { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
.asin-cell-meta { display: block; margin-top: 3px; color: #73869a; font-size: 12px; white-space: nowrap; }
|
|
.asin-empty-value, .asin-empty-hint { color: #8b9aaa; }
|
|
.asin-cell-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
|
|
.asin-cell-actions .btn-sm { min-height: 38px; padding: 7px 10px; }
|
|
.skip-price-entry { display: grid !important; grid-template-columns: 58px minmax(0, 1fr) 140px; align-items: center; gap: 8px !important; }
|
|
.skip-price-country { color: var(--c-text-2); font-weight: 600; }
|
|
.skip-price-entry input { min-width: 0 !important; width: auto !important; }
|
|
|
|
#panel-query-asin .panel-box > .form-row, #panel-skip-price-asin .panel-box > .form-row { display: grid; grid-template-columns: minmax(150px, 0.8fr) minmax(180px, 1fr) minmax(180px, 1fr) auto auto; gap: 12px; align-items: end; }
|
|
#panel-query-asin .panel-box > .form-row .form-group, #panel-skip-price-asin .panel-box > .form-row .form-group { min-width: 0 !important; }
|
|
|
|
.category-table-scroll .category-path-value { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.category-table-scroll .category-path { display: none; }
|
|
.category-tag { background: #e7f0f8; border-color: #c2d5e6; color: var(--c-primary-strong); }
|
|
.tree-node-mark { background: #e7f0f8; color: var(--c-primary-strong); }
|
|
.tree-node-mark:not(.is-leaf):hover { background: #5f85ad; color: #ffffff; }
|
|
.column-permission-tree, .multi-select-panel, .column-permission-select { background: #ffffff; border-color: #cbd9e6; color: var(--c-text); color-scheme: light; }
|
|
.column-tree-group-toggle { background: #edf5fb; color: var(--c-text); }
|
|
.column-tree-group-toggle:hover, .column-tree-toggle:hover { background: #e1edf6; color: var(--c-primary-strong); }
|
|
.column-tree-node label { color: var(--c-text-2); }
|
|
.multi-select-option { color: var(--c-text-2); }
|
|
.multi-select-option:hover { background: #edf5fb; color: var(--c-text); }
|
|
.column-permission-card { background: #e7f0f8; color: var(--c-primary-strong); border-color: #bfd3e5; }
|
|
.image-video-card { background: #ffffff; border-color: var(--c-border); }
|
|
.image-video-card:hover { border-color: #a7bfd4; box-shadow: 0 14px 28px -18px rgba(39, 67, 94, 0.32); }
|
|
.image-video-status { background: #edf4fa; color: var(--c-text-2); }
|
|
.image-video-status.SUCCESS { color: #3e7258; background: #e8f2eb; }
|
|
.image-video-status.FAILED { color: #934a52; background: #f8ebeb; }
|
|
.image-video-status.RUNNING, .image-video-status.POLLING { color: #8c642b; background: #f7efdf; }
|
|
.image-video-info-row a, .image-video-copy-link { color: var(--c-primary-strong); }
|
|
.image-video-card-action { border-color: #a7bfd4; background: #ffffff; color: var(--c-primary-strong); }
|
|
.image-video-card-action:hover { background: #5f85ad; color: #ffffff; }
|
|
.image-video-empty { border-color: #b8cfe2; background: #edf5fb; color: var(--c-text-2); }
|
|
.shop-data-result-list, .shop-data-result { border-color: #dfe8ef; }
|
|
.shop-data-result.selected { background: #edf5fb; }
|
|
.image-video-permission-tabs { background: #edf4fa; border-color: #d5e1eb; }
|
|
.image-video-permission-tab { color: var(--c-text-2); }
|
|
.image-video-permission-tab:hover, .image-video-permission-tab:focus-visible { color: var(--c-text); background: #e3eff7; }
|
|
.image-video-permission-tab.active { background: #ffffff; color: var(--c-primary-strong); }
|
|
.image-video-permission-list { border-color: #d5e1eb; background: #ffffff; }
|
|
.image-video-permission-row { border-bottom-color: #e0e8ef; }
|
|
.image-video-permission-state { background: #f0f4f8; color: var(--c-text-2); }
|
|
.image-video-permission-state.granted { border-color: #b8cfe2; background: #e7f0f8; color: var(--c-primary-strong); }
|
|
.image-video-permission-state.pending { border-color: #e1c98d; background: #f8f0df; color: #8b652f; }
|
|
select option { background: #ffffff; color: var(--c-text); }
|
|
::-webkit-scrollbar-thumb { background: #b9cbe0; background-clip: content-box; }
|
|
::-webkit-scrollbar-thumb:hover { background: #95aec7; background-clip: content-box; }
|
|
:focus-visible { outline-color: #4f78a5; }
|
|
|
|
@media (max-width: 960px) {
|
|
.admin-content { padding: 24px 20px 44px; }
|
|
}
|
|
@media (max-width: 760px) {
|
|
.admin-content { padding: 18px 14px 32px; }
|
|
.table-scroll { border-radius: 9px; }
|
|
.shop-manage-table-scroll > table, .category-table-scroll > table, .query-asin-table-scroll > table, .skip-price-asin-table-scroll > table { min-width: 920px; }
|
|
#panel-query-asin .panel-box > .form-row, #panel-skip-price-asin .panel-box > .form-row { grid-template-columns: minmax(0, 1fr); align-items: stretch; }
|
|
.skip-price-entry { grid-template-columns: 56px minmax(0, 1fr); }
|
|
.skip-price-entry .skip-price-minimum-input { grid-column: 2; }
|
|
}
|
|
|
|
|
|
/* 列表布局第二轮:桌面满宽,窄屏在容器内横向滚动,避免列被压成竖排 */
|
|
#panel-users .user-table-scroll > table { min-width: 860px; }
|
|
#panel-dedupe-total-data .dedupe-table-scroll > table { min-width: 900px; }
|
|
#panel-invalid-asin-data .invalid-asin-table-scroll > table { min-width: 760px; }
|
|
#panel-columns .columns-table-scroll > table { min-width: 980px; }
|
|
#panel-version .version-table-scroll > table { min-width: 760px; }
|
|
#panel-digital-human-version .digital-human-version-table-scroll > table { min-width: 1120px; }
|
|
#panel-history .history-table-scroll > table { min-width: 820px; }
|
|
#panel-shop-keys .shop-key-table-scroll > table { min-width: 980px; }
|
|
|
|
@media (max-width: 760px) {
|
|
#panel-users .user-table-scroll > table { min-width: 720px; }
|
|
#panel-dedupe-total-data .dedupe-table-scroll > table { min-width: 860px; }
|
|
#panel-invalid-asin-data .invalid-asin-table-scroll > table { min-width: 720px; }
|
|
#panel-columns .columns-table-scroll > table { min-width: 900px; }
|
|
#panel-version .version-table-scroll > table { min-width: 700px; }
|
|
#panel-digital-human-version .digital-human-version-table-scroll > table { min-width: 980px; }
|
|
#panel-history .history-table-scroll > table { min-width: 760px; }
|
|
#panel-shop-keys .shop-key-table-scroll > table { min-width: 900px; }
|
|
}
|
|
|
|
|
|
/* ===== 全局交互引导、反馈与确认 ===== */
|
|
.admin-operation-guide {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: 18px;
|
|
margin: 0 0 18px;
|
|
padding: 15px 18px;
|
|
border: 1px solid #cbdced;
|
|
border-radius: 12px;
|
|
background: linear-gradient(110deg, #edf6ff, #f8fbff 68%);
|
|
color: #294968;
|
|
box-shadow: 0 9px 18px -18px rgba(47, 93, 139, 0.55);
|
|
}
|
|
|
|
.admin-operation-guide__main { display: flex; gap: 12px; min-width: 0; }
|
|
.admin-operation-guide__icon { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 32px; width: 32px; height: 32px; border-radius: 10px; background: #dcecfb; color: #3f73a6; }
|
|
.admin-operation-guide__icon svg { width: 18px; height: 18px; }
|
|
.admin-operation-guide__title { font-size: 13px; font-weight: 700; color: #2d5f90; }
|
|
.admin-operation-guide__text { margin: 3px 0 0; color: #5a7189; font-size: 13px; line-height: 1.55; }
|
|
.admin-operation-guide__steps { display: flex; flex-wrap: wrap; gap: 8px 18px; margin: 9px 0 0; padding: 0; list-style: none; counter-reset: admin-guide-step; }
|
|
.admin-operation-guide__steps li { display: inline-flex; align-items: center; gap: 5px; color: #486780; font-size: 12px; }
|
|
.admin-operation-guide__steps li::before { counter-increment: admin-guide-step; content: counter(admin-guide-step); display: inline-flex; align-items: center; justify-content: center; width: 17px; height: 17px; border-radius: 50%; background: #cfe1f2; color: #315f8e; font-size: 10px; font-weight: 700; }
|
|
.admin-operation-guide__toggle { flex: 0 0 auto; min-height: 34px; padding: 6px 10px; border: 1px solid #bcd2e6; border-radius: 8px; background: #ffffff; color: #3b668f; cursor: pointer; font: inherit; font-size: 12px; font-weight: 600; }
|
|
.admin-operation-guide__toggle:hover { border-color: #8fb4d6; background: #f4f9fe; }
|
|
.admin-operation-guide.is-collapsed { padding: 10px 14px; align-items: center; }
|
|
.admin-operation-guide.is-collapsed .admin-operation-guide__text, .admin-operation-guide.is-collapsed .admin-operation-guide__steps { display: none; }
|
|
.admin-operation-guide.is-collapsed .admin-operation-guide__main { align-items: center; }
|
|
|
|
.admin-toast-region { position: fixed; top: 92px; right: 24px; z-index: 4100; display: grid; gap: 10px; width: min(390px, calc(100vw - 32px)); pointer-events: none; }
|
|
.admin-toast { display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px; border: 1px solid #bfd3e6; border-radius: 11px; background: rgba(255, 255, 255, 0.98); color: #2f4f6d; box-shadow: 0 18px 36px -24px rgba(38, 69, 101, 0.45); animation: admin-toast-in 180ms ease both; }
|
|
.admin-toast::before { content: "✓"; display: inline-flex; align-items: center; justify-content: center; flex: 0 0 20px; width: 20px; height: 20px; border-radius: 50%; background: #e7f2ea; color: #3f7657; font-size: 12px; font-weight: 800; }
|
|
.admin-toast.is-error { border-color: #e5c2c8; color: #834650; }
|
|
.admin-toast.is-error::before { content: "!"; background: #faebed; color: #a9545d; }
|
|
.admin-toast.is-info::before { content: "i"; background: #e7f0f8; color: #3d6e9d; font-family: Georgia, serif; }
|
|
.admin-toast__text { min-width: 0; line-height: 1.5; font-size: 13px; }
|
|
@keyframes admin-toast-in { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: translateY(0); } }
|
|
|
|
body.admin-confirm-open { overflow: hidden; }
|
|
|
|
.admin-confirm-mask { position: fixed; inset: 0; z-index: 4050; display: none; align-items: center; justify-content: center; padding: 20px; background: rgba(39, 65, 91, 0.32); backdrop-filter: blur(4px); }
|
|
.admin-confirm-mask.show { display: flex; }
|
|
.admin-confirm-dialog { display: grid; grid-template-columns: 42px minmax(0, 1fr); gap: 13px 14px; width: min(460px, calc(100vw - 36px)); padding: 22px; border: 1px solid #c5d8e9; border-radius: 16px; background: #ffffff; box-shadow: 0 28px 72px rgba(35, 62, 91, 0.24); }
|
|
.admin-confirm-dialog__icon { display: inline-flex; align-items: center; justify-content: center; width: 42px; height: 42px; border-radius: 12px; background: #fff2e7; color: #a66b36; }
|
|
.admin-confirm-dialog__icon svg { width: 22px; height: 22px; }
|
|
.admin-confirm-dialog__content h2 { margin: 1px 0 6px; color: #29435e; font-size: 17px; }
|
|
.admin-confirm-dialog__content p { margin: 0; color: #60758b; line-height: 1.6; font-size: 13px; white-space: pre-wrap; }
|
|
.admin-confirm-dialog__actions { grid-column: 1 / -1; display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; }
|
|
|
|
.btn.is-busy { position: relative; pointer-events: none; opacity: 0.72; }
|
|
.btn.is-busy::before { content: ""; display: inline-block; width: 13px; height: 13px; margin-right: 6px; border: 2px solid rgba(255,255,255,0.45); border-top-color: #ffffff; border-radius: 50%; vertical-align: -2px; animation: admin-action-spin 0.75s linear infinite; }
|
|
.btn-secondary.is-busy::before { border-color: rgba(67,103,143,0.25); border-top-color: #3f73a6; }
|
|
@keyframes admin-action-spin { to { transform: rotate(360deg); } }
|
|
|
|
.table-help { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; margin-left: 4px; border-radius: 50%; background: #d9eaf8; color: #3f73a6; font-size: 10px; font-weight: 700; vertical-align: 1px; }
|
|
#panel-shop-keys .shop-key-table-scroll > table { min-width: 1140px; table-layout: fixed; }
|
|
#panel-shop-keys .shop-key-table-scroll th:nth-child(1) { width: 6%; }
|
|
#panel-shop-keys .shop-key-table-scroll th:nth-child(2) { width: 13%; }
|
|
#panel-shop-keys .shop-key-table-scroll th:nth-child(3) { width: 18%; }
|
|
#panel-shop-keys .shop-key-table-scroll th:nth-child(4) { width: 20%; }
|
|
#panel-shop-keys .shop-key-table-scroll th:nth-child(5) { width: 12%; }
|
|
#panel-shop-keys .shop-key-table-scroll th:nth-child(6), #panel-shop-keys .shop-key-table-scroll th:nth-child(7) { width: 12%; }
|
|
#panel-shop-keys .shop-key-table-scroll th:nth-child(8) { width: 15%; }
|
|
#panel-shop-keys .shop-key-table-scroll td { overflow: hidden; }
|
|
#panel-shop-keys .shop-key-whitelist-status { min-width: 82px; justify-content: center; padding: 5px 10px; }
|
|
#panel-shop-keys .shop-key-whitelist-status::before { content: ""; width: 6px; height: 6px; margin-right: 5px; border-radius: 50%; background: currentColor; }
|
|
#panel-shop-keys .table-ellipsis { max-width: 100%; }
|
|
.empty-tip[role="status"] { padding: 38px 18px; color: #70849a; }
|
|
|
|
@media (max-width: 760px) {
|
|
.admin-operation-guide { padding: 12px; gap: 10px; }
|
|
.admin-operation-guide__steps { gap: 7px 10px; }
|
|
.admin-operation-guide__toggle { min-height: 38px; }
|
|
.admin-toast-region { top: 80px; right: 16px; }
|
|
.admin-confirm-dialog { padding: 18px; }
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<a class="skip-link" href="#adminContent">跳转到主要内容</a>
|
|
<!-- <div class="nav"><a href="/home">返回首页</a></div> -->
|
|
<div class="request-loading-bar" id="requestLoadingBar"></div>
|
|
<div class="request-loading" id="requestLoading">
|
|
<span class="request-spinner"></span>
|
|
<span>请求处理中...</span>
|
|
</div>
|
|
<div class="dedupe-export-wait-mask" id="dedupeTotalDataExportWait" role="dialog" aria-modal="true"
|
|
aria-labelledby="dedupeTotalDataExportWaitTitle" aria-hidden="true">
|
|
<div class="dedupe-export-wait">
|
|
<span class="request-spinner" aria-hidden="true"></span>
|
|
<div>
|
|
<div class="dedupe-export-wait-title" id="dedupeTotalDataExportWaitTitle">正在生成导出文件</div>
|
|
<div class="dedupe-export-wait-detail">
|
|
数据量较大,请耐心等待并保持页面打开。已等待 <span id="dedupeTotalDataExportWaitSeconds">0</span> 秒
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="admin-layout">
|
|
<aside class="admin-sidebar">
|
|
<div class="admin-brand">
|
|
<span class="admin-brand-mark" aria-hidden="true">数</span>
|
|
<span class="admin-brand-text">
|
|
<span class="admin-brand-name">数富AI</span>
|
|
<span class="admin-brand-sub">电商运营管理后台</span>
|
|
</span>
|
|
</div>
|
|
<nav class="admin-menu" id="adminMenu" aria-label="管理菜单">
|
|
<!-- 静态兜底菜单:JS 加载后按后端权限重渲染 -->
|
|
<div class="menu-group" data-menu-group="account">
|
|
<button class="menu-group-title" type="button" aria-expanded="true">
|
|
账号与权限
|
|
<span class="menu-group-chevron" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"></path></svg></span>
|
|
</button>
|
|
<div class="menu-group-body">
|
|
<button class="tab active" type="button" data-tab="users" aria-current="page"><span class="adm-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M22 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg></span><span class="adm-label">用户管理</span></button>
|
|
<button class="tab" type="button" data-tab="columns" aria-controls="panel-columns"><span class="adm-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="7" height="7" x="3" y="3" rx="1"></rect><rect width="7" height="7" x="14" y="3" rx="1"></rect><rect width="7" height="7" x="14" y="14" rx="1"></rect><rect width="7" height="7" x="3" y="14" rx="1"></rect></svg></span><span class="adm-label">菜单权限配置</span></button>
|
|
</div>
|
|
</div>
|
|
<div class="menu-group" data-menu-group="data">
|
|
<button class="menu-group-title" type="button" aria-expanded="true">
|
|
数据管理
|
|
<span class="menu-group-chevron" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"></path></svg></span>
|
|
</button>
|
|
<div class="menu-group-body">
|
|
<button class="tab" type="button" data-tab="dedupe-total-data" aria-controls="panel-dedupe-total-data"><span class="adm-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83Z"></path><path d="m22 17.65-9.17 4.16a2 2 0 0 1-1.66 0L2 17.65"></path><path d="m22 12.65-9.17 4.16a2 2 0 0 1-1.66 0L2 12.65"></path></svg></span><span class="adm-label">去重数据汇总</span></button>
|
|
<button class="tab" type="button" data-tab="invalid-asin-data" aria-controls="panel-invalid-asin-data"><span class="adm-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"></path><path d="M12 9v4"></path><path d="M12 17h.01"></path></svg></span><span class="adm-label">无效ASIN数据</span></button>
|
|
<button class="tab" type="button" data-tab="query-asin" aria-controls="panel-query-asin"><span class="adm-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="8"></circle><path d="m21 21-4.3-4.3"></path></svg></span><span class="adm-label">查询 ASIN</span></button>
|
|
<button class="tab" type="button" data-tab="product-categories" aria-controls="panel-product-categories"><span class="adm-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"></path></svg></span><span class="adm-label">商品类目</span></button>
|
|
</div>
|
|
</div>
|
|
<div class="menu-group" data-menu-group="shop">
|
|
<button class="menu-group-title" type="button" aria-expanded="true">
|
|
店铺管理
|
|
<span class="menu-group-chevron" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"></path></svg></span>
|
|
</button>
|
|
<div class="menu-group-body">
|
|
<button class="tab" type="button" data-tab="shop-keys" aria-controls="panel-shop-keys"><span class="adm-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15.5 7.5 2.3 2.3a1 1 0 0 0 1.4 0l2.1-2.1a1 1 0 0 0 0-1.4L19 4"></path><path d="m21 2-9.6 9.6"></path><circle cx="7.5" cy="15.5" r="5.5"></circle></svg></span><span class="adm-label">店铺密钥管理</span></button>
|
|
<button class="tab" type="button" data-tab="shop-manage" aria-controls="panel-shop-manage"><span class="adm-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m2 7 4.41-4.41A2 2 0 0 1 7.83 2h8.34a2 2 0 0 1 1.42.59L22 7"></path><path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"></path><path d="M15 22v-4a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2v4"></path><path d="M2 7h20"></path><path d="M22 7v3a2 2 0 0 1-2 2 2.7 2.7 0 0 1-1.59-.63.7.7 0 0 0-.82 0A2.7 2.7 0 0 1 16 12a2.7 2.7 0 0 1-1.59-.63.7.7 0 0 0-.82 0A2.7 2.7 0 0 1 12 12a2.7 2.7 0 0 1-1.59-.63.7.7 0 0 0-.82 0A2.7 2.7 0 0 1 8 12a2.7 2.7 0 0 1-1.59-.63.7.7 0 0 0-.82 0A2.7 2.7 0 0 1 4 12a2 2 0 0 1-2-2V7"></path></svg></span><span class="adm-label">店铺管理</span></button>
|
|
<button class="tab" type="button" data-tab="skip-price-asin" aria-controls="panel-skip-price-asin"><span class="adm-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><path d="m4.9 4.9 14.2 14.2"></path></svg></span><span class="adm-label">跳过跟价 ASIN</span></button>
|
|
<button class="tab" type="button" data-tab="shop-data-crawl-tasks" aria-controls="panel-shop-data-crawl-tasks"><span class="adm-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="12" cy="5" rx="9" ry="3"></ellipse><path d="M3 5v14a9 3 0 0 0 18 0V5"></path><path d="M3 12a9 3 0 0 0 18 0"></path></svg></span><span class="adm-label">店铺数据记录</span></button>
|
|
</div>
|
|
</div>
|
|
<div class="menu-group" data-menu-group="record">
|
|
<button class="menu-group-title" type="button" aria-expanded="true">
|
|
记录与版本
|
|
<span class="menu-group-chevron" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"></path></svg></span>
|
|
</button>
|
|
<div class="menu-group-body">
|
|
<button class="tab" type="button" data-tab="history" aria-controls="panel-history"><span class="adm-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path><path d="M3 3v5h5"></path><path d="M12 7v5l4 2"></path></svg></span><span class="adm-label">生成记录</span></button>
|
|
<button class="tab" type="button" data-tab="version" aria-controls="panel-version"><span class="adm-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m7.5 4.27 9 5.15"></path><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"></path><path d="M3.3 7 12 12l8.7-5"></path><path d="M12 22V12"></path></svg></span><span class="adm-label">软件版本管理</span></button>
|
|
<button class="tab" type="button" data-tab="digital-human-version" aria-controls="panel-digital-human-version"><span class="adm-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 8V4H8"></path><rect width="16" height="12" x="4" y="8" rx="2"></rect><path d="M2 14h2"></path><path d="M20 14h2"></path><path d="M15 13v2"></path><path d="M9 13v2"></path></svg></span><span class="adm-label">数字人版本管理</span></button>
|
|
<button class="tab" type="button" data-tab="image-video-tasks" aria-controls="panel-image-video-tasks"><span class="adm-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m22 8-6 4 6 4V8Z"></path><rect width="14" height="12" x="2" y="6" rx="2" ry="2"></rect></svg></span><span class="adm-label">视频任务记录</span></button>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
<div class="admin-sidebar-foot">数富AI · 管理控制台</div>
|
|
</aside>
|
|
<div class="admin-main">
|
|
<header class="admin-topbar">
|
|
<div class="admin-topbar-left">
|
|
<span class="admin-topbar-kicker">运营管理控制台</span>
|
|
<div class="admin-page-heading">
|
|
<span class="admin-page-section">管理后台</span>
|
|
<span class="admin-page-separator" aria-hidden="true">/</span>
|
|
<h1 class="admin-page-title" id="adminPageTitle">用户管理</h1>
|
|
</div>
|
|
</div>
|
|
<div class="admin-user-box">
|
|
<span class="admin-user-avatar" id="adminUserAvatar" aria-hidden="true">管</span>
|
|
<span class="admin-user-name" id="adminCurrentUsername">加载中...</span>
|
|
<span class="admin-user-role" id="adminCurrentUserRole" style="display:none;"></span>
|
|
<button class="admin-user-logout" id="btnAdminLogout" type="button">退出登录</button>
|
|
</div>
|
|
</header>
|
|
<main class="admin-content" id="adminContent">
|
|
<section class="admin-operation-guide" id="adminOperationGuide" aria-labelledby="adminOperationGuideTitle">
|
|
<div class="admin-operation-guide__main">
|
|
<span class="admin-operation-guide__icon" aria-hidden="true">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"></circle><path d="M12 10v6"></path><path d="M12 7h.01"></path></svg>
|
|
</span>
|
|
<div>
|
|
<div class="admin-operation-guide__title" id="adminOperationGuideTitle">当前页面操作提示</div>
|
|
<p class="admin-operation-guide__text" id="adminOperationGuideText">先查看数据,再使用上方筛选快速定位所需记录。</p>
|
|
<ol class="admin-operation-guide__steps" id="adminOperationGuideSteps"></ol>
|
|
</div>
|
|
</div>
|
|
<button class="admin-operation-guide__toggle" id="adminOperationGuideToggle" type="button" aria-expanded="true">收起提示</button>
|
|
</section>
|
|
|
|
|
|
<!-- 用户管理 -->
|
|
<div id="panel-users" class="tab-panel">
|
|
<div class="form-box">
|
|
<form id="createUserForm" novalidate>
|
|
<h3 style="margin-bottom:16px;">创建用户</h3>
|
|
<p style="margin-bottom:16px;font-size:13px;color:var(--c-text-2);">
|
|
当前没有开放注册入口,仅管理员可在此创建用户。层级关系:超级管理员 -> 管理员 -> 普通账号。</p>
|
|
<div class="form-group">
|
|
<label for="username">用户名</label>
|
|
<input type="text" id="username" autocomplete="username" placeholder="用户名(至少 2 个字符)">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="password">密码</label>
|
|
<input type="password" id="password" autocomplete="new-password" placeholder="密码(至少 6 个字符)">
|
|
</div>
|
|
<div class="form-group" id="formGroupRole">
|
|
<label for="createRole">角色</label>
|
|
<select id="createRole">
|
|
<option value="normal">普通账号</option>
|
|
<option value="admin" id="optAdmin">管理员</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group" id="formGroupCreatedBy" style="display:none;">
|
|
<label for="createCreatedBy">所属管理员</label>
|
|
<select id="createCreatedBy">
|
|
<option value="">请选择管理员</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group" id="formGroupCreateColumns">
|
|
<label id="createColumnPermissionLabel">菜单权限(勾选上级菜单会继承全部子菜单)</label>
|
|
<div id="createColumnCards" class="column-permission-cards"></div>
|
|
<div id="createColumnPermissionWrap" class="column-permission-tree" role="group" aria-labelledby="createColumnPermissionLabel"></div>
|
|
</div>
|
|
<button class="btn" id="btnCreate" type="button">创建用户</button>
|
|
<p class="msg" id="msgCreate"></p>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="panel-box">
|
|
<h3 style="margin-bottom:16px;">用户列表</h3>
|
|
<div class="form-row" style="margin-bottom:16px;">
|
|
<div class="form-group" style="min-width:180px;">
|
|
<label>用户名(模糊搜索)</label>
|
|
<input type="text" id="searchUsername" placeholder="输入用户名关键字">
|
|
</div>
|
|
<div class="form-group" id="filterCreatedByGroup" style="min-width:160px;display:none;">
|
|
<label>所属管理员</label>
|
|
<select id="filterCreatedBy">
|
|
<option value="">全部</option>
|
|
</select>
|
|
</div>
|
|
<button class="btn" id="btnSearchUsers">查询</button>
|
|
</div>
|
|
<div class="table-scroll user-table-scroll">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>用户名</th>
|
|
<th>角色</th>
|
|
<th>所属管理员</th>
|
|
<th>创建时间</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="userListBody"></tbody>
|
|
</table>
|
|
</div>
|
|
<div class="pagination" id="userPagination"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 栏目权限配置 -->
|
|
<div id="panel-columns" class="tab-panel">
|
|
<div class="form-box">
|
|
<h3 style="margin-bottom:16px;">新增菜单</h3>
|
|
<div class="form-row">
|
|
<div class="form-group" style="min-width:200px;">
|
|
<label>菜单名称</label>
|
|
<input type="text" id="columnName" placeholder="例如:店铺管理">
|
|
</div>
|
|
<div class=" form-group" style="min-width:200px;">
|
|
<label>菜单标识</label>
|
|
<input type="text" id="columnKey" placeholder="例如:shop_manage">
|
|
</div>
|
|
<div class="form-group" style="min-width:220px;">
|
|
<label>页面路径</label>
|
|
<input type="text" id="columnRoutePath" placeholder="例如:dedupe-total-data">
|
|
</div>
|
|
<div class="form-group" style="min-width:140px;">
|
|
<label>排序</label>
|
|
<input type="number" id="columnSortOrder" placeholder="例如:10">
|
|
</div>
|
|
<div class="form-group" style="min-width:160px;">
|
|
<label>菜单类型</label>
|
|
<select id="columnMenuType">
|
|
<option value="admin">后台(admin)</option>
|
|
<option value="app">软件(app)</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group" style="min-width:220px;">
|
|
<label>上级菜单(可选)</label>
|
|
<select id="columnParentId"><option value="">无(一级菜单)</option></select>
|
|
</div>
|
|
<button class="btn" id="btnAddColumn">新增菜单</button>
|
|
</div>
|
|
<p class="msg" id="msgColumn"></p>
|
|
</div>
|
|
<div class="panel-box">
|
|
<h3 style="margin-bottom:16px;">菜单列表</h3>
|
|
<div class="table-scroll columns-table-scroll">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>菜单名称</th>
|
|
<th>菜单标识</th>
|
|
<th>菜单类型</th>
|
|
<th>上级菜单</th>
|
|
<th>排序</th>
|
|
<th>页面路径</th>
|
|
<th>创建时间</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="columnListBody"></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 软件版本管理 -->
|
|
<div id="panel-version" class="tab-panel">
|
|
<div class="form-box">
|
|
<h3 style="margin-bottom:16px;">上传新版本</h3>
|
|
<p style="margin-bottom:16px;font-size:13px;color:var(--c-text-2);">
|
|
上传软件 ZIP 包,系统会自动计算 MD5 并存储到 OSS。
|
|
</p>
|
|
<div class="form-row">
|
|
<div class="form-group" style="min-width:200px;">
|
|
<label>版本号 *</label>
|
|
<input type="text" id="versionNumber" placeholder="例如:1.0.0">
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>ZIP 压缩包 *</label>
|
|
<input type="file" id="versionZip" accept=".zip">
|
|
<p style="font-size:12px;color:var(--c-text-3);margin-top:4px;">仅支持 .zip 格式</p>
|
|
</div>
|
|
<button class="btn" id="btnUploadVersion">上传软件版本</button>
|
|
<p class="msg" id="msgVersion"></p>
|
|
</div>
|
|
<div class="panel-box">
|
|
<h3 style="margin-bottom:16px;">版本列表</h3>
|
|
<div class="table-scroll version-table-scroll">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th style="width:120px;">版本号</th>
|
|
<th>下载链接</th>
|
|
<th style="width:160px;">创建时间</th>
|
|
<th style="width:120px;">操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="versionListBody"></tbody>
|
|
</table>
|
|
</div>
|
|
<div class="pagination" id="versionPagination"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 数字人版本管理 -->
|
|
<div id="panel-digital-human-version" class="tab-panel">
|
|
<div class="form-box">
|
|
<h3 style="margin-bottom:16px;">上传新版本</h3>
|
|
<p style="margin-bottom:16px;font-size:13px;color:var(--c-text-2);">
|
|
上传数字人程序 ZIP 包,系统会自动计算 MD5 并存储到 OSS。上传后状态为草稿,需要手动发布。
|
|
</p>
|
|
<div class="form-row">
|
|
<div class="form-group" style="min-width:200px;">
|
|
<label>版本号 *</label>
|
|
<input type="text" id="digitalHumanVersionNumber" placeholder="例如:1.0.0">
|
|
</div>
|
|
<div class="form-group" style="min-width:200px;">
|
|
<label>最低客户端版本</label>
|
|
<input type="text" id="digitalHumanMinClientVersion" placeholder="例如:2.0.0(可选)">
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>更新日志</label>
|
|
<textarea id="digitalHumanVersionChangelog" rows="3" placeholder="例如:修复数字人口型同步问题,优化启动速度"
|
|
style="width:100%;padding:10px;border:1px solid var(--c-border);border-radius:var(--radius-sm);resize:vertical;"></textarea>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>ZIP 压缩包 *</label>
|
|
<input type="file" id="digitalHumanVersionZip" accept=".zip">
|
|
</div>
|
|
<button class="btn" id="btnUploadDigitalHumanVersion">上传(草稿状态)</button>
|
|
<p class="msg" id="msgDigitalHumanVersion"></p>
|
|
</div>
|
|
<div class="panel-box">
|
|
<h3 style="margin-bottom:16px;">版本列表</h3>
|
|
<div class="table-scroll digital-human-version-table-scroll">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th style="width:80px;">版本号</th>
|
|
<th style="width:60px;">状态</th>
|
|
<th style="width:60px;">最新</th>
|
|
<th style="width:80px;">文件大小</th>
|
|
<th style="width:120px;">MD5</th>
|
|
<th>更新日志</th>
|
|
<th style="width:140px;">发布时间</th>
|
|
<th style="width:240px;">操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="digitalHumanVersionListBody"></tbody>
|
|
</table>
|
|
</div>
|
|
<div class="pagination" id="digitalHumanVersionPagination"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 数据去重总数据 -->
|
|
<div id="panel-dedupe-total-data" class="tab-panel">
|
|
<div class="form-box">
|
|
<div class="dedupe-group-access">
|
|
<div class="dedupe-group-access-main">
|
|
<span class="dedupe-group-access-title">数据权限分组</span>
|
|
<div class="dedupe-group-summary" id="dedupeGroupSummary">正在加载...</div>
|
|
</div>
|
|
<button class="btn btn-secondary" id="btnManageDedupeGroups" type="button">管理分组</button>
|
|
</div>
|
|
<div class="form-row" style="align-items:flex-start;gap:16px;">
|
|
<div style="flex:1;min-width:320px;">
|
|
<h3 style="margin-bottom:16px;">新增ASIN</h3>
|
|
<div class="form-row">
|
|
<div class="form-group" style="min-width:320px;">
|
|
<label>上传 Excel 文件(读取 ASIN 列,可选 国家 列)</label>
|
|
<input type="file" id="dedupeTotalDataFile" accept=".xlsx,.xls">
|
|
</div>
|
|
<div class="form-group" style="min-width:220px;">
|
|
<label>分组</label>
|
|
<select id="dedupeTotalDataImportGroupId">
|
|
<option value="">请选择分组</option>
|
|
</select>
|
|
</div>
|
|
<button class="btn" id="btnAddDedupeTotalData">上传并导入</button>
|
|
</div>
|
|
<p class="msg" id="msgDedupeTotalData"></p>
|
|
<div class="progress-wrap" id="dedupeTotalDataProgressWrap" style="display:none;">
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" id="dedupeTotalDataProgressFill"></div>
|
|
</div>
|
|
<div class="progress-text" id="dedupeTotalDataProgressText"></div>
|
|
</div>
|
|
</div>
|
|
<div style="flex:1;min-width:320px;">
|
|
<h3 style="margin-bottom:16px;">删除匹配总数据</h3>
|
|
<div class="form-row">
|
|
<div class="form-group" style="min-width:320px;">
|
|
<label>上传 Excel 文件(读取 ASIN 列)</label>
|
|
<input type="file" id="dedupeTotalDataDeleteFile" accept=".xlsx,.xls">
|
|
</div>
|
|
<div class="form-group" style="min-width:220px;">
|
|
<label>分组</label>
|
|
<select id="dedupeTotalDataDeleteGroupId">
|
|
<option value="">请选择分组</option>
|
|
</select>
|
|
</div>
|
|
<button class="btn btn-danger" id="btnDeleteImportDedupeTotalData">上传并删除</button>
|
|
</div>
|
|
<p class="msg" id="msgDeleteDedupeTotalData"></p>
|
|
<div class="progress-wrap" id="dedupeTotalDataDeleteProgressWrap" style="display:none;">
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" id="dedupeTotalDataDeleteProgressFill"></div>
|
|
</div>
|
|
<div class="progress-text" id="dedupeTotalDataDeleteProgressText"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="panel-box">
|
|
<h3 style="margin-bottom:16px;">ASIN列表</h3>
|
|
<div class="dedupe-filter-row">
|
|
<div class="form-group">
|
|
<label>数据值(模糊搜索)</label>
|
|
<input type="text" id="searchDedupeTotalData" placeholder="输入关键字">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>用户名(模糊搜索)</label>
|
|
<input type="text" id="searchDedupeTotalDataUsername" placeholder="输入用户名">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>分组</label>
|
|
<select id="dedupeTotalDataGroupFilterId">
|
|
<option value="">全部分组</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>国家</label>
|
|
<select id="dedupeTotalDataCountryFilter">
|
|
<option value="">全部国家</option>
|
|
<option value="DE">德国</option>
|
|
<option value="UK">英国</option>
|
|
<option value="FR">法国</option>
|
|
<option value="IT">意大利</option>
|
|
<option value="ES">西班牙</option>
|
|
</select>
|
|
</div>
|
|
<div class="dedupe-filter-actions">
|
|
<button class="btn" id="btnSearchDedupeTotalData">查询</button>
|
|
</div>
|
|
</div>
|
|
<div class="dedupe-filter-date-row">
|
|
<div class="form-group">
|
|
<label>开始日期</label>
|
|
<input type="date" id="exportDedupeTotalDataStartDate">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>结束日期</label>
|
|
<input type="date" id="exportDedupeTotalDataEndDate">
|
|
</div>
|
|
<div class="dedupe-filter-actions">
|
|
<button class="btn btn-secondary" id="btnExportDedupeTotalData" type="button">导出 XLSX</button>
|
|
</div>
|
|
</div>
|
|
<div class="table-scroll dedupe-table-scroll">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>ASIN值</th>
|
|
<th>国家</th>
|
|
<th>用户名</th>
|
|
<th>分组</th>
|
|
<th>创建时间</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="dedupeTotalDataListBody"></tbody>
|
|
</table>
|
|
</div>
|
|
<div class="pagination" id="dedupeTotalDataPagination"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 不符合ASIN数据 -->
|
|
<div id="panel-invalid-asin-data" class="tab-panel">
|
|
<div class="form-box">
|
|
<h3 style="margin-bottom:16px;">新增无效ASIN数据</h3>
|
|
<div class="form-row">
|
|
<div class="form-group" style="min-width:220px;">
|
|
<label>ASIN</label>
|
|
<input type="text" id="invalidAsinDataValue" placeholder="请输入 ASIN">
|
|
</div>
|
|
<div class="form-group" style="min-width:220px;">
|
|
<label>品牌</label>
|
|
<input type="text" id="invalidAsinDataBrand" placeholder="请输入品牌(可选)">
|
|
</div>
|
|
<div class="form-group" style="min-width:220px;">
|
|
<label>分组</label>
|
|
<div style="display:flex;gap:8px;align-items:center;">
|
|
<select id="invalidAsinDataGroupSelect" style="min-width:150px;">
|
|
<option value="">请选择分组</option>
|
|
</select>
|
|
<button class="btn btn-secondary" id="btnManageInvalidAsinDataGroups" type="button">管理分组</button>
|
|
</div>
|
|
</div>
|
|
<button class="btn" id="btnAddInvalidAsinData">新增</button>
|
|
</div>
|
|
<p class="msg" id="msgInvalidAsinData"></p>
|
|
</div>
|
|
<div class="panel-box">
|
|
<h3 style="margin-bottom:16px;">无效ASIN数据列表</h3>
|
|
<div class="form-row" style="margin-bottom:16px;">
|
|
<div class="form-group" style="min-width:220px;">
|
|
<label>ASIN / 品牌(模糊搜索)</label>
|
|
<input type="text" id="searchInvalidAsinData" placeholder="输入关键字">
|
|
</div>
|
|
<div class="form-group" style="min-width:180px;">
|
|
<label>分组</label>
|
|
<select id="invalidAsinDataFilterGroupId">
|
|
<option value="">全部分组</option>
|
|
</select>
|
|
</div>
|
|
<button class=" btn" id="btnSearchInvalidAsinData">查询</button>
|
|
</div>
|
|
<div class="table-scroll invalid-asin-table-scroll">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>ASIN</th>
|
|
<th>品牌</th>
|
|
<th>分组</th>
|
|
<th>来源</th>
|
|
<th>创建时间</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="invalidAsinDataListBody"></tbody>
|
|
</table>
|
|
</div>
|
|
<div class="pagination" id="invalidAsinDataPagination"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 店铺密钥管理 -->
|
|
<div id="panel-shop-keys" class="tab-panel">
|
|
<div class="form-box">
|
|
<h3 style="margin-bottom:16px;">新增店铺密钥</h3>
|
|
<div class="form-row">
|
|
<div class="form-group" style="min-width:180px;">
|
|
<label>备注名</label>
|
|
<input type="text" id="shopKeyRemarkName" maxlength="128" placeholder="请输入备注名(可选)">
|
|
</div>
|
|
<div class="form-group" style="min-width:220px;">
|
|
<label>紫鸟账号名称</label>
|
|
<input type="text" id="shopKeyZiniaoAccountName" placeholder="请输入紫鸟账号名称">
|
|
</div>
|
|
<div class=" form-group" style="min-width:260px;">
|
|
<label>紫鸟令牌</label>
|
|
<input type="text" id="shopKeyZiniaoToken" placeholder="请输入紫鸟令牌">
|
|
</div>
|
|
<button class=" btn" id="btnCreateShopKey">新增店铺密钥</button>
|
|
</div>
|
|
<p class="msg" id="msgShopKey"></p>
|
|
</div>
|
|
<div class="panel-box">
|
|
<h3 style="margin-bottom:16px;">店铺密钥列表</h3>
|
|
<div class="shop-key-table-scroll">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>序号</th>
|
|
<th>备注名</th>
|
|
<th>紫鸟账号名称</th>
|
|
<th>紫鸟令牌</th>
|
|
<th title="显示紫鸟账号当前 IP 白名单检测结果;悬停可查看检测详情">白名单状态 <span class="table-help" aria-hidden="true">?</span></th>
|
|
<th>创建时间</th>
|
|
<th>修改时间</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="shopKeyListBody"></tbody>
|
|
</table>
|
|
</div>
|
|
<div class="pagination" id="shopKeyPagination"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 店铺管理 -->
|
|
<div id="panel-shop-manage" class="tab-panel">
|
|
<div class="form-box">
|
|
<h3 style="margin-bottom:16px;">新增店铺</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="shopManageGroupSelect" style="min-width:150px;">
|
|
<option value="">请选择分组</option>
|
|
</select>
|
|
<button class="btn btn-secondary" id="btnManageShopGroups" type="button">管理分组</button>
|
|
</div>
|
|
</div>
|
|
<div class="form-group" style="min-width:160px;">
|
|
<label>店铺名</label>
|
|
<input type="text" id="shopManageShopName" placeholder="请输入店铺名称">
|
|
</div>
|
|
<div class=" form-group" style="min-width:180px;">
|
|
<label>店铺商城名</label>
|
|
<input type="text" id="shopManageMallName" placeholder="请输入店铺商城名">
|
|
</div>
|
|
<div class="form-group" style="min-width:180px;">
|
|
<label>自动化账号</label>
|
|
<input type="text" id="shopManageZnUsername" maxlength="128" placeholder="请输入自动化账号(可选)">
|
|
</div>
|
|
<div class="form-group" style="min-width:180px;">
|
|
<label>账号</label>
|
|
<input type="text" id="shopManageAccount" placeholder="请输入账号">
|
|
</div>
|
|
<div class=" form-group" style="min-width:180px;">
|
|
<label>密码</label>
|
|
<input type="text" id="shopManagePassword" placeholder="请输入密码">
|
|
</div>
|
|
<button class=" btn" id="btnCreateShopManage">新增店铺</button>
|
|
</div>
|
|
<p class="msg" id="msgShopManage"></p>
|
|
</div>
|
|
<div class="panel-box">
|
|
<h3 style="margin-bottom:16px;">店铺列表</h3>
|
|
<div class="form-row" style="margin-bottom:12px;">
|
|
<div class="form-group" style="min-width:180px;">
|
|
<label>分组</label>
|
|
<select id="shopManageFilterGroupId">
|
|
<option value="">全部分组</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group" style="min-width:220px;">
|
|
<label>店铺名</label>
|
|
<input type="text" id="shopManageFilterShopName" placeholder="请输入店铺名">
|
|
</div>
|
|
<button class="btn" id="btnSearchShopManage">查询</button>
|
|
</div>
|
|
<div class="table-scroll shop-manage-table-scroll">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>序号</th>
|
|
<th>分组</th>
|
|
<th>店铺名</th>
|
|
<th>店铺商城名</th>
|
|
<th>自动化账号</th>
|
|
<th>账号</th>
|
|
<th>密码</th>
|
|
<th>创建时间</th>
|
|
<th>修改时间</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="shopManageListBody"></tbody>
|
|
</table>
|
|
</div>
|
|
<div class="pagination" id="shopManagePagination"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 查看生成记录 -->
|
|
<div id="panel-skip-price-asin" class="tab-panel">
|
|
<div class="form-box">
|
|
<h3 style="margin-bottom:16px;">新增 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="skipPriceAsinGroupSelect" style="min-width:150px;">
|
|
<option value="">请选择分组</option>
|
|
</select>
|
|
<button class="btn btn-secondary" id="btnManageSkipPriceAsinGroups" type="button">管理分组</button>
|
|
</div>
|
|
</div>
|
|
<div class="form-group" style="min-width:180px;">
|
|
<label>店铺名</label>
|
|
<input type="text" id="skipPriceAsinShopName" placeholder="请输入店铺名称">
|
|
</div>
|
|
<div class=" form-group" style="min-width:220px;">
|
|
<label>国家</label>
|
|
<div style="margin-bottom:8px;">
|
|
<label> </label>
|
|
<button class="btn btn-secondary" id="btnChooseSkipPriceAsinShop" type="button">选择店铺</button>
|
|
</div>
|
|
<select id="skipPriceAsinCountries" class="js-dropdown-multi" multiple>
|
|
<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 id="skipPriceAsinInputsLabel">ASIN / 最低价</label>
|
|
<div id="skipPriceAsinInputs" role="group" aria-labelledby="skipPriceAsinInputsLabel" style="display:flex;flex-direction:column;gap:8px;">
|
|
<div style="color:var(--c-text-3);font-size:13px;">请选择国家后输入对应 ASIN 和最低价</div>
|
|
</div>
|
|
</div>
|
|
<button class="btn" id="btnCreateSkipPriceAsin">新增 ASIN</button>
|
|
</div>
|
|
<p class="msg" id="msgSkipPriceAsin"></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;">导入文件新增</h3>
|
|
<div class="form-row">
|
|
<div class="form-group" style="min-width:320px;">
|
|
<label>上传 Excel(先选择分组;文件名必须是该分组下的店铺名;表头为 国家 / 删除ASIN / 最低价)</label>
|
|
<input type="file" id="skipPriceAsinImportFile" accept=".xlsx,.xls">
|
|
</div>
|
|
<button class="btn" id="btnImportSkipPriceAsin" type="button">上传并新增</button>
|
|
</div>
|
|
<p class="msg" id="msgSkipPriceAsinImport"></p>
|
|
<div class="progress-wrap" id="skipPriceAsinImportProgressWrap" style="display:none;">
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" id="skipPriceAsinImportProgressFill"></div>
|
|
</div>
|
|
<div class="progress-text" id="skipPriceAsinImportProgressText"></div>
|
|
</div>
|
|
</div>
|
|
<div style="flex:1;min-width:320px;">
|
|
<h3 style="margin-bottom:12px;">导入文件删除</h3>
|
|
<div class="form-row">
|
|
<div class="form-group" style="min-width:320px;">
|
|
<label>上传 Excel(先选择分组;文件名必须是该分组下的店铺名;按各国家删除ASIN列匹配删除)</label>
|
|
<input type="file" id="skipPriceAsinDeleteImportFile" accept=".xlsx,.xls">
|
|
</div>
|
|
<button class="btn btn-danger" id="btnDeleteImportSkipPriceAsin" type="button">上传并删除</button>
|
|
</div>
|
|
<p class="msg" id="msgSkipPriceAsinDeleteImport"></p>
|
|
<div class="progress-wrap" id="skipPriceAsinDeleteImportProgressWrap" style="display:none;">
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" id="skipPriceAsinDeleteImportProgressFill"></div>
|
|
</div>
|
|
<div class="progress-text" id="skipPriceAsinDeleteImportProgressText"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="panel-box">
|
|
<h3 style="margin-bottom:16px;">店铺列表</h3>
|
|
<div class="form-row" style="margin-bottom:12px;">
|
|
<div class="form-group" style="min-width:180px;">
|
|
<label>分组</label>
|
|
<select id="skipPriceAsinFilterGroupId">
|
|
<option value="">全部分组</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group" style="min-width:220px;">
|
|
<label>店铺名</label>
|
|
<input type="text" id="skipPriceAsinFilterShopName" placeholder="请输入店铺名">
|
|
</div>
|
|
<div class="form-group" style="min-width:220px;">
|
|
<label>ASIN</label>
|
|
<input type="text" id="skipPriceAsinFilterAsin" placeholder="请输入 ASIN">
|
|
</div>
|
|
<button class="btn" id="btnSearchSkipPriceAsin">查询</button>
|
|
<button class="btn btn-secondary" id="btnExportSkipPriceAsin" type="button">导出 XLSX</button>
|
|
</div>
|
|
<div class="table-scroll skip-price-asin-table-scroll">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>序号</th>
|
|
<th>分组</th>
|
|
<th>店铺名</th>
|
|
<th>德国</th>
|
|
<th>英国</th>
|
|
<th>法国</th>
|
|
<th>意大利</th>
|
|
<th>西班牙</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="skipPriceAsinListBody"></tbody>
|
|
</table>
|
|
</div>
|
|
<div class="pagination" id="skipPriceAsinPagination"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="panel-query-asin" class="tab-panel">
|
|
<div class="form-box">
|
|
<h3 style="margin-bottom:16px;">新增查询 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" class="js-dropdown-multi" multiple>
|
|
<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 id="queryAsinInputsLabel">ASIN</label>
|
|
<div id="queryAsinInputs" role="group" aria-labelledby="queryAsinInputsLabel" style="display:flex;flex-direction:column;gap:8px;">
|
|
<div style="color:var(--c-text-3);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;">导入添加</h3>
|
|
<div class="form-row">
|
|
<div class="form-group" style="min-width:320px;">
|
|
<label>上传 Excel(支持两种格式:1. 分组/店铺名/德国-西班牙;2. 店铺账号/ASIN/中文国家名。文件无分组列时取页面当前分组)</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;">导入删除</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;">店铺列表</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>
|
|
<button class="btn btn-secondary" id="btnExportQueryAsin" type="button">导出 XLSX</button>
|
|
</div>
|
|
<div class="table-scroll query-asin-table-scroll">
|
|
<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>
|
|
<div class="pagination" id="queryAsinPagination"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="panel-product-categories" class="tab-panel">
|
|
<div class="form-box">
|
|
<h3 style="margin-bottom:16px;">新增商品类目</h3>
|
|
<div class="form-row">
|
|
<div class="form-group" style="min-width:220px;">
|
|
<label>上级类目</label>
|
|
<select id="productCategoryParentId">
|
|
<option value="">顶级类目</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group" style="min-width:220px;">
|
|
<label>类目名称</label>
|
|
<input type="text" id="productCategoryName" placeholder="例如:洁面">
|
|
</div>
|
|
<div class="form-group" style="min-width:120px;">
|
|
<label>排序</label>
|
|
<input type="number" id="productCategorySortOrder" placeholder="例如:10">
|
|
</div>
|
|
<div class="form-group" style="min-width:280px;flex:1;">
|
|
<label>备注</label>
|
|
<input type="text" id="productCategoryDescription" placeholder="可填写风险说明或使用场景">
|
|
</div>
|
|
<button class="btn" id="btnCreateProductCategory">新增类目</button>
|
|
<button class="btn btn-secondary" id="btnCancelProductCategoryEdit" type="button"
|
|
style="display:none;">取消编辑</button>
|
|
</div>
|
|
<p class="msg" id="msgProductCategory"></p>
|
|
</div>
|
|
<div class="panel-box">
|
|
<div style="display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:16px;">
|
|
<h3 style="margin-bottom:0;">类目树</h3>
|
|
<div class="form-row" style="gap:8px;margin:0;flex:0 1 420px;">
|
|
<div class="form-group" style="min-width:220px;flex:1;margin:0;">
|
|
<input type="text" id="productCategoryKeyword" placeholder="搜索类目名称、编码或备注">
|
|
</div>
|
|
<button class="btn btn-sm" id="btnSearchProductCategory" type="button">搜索</button>
|
|
<button class="btn btn-sm btn-secondary" id="btnClearProductCategorySearch"
|
|
type="button">清空</button>
|
|
<button class="btn btn-sm btn-secondary" id="btnExportProductCategory" type="button">导出</button>
|
|
</div>
|
|
</div>
|
|
<div class="table-scroll category-table-scroll">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th style="width:34%;">类目</th>
|
|
<th>层级路径</th>
|
|
<th style="width:90px;">排序</th>
|
|
<th style="width:120px;">来源</th>
|
|
<th>备注</th>
|
|
<th style="width:150px;">操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="productCategoryListBody"></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="panel-image-video-tasks" class="tab-panel">
|
|
<div class="form-box">
|
|
<h3 style="margin-bottom:16px;">视频任务记录筛选</h3>
|
|
<div class="form-row">
|
|
<div class="form-group" style="min-width:150px;"><label>用户名</label><input type="text"
|
|
id="imageVideoFilterUsername" placeholder="模糊搜索"></div>
|
|
<div class="form-group" style="min-width:170px;"><label>提交开始</label><input type="datetime-local"
|
|
id="imageVideoFilterFrom"></div>
|
|
<div class="form-group" style="min-width:170px;"><label>提交结束</label><input type="datetime-local"
|
|
id="imageVideoFilterTo"></div>
|
|
<button class="btn" id="btnFilterImageVideoTasks" type="button">查询</button>
|
|
<button class="btn btn-secondary" id="btnResetImageVideoTasks" type="button">重置</button>
|
|
</div>
|
|
</div>
|
|
<div class="panel-box image-video-panel-box">
|
|
<div class="image-video-results">
|
|
<div class="image-video-toolbar">
|
|
<div class="image-video-toolbar-main">
|
|
<button class="btn btn-secondary image-video-permission-btn" id="btnOpenImageVideoPermissions"
|
|
type="button">权限配置</button>
|
|
<button class="btn image-video-batch-btn" id="btnBatchDownloadImageVideos" type="button"
|
|
disabled>
|
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
<path d="M12 3v12m0 0 4-4m-4 4-4-4M5 21h14"></path>
|
|
</svg>
|
|
批量下载
|
|
</button>
|
|
<label class="image-video-select-all">
|
|
<input type="checkbox" id="imageVideoSelectAll">
|
|
全选当前页
|
|
</label>
|
|
<span class="image-video-download-progress" id="imageVideoDownloadProgress"
|
|
aria-live="polite"></span>
|
|
</div>
|
|
<span class="image-video-summary" id="imageVideoTaskTotal"></span>
|
|
</div>
|
|
<div class="image-video-grid" id="imageVideoTaskGrid" aria-live="polite"></div>
|
|
</div>
|
|
<div class="pagination" id="imageVideoTaskPagination"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="panel-shop-data-crawl-tasks" class="tab-panel">
|
|
<div class="form-box">
|
|
<h3 style="margin-bottom:16px;">店铺数据记录筛选</h3>
|
|
<div class="form-row">
|
|
<div class="form-group" style="min-width:150px;"><label>店铺</label><input type="text"
|
|
id="shopDataTaskFilterShop" placeholder="模糊搜索店铺名"></div>
|
|
<div class="form-group" style="min-width:140px;"><label>分组</label><input type="text"
|
|
id="shopDataTaskFilterGroup" placeholder="模糊搜索分组"></div>
|
|
<div class="form-group" style="min-width:170px;"><label>创建开始</label><input
|
|
type="datetime-local" id="shopDataTaskFilterFrom"></div>
|
|
<div class="form-group" style="min-width:170px;"><label>创建结束</label><input
|
|
type="datetime-local" id="shopDataTaskFilterTo"></div>
|
|
<button class="btn" id="btnFilterShopDataTasks" type="button">查询</button>
|
|
<button class="btn btn-secondary" id="btnResetShopDataTasks" type="button">重置</button>
|
|
</div>
|
|
</div>
|
|
<div class="panel-box image-video-panel-box">
|
|
<div class="image-video-results">
|
|
<div class="image-video-toolbar">
|
|
<div class="image-video-toolbar-main">
|
|
<button class="btn btn-secondary image-video-permission-btn"
|
|
id="btnOpenShopDataTaskPermissions" type="button">权限配置</button>
|
|
<button class="btn image-video-batch-btn" id="btnBatchDownloadShopDataTasks"
|
|
type="button" disabled>
|
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
<path d="M12 3v12m0 0 4-4m-4 4-4-4M5 21h14"></path>
|
|
</svg>
|
|
批量下载
|
|
</button>
|
|
<label class="image-video-select-all">
|
|
<input type="checkbox" id="shopDataTaskSelectAll">
|
|
全选当前页
|
|
</label>
|
|
<span class="image-video-download-progress" id="shopDataTaskDownloadProgress"
|
|
aria-live="polite"></span>
|
|
</div>
|
|
<span class="image-video-summary" id="shopDataTaskTotal"></span>
|
|
</div>
|
|
<div class="image-video-grid" id="shopDataTaskGrid" aria-live="polite"></div>
|
|
</div>
|
|
<div class="pagination" id="shopDataTaskPagination"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="panel-history" class="tab-panel">
|
|
<div class="form-box">
|
|
<h3 style="margin-bottom:16px;">筛选条件</h3>
|
|
<div class="form-row">
|
|
<div class="form-group" style="min-width:140px;">
|
|
<label>指定用户</label>
|
|
<select id="filterUser">
|
|
<option value="">全部用户</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group" style="min-width:140px;">
|
|
<label>开始时间</label>
|
|
<input type="datetime-local" id="filterTimeStart">
|
|
</div>
|
|
<div class="form-group" style="min-width:140px;">
|
|
<label>结束时间</label>
|
|
<input type="datetime-local" id="filterTimeEnd">
|
|
</div>
|
|
<button class="btn" id="btnFilterHistory">查询</button>
|
|
</div>
|
|
</div>
|
|
<div class="panel-box">
|
|
<h3 style="margin-bottom:16px;">生成记录</h3>
|
|
<div class="table-scroll history-table-scroll">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>用户</th>
|
|
<th>类型</th>
|
|
<th>创建时间</th>
|
|
<th>结果预览</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="historyListBody"></tbody>
|
|
</table>
|
|
</div>
|
|
<div class="pagination" id="historyPagination"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 编辑用户弹窗 -->
|
|
<div class="modal-mask" id="editUserModal">
|
|
<div class="modal">
|
|
<form id="editUserForm" novalidate>
|
|
<h3>编辑用户</h3>
|
|
<input type="hidden" id="editUserId">
|
|
<div class="form-group">
|
|
<label for="editUsername">用户名</label>
|
|
<input type="text" id="editUsername" autocomplete="username" readonly style="background:#f4f6fa;">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="editPassword">新密码(不修改可留空)</label>
|
|
<input type="password" id="editPassword" autocomplete="new-password" placeholder="留空则不修改密码">
|
|
</div>
|
|
<div class="form-group" id="editFormGroupRole" style="display:none;">
|
|
<label for="editRole">角色</label>
|
|
<select id="editRole">
|
|
<option value="normal">普通账号</option>
|
|
<option value="admin">管理员</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group" id="editFormGroupCreator" style="display:none;">
|
|
<label>所属管理员</label>
|
|
<input type="text" id="editCreatorName" readonly style="background:#f4f6fa;">
|
|
</div>
|
|
<div class="form-group">
|
|
<label id="editColumnPermissionLabel">菜单权限(勾选上级菜单会继承全部子菜单)</label>
|
|
<div id="editColumnCards" class="column-permission-cards"></div>
|
|
<div id="editColumnPermissionWrap" class="column-permission-tree" role="group" aria-labelledby="editColumnPermissionLabel"></div>
|
|
</div>
|
|
<p class="msg" id="msgEdit"></p>
|
|
<div style="margin-top:16px;display:flex;gap:8px;">
|
|
<button class="btn" id="btnSaveUser" type="button">保存</button>
|
|
<button class="btn btn-secondary" id="btnCloseEdit" type="button">取消</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 编辑总数据弹窗 -->
|
|
<div class="modal-mask" id="editDedupeTotalDataModal">
|
|
<div class="modal">
|
|
<h3>编辑ASIN</h3>
|
|
<input type="hidden" id="editDedupeTotalDataId">
|
|
<div class="form-group">
|
|
<label>ASIN值</label>
|
|
<input type="text" id="editDedupeTotalDataValue" placeholder="请输入总数据值">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>分组</label>
|
|
<select id="editDedupeTotalDataGroupId">
|
|
<option value="">请选择分组</option>
|
|
</select>
|
|
</div>
|
|
<p class=" msg" id="msgEditDedupeTotalData"></p>
|
|
<div style="margin-top:16px;display:flex;gap:8px;">
|
|
<button class="btn" id="btnSaveDedupeTotalData">保存</button>
|
|
<button class="btn btn-secondary" id="btnCloseEditDedupeTotalData">取消</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 编辑不符合ASIN数据弹窗 -->
|
|
<div class="modal-mask" id="editInvalidAsinDataModal">
|
|
<div class="modal">
|
|
<h3>编辑无效ASIN数据</h3>
|
|
<input type="hidden" id="editInvalidAsinDataId">
|
|
<input type="hidden" id="editInvalidAsinDataRecordSource">
|
|
<div class="form-group">
|
|
<label>ASIN</label>
|
|
<input type="text" id="editInvalidAsinDataValue" placeholder="请输入 ASIN">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>品牌</label>
|
|
<input type="text" id="editInvalidAsinDataBrand" placeholder="请输入品牌(可选)">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>来源</label>
|
|
<input type="text" id="editInvalidAsinDataSourceLabel" readonly>
|
|
</div>
|
|
<div class="form-group" id="editInvalidAsinDataGroupForm">
|
|
<label>分组</label>
|
|
<div style="display:flex;gap:8px;align-items:center;">
|
|
<select id="editInvalidAsinDataGroupSelect" style="min-width:200px;">
|
|
<option value="">请选择分组</option>
|
|
</select>
|
|
<button class="btn btn-secondary" id="btnManageInvalidAsinDataGroupsFromEdit" type="button">管理分组</button>
|
|
</div>
|
|
</div>
|
|
<p class=" msg" id="msgEditInvalidAsinData"></p>
|
|
<div style="margin-top:16px;display:flex;gap:8px;">
|
|
<button class="btn" id="btnSaveInvalidAsinData">保存</button>
|
|
<button class="btn btn-secondary" id="btnCloseEditInvalidAsinData">取消</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 编辑栏目弹窗 -->
|
|
<div class="modal-mask" id="editColumnModal">
|
|
<div class="modal">
|
|
<h3>编辑栏目</h3>
|
|
<input type="hidden" id="editColumnId">
|
|
<div class="form-group">
|
|
<label>菜单名称</label>
|
|
<input type="text" id="editColumnName" placeholder="菜单名称">
|
|
</div>
|
|
<div class=" form-group">
|
|
<label>菜单标识</label>
|
|
<input type="text" id="editColumnKey" placeholder="菜单标识">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>页面路径</label>
|
|
<input type="text" id="editColumnRoutePath" placeholder="页面路径">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>排序</label>
|
|
<input type="number" id="editColumnSortOrder" placeholder="排序">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>菜单类型</label>
|
|
<select id="editColumnMenuType">
|
|
<option value="admin">后台(admin)</option>
|
|
<option value="app">软件(app)</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>上级菜单(可选)</label>
|
|
<select id="editColumnParentId"><option value="">无(一级菜单)</option></select>
|
|
</div>
|
|
<p class="msg" id="msgEditColumn"></p>
|
|
<div style="margin-top:16px;display:flex;gap:8px;">
|
|
<button class="btn" id="btnSaveColumn">保存</button>
|
|
<button class="btn btn-secondary" id="btnCloseEditColumn">取消</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 分组管理弹窗 -->
|
|
<div class="modal-mask" id="shopManageGroupModal">
|
|
<div class="modal shop-group-modal">
|
|
<div class="shop-group-modal-header">
|
|
<h3>分组管理</h3>
|
|
</div>
|
|
<div class="shop-group-editor">
|
|
<input type="hidden" id="shopManageGroupEditId">
|
|
<input type="hidden" id="shopManageGroupLeaderUserId">
|
|
<div class="form-group">
|
|
<label>组长</label>
|
|
<input type="text" id="shopManageGroupLeaderName" placeholder="当前登录用户" readonly
|
|
style="background:#f4f6fa;">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>分组名称</label>
|
|
<input type="text" id="shopManageGroupInput" placeholder="请输入分组名称">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>组员</label>
|
|
<select id="shopManageGroupMemberSelect" class="shop-group-member-select" multiple size="6">
|
|
</select>
|
|
<div id="shopManageGroupMemberHelp" class="shop-group-help">可添加当前组长创建的普通员工账号,按住 Ctrl 或 Command 可多选。
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="shop-group-action-bar">
|
|
<button class="btn" id="btnSaveShopManageGroup" type="button">保存分组</button>
|
|
<button class="btn btn-secondary" id="btnCancelShopManageGroupEdit" type="button">取消编辑</button>
|
|
</div>
|
|
<p class="msg" id="msgShopManageGroup"></p>
|
|
<div class="shop-group-table-wrap">
|
|
<table class="shop-group-table">
|
|
<colgroup>
|
|
<col class="col-index">
|
|
<col class="col-name">
|
|
<col class="col-leader">
|
|
<col class="col-count">
|
|
<col class="col-members">
|
|
<col class="col-time">
|
|
<col class="col-time">
|
|
<col class="col-action">
|
|
</colgroup>
|
|
<thead>
|
|
<tr>
|
|
<th>序号</th>
|
|
<th>分组名称</th>
|
|
<th>组长</th>
|
|
<th>组员数量</th>
|
|
<th>组员</th>
|
|
<th>创建时间</th>
|
|
<th>修改时间</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="shopManageGroupListBody"></tbody>
|
|
</table>
|
|
</div>
|
|
<div class="shop-group-modal-footer">
|
|
<button class="btn btn-secondary" id="btnCloseShopManageGroupModal" type="button">关闭</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 编辑店铺管理弹窗 -->
|
|
<div class="modal-mask" id="chooseSkipPriceAsinShopModal">
|
|
<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="chooseSkipPriceAsinShopGroupId">
|
|
<option value="">全部分组</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group" style="min-width:220px;">
|
|
<label>店铺名</label>
|
|
<input type="text" id="chooseSkipPriceAsinShopKeyword" placeholder="请输入店铺名">
|
|
</div>
|
|
<button class="btn" id="btnSearchChooseSkipPriceAsinShop" 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="chooseSkipPriceAsinShopListBody"></tbody>
|
|
</table>
|
|
</div>
|
|
<div class="pagination" id="chooseSkipPriceAsinShopPagination"></div>
|
|
<div style="margin-top:16px;display:flex;gap:8px;justify-content:flex-end;">
|
|
<button class="btn btn-secondary" id="btnCloseChooseSkipPriceAsinShopModal" type="button">关闭</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-mask" id="editSkipPriceAsinModal">
|
|
<div class="modal">
|
|
<h3>编辑跳过跟价 ASIN</h3>
|
|
<input type="hidden" id="editSkipPriceAsinId">
|
|
<input type="hidden" id="editSkipPriceAsinCountry">
|
|
<div class="form-group">
|
|
<label>店铺名</label>
|
|
<input type="text" id="editSkipPriceAsinShopName" readonly style="background:#f4f6fa;">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>国家</label>
|
|
<input type="text" id="editSkipPriceAsinCountryLabel" readonly style="background:#f4f6fa;">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>ASIN</label>
|
|
<input type="text" id="editSkipPriceAsinValue" placeholder="请输入 ASIN">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>最低价</label>
|
|
<input type="number" id="editSkipPriceMinimumPrice" min="0" step="0.01" placeholder="请输入最低价,可留空">
|
|
</div>
|
|
<p class="msg" id="msgEditSkipPriceAsin"></p>
|
|
<div style="margin-top:16px;display:flex;gap:8px;">
|
|
<button class="btn" id="btnSaveSkipPriceAsin">保存</button>
|
|
<button class="btn btn-secondary" id="btnCloseEditSkipPriceAsin">取消</button>
|
|
</div>
|
|
</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:#f4f6fa;">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>国家</label>
|
|
<input type="text" id="editQueryAsinCountryLabel" readonly style="background:#f4f6fa;">
|
|
</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>
|
|
<input type="hidden" id="editShopManageId">
|
|
<div class="form-group">
|
|
<label>分组</label>
|
|
<div style="display:flex;gap:8px;align-items:center;">
|
|
<select id="editShopManageGroupSelect" style="min-width:200px;">
|
|
<option value="">请选择分组</option>
|
|
</select>
|
|
<button class="btn btn-secondary" id="btnManageShopGroupsFromEdit" type="button">管理分组</button>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>店铺名</label>
|
|
<input type="text" id="editShopManageShopName" placeholder="店铺名">
|
|
</div>
|
|
<div class=" form-group">
|
|
<label>店铺商城名</label>
|
|
<input type="text" id="editShopManageMallName" placeholder="店铺商城名">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>自动化账号</label>
|
|
<input type="text" id="editShopManageZnUsername" maxlength="128" placeholder="自动化账号(可选)">
|
|
</div>
|
|
<div class=" form-group">
|
|
<label>账号</label>
|
|
<input type="text" id="editShopManageAccount" placeholder="账号">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>密码</label>
|
|
<input type="text" id="editShopManagePassword" placeholder="密码">
|
|
</div>
|
|
<p class="msg" id="msgEditShopManage"></p>
|
|
<div style="margin-top:16px;display:flex;gap:8px;">
|
|
<button class="btn" id="btnSaveShopManage">保存</button>
|
|
<button class="btn btn-secondary" id="btnCloseEditShopManage">取消</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 编辑店铺密钥弹窗 -->
|
|
<div class="modal-mask" id="editShopKeyModal">
|
|
<div class="modal">
|
|
<h3>编辑店铺密钥</h3>
|
|
<input type="hidden" id="editShopKeyId">
|
|
<div class="form-group">
|
|
<label>备注名</label>
|
|
<input type="text" id="editShopKeyRemarkName" maxlength="128" placeholder="备注名(可选)">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>紫鸟账号名称</label>
|
|
<input type="text" id="editShopKeyZiniaoAccountName" placeholder="紫鸟账号名称">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>紫鸟令牌</label>
|
|
<input type="text" id="editShopKeyZiniaoToken" placeholder="紫鸟令牌">
|
|
</div>
|
|
<p class="msg" id="msgEditShopKey"></p>
|
|
<div style="margin-top:16px;display:flex;gap:8px;">
|
|
<button class="btn" id="btnSaveShopKey">保存</button>
|
|
<button class="btn btn-secondary" id="btnCloseEditShopKey">取消</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-mask" id="imageVideoPermissionModal">
|
|
<div class="modal image-video-permission-modal" role="dialog" aria-modal="true"
|
|
aria-labelledby="imageVideoPermissionTitle">
|
|
<div class="image-video-permission-head">
|
|
<h3 id="imageVideoPermissionTitle">视频任务记录权限配置</h3>
|
|
<button class="btn btn-secondary btn-sm" id="btnCloseImageVideoPermissions" type="button">关闭</button>
|
|
</div>
|
|
<div class="image-video-permission-tabs" role="tablist" aria-label="视频权限用户范围">
|
|
<button class="image-video-permission-tab active" type="button" role="tab" aria-selected="true"
|
|
data-image-video-permission-view="granted">已分配用户 <span
|
|
id="imageVideoPermissionGrantedCount">(0)</span></button>
|
|
<button class="image-video-permission-tab" type="button" role="tab" aria-selected="false"
|
|
data-image-video-permission-view="all">全部用户 <span
|
|
id="imageVideoPermissionAllCount">(0)</span></button>
|
|
</div>
|
|
<div class="image-video-permission-tools">
|
|
<input class="image-video-permission-search" id="imageVideoPermissionSearch" type="search"
|
|
placeholder="搜索用户名">
|
|
<label class="image-video-select-all">
|
|
<input type="checkbox" id="imageVideoPermissionSelectAll">
|
|
全选搜索结果
|
|
</label>
|
|
</div>
|
|
<p class="image-video-permission-summary" id="imageVideoPermissionSummary"></p>
|
|
<div class="image-video-permission-list" id="imageVideoPermissionList" aria-live="polite"></div>
|
|
<p class="msg" id="imageVideoPermissionMessage" aria-live="polite"></p>
|
|
<div class="image-video-permission-actions">
|
|
<button class="btn btn-secondary" id="btnCancelImageVideoPermissions" type="button">取消</button>
|
|
<button class="btn" id="btnSaveImageVideoPermissions" type="button">保存</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-mask" id="shopDataTaskPermissionModal">
|
|
<div class="modal image-video-permission-modal" role="dialog" aria-modal="true"
|
|
aria-labelledby="shopDataTaskPermissionTitle">
|
|
<div class="image-video-permission-head">
|
|
<h3 id="shopDataTaskPermissionTitle">店铺数据记录权限配置</h3>
|
|
<button class="btn btn-secondary btn-sm" id="btnCloseShopDataTaskPermissions"
|
|
type="button">关闭</button>
|
|
</div>
|
|
<div class="image-video-permission-tabs" role="tablist" aria-label="店铺数据记录权限用户范围">
|
|
<button class="image-video-permission-tab active" type="button" role="tab"
|
|
aria-selected="true" data-shop-data-permission-view="granted">已分配用户 <span
|
|
id="shopDataTaskPermissionGrantedCount">(0)</span></button>
|
|
<button class="image-video-permission-tab" type="button" role="tab" aria-selected="false"
|
|
data-shop-data-permission-view="all">全部用户 <span
|
|
id="shopDataTaskPermissionAllCount">(0)</span></button>
|
|
</div>
|
|
<div class="image-video-permission-tools">
|
|
<input class="image-video-permission-search" id="shopDataTaskPermissionSearch" type="search"
|
|
placeholder="搜索用户名">
|
|
<label class="image-video-select-all">
|
|
<input type="checkbox" id="shopDataTaskPermissionSelectAll">
|
|
全选搜索结果
|
|
</label>
|
|
</div>
|
|
<p class="image-video-permission-summary" id="shopDataTaskPermissionSummary"></p>
|
|
<div class="image-video-permission-list" id="shopDataTaskPermissionList" aria-live="polite"></div>
|
|
<p class="msg" id="shopDataTaskPermissionMessage" aria-live="polite"></p>
|
|
<div class="image-video-permission-actions">
|
|
<button class="btn btn-secondary" id="btnCancelShopDataTaskPermissions" type="button">取消</button>
|
|
<button class="btn" id="btnSaveShopDataTaskPermissions" type="button">保存</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
// 侧边栏分组折叠:独立于 admin.js,即使主 JS 加载失败也可用;admin.js 重渲染菜单后也会调用 __initAdminMenuCollapse
|
|
(function () {
|
|
var KEY = 'shufuAdminMenuCollapsed';
|
|
function readState() {
|
|
try { return JSON.parse(localStorage.getItem(KEY) || '{}') || {}; } catch (e) { return {}; }
|
|
}
|
|
function bindGroup(group) {
|
|
var titleEl = group.querySelector('.menu-group-title');
|
|
if (!titleEl || titleEl._bound) return;
|
|
titleEl._bound = true;
|
|
var key = group.getAttribute('data-menu-group') || '';
|
|
var initiallyCollapsed = !!(key && readState()[key]);
|
|
if (initiallyCollapsed) group.classList.add('is-collapsed');
|
|
titleEl.setAttribute('aria-expanded', initiallyCollapsed ? 'false' : 'true');
|
|
titleEl.addEventListener('click', function () {
|
|
var collapsed = group.classList.toggle('is-collapsed');
|
|
titleEl.setAttribute('aria-expanded', collapsed ? 'false' : 'true');
|
|
if (key) {
|
|
var state = readState();
|
|
if (collapsed) state[key] = true; else delete state[key];
|
|
try { localStorage.setItem(KEY, JSON.stringify(state)); } catch (e) { }
|
|
}
|
|
});
|
|
}
|
|
// 为已有的相邻表单标签补上 for 关联;嵌套复选框标签保持原生包裹语义。
|
|
function associateFormLabels(root) {
|
|
root.querySelectorAll('.form-group').forEach(function (group) {
|
|
var label = Array.prototype.find.call(group.children, function (child) {
|
|
return child.tagName === 'LABEL' && !child.htmlFor && !child.querySelector('input, select, textarea');
|
|
});
|
|
if (!label) return;
|
|
var control = Array.prototype.find.call(group.querySelectorAll('input[id], select[id], textarea[id]'), function (item) {
|
|
return !item.classList.contains('multi-select-native');
|
|
});
|
|
if (control) label.htmlFor = control.id;
|
|
});
|
|
}
|
|
associateFormLabels(document);
|
|
window.__initAdminMenuCollapse = function () {
|
|
document.querySelectorAll('#adminMenu .menu-group').forEach(bindGroup);
|
|
};
|
|
window.__initAdminMenuCollapse();
|
|
})();
|
|
</script>
|
|
<script src="/static/admin.js?v=admin-menu-v2"></script>
|
|
<div class="admin-toast-region" id="adminToastRegion" role="status" aria-live="polite" aria-atomic="true"></div>
|
|
<div class="admin-confirm-mask" id="adminConfirmModal" aria-hidden="true">
|
|
<section class="admin-confirm-dialog" role="alertdialog" aria-modal="true" aria-labelledby="adminConfirmTitle" aria-describedby="adminConfirmMessage">
|
|
<div class="admin-confirm-dialog__icon" aria-hidden="true">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4"></path><path d="M12 17h.01"></path><path d="m10.3 3.9-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3.1l-8-14a2 2 0 0 0-3.4 0Z"></path></svg>
|
|
</div>
|
|
<div class="admin-confirm-dialog__content">
|
|
<h2 id="adminConfirmTitle">请确认操作</h2>
|
|
<p id="adminConfirmMessage">该操作可能影响已有数据。</p>
|
|
</div>
|
|
<div class="admin-confirm-dialog__actions">
|
|
<button class="btn btn-secondary" id="adminConfirmCancel" type="button">取消</button>
|
|
<button class="btn btn-danger" id="adminConfirmAccept" type="button">确认删除</button>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
|
|
<script src="/static/admin-interactions.js?v=admin-interactions-v1"></script>
|
|
</body>
|
|
|
|
</html>
|