From 71e0fe40a97ebb502b7e037b0c330726a7f157a1 Mon Sep 17 00:00:00 2001 From: liumangmang Date: Wed, 1 Jul 2026 15:47:51 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=8C=89=E7=85=A7=E6=96=B0?= =?UTF-8?q?=E7=89=88=20ui=5Fredesign=5Fprototype.html=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=BB=91=E5=AE=9A=E6=8A=BD=E5=B1=89=E5=92=8C?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E4=B8=8A=E6=B8=B8=E5=88=86=E7=BB=84=E5=BC=B9?= =?UTF-8?q?=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/views/Websites.vue | 793 ++++++++++++++++++++++---------- 1 file changed, 561 insertions(+), 232 deletions(-) diff --git a/frontend/src/views/Websites.vue b/frontend/src/views/Websites.vue index ab77ef9..a301e30 100644 --- a/frontend/src/views/Websites.vue +++ b/frontend/src/views/Websites.vue @@ -206,65 +206,112 @@ - + - - - +
+ + + +
- - - +
+ + + +
+ -
- 已选 {{ sourceGroupKeys.length }} 个上游分组 - 选择分组 + +
+
+
+ 已选 {{ sourceGroupKeys.length }} 个上游分组 +
+ +

暂无选择,请点击按钮进行选择

+ +
+ + {{ getGroupLabel(key) }} + +
+
+
-
- - {{ getGroupLabel(key) }} - -
-
暂无选择,请点击按钮进行选择
+ + - - - - - +
+ + + + + +
- +
+ + + +
- + + +
+ +
+
- +
- +
上游站点
-
全部上游 - {{ upstreamGroupOptions.length }} -
-
{{ upstreamGroupOptions.length }} + +
+ {{ upstream.name }} + {{ upstreamCounts[upstream.id] || 0 }} +
- +
- 可选分组列表 (已选 {{ tempSelectedKeys.filter(k => filteredGroupsForModal.some(g => g.key === k)).length }}/{{ filteredGroupsForModal.length }}) + 可选分组列表 (已选 {{ tempSelectedKeys.filter(k => filteredGroupsForModal.some(g => g.key === k)).length }}/{{ filteredGroupsForModal.length }})
@@ -320,62 +370,63 @@ v-else v-for="item in filteredGroupsForModal" :key="item.key" - class="group-row-item" + class="group-card-item" :class="{ selected: tempSelectedKeys.includes(item.key) }" @click="toggleGroupKey(item.key)" > - -
-
- {{ item.source.upstream_name }} - - 倍率: {{ item.rate }} - -
-
- {{ item.source.group_name }} - ID: {{ item.source.group_id }} +
+ +
+
+ {{ item.source.upstream_name }} + ID: {{ item.source.group_id }} +
+

{{ item.source.group_name }}

+
+ 倍率: + {{ formatRate(item.rate) }} +
- +
已选分组 ({{ tempSelectedKeys.length }}) - 清空 +
- 暂无选定分组 + +

暂无选定分组

-
- - {{ getGroupDetails(key)?.source.upstream_name }} - - - {{ getGroupDetails(key)?.source.group_name }} - +
+

+ {{ getGroupDetails(key)?.source.upstream_name }} · ID {{ getGroupDetails(key)?.source.group_id }} +

+
{{ getGroupDetails(key)?.source.group_name }}
-
- {{ key }} +
+
{{ key }}
- - - +
@@ -661,7 +712,7 @@ import { computed, onMounted, ref } from 'vue' import { ElMessage, ElMessageBox } from 'element-plus' import type { FormInstance } from 'element-plus' import dayjs from 'dayjs' -import { ArrowDown, Delete, Edit, Plus, Grid, Connection, Link, Upload, Key, Refresh, Sort, WarningFilled, Search, Close } from '@element-plus/icons-vue' +import { ArrowDown, Delete, Edit, Plus, Minus, Grid, Connection, Link, Upload, Key, Refresh, Sort, WarningFilled, Search, Close } from '@element-plus/icons-vue' import { upstreamsApi, websitesApi, @@ -1281,6 +1332,19 @@ function confirmGroupSelection() { groupSelectVisible.value = false } +function adjustPercent(amount: number) { + let val = Number(bindingForm.value.percent) || 0 + val = Math.max(0, val + amount) + bindingForm.value.percent = Number(val.toFixed(2)) +} + +function formatRate(rate: string | number) { + if (typeof rate === 'number') return rate.toFixed(2) + const parsed = parseFloat(String(rate)) + if (!isNaN(parsed)) return parsed.toFixed(2) + return rate +} + async function syncBinding(row: GroupBindingData & { _syncing?: boolean }) { row._syncing = true @@ -1726,66 +1790,276 @@ onMounted(loadAll) } /* Custom group selector layout styles */ -.selected-groups-summary { +.custom-selector-container { display: flex; - justify-content: space-between; align-items: center; - padding: 8px 12px; - background: rgba(255, 244, 232, 0.02); - border: 1px solid var(--border-color); - border-radius: 8px; - margin-bottom: 8px; + justify-content: space-between; + gap: 16px; + padding: 12px; + background: #160c0a; + border: 1px solid #3e2821; + border-radius: 6px; } -.summary-text { - font-size: 13px; - color: var(--text-secondary); +.selector-info-area { + flex: 1; + min-width: 0; } -.highlight-text { - color: var(--color-primary-strong); +.selected-count-line { + font-size: 12px; + color: #a68d85; +} + +.accent-bold-text { + color: #df9b56; font-weight: 700; } -.selected-tags-box { +.empty-placeholder-text { + font-size: 12px; + color: rgba(166, 141, 133, 0.6); + margin-top: 4px; +} + +.tags-container-inline { display: flex; flex-wrap: wrap; gap: 6px; - padding: 10px; - background: rgba(0, 0, 0, 0.1); - border: 1px solid var(--border-color); - border-radius: 8px; - max-height: 140px; - overflow-y: auto; + margin-top: 8px; } -.group-tag { - background: rgba(217, 139, 66, 0.08) !important; - border-color: rgba(217, 139, 66, 0.2) !important; - color: var(--color-primary-strong) !important; +.custom-inline-tag { + background: rgba(223, 155, 86, 0.08) !important; + border-color: rgba(223, 155, 86, 0.2) !important; + color: #df9b56 !important; max-width: 100%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; } -.no-groups-hint { +.btn-select-trigger { + padding: 8px 16px; + background: #df9b56; + color: #1b110e; + border: none; font-size: 12px; - color: var(--text-muted); + font-weight: 700; + border-radius: 4px; + cursor: pointer; + transition: background 0.2s; + flex-shrink: 0; +} + +.btn-select-trigger:hover { + background: #cb8440; +} + +/* Custom Stepper Input */ +.custom-percent-stepper { + display: flex; + border: 1px solid #3e2821; + border-radius: 4px; + background: #160c0a; + overflow: hidden; + height: 36px; + align-items: center; + width: 100%; +} + +.stepper-btn { + width: 36px; + height: 100%; + border: none; + background: transparent; + color: #a68d85; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s; +} + +.stepper-btn:hover { + background: #271a16; + color: #f5ecea; +} + +.stepper-input { + flex: 1; + border: none; + background: transparent; text-align: center; - padding: 12px; - border: 1px dashed var(--border-color); + font-size: 13px; + color: #f5ecea; + outline: none; + width: 100%; +} + +.stepper-input::-webkit-inner-spin-button, +.stepper-input::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; +} + +/* Custom Switch Toggle */ +.switch-toggle-line { + display: flex; + align-items: center; + min-height: 36px; +} + +.custom-switch-toggle { + width: 48px; + height: 24px; + border-radius: 12px; + background: #160c0a; + border: 1px solid #3e2821; + padding: 2px; + cursor: pointer; + display: flex; + align-items: center; + position: relative; + transition: all 0.2s; +} + +.custom-switch-toggle.active { + border-color: #df9b56; +} + +.toggle-circle { + width: 18px; + height: 18px; + border-radius: 50%; + background: #a68d85; + transition: transform 0.2s, background-color 0.2s; + transform: translateX(0); +} + +.custom-switch-toggle.active .toggle-circle { + transform: translateX(24px); + background: #df9b56; +} + +/* Redesigned Button Actions */ +.btn-cancel, .btn-save { + font-size: 12px; + font-weight: 700; + border-radius: 4px; + border: none !important; + transition: all 0.2s; +} + +.btn-cancel { + background: #f5ecea !important; + color: #1b110e !important; +} + +.btn-cancel:hover { + background: rgba(245, 236, 234, 0.9) !important; +} + +.btn-save { + background: #df9b56 !important; + color: #1b110e !important; +} + +.btn-save:hover { + background: #cb8440 !important; +} + +/* Custom Theme Dialog & Drawer */ +.custom-binding-drawer .el-drawer__body, +.custom-binding-drawer .el-drawer__header, +.custom-binding-drawer .el-drawer__footer { + background: #271a16 !important; + color: #f5ecea !important; +} + +.custom-binding-drawer .el-drawer__header { + border-bottom: 1px solid #3e2821; + margin-bottom: 0; + padding: 16px 20px; +} + +.custom-binding-drawer .el-drawer__title { + color: #f5ecea !important; + font-weight: 700; +} + +.custom-binding-drawer .el-drawer__footer { + border-top: 1px solid #3e2821; + background: rgba(22, 12, 10, 0.3) !important; + padding: 16px 20px; +} + +.custom-binding-drawer .el-form-item__label { + color: #a68d85 !important; + font-size: 12px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +/* Dialog Theme */ +.custom-theme-dialog .el-dialog { + background: #271a16 !important; + border: 1px solid #3e2821; border-radius: 8px; } +.custom-theme-dialog .el-dialog__header { + border-bottom: 1px solid #3e2821; + margin-right: 0; + padding: 16px 20px 12px; +} + +.custom-theme-dialog .el-dialog__title { + color: #f5ecea !important; + font-weight: 700; + font-size: 15px; +} + +.custom-theme-dialog .el-dialog__footer { + border-top: 1px solid #3e2821; + background: rgba(22, 12, 10, 0.3); + padding: 12px 20px; +} + +/* Select Option Input Search box */ +.custom-theme-search .el-input__wrapper { + background: #160c0a !important; + border: 1px solid #3e2821 !important; + box-shadow: none !important; +} + +.custom-theme-search .el-input__inner { + color: #f5ecea !important; + font-size: 12px; +} + +.custom-theme-search .el-input__inner::placeholder { + color: rgba(166, 141, 133, 0.4) !important; +} + +/* Element Select Box Theme */ +.custom-theme-select .el-select__wrapper { + background: #160c0a !important; + border: 1px solid #3e2821 !important; + box-shadow: none !important; +} + +.custom-theme-select .el-select__placeholder { + color: #f5ecea !important; +} + +/* Layout for selectors dialog */ .group-selector-layout { display: grid; - grid-template-columns: 180px 1fr 200px; + grid-template-columns: 180px 1fr 220px; gap: 16px; height: 450px; - border: 1px solid var(--border-color); + border: 1px solid #3e2821; border-radius: 8px; - background: var(--bg-surface); + background: #271a16; overflow: hidden; } @@ -1797,19 +2071,20 @@ onMounted(loadAll) } .left-panel { - border-right: 1px solid var(--border-color); + border-right: 1px solid #3e2821; } + .right-panel { - border-left: 1px solid var(--border-color); + border-left: 1px solid #3e2821; } .panel-header { padding: 10px 14px; - font-size: 13px; + font-size: 12px; font-weight: 600; - color: var(--text-primary); - background: rgba(255, 244, 232, 0.03); - border-bottom: 1px solid var(--border-color); + color: #f5ecea; + background: rgba(22, 12, 10, 0.3); + border-bottom: 1px solid #3e2821; min-height: 38px; display: flex; align-items: center; @@ -1825,157 +2100,210 @@ onMounted(loadAll) padding: 8px; } -/* Left panel items */ -.left-panel .list-item { +/* Left panel sidebar category filters */ +.site-filter-btn { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 12px; - border-radius: 6px; + border-radius: 4px; cursor: pointer; margin-bottom: 4px; - transition: background 0.15s ease; - font-size: 13px; - color: var(--text-secondary); -} - -.left-panel .list-item:hover { - background: rgba(255, 244, 232, 0.04); - color: var(--text-primary); -} - -.left-panel .list-item.active { - background: var(--color-primary-soft); - color: var(--color-primary-strong); - font-weight: 500; -} - -.upstream-name-text { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -/* Middle panel group items */ -.group-row-item { - display: flex; - align-items: center; - gap: 12px; - padding: 10px 12px; - border-radius: 6px; - cursor: pointer; - margin-bottom: 6px; + background: transparent; border: 1px solid transparent; + font-size: 12px; + color: #a68d85; + width: 100%; + text-align: left; transition: all 0.15s ease; } -.group-row-item:hover { - background: rgba(255, 244, 232, 0.03); - border-color: rgba(218, 183, 142, 0.1); +.site-filter-btn:hover { + background: #160c0a; + color: #f5ecea; } -.group-row-item.selected { - background: rgba(217, 139, 66, 0.04); - border-color: rgba(217, 139, 66, 0.15); -} - -.group-row-content { - flex: 1; - min-width: 0; -} - -.row-top, .row-bottom { - display: flex; - justify-content: space-between; - align-items: center; - gap: 8px; -} - -.row-bottom { - margin-top: 4px; -} - -.row-upstream-name { - font-size: 11px; - font-weight: 500; - text-transform: uppercase; - color: var(--text-muted); -} - -.row-rate { - font-size: 11px; - color: var(--text-muted); -} - -.rate-highlight { - color: var(--color-warning); +.site-filter-btn.active { + background: rgba(223, 155, 86, 0.1); + border-color: rgba(223, 155, 86, 0.4); + color: #df9b56; font-weight: 600; } -.row-group-name { - font-size: 13px; - font-weight: 600; - color: var(--text-primary); - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; +.site-count-badge { + background: #160c0a; + color: #a68d85; + padding: 2px 6px; + border-radius: 10px; + font-size: 9px; } -.row-group-id { - font-size: 11px; - color: var(--text-soft); - font-family: monospace; +.site-count-badge.badge-active { + background: #f5ecea; + color: #1b110e; + font-weight: 700; } -/* Right panel selected items */ -.selected-row-item { +/* Middle panel group card items */ +.group-card-item { display: flex; align-items: center; justify-content: space-between; - gap: 8px; - padding: 6px 10px; - background: rgba(255, 244, 232, 0.02); - border: 1px solid var(--border-color); + gap: 12px; + padding: 12px; border-radius: 6px; - margin-bottom: 6px; - font-size: 12px; + cursor: pointer; + margin-bottom: 8px; + background: #160c0a; + border: 1px solid rgba(62, 40, 33, 0.6); + transition: all 0.15s ease; } -.selected-row-info { +.group-card-item:hover { + border-color: #df9b56; +} + +.group-card-item.selected { + background: rgba(223, 155, 86, 0.04); + border-color: #df9b56; +} + +.card-left-part { display: flex; - flex-direction: column; + align-items: center; + gap: 12px; min-width: 0; flex: 1; } -.selected-upstream-name { - font-size: 10px; - color: var(--text-muted); +.card-details-info { + min-width: 0; + flex: 1; +} + +.card-meta-line { + display: flex; + align-items: center; +} + +.card-upstream-badge { + background: rgba(223, 155, 86, 0.1); + color: #df9b56; + padding: 2px 6px; + border-radius: 3px; + font-size: 9px; + font-weight: 700; text-transform: uppercase; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; } -.selected-group-name { - font-weight: 500; - color: var(--text-primary); - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; +.card-id-text { + color: #a68d85; + font-size: 10px; + margin-left: 8px; } -/* Empty Hints */ -.empty-hint-dialog { - text-align: center; - padding: 40px 16px; - color: var(--text-muted); +.card-name-title { font-size: 13px; + color: #f5ecea; + margin-top: 6px; + font-weight: 600; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } -.empty-hint-dialog.small { - padding: 24px 12px; + +.card-right-part { + text-align: right; + flex-shrink: 0; +} + +.card-rate-label { + font-size: 9px; + color: #a68d85; + display: block; +} + +.card-rate-value { + font-size: 13px; + font-weight: 700; + color: #df9b56; +} + +.accent-text-bold { + color: #df9b56; + font-weight: 700; +} + +/* Right panel selected card items */ +.selected-card-item { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + padding: 10px; + background: #160c0a; + border: 1px solid #3e2821; + border-radius: 4px; + margin-bottom: 8px; +} + +.selected-card-info-box { + flex: 1; + min-width: 0; +} + +.selected-card-meta-line { + font-size: 9px; + color: #a68d85; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.selected-card-title-text { font-size: 12px; + color: #f5ecea; + font-weight: 500; + margin-top: 2px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.btn-trash-item { + background: transparent; + border: none; + color: #a68d85; + cursor: pointer; + padding: 4px; + transition: color 0.15s; + display: flex; + align-items: center; + justify-content: center; +} + +.btn-trash-item:hover { + color: #df9b56; +} + +.btn-clear-link { + background: transparent; + border: none; + color: #df9b56; + font-size: 11px; + cursor: pointer; + transition: color 0.15s; +} + +.btn-clear-link:hover { + color: #cb8440; +} + +.empty-layers-icon { + font-size: 24px; + color: rgba(166, 141, 133, 0.2); + margin-bottom: 8px; } /* Responsive dialog styling */ @@ -1990,7 +2318,7 @@ onMounted(loadAll) .left-panel { border-right: none; - border-bottom: 1px solid var(--border-color); + border-bottom: 1px solid #3e2821; max-height: 120px; height: auto; } @@ -2003,9 +2331,10 @@ onMounted(loadAll) padding: 8px; } - .left-panel .list-item { + .left-panel .site-filter-btn { margin-bottom: 0; padding: 4px 10px; + width: auto; } .middle-panel { @@ -2014,7 +2343,7 @@ onMounted(loadAll) .right-panel { border-left: none; - border-top: 1px solid var(--border-color); + border-top: 1px solid #3e2821; max-height: 160px; } }