2557 lines
92 KiB
HTML
2557 lines
92 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>管理后台 - 南日AI</title>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
font-family: "Microsoft YaHei", "PingFang SC", sans-serif;
|
||
background: #f5f5f5;
|
||
padding: 24px;
|
||
}
|
||
|
||
.page-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 16px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.page-head h1 {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.admin-user-box {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding: 8px 12px;
|
||
background: #fff;
|
||
border: 1px solid #e6eaf2;
|
||
border-radius: 999px;
|
||
box-shadow: 0 4px 14px rgba(102, 126, 234, 0.08);
|
||
}
|
||
|
||
.admin-user-name {
|
||
font-size: 14px;
|
||
color: #333;
|
||
max-width: 220px;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.admin-user-role {
|
||
font-size: 12px;
|
||
color: #667eea;
|
||
background: #eef1ff;
|
||
padding: 4px 8px;
|
||
border-radius: 999px;
|
||
}
|
||
|
||
.admin-user-logout {
|
||
padding: 6px 12px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.nav {
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.nav a {
|
||
color: #667eea;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.nav a:hover {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
h1 {
|
||
font-size: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
/* Tabs */
|
||
.tabs {
|
||
display: flex;
|
||
gap: 4px;
|
||
margin-bottom: 20px;
|
||
border-bottom: 1px solid #e0e0e0;
|
||
}
|
||
|
||
.tab {
|
||
padding: 12px 24px;
|
||
cursor: pointer;
|
||
color: #666;
|
||
font-size: 15px;
|
||
border-bottom: 2px solid transparent;
|
||
margin-bottom: -1px;
|
||
}
|
||
|
||
.tab:hover {
|
||
color: #667eea;
|
||
}
|
||
|
||
.tab.active {
|
||
color: #667eea;
|
||
font-weight: 600;
|
||
border-bottom-color: #667eea;
|
||
}
|
||
|
||
.tab-panel {
|
||
display: none;
|
||
}
|
||
|
||
.tab-panel.active {
|
||
display: block;
|
||
}
|
||
|
||
/* Form & Table */
|
||
.form-box,
|
||
.panel-box {
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
padding: 24px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.form-group label {
|
||
display: block;
|
||
font-size: 14px;
|
||
margin-bottom: 6px;
|
||
}
|
||
|
||
.form-group input,
|
||
.form-group select {
|
||
width: 100%;
|
||
padding: 10px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.form-group input[type="checkbox"] {
|
||
width: auto;
|
||
margin-right: 8px;
|
||
}
|
||
|
||
.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;
|
||
}
|
||
|
||
.btn {
|
||
padding: 10px 20px;
|
||
background: #667eea;
|
||
color: #fff;
|
||
border: none;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.btn:hover {
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.btn-sm {
|
||
padding: 6px 12px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.btn-danger {
|
||
background: #e74c3c;
|
||
}
|
||
|
||
.btn-secondary {
|
||
background: #95a5a6;
|
||
}
|
||
|
||
.msg {
|
||
margin-top: 12px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.msg.ok {
|
||
color: #27ae60;
|
||
}
|
||
|
||
.msg.err {
|
||
color: #e74c3c;
|
||
}
|
||
|
||
.progress-wrap {
|
||
margin-top: 12px;
|
||
}
|
||
|
||
.progress-bar {
|
||
width: 100%;
|
||
height: 10px;
|
||
background: #edf0f5;
|
||
border-radius: 999px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.progress-fill {
|
||
width: 0;
|
||
height: 100%;
|
||
background: #667eea;
|
||
transition: width 0.2s ease;
|
||
}
|
||
|
||
.progress-text {
|
||
margin-top: 8px;
|
||
font-size: 13px;
|
||
color: #666;
|
||
}
|
||
|
||
.request-loading-bar {
|
||
position: fixed;
|
||
left: 0;
|
||
top: 0;
|
||
width: 0;
|
||
height: 3px;
|
||
background: #667eea;
|
||
opacity: 0;
|
||
z-index: 3000;
|
||
transition: width 0.2s ease, opacity 0.2s ease;
|
||
}
|
||
|
||
.request-loading-bar.show {
|
||
width: 74%;
|
||
opacity: 1;
|
||
}
|
||
|
||
.request-loading-bar.finishing {
|
||
width: 100%;
|
||
opacity: 0;
|
||
}
|
||
|
||
.request-loading {
|
||
position: fixed;
|
||
right: 24px;
|
||
top: 72px;
|
||
display: none;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding: 10px 14px;
|
||
color: #333;
|
||
background: rgba(255, 255, 255, 0.96);
|
||
border: 1px solid #e6eaf2;
|
||
border-radius: 8px;
|
||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
||
font-size: 13px;
|
||
z-index: 3000;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.request-loading.show {
|
||
display: flex;
|
||
}
|
||
|
||
.request-spinner {
|
||
width: 16px;
|
||
height: 16px;
|
||
border: 2px solid #dce2ff;
|
||
border-top-color: #667eea;
|
||
border-radius: 50%;
|
||
animation: request-spin 0.8s linear infinite;
|
||
}
|
||
|
||
@keyframes request-spin {
|
||
to {
|
||
transform: rotate(360deg);
|
||
}
|
||
}
|
||
|
||
table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
}
|
||
|
||
th,
|
||
td {
|
||
padding: 12px;
|
||
text-align: left;
|
||
border-bottom: 1px solid #eee;
|
||
font-size: 14px;
|
||
}
|
||
|
||
th {
|
||
background: #f8f9fa;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.pagination {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
margin-top: 16px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.pagination span {
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
|
||
.pagination button {
|
||
padding: 6px 12px;
|
||
border: 1px solid #ddd;
|
||
background: #fff;
|
||
cursor: pointer;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.pagination button:hover:not(:disabled) {
|
||
background: #f0f0f0;
|
||
}
|
||
|
||
.pagination button:disabled {
|
||
opacity: 0.5;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.thumb {
|
||
width: 60px;
|
||
height: 60px;
|
||
object-fit: cover;
|
||
border-radius: 4px;
|
||
margin-right: 8px;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.thumb-wrap {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 4px;
|
||
}
|
||
|
||
.empty-tip {
|
||
color: #999;
|
||
font-size: 14px;
|
||
padding: 24px;
|
||
text-align: center;
|
||
}
|
||
|
||
.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: 18px;
|
||
height: 18px;
|
||
border: 0;
|
||
border-radius: 4px;
|
||
background: #eef1ff;
|
||
color: #667eea;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
cursor: pointer;
|
||
padding: 0;
|
||
line-height: 1;
|
||
}
|
||
|
||
.tree-node-mark.is-leaf {
|
||
background: transparent;
|
||
cursor: default;
|
||
}
|
||
|
||
.category-path {
|
||
color: #777;
|
||
font-size: 12px;
|
||
margin-top: 4px;
|
||
}
|
||
|
||
.category-tag {
|
||
display: inline-block;
|
||
padding: 3px 8px;
|
||
border-radius: 999px;
|
||
background: #f1f3f5;
|
||
color: #666;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.modal-mask {
|
||
display: none;
|
||
position: fixed;
|
||
left: 0;
|
||
top: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: rgba(0, 0, 0, 0.4);
|
||
z-index: 1000;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.modal-mask.show {
|
||
display: flex;
|
||
}
|
||
|
||
#shopManageGroupModal {
|
||
z-index: 1010;
|
||
}
|
||
|
||
.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: #333;
|
||
}
|
||
|
||
.dedupe-group-summary {
|
||
min-width: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
flex-wrap: wrap;
|
||
color: #707781;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.dedupe-group-summary-chip {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
max-width: 220px;
|
||
padding: 4px 8px;
|
||
border: 1px solid #dfe4ea;
|
||
border-radius: 4px;
|
||
background: #f8f9fa;
|
||
color: #4f5965;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.modal {
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
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;
|
||
}
|
||
|
||
.modal h3 {
|
||
margin-bottom: 16px;
|
||
font-size: 16px;
|
||
}
|
||
|
||
#shopManageGroupModal .shop-group-modal {
|
||
width: min(1180px, calc(100vw - 48px));
|
||
max-width: none;
|
||
max-height: calc(100vh - 48px);
|
||
padding: 0;
|
||
overflow: hidden;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.shop-group-modal-header {
|
||
padding: 20px 24px 14px;
|
||
border-bottom: 1px solid #edf0f5;
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
.shop-group-modal-header h3 {
|
||
margin: 0;
|
||
}
|
||
|
||
.shop-group-editor {
|
||
padding: 18px 24px 14px;
|
||
display: grid;
|
||
grid-template-columns: minmax(180px, 240px) minmax(240px, 320px) minmax(360px, 1fr);
|
||
gap: 16px;
|
||
align-items: start;
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
.shop-group-editor .form-group {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.shop-group-member-select {
|
||
min-height: 128px;
|
||
max-height: 180px;
|
||
}
|
||
|
||
.shop-group-help {
|
||
color: #777;
|
||
font-size: 12px;
|
||
line-height: 1.5;
|
||
margin-top: 6px;
|
||
}
|
||
|
||
.shop-group-action-bar {
|
||
padding: 0 24px 12px;
|
||
display: flex;
|
||
gap: 8px;
|
||
justify-content: flex-end;
|
||
align-items: center;
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
#msgShopManageGroup {
|
||
margin: 0;
|
||
padding: 0 24px 10px;
|
||
min-height: 18px;
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
.shop-group-table-wrap {
|
||
margin: 0 24px;
|
||
border: 1px solid #edf0f5;
|
||
border-radius: 8px;
|
||
overflow: auto;
|
||
min-height: 220px;
|
||
flex: 1 1 auto;
|
||
}
|
||
|
||
.shop-group-table {
|
||
min-width: 1040px;
|
||
table-layout: fixed;
|
||
}
|
||
|
||
.shop-group-table th {
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 1;
|
||
}
|
||
|
||
.shop-group-table th,
|
||
.shop-group-table td {
|
||
vertical-align: top;
|
||
}
|
||
|
||
.shop-group-table .col-index {
|
||
width: 58px;
|
||
}
|
||
|
||
.shop-group-table .col-name {
|
||
width: 130px;
|
||
}
|
||
|
||
.shop-group-table .col-leader {
|
||
width: 110px;
|
||
}
|
||
|
||
.shop-group-table .col-count {
|
||
width: 86px;
|
||
}
|
||
|
||
.shop-group-table .col-members {
|
||
width: auto;
|
||
}
|
||
|
||
.shop-group-table .col-time {
|
||
width: 120px;
|
||
}
|
||
|
||
.shop-group-table .col-action {
|
||
width: 128px;
|
||
}
|
||
|
||
.shop-group-time-cell,
|
||
.shop-group-action-cell {
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.shop-group-name-cell,
|
||
.shop-group-leader-cell {
|
||
word-break: break-word;
|
||
}
|
||
|
||
.shop-group-members {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 6px;
|
||
max-height: 96px;
|
||
overflow-y: auto;
|
||
padding-right: 4px;
|
||
}
|
||
|
||
.shop-group-member-chip {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
max-width: 150px;
|
||
padding: 3px 8px;
|
||
border-radius: 999px;
|
||
background: #eef1ff;
|
||
color: #4f63d8;
|
||
font-size: 12px;
|
||
line-height: 1.4;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.shop-group-modal-footer {
|
||
padding: 14px 24px 18px;
|
||
display: flex;
|
||
gap: 8px;
|
||
justify-content: flex-end;
|
||
border-top: 1px solid #edf0f5;
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
.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;
|
||
}
|
||
|
||
.multi-select-native {
|
||
position: absolute;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
width: 1px !important;
|
||
height: 1px !important;
|
||
min-height: 0 !important;
|
||
padding: 0 !important;
|
||
border: 0 !important;
|
||
}
|
||
|
||
.multi-select-dropdown {
|
||
position: relative;
|
||
width: 100%;
|
||
}
|
||
|
||
.multi-select-trigger {
|
||
width: 100%;
|
||
min-height: 42px;
|
||
padding: 10px 34px 10px 12px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 6px;
|
||
background: #fff;
|
||
color: #333;
|
||
font-size: 14px;
|
||
text-align: left;
|
||
cursor: pointer;
|
||
position: relative;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.multi-select-trigger::after {
|
||
content: "";
|
||
position: absolute;
|
||
right: 12px;
|
||
top: 50%;
|
||
width: 7px;
|
||
height: 7px;
|
||
border-right: 1.5px solid #666;
|
||
border-bottom: 1.5px solid #666;
|
||
transform: translateY(-65%) rotate(45deg);
|
||
}
|
||
|
||
.multi-select-dropdown.open .multi-select-trigger {
|
||
border-color: #667eea;
|
||
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.12);
|
||
}
|
||
|
||
.multi-select-panel {
|
||
display: none;
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
top: calc(100% + 6px);
|
||
z-index: 30;
|
||
background: #fff;
|
||
border: 1px solid #ddd;
|
||
border-radius: 8px;
|
||
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.14);
|
||
padding: 6px;
|
||
max-height: 220px;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.multi-select-dropdown.open .multi-select-panel {
|
||
display: block;
|
||
}
|
||
|
||
.multi-select-option {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
min-height: 34px;
|
||
padding: 7px 8px;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
color: #333;
|
||
}
|
||
|
||
.multi-select-option:hover {
|
||
background: #f4f6ff;
|
||
}
|
||
|
||
.multi-select-option input {
|
||
width: auto;
|
||
margin: 0;
|
||
}
|
||
|
||
.column-permission-card {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 4px 10px;
|
||
background: #e8ebf7;
|
||
color: #667eea;
|
||
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: #999;
|
||
border: none;
|
||
background: none;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.column-permission-card .col-card-remove:hover {
|
||
color: #e74c3c;
|
||
}
|
||
|
||
.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: #27b38b;
|
||
}
|
||
|
||
.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: #333;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.image-video-select-all input {
|
||
width: 16px;
|
||
height: 16px;
|
||
accent-color: #27b38b;
|
||
}
|
||
|
||
.image-video-download-progress {
|
||
min-height: 18px;
|
||
color: #527067;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.image-video-summary {
|
||
color: #666;
|
||
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 #e0e0e0;
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, .05);
|
||
transition: border-color .2s ease, box-shadow .2s ease, transform .2s ease;
|
||
}
|
||
|
||
.image-video-card:hover {
|
||
border-color: #cbd7d3;
|
||
box-shadow: 0 6px 16px rgba(32, 74, 62, .1);
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
.image-video-card.selected {
|
||
border-color: #27b38b;
|
||
box-shadow: 0 0 0 2px rgba(39, 179, 139, .12), 0 6px 16px rgba(32, 74, 62, .1);
|
||
}
|
||
|
||
.image-video-media {
|
||
position: relative;
|
||
width: 100%;
|
||
aspect-ratio: 16/9;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: #0b0d0c;
|
||
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: #27b38b;
|
||
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: #b9c1be;
|
||
text-align: center;
|
||
}
|
||
|
||
.image-video-unavailable svg {
|
||
width: 34px;
|
||
height: 34px;
|
||
fill: none;
|
||
stroke: currentColor;
|
||
stroke-width: 1.5;
|
||
}
|
||
|
||
.image-video-unavailable strong {
|
||
color: #e0e4e2;
|
||
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: #2b3532;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.image-video-status {
|
||
flex: 0 0 auto;
|
||
display: inline-block;
|
||
padding: 3px 8px;
|
||
border-radius: 4px;
|
||
background: #eef1f0;
|
||
color: #5b6461;
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.image-video-status.SUCCESS {
|
||
color: #14733b;
|
||
background: #e5f5eb;
|
||
}
|
||
|
||
.image-video-status.FAILED {
|
||
color: #a82d2d;
|
||
background: #fbe9e9;
|
||
}
|
||
|
||
.image-video-status.RUNNING,
|
||
.image-video-status.POLLING {
|
||
color: #8a6200;
|
||
background: #fff3cd;
|
||
}
|
||
|
||
.image-video-card-info {
|
||
display: grid;
|
||
gap: 7px;
|
||
}
|
||
|
||
.image-video-info-row {
|
||
display: grid;
|
||
grid-template-columns: 68px minmax(0, 1fr);
|
||
gap: 8px;
|
||
color: #777;
|
||
font-size: 13px;
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.image-video-info-row span,
|
||
.image-video-info-row a {
|
||
min-width: 0;
|
||
color: #333;
|
||
overflow-wrap: anywhere;
|
||
}
|
||
|
||
.image-video-info-row a {
|
||
color: #218a6d;
|
||
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: #218a6d;
|
||
cursor: pointer;
|
||
font: inherit;
|
||
text-align: left;
|
||
}
|
||
|
||
.image-video-copy-link:hover {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
.image-video-copy-link.copied {
|
||
color: #14733b;
|
||
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 #27b38b;
|
||
border-radius: 4px;
|
||
background: #fff;
|
||
color: #218a6d;
|
||
cursor: pointer;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.image-video-card-action:hover {
|
||
background: #27b38b;
|
||
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 #d7ddda;
|
||
border-radius: 8px;
|
||
color: #777;
|
||
text-align: center;
|
||
background: #fafbfb;
|
||
}
|
||
|
||
.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: #f1f4f3;
|
||
}
|
||
|
||
.image-video-permission-tab {
|
||
flex: 1;
|
||
min-height: 34px;
|
||
padding: 7px 10px;
|
||
border: 0;
|
||
border-radius: 4px;
|
||
background: transparent;
|
||
color: #68736f;
|
||
cursor: pointer;
|
||
font: inherit;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.image-video-permission-tab.active {
|
||
background: #fff;
|
||
color: #16835e;
|
||
box-shadow: 0 1px 4px rgba(38, 70, 58, .12);
|
||
font-weight: 600;
|
||
}
|
||
|
||
.image-video-permission-search {
|
||
flex: 1;
|
||
min-width: 0;
|
||
padding: 9px 10px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 6px;
|
||
font: inherit;
|
||
}
|
||
|
||
.image-video-permission-list {
|
||
max-height: 52vh;
|
||
overflow: auto;
|
||
border: 1px solid #e1e5e3;
|
||
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 #edf0ef;
|
||
}
|
||
|
||
.image-video-permission-row:last-child {
|
||
border-bottom: 0;
|
||
}
|
||
|
||
.image-video-permission-row input {
|
||
width: 16px;
|
||
height: 16px;
|
||
accent-color: #27b38b;
|
||
}
|
||
|
||
.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: #293330;
|
||
}
|
||
|
||
.image-video-permission-role {
|
||
color: #727b78;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.image-video-permission-state {
|
||
min-width: 68px;
|
||
padding: 4px 8px;
|
||
border: 1px solid #d8dfdc;
|
||
border-radius: 4px;
|
||
background: #fff;
|
||
color: #6d7773;
|
||
cursor: pointer;
|
||
font-size: 12px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.image-video-permission-state.granted {
|
||
border-color: #a9ddca;
|
||
background: #ecfaf4;
|
||
color: #16835e;
|
||
}
|
||
|
||
.image-video-permission-state.pending {
|
||
border-color: #efd39b;
|
||
background: #fff8e8;
|
||
color: #a56b00;
|
||
}
|
||
|
||
.image-video-permission-summary {
|
||
margin: 0 0 10px;
|
||
color: #66716d;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.image-video-permission-empty {
|
||
padding: 36px 16px;
|
||
color: #777;
|
||
text-align: center;
|
||
}
|
||
|
||
.image-video-permission-actions {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 8px;
|
||
margin-top: 16px;
|
||
}
|
||
|
||
@media (max-width: 760px) {
|
||
.admin-user-box {
|
||
position: static !important;
|
||
width: max-content;
|
||
max-width: 100%;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.tabs {
|
||
max-width: 100%;
|
||
overflow-x: auto;
|
||
overscroll-behavior-x: contain;
|
||
}
|
||
|
||
.tab {
|
||
flex: 0 0 auto;
|
||
padding: 10px 14px;
|
||
}
|
||
|
||
.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;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<!-- <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>
|
||
<h1>管理后台</h1>
|
||
|
||
<div class="admin-user-box" style="position:absolute;top:24px;right:24px;z-index:10;">
|
||
<span class="admin-user-name" id="adminCurrentUsername">加载中...</span>
|
||
<span class="admin-user-role" id="adminCurrentUserRole" style="display:none;"></span>
|
||
<button class="btn btn-secondary admin-user-logout" id="btnAdminLogout" type="button">退出登录</button>
|
||
</div>
|
||
|
||
<div class="tabs" id="adminTabs">
|
||
<div class="tab active" data-tab="users">用户管理</div>
|
||
<div class="tab" data-tab="columns">栏目权限配置</div>
|
||
<div class="tab" data-tab="dedupe-total-data">数据去重总数据</div>
|
||
<div class="tab" data-tab="invalid-asin-data">不符合ASIN数据</div>
|
||
<div class="tab" data-tab="shop-keys">店铺密钥管理</div>
|
||
<div class="tab" data-tab="shop-manage">店铺管理</div>
|
||
<div class="tab" data-tab="skip-price-asin">跳过跟价 ASIN</div>
|
||
<div class="tab" data-tab="query-asin">查询 ASIN</div>
|
||
<div class="tab" data-tab="product-categories">商品类目</div>
|
||
<div class="tab" data-tab="history">查看生成记录</div>
|
||
<div class="tab" data-tab="version">软件版本管理</div>
|
||
<div class="tab" data-tab="digital-human-version">数字人版本管理</div>
|
||
</div>
|
||
|
||
<!-- 用户管理 -->
|
||
<div id="panel-users" class="tab-panel">
|
||
<div class="form-box">
|
||
<h3 style="margin-bottom:16px;font-size:15px;">创建用户</h3>
|
||
<p style="margin-bottom:16px;font-size:13px;color:#666;">
|
||
当前没有开放注册入口,仅管理员可在此创建用户。层级关系:超级管理员 -> 管理员 -> 普通账号。</p>
|
||
<div class="form-group">
|
||
<label>用户名</label>
|
||
<input type="text" id="username" placeholder="用户名(至少 2 个字符)">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>密码</label>
|
||
<input type="password" id="password" placeholder="密码(至少 6 个字符)">
|
||
</div>
|
||
<div class="form-group" id="formGroupRole">
|
||
<label>角色</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>所属管理员</label>
|
||
<select id="createCreatedBy">
|
||
<option value="">请选择管理员</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group" id="formGroupCreateColumns">
|
||
<label>菜单权限(可多选,Ctrl/Shift 点选)</label>
|
||
<div id="createColumnCards" class="column-permission-cards"></div>
|
||
<select id="createColumnPermissionWrap" class="column-permission-select" multiple></select>
|
||
</div>
|
||
<button class="btn" id="btnCreate">创建用户</button>
|
||
<p class="msg" id="msgCreate"></p>
|
||
</div>
|
||
|
||
<div class="panel-box">
|
||
<h3 style="margin-bottom:16px;font-size:15px;">用户列表</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>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>用户名</th>
|
||
<th>角色</th>
|
||
<th>所属管理员</th>
|
||
<th>创建时间</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="userListBody"></tbody>
|
||
</table>
|
||
<div class="pagination" id="userPagination"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 栏目权限配置 -->
|
||
<div id="panel-columns" class="tab-panel">
|
||
<div class="form-box">
|
||
<h3 style="margin-bottom:16px;font-size:15px;">新增菜单</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>
|
||
<button class="btn" id="btnAddColumn">新增菜单</button>
|
||
</div>
|
||
<p class="msg" id="msgColumn"></p>
|
||
</div>
|
||
<div class="panel-box">
|
||
<h3 style="margin-bottom:16px;font-size:15px;">栏目列表</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>ID</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 id="panel-version" class="tab-panel">
|
||
<div class="form-box">
|
||
<h3 style="margin-bottom:16px;font-size:15px;">上传新版本</h3>
|
||
<p style="margin-bottom:16px;font-size:13px;color:#666;">
|
||
上传软件 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:#999;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;font-size:15px;">版本列表</h3>
|
||
<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 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;font-size:15px;">上传新版本</h3>
|
||
<p style="margin-bottom:16px;font-size:13px;color:#666;">
|
||
上传数字人程序 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 #ddd;border-radius:6px;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;font-size:15px;">版本列表</h3>
|
||
<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 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;font-size:15px;">新增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>
|
||
<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;font-size:15px;">删除匹配总数据</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>
|
||
<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;font-size:15px;">ASIN列表</h3>
|
||
<div class="form-row" style="margin-bottom:16px;">
|
||
<div class="form-group" style="min-width:220px;">
|
||
<label>数据值(模糊搜索)</label>
|
||
<input type="text" id="searchDedupeTotalData" placeholder="输入关键字">
|
||
</div>
|
||
<div class="form-group" style="min-width:220px;">
|
||
<label>用户名(模糊搜索)</label>
|
||
<input type="text" id="searchDedupeTotalDataUsername" placeholder="输入用户名">
|
||
</div>
|
||
<button class=" btn" id="btnSearchDedupeTotalData">查询</button>
|
||
</div>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>ASIN值</th>
|
||
<th>用户名</th>
|
||
<th>创建时间</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="dedupeTotalDataListBody"></tbody>
|
||
</table>
|
||
<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;font-size:15px;">新增不符合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>
|
||
<button class="btn" id="btnAddInvalidAsinData">新增</button>
|
||
</div>
|
||
<p class="msg" id="msgInvalidAsinData"></p>
|
||
</div>
|
||
<div class="panel-box">
|
||
<h3 style="margin-bottom:16px;font-size:15px;">不符合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>
|
||
<button class=" btn" id="btnSearchInvalidAsinData">查询</button>
|
||
</div>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>ASIN</th>
|
||
<th>品牌</th>
|
||
<th>创建时间</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="invalidAsinDataListBody"></tbody>
|
||
</table>
|
||
<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;font-size:15px;">新增店铺密钥</h3>
|
||
<div class="form-row">
|
||
<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;font-size:15px;">店铺密钥列表</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>序号</th>
|
||
<th>紫鸟账号名称</th>
|
||
<th>紫鸟令牌</th>
|
||
<th>创建时间</th>
|
||
<th>修改时间</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="shopKeyListBody"></tbody>
|
||
</table>
|
||
<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;font-size:15px;">新增店铺</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="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;font-size:15px;">店铺列表</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>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<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 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;font-size:15px;">新增 ASIN</h3>
|
||
<div class="form-row">
|
||
<div class="form-group" style="min-width:220px;">
|
||
<label>分组</label>
|
||
<div style="display:flex;gap:8px;align-items:center;">
|
||
<select id="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>ASIN / 最低价</label>
|
||
<div id="skipPriceAsinInputs" style="display:flex;flex-direction:column;gap:8px;">
|
||
<div style="color:#999;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;font-size:14px;">导入文件新增</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;font-size:14px;">导入文件删除</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;font-size:15px;">店铺列表</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>
|
||
<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 class="pagination" id="skipPriceAsinPagination"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="panel-query-asin" class="tab-panel">
|
||
<div class="form-box">
|
||
<h3 style="margin-bottom:16px;font-size:15px;">新增查询 ASIN</h3>
|
||
<div class="form-row">
|
||
<div class="form-group" style="min-width:220px;">
|
||
<label>分组</label>
|
||
<div style="display:flex;gap:8px;align-items:center;">
|
||
<select id="queryAsinGroupSelect" style="min-width:150px;">
|
||
<option value="">请选择分组</option>
|
||
</select>
|
||
<button class="btn btn-secondary" id="btnManageQueryAsinGroups" type="button">管理分组</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-group" style="min-width:340px;">
|
||
<label>店铺名</label>
|
||
<div style="display:flex;gap:8px;align-items:center;">
|
||
<input type="text" id="queryAsinShopName" placeholder="请输入店铺名称" style="flex:1;min-width:180px;">
|
||
<button class="btn btn-secondary" id="btnChooseQueryAsinShop" type="button">选择店铺</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-group" style="min-width:220px;">
|
||
<label>国家</label>
|
||
<select id="queryAsinCountries" 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>ASIN</label>
|
||
<div id="queryAsinInputs" style="display:flex;flex-direction:column;gap:8px;">
|
||
<div style="color:#999;font-size:13px;">请选择国家后输入对应 ASIN</div>
|
||
</div>
|
||
</div>
|
||
<button class="btn" id="btnCreateQueryAsin" style="align-self:flex-end;margin-bottom:40px;">新增
|
||
ASIN</button>
|
||
</div>
|
||
<p class="msg" id="msgQueryAsin"></p>
|
||
<div class="form-row"
|
||
style="align-items:flex-start;gap:16px;margin-top:18px;border-top:1px solid #f0f0f0;padding-top:16px;">
|
||
<div style="flex:1;min-width:320px;">
|
||
<h3 style="margin-bottom:12px;font-size:14px;">导入添加</h3>
|
||
<div class="form-row">
|
||
<div class="form-group" style="min-width:320px;">
|
||
<label>上传 Excel(支持两种格式: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;font-size:14px;">导入删除</h3>
|
||
<div class="form-row">
|
||
<div class="form-group" style="min-width:320px;">
|
||
<label>上传 Excel(支持按 分组/店铺名/国家列 或 店铺账号/ASIN/中文国家名 删除;文件无分组列时取页面当前分组)</label>
|
||
<input type="file" id="queryAsinDeleteImportFile" accept=".xlsx,.xls">
|
||
</div>
|
||
<button class="btn btn-danger" id="btnDeleteImportQueryAsin" type="button">上传并删除</button>
|
||
</div>
|
||
<p class="msg" id="msgQueryAsinDeleteImport"></p>
|
||
<div class="progress-wrap" id="queryAsinDeleteImportProgressWrap" style="display:none;">
|
||
<div class="progress-bar">
|
||
<div class="progress-fill" id="queryAsinDeleteImportProgressFill"></div>
|
||
</div>
|
||
<div class="progress-text" id="queryAsinDeleteImportProgressText"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="panel-box">
|
||
<h3 style="margin-bottom:16px;font-size:15px;">店铺列表</h3>
|
||
<div class="form-row" style="margin-bottom:12px;">
|
||
<div class="form-group" style="min-width:180px;">
|
||
<label>分组</label>
|
||
<select id="queryAsinFilterGroupId">
|
||
<option value="">全部分组</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group" style="min-width:220px;">
|
||
<label>店铺名</label>
|
||
<input type="text" id="queryAsinFilterShopName" placeholder="请输入店铺名">
|
||
</div>
|
||
<div class="form-group" style="min-width:220px;">
|
||
<label>ASIN</label>
|
||
<input type="text" id="queryAsinFilterAsin" placeholder="请输入 ASIN">
|
||
</div>
|
||
<button class="btn" id="btnSearchQueryAsin">查询</button>
|
||
<button class="btn btn-secondary" id="btnExportQueryAsin" type="button">导出 XLSX</button>
|
||
</div>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>序号</th>
|
||
<th>分组</th>
|
||
<th>店铺名</th>
|
||
<th>德国</th>
|
||
<th>英国</th>
|
||
<th>法国</th>
|
||
<th>意大利</th>
|
||
<th>西班牙</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="queryAsinListBody"></tbody>
|
||
</table>
|
||
<div class="pagination" id="queryAsinPagination"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="panel-product-categories" class="tab-panel">
|
||
<div class="form-box">
|
||
<h3 style="margin-bottom:16px;font-size:15px;">新增商品类目</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="font-size:15px;">类目树</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>
|
||
<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 id="panel-image-video-tasks" class="tab-panel">
|
||
<div class="form-box">
|
||
<h3 style="margin-bottom:16px;font-size:15px;">视频任务筛选</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-history" class="tab-panel">
|
||
<div class="form-box">
|
||
<h3 style="margin-bottom:16px;font-size:15px;">筛选条件</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;font-size:15px;">生成记录</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>用户</th>
|
||
<th>类型</th>
|
||
<th>创建时间</th>
|
||
<th>结果预览</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="historyListBody"></tbody>
|
||
</table>
|
||
<div class="pagination" id="historyPagination"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 编辑用户弹窗 -->
|
||
<div class="modal-mask" id="editUserModal">
|
||
<div class="modal">
|
||
<h3>编辑用户</h3>
|
||
<input type="hidden" id="editUserId">
|
||
<div class="form-group">
|
||
<label>用户名</label>
|
||
<input type="text" id="editUsername" readonly style="background:#f5f5f5;">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>新密码(不修改可留空)</label>
|
||
<input type="password" id="editPassword" placeholder="留空则不修改密码">
|
||
</div>
|
||
<div class="form-group" id="editFormGroupRole" style="display:none;">
|
||
<label>角色</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:#f5f5f5;">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>菜单权限(可多选,Ctrl/Shift 点选)</label>
|
||
<div id="editColumnCards" class="column-permission-cards"></div>
|
||
<select id="editColumnPermissionWrap" class="column-permission-select" multiple></select>
|
||
</div>
|
||
<p class="msg" id="msgEdit"></p>
|
||
<div style="margin-top:16px;display:flex;gap:8px;">
|
||
<button class="btn" id="btnSaveUser">保存</button>
|
||
<button class="btn btn-secondary" id="btnCloseEdit">取消</button>
|
||
</div>
|
||
</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>
|
||
<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">
|
||
<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>
|
||
<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>
|
||
<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:#f5f5f5;">
|
||
</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:#f5f5f5;">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>国家</label>
|
||
<input type="text" id="editSkipPriceAsinCountryLabel" readonly style="background:#f5f5f5;">
|
||
</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:#f5f5f5;">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>国家</label>
|
||
<input type="text" id="editQueryAsinCountryLabel" readonly style="background:#f5f5f5;">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>ASIN</label>
|
||
<input type="text" id="editQueryAsinValue" placeholder="请输入 ASIN">
|
||
</div>
|
||
<p class="msg" id="msgEditQueryAsin"></p>
|
||
<div style="margin-top:16px;display:flex;gap:8px;">
|
||
<button class="btn" id="btnSaveQueryAsin">保存</button>
|
||
<button class="btn btn-secondary" id="btnCloseEditQueryAsin">取消</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="modal-mask" id="editShopManageModal">
|
||
<div class="modal">
|
||
<h3>编辑店铺</h3>
|
||
<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="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="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>
|
||
<script src="/static/admin.js?v=dedupe-groups-1"></script>
|
||
</body>
|
||
|
||
</html>
|