界面:优化局部切换并统一字体与视觉状态

This commit is contained in:
WuYongJie 2026-07-21 21:54:59 +08:00
parent 72bf5acf7d
commit 0272e07848
15 changed files with 213 additions and 100 deletions

View File

@ -37,6 +37,7 @@ class Menu extends Presenter
return '<li class="group relative pb-2.5 text-sm"> return '<li class="group relative pb-2.5 text-sm">
<a id="' . $this->getId($item) . '" class="' . $this->getClass($item) . ''. $this->getActiveState($item) . '" href="' . $item->getUrl() . '" ' . $item->getAttributes() . '> <a id="' . $this->getId($item) . '" class="' . $this->getClass($item) . ''. $this->getActiveState($item) . '" href="' . $item->getUrl() . '" ' . $item->getAttributes() . '>
' . $this->getIcon($item) . ' ' . $this->getIcon($item) . '
' . $this->getActiveIndicator($item) . '
' . $item->title . ' ' . $item->title . '
<span class="bg-purple absolute h-5 ltr:-right-5 rtl:-left-5 ltr:rounded-tl-lg ltr:rounded-bl-lg rtl:rounded-tr-lg rtl:rounded-br-lg opacity-0 group-hover:opacity-100 transition-all pointer-events-none" style="width: 5px;"></span> <span class="bg-purple absolute h-5 ltr:-right-5 rtl:-left-5 ltr:rounded-tl-lg ltr:rounded-bl-lg rtl:rounded-tr-lg rtl:rounded-br-lg opacity-0 group-hover:opacity-100 transition-all pointer-events-none" style="width: 5px;"></span>
</a> </a>
@ -231,6 +232,15 @@ class Menu extends Presenter
</div>' . PHP_EOL; </div>' . PHP_EOL;
} }
public function getActiveIndicator($item)
{
if (! $item->isActive() || ! empty($item->icon)) {
return '';
}
return '<span class="menu-active-indicator material-icons-round" aria-hidden="true">chevron_right</span>';
}
public function getChevron($item) public function getChevron($item)
{ {
$state = $this->chevronState($item); $state = $this->chevronState($item);

7
presets.js vendored
View File

@ -3,9 +3,10 @@ const defaultTheme = require('tailwindcss/defaultTheme')
const fontFamily = defaultTheme.fontFamily; const fontFamily = defaultTheme.fontFamily;
fontFamily['sans'] = [ fontFamily['sans'] = [
'Quicksand', // <-- Quicksand is default sans font now 'JetBrains Mono',
'system-ui', 'Microsoft YaHei',
// <-- Can provide more font fallbacks here 'PingFang SC',
'monospace',
]; ];
module.exports = { module.exports = {

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -16,9 +16,10 @@ import TaobaoAlipayBills from './../../components/business/TaobaoAlipayBills.vue
import AccountBills from './../../components/business/AccountBills.vue'; import AccountBills from './../../components/business/AccountBills.vue';
const GENERIC_TABS = ['taobao-wechat', 'pinduoduo', 'jd-wallet', 'jd-transactions', 'douyin', 'dewu']; const GENERIC_TABS = ['taobao-wechat', 'pinduoduo', 'jd-wallet', 'jd-transactions', 'douyin', 'dewu'];
const STORE_RECEIVING_TABS = ['taobao-alipay', ...GENERIC_TABS];
function pageContext() { function pageContext(pathname = window.location.pathname) {
const parts = (window.location.pathname || '').split('/').filter(Boolean); const parts = (pathname || '').split('/').filter(Boolean);
const idx = parts.indexOf('workspace'); const idx = parts.indexOf('workspace');
if (idx === -1) { if (idx === -1) {
@ -33,25 +34,22 @@ function pageContext() {
}; };
} }
const { companyId, page, tab } = pageContext(); function resolveComponent(context) {
const alipayBase = context.companyId
const alipayBase = companyId ? `/${context.companyId}/ecommerce-finance/alipay-bills`
? `/${companyId}/ecommerce-finance/alipay-bills`
: '/ecommerce-finance/alipay-bills'; : '/ecommerce-finance/alipay-bills';
const accountBase = context.companyId
const accountBase = companyId ? `/${context.companyId}/ecommerce-finance/account-bills`
? `/${companyId}/ecommerce-finance/account-bills`
: '/ecommerce-finance/account-bills'; : '/ecommerce-finance/account-bills';
function resolveComponent() {
// 店铺收款账户账单 › 淘系支付宝账户(独立实现) // 店铺收款账户账单 › 淘系支付宝账户(独立实现)
if (page === 'store-receiving-bills' && tab === 'taobao-alipay') { if (context.page === 'store-receiving-bills' && context.tab === 'taobao-alipay') {
return { Component: TaobaoAlipayBills, props: { apiBase: alipayBase } }; return { Component: TaobaoAlipayBills, props: { apiBase: alipayBase } };
} }
// 店铺收款账户账单 › 其它账户类型(通用实现) // 店铺收款账户账单 › 其它账户类型(通用实现)
if (page === 'store-receiving-bills' && GENERIC_TABS.indexOf(tab) !== -1) { if (context.page === 'store-receiving-bills' && GENERIC_TABS.indexOf(context.tab) !== -1) {
return { Component: AccountBills, props: { apiBase: accountBase, billType: tab } }; return { Component: AccountBills, props: { apiBase: accountBase, billType: context.tab } };
} }
return null; return null;
@ -60,18 +58,89 @@ function resolveComponent() {
const mount = document.querySelector('.business-blank-page'); const mount = document.querySelector('.business-blank-page');
if (mount) { if (mount) {
const resolved = resolveComponent(); const initialContext = pageContext();
function isStoreReceivingContext(context) {
return context.page === 'store-receiving-bills'
&& STORE_RECEIVING_TABS.indexOf(context.tab) !== -1;
}
function updateActiveTab(tab) {
document.querySelectorAll('.business-tab-link').forEach((link) => {
const linkContext = pageContext(new URL(link.href, window.location.origin).pathname);
const isActive = linkContext.tab === tab;
link.classList.toggle('is-active', isActive);
if (isActive) {
link.setAttribute('aria-current', 'page');
} else {
link.removeAttribute('aria-current');
}
});
}
/* eslint-disable no-new */ /* eslint-disable no-new */
new Vue({ const workspace = new Vue({
el: mount, el: mount,
data: {
context: initialContext,
},
render(h) { render(h) {
const resolved = resolveComponent(this.context);
if (resolved) { if (resolved) {
return h(resolved.Component, { props: resolved.props }); return h(resolved.Component, {
key: this.context.tab,
props: resolved.props,
});
} }
return h('div', { class: 'business-page-empty' }, '该页面尚未实现'); return h('div', { class: 'business-page-empty' }, '该页面尚未实现');
}, },
}); });
function navigate(url, pushState = true) {
const target = new URL(url, window.location.origin);
const nextContext = pageContext(target.pathname);
if (target.origin !== window.location.origin || !isStoreReceivingContext(nextContext)) {
return false;
}
if (pushState && target.pathname !== window.location.pathname) {
window.history.pushState({}, '', `${target.pathname}${target.search}${target.hash}`);
}
workspace.context = nextContext;
updateActiveTab(nextContext.tab);
return true;
}
document.addEventListener('click', (event) => {
const link = event.target.closest('.business-tab-link');
if (!link
|| event.defaultPrevented
|| event.button !== 0
|| event.metaKey
|| event.ctrlKey
|| event.shiftKey
|| event.altKey
) {
return;
}
if (navigate(link.href)) {
event.preventDefault();
}
});
window.addEventListener('popstate', () => {
navigate(window.location.href, false);
});
updateActiveTab(initialContext.tab);
} }

View File

@ -1,6 +1,46 @@
@import url("../../../public/css/third_party/vue-html-editor_custom.css"); @import url("../../../public/css/third_party/vue-html-editor_custom.css");
@import url("../../../public/css/third_party/dropzone_custom.css"); @import url("../../../public/css/third_party/dropzone_custom.css");
@font-face {
font-family: "JetBrains Mono";
src: url("/public/fonts/jetbrains-mono/JetBrainsMono-ExtraLight.woff2") format("woff2");
font-display: swap;
font-style: normal;
font-weight: 200;
}
@font-face {
font-family: "JetBrains Mono";
src: url("/public/fonts/jetbrains-mono/JetBrainsMono-Light.woff2") format("woff2");
font-display: swap;
font-style: normal;
font-weight: 300;
}
@font-face {
font-family: "JetBrains Mono";
src: url("/public/fonts/jetbrains-mono/JetBrainsMono-Regular.woff2") format("woff2");
font-display: swap;
font-style: normal;
font-weight: 400;
}
@font-face {
font-family: "JetBrains Mono";
src: url("/public/fonts/jetbrains-mono/JetBrainsMono-Medium.woff2") format("woff2");
font-display: swap;
font-style: normal;
font-weight: 500;
}
@font-face {
font-family: "JetBrains Mono";
src: url("/public/fonts/jetbrains-mono/JetBrainsMono-Bold.woff2") format("woff2");
font-display: swap;
font-style: normal;
font-weight: 700;
}
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
@ -102,12 +142,12 @@
.menu-scroll::-webkit-scrollbar-track { .menu-scroll::-webkit-scrollbar-track {
border-radius: 10px; border-radius: 10px;
background-color: #fcfcfc; background-color: #EEE9DF;
} }
.menu-scroll::-webkit-scrollbar-thumb { .menu-scroll::-webkit-scrollbar-thumb {
border-radius: 10px; border-radius: 10px;
background-color: #DCE2F9; background-color: #B9954F;
} }
.menu-list ul svg { .menu-list ul svg {
@ -259,8 +299,6 @@
--vip-rail-bg: #050506; --vip-rail-bg: #050506;
--vip-rail-gold: #F2E7C5; --vip-rail-gold: #F2E7C5;
--vip-sidebar-bg: #1D1D1F; --vip-sidebar-bg: #1D1D1F;
--vip-sidebar-text: #F5F0E6;
--vip-sidebar-text-soft: #E7E0D2;
--vip-sidebar-gold: #F0E4BF; --vip-sidebar-gold: #F0E4BF;
--vip-sidebar-gold-soft: #DDD0AA; --vip-sidebar-gold-soft: #DDD0AA;
--vip-sidebar-active: #2A2927; --vip-sidebar-active: #2A2927;
@ -269,6 +307,8 @@
--vip-content-accent-soft: #F7F0DE; --vip-content-accent-soft: #F7F0DE;
--vip-content-accent-dark: #856632; --vip-content-accent-dark: #856632;
--vip-border: #D8D2C7; --vip-border: #D8D2C7;
scrollbar-color: #B9954F #EEE9DF;
scrollbar-width: thin;
} }
body { body {
@ -290,7 +330,7 @@ body {
.finance-theme-sidebar { .finance-theme-sidebar {
background-color: var(--vip-sidebar-bg) !important; background-color: var(--vip-sidebar-bg) !important;
color: var(--vip-sidebar-text); color: var(--vip-sidebar-gold);
} }
.finance-theme-sidebar .text-purple, .finance-theme-sidebar .text-purple,
@ -298,12 +338,12 @@ body {
.finance-theme-sidebar a, .finance-theme-sidebar a,
.finance-theme-sidebar button, .finance-theme-sidebar button,
.finance-theme-sidebar summary { .finance-theme-sidebar summary {
color: var(--vip-sidebar-text) !important; color: var(--vip-sidebar-gold) !important;
} }
.finance-theme-sidebar .menu__submenu a, .finance-theme-sidebar .menu__submenu a,
.finance-theme-sidebar .menu__submenu .text-purple { .finance-theme-sidebar .menu__submenu .text-purple {
color: var(--vip-sidebar-text-soft) !important; color: var(--vip-sidebar-gold) !important;
} }
.finance-theme-sidebar .material-icons, .finance-theme-sidebar .material-icons,
@ -312,6 +352,11 @@ body {
color: var(--vip-sidebar-gold) !important; color: var(--vip-sidebar-gold) !important;
} }
.finance-theme-toggle,
.finance-theme-toggle .material-icons {
color: var(--vip-sidebar-gold) !important;
}
.finance-theme-sidebar .main-menu .menu__submenu a, .finance-theme-sidebar .main-menu .menu__submenu a,
.finance-theme-sidebar .main-menu .menu__submenu summary > div { .finance-theme-sidebar .main-menu .menu__submenu summary > div {
font-size: 0.75rem !important; font-size: 0.75rem !important;
@ -326,6 +371,22 @@ body {
border-radius: 0.25rem; border-radius: 0.25rem;
} }
.finance-theme-sidebar .menu-active-indicator {
display: inline-flex;
flex: 0 0 auto;
align-items: center;
justify-content: center;
width: 1rem;
height: 1rem;
margin-inline-end: 0.35rem;
border: 1px solid rgba(246, 233, 194, 0.72);
border-radius: 999px;
background-color: rgba(246, 233, 194, 0.14);
color: #F6E9C2 !important;
font-size: 0.875rem !important;
line-height: 1rem !important;
}
.finance-theme-sidebar .main-menu a:hover, .finance-theme-sidebar .main-menu a:hover,
.finance-theme-sidebar .main-menu summary:hover > div { .finance-theme-sidebar .main-menu summary:hover > div {
background-color: rgba(240, 228, 191, 0.10); background-color: rgba(240, 228, 191, 0.10);
@ -366,6 +427,47 @@ body {
background-color: rgba(242, 231, 197, 0.24); background-color: rgba(242, 231, 197, 0.24);
} }
*::-webkit-scrollbar {
width: 8px;
height: 8px;
}
*::-webkit-scrollbar-track {
background-color: #EEE9DF;
}
*::-webkit-scrollbar-thumb {
border: 2px solid #EEE9DF;
border-radius: 999px;
background-color: #B9954F;
}
*::-webkit-scrollbar-thumb:hover {
background-color: #A17D3E;
}
.finance-theme-rail,
.finance-theme-sidebar,
.finance-theme-rail .menu-scroll,
.finance-theme-sidebar.menu-scroll {
scrollbar-color: #D7C58F transparent;
}
.finance-theme-rail::-webkit-scrollbar-track,
.finance-theme-sidebar::-webkit-scrollbar-track,
.finance-theme-rail .menu-scroll::-webkit-scrollbar-track,
.finance-theme-sidebar.menu-scroll::-webkit-scrollbar-track {
background-color: transparent;
}
.finance-theme-rail::-webkit-scrollbar-thumb,
.finance-theme-sidebar::-webkit-scrollbar-thumb,
.finance-theme-rail .menu-scroll::-webkit-scrollbar-thumb,
.finance-theme-sidebar.menu-scroll::-webkit-scrollbar-thumb {
border-color: transparent;
background-color: #D7C58F;
}
.finance-theme-sidebar .bg-purple { .finance-theme-sidebar .bg-purple {
background-color: #F6E9C2 !important; background-color: #F6E9C2 !important;
} }
@ -941,7 +1043,7 @@ form {
body { body {
@apply text-black; @apply text-black;
font-family: "Quicksand", sans-serif; font-family: "JetBrains Mono", "Microsoft YaHei", "PingFang SC", monospace;
height: 100%; height: 100%;
} }

View File

@ -1,16 +1,2 @@
@stack('footer_start') @stack('footer_start')
<footer class="footer container">
<div class="flex flex-col sm:flex-row items-center justify-between lg:mt-20 py-7 text-sm font-light">
<div>
{{ trans('footer.powered') }}:
@if (config('app.offline'))
<span>{{ trans('footer.software') }}</span>
@else
<x-link href="{{ trans('footer.link') }}" target="_blank" override="class">{{ trans('footer.software') }}</x-link>
@endif
&nbsp;<span class="material-icons align-middle text-black-300">code</span>&nbsp;
{{ trans('footer.version') }} {{ version('short') }}
</div>
</div>
</footer>
@stack('footer_end') @stack('footer_end')

View File

@ -250,11 +250,11 @@
@stack('add_new_menu_end') @stack('add_new_menu_end')
<button type="button" class="toggle-button absolute ltr:-right-2 rtl:-left-2 top-8 cursor-pointer transition-opacity ease-in-out z-50"> <button type="button" class="finance-theme-toggle toggle-button absolute ltr:-right-2 rtl:-left-2 top-8 cursor-pointer transition-opacity ease-in-out z-50">
<span class="material-icons text-lg text-purple transform ltr:rotate-90 rtl:-rotate-90 pointer-events-none">expand_circle_down</span> <span class="material-icons text-lg text-purple transform ltr:rotate-90 rtl:-rotate-90 pointer-events-none">expand_circle_down</span>
</button> </button>
<span data-menu-close id="menu-cancel" class="material-icons absolute ltr:-right-2 rtl:-left-1.5 transition-all top-8 text-lg text-purple cursor-pointer z-10 hidden">cancel</span> <span data-menu-close id="menu-cancel" class="finance-theme-toggle material-icons absolute ltr:-right-2 rtl:-left-1.5 transition-all top-8 text-lg text-purple cursor-pointer z-10 hidden">cancel</span>
<div class="fixed w-full h-full invisible lg:hidden js-menu-background" style="background-color: rgba(0, 0, 0, 0.5); z-index: -1;"></div> <div class="fixed w-full h-full invisible lg:hidden js-menu-background" style="background-color: rgba(0, 0, 0, 0.5); z-index: -1;"></div>
</div> </div>

View File

@ -1,12 +1,2 @@
@stack('footer_start') @stack('footer_start')
<footer class="footer">
<div class="lg:absolute bottom-10 ltr:right-6 rtl:left-6 lg:ltr:right-24 lg:rtl:left-24 flex flex-col sm:flex-row items-center justify-end text-sm font-light">
{{ trans('footer.powered') }}:&nbsp;
@if (config('app.offline'))
<span>{{ trans('footer.software') }}</span>
@else
<x-link href="{{ trans('footer.link') }}" target="_blank" override="class">{{ trans('footer.software') }}</x-link>
@endif
</div>
</footer>
@stack('footer_end') @stack('footer_end')

View File

@ -1,15 +1,2 @@
@stack('footer_start') @stack('footer_start')
<footer class="footer container">
<div class="flex flex-col sm:flex-row items-center justify-between lg:mt-20 py-7 text-sm font-light">
<div>
{{ trans('footer.powered') }}:
@if (config('app.offline'))
<span>{{ trans('footer.software') }}</span> |
@else
<a href="{{ trans('footer.link') }}" target="_blank">{{ trans('footer.software') }}</a> |
@endif
{{ trans('footer.version') }} {{ version('short') }}
</div>
</div>
</footer>
@stack('footer_end') @stack('footer_end')

View File

@ -1,18 +1,2 @@
@stack('footer_start') @stack('footer_start')
<footer class="footer container">
<div class="flex flex-col sm:flex-row items-center justify-between lg:mt-20 py-7 text-sm font-light">
<div>
{{ trans('footer.powered') }}:
@if (config('app.offline'))
<span>{{ trans('footer.software') }}</span>
@else
<x-link href="{{ trans('footer.link') }}" target="_blank" override="class">{{ trans('footer.software') }}</x-link>
@endif
&nbsp;<span class="material-icons align-middle text-black-300">code</span>&nbsp;
{{ trans('footer.version') }} {{ version('short') }}
</div>
</div>
</footer>
@stack('footer_end') @stack('footer_end')

View File

@ -1,18 +1,2 @@
@stack('footer_start') @stack('footer_start')
<footer class="footer container">
<div class="flex flex-col sm:flex-row items-center justify-between lg:mt-20 py-7 text-sm font-light">
<div>
{{ trans('footer.powered') }}:
@if (config('app.offline'))
<span>{{ trans('footer.software') }}</span>
@else
<x-link href="{{ trans('footer.link') }}" target="_blank" override="class">{{ trans('footer.software') }}</x-link>
@endif
&nbsp;<span class="material-icons align-middle text-black-300">code</span>&nbsp;
{{ trans('footer.version') }} {{ version('short') }}
</div>
</div>
</footer>
@stack('footer_end') @stack('footer_end')